diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-dart.ts b/src/services/tree-sitter/__tests__/fixtures/sample-dart.ts new file mode 100644 index 0000000000..e5ad987da7 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-dart.ts @@ -0,0 +1,58 @@ +export default `abstract class Animal { + String speak(); +} + +class Point { + const Point(); + Point.named(); + factory Point.origin() => const Point(); + + int get x => 0; + set x(int value) {} + + Point operator +(Point other) => this; +} + +mixin Runner { + void run() { + print("running"); + } +} + +enum Status { + ready, + running; + + const Status(); +} + +class Dog extends Animal with Runner { + final String name; + + Dog(this.name); + + @override + String speak() { + return "\$name barks"; + } +} + +extension StringTools on String { + String doubled() { + return this + this; + } +} + +extension type UserId(int value) { + UserId.zero() : value = 0; +} + +typedef Operation = int Function(int left, int right); + +int get answer => 42; +set answer(int value) {} + +int add(int left, int right) { + return left + right; +} +` diff --git a/src/services/tree-sitter/__tests__/languageParser.spec.ts b/src/services/tree-sitter/__tests__/languageParser.spec.ts index 9bf9ecc881..fe4dcdb2d9 100644 --- a/src/services/tree-sitter/__tests__/languageParser.spec.ts +++ b/src/services/tree-sitter/__tests__/languageParser.spec.ts @@ -49,6 +49,12 @@ describe("loadRequiredLanguageParsers", () => { expect(parsers.kts.query).toBeDefined() }) + it("should load Dart parser for .dart files", async () => { + const parsers = await loadRequiredLanguageParsers(["test.dart"], WASM_DIR) + expect(parsers.dart).toBeDefined() + expect(parsers.dart.query).toBeDefined() + }) + it("should throw error for unsupported file extensions", async () => { const files = ["test.unsupported"] await expect(loadRequiredLanguageParsers(files, WASM_DIR)).rejects.toThrow("Unsupported language: unsupported") diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.dart.spec.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.dart.spec.ts new file mode 100644 index 0000000000..31d84dcd07 --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.dart.spec.ts @@ -0,0 +1,36 @@ +import { dartQuery } from "../queries" +import { testParseSourceCodeDefinitions } from "./helpers" +import sampleDartContent from "./fixtures/sample-dart" + +const dartOptions = { + language: "dart", + wasmFile: "tree-sitter-dart.wasm", + queryString: dartQuery, + extKey: "dart", +} + +describe("parseSourceCodeDefinitionsForFile with Dart", () => { + it("should capture common Dart declarations", async () => { + const result = await testParseSourceCodeDefinitions("/test/file.dart", sampleDartContent, dartOptions) + + expect(result).toMatch(/abstract class Animal/) + expect(result).toMatch(/class Point/) + expect(result).toMatch(/const Point\(\)/) + expect(result).toMatch(/Point\.named\(\)/) + expect(result).toMatch(/factory Point\.origin\(\)/) + expect(result).toMatch(/int get x/) + expect(result).toMatch(/set x\(int value\)/) + expect(result).toMatch(/Point operator \+/) + expect(result).toMatch(/mixin Runner/) + expect(result).toMatch(/enum Status/) + expect(result).toMatch(/const Status\(\)/) + expect(result).toMatch(/class Dog extends Animal with Runner/) + expect(result).toMatch(/extension StringTools on String/) + expect(result).toMatch(/extension type UserId/) + expect(result).toMatch(/typedef Operation/) + expect(result).toMatch(/int get answer/) + expect(result).toMatch(/set answer\(int value\)/) + expect(result).toMatch(/String speak\(\)/) + expect(result).toMatch(/int add\(int left, int right\)/) + }) +}) diff --git a/src/services/tree-sitter/index.ts b/src/services/tree-sitter/index.ts index 3c124e5b74..73dd712c64 100644 --- a/src/services/tree-sitter/index.ts +++ b/src/services/tree-sitter/index.ts @@ -90,6 +90,8 @@ const extensions = [ "erb", // Visual Basic .NET "vb", + // Dart + "dart", ].map((e) => `.${e}`) export { extensions } diff --git a/src/services/tree-sitter/languageParser.ts b/src/services/tree-sitter/languageParser.ts index a8ac0a9ead..b7faf2cdba 100644 --- a/src/services/tree-sitter/languageParser.ts +++ b/src/services/tree-sitter/languageParser.ts @@ -28,6 +28,7 @@ import { embeddedTemplateQuery, elispQuery, elixirQuery, + dartQuery, } from "./queries" export interface LanguageParser { @@ -218,6 +219,10 @@ export async function loadRequiredLanguageParsers(filesToParse: string[], source language = await loadLanguage("elixir", sourceDirectory) query = new Query(language, elixirQuery) break + case "dart": + language = await loadLanguage("dart", sourceDirectory) + query = new Query(language, dartQuery) + break default: throw new Error(`Unsupported language: ${ext}`) } diff --git a/src/services/tree-sitter/queries/dart.ts b/src/services/tree-sitter/queries/dart.ts new file mode 100644 index 0000000000..ea59e7dc40 --- /dev/null +++ b/src/services/tree-sitter/queries/dart.ts @@ -0,0 +1,65 @@ +// Definition captures adapted from tree-sitter-dart's canonical tags query: +// https://github.com/UserNobody14/tree-sitter-dart/blob/master/queries/tags.scm +export default ` +(class_definition + name: (identifier) @name) @definition.class + +(method_signature + (function_signature)) @definition.method + +(type_alias + (type_identifier) @name) @definition.type + +(method_signature + (getter_signature + name: (identifier) @name)) @definition.method + +(method_signature + (setter_signature + name: (identifier) @name)) @definition.method + +(method_signature + (function_signature + name: (identifier) @name)) @definition.method + +(method_signature + (factory_constructor_signature + (identifier) @name)) @definition.method + +(method_signature + (constructor_signature + name: (identifier) @name)) @definition.method + +(method_signature + (operator_signature)) @definition.method + +(constructor_signature + name: (identifier) @name) @definition.method + +(constant_constructor_signature + (identifier) @name) @definition.method + +(mixin_declaration + (mixin) + (identifier) @name) @definition.mixin + +(extension_declaration + name: (identifier) @name) @definition.extension + +(extension_type_declaration + name: (identifier) @name) @definition.extension + +(enum_declaration + name: (identifier) @name) @definition.enum + +(program + (getter_signature + name: (identifier) @name) @definition.function) + +(program + (setter_signature + name: (identifier) @name) @definition.function) + +(function_signature + name: (identifier) @name) @definition.function +` diff --git a/src/services/tree-sitter/queries/index.ts b/src/services/tree-sitter/queries/index.ts index de9b9cafa3..0faa256269 100644 --- a/src/services/tree-sitter/queries/index.ts +++ b/src/services/tree-sitter/queries/index.ts @@ -26,3 +26,4 @@ export { zigQuery } from "./zig" export { default as embeddedTemplateQuery } from "./embedded_template" export { elispQuery } from "./elisp" export { scalaQuery } from "./scala" +export { default as dartQuery } from "./dart"