diff --git a/lib/binding_web/binding.c b/lib/binding_web/binding.c index 9180f405..d020da7c 100644 --- a/lib/binding_web/binding.c +++ b/lib/binding_web/binding.c @@ -184,6 +184,20 @@ TSTree *ts_parser_parse_wasm( return ts_parser_parse(self, old_tree, input); } +/**********************/ +/* Section - Language */ +/**********************/ + +int ts_language_type_is_named_wasm(const TSLanguage *self, TSSymbol typeId) { + const TSSymbolType symbolType = ts_language_symbol_type(self, typeId); + return symbolType == TSSymbolTypeRegular; +} + +int ts_language_type_is_visible_wasm(const TSLanguage *self, TSSymbol typeId) { + const TSSymbolType symbolType = ts_language_symbol_type(self, typeId); + return symbolType <= TSSymbolTypeAnonymous; +} + /******************/ /* Section - Tree */ /******************/ diff --git a/lib/binding_web/binding.js b/lib/binding_web/binding.js index 47d72742..b2b3c73b 100644 --- a/lib/binding_web/binding.js +++ b/lib/binding_web/binding.js @@ -646,6 +646,32 @@ class Language { return this.fields[fieldId] || null; } + idForNodeType(type, named) { + const typeLength = lengthBytesUTF8(type); + const typeAddress = C._malloc(typeLength + 1); + stringToUTF8(type, typeAddress, typeLength + 1); + const result = C._ts_language_symbol_for_name(this[0], typeAddress, typeLength, named); + C._free(typeAddress); + return result; + } + + get nodeTypeCount() { + return C._ts_language_symbol_count(this[0]); + } + + nodeTypeForId(typeId) { + const name = C._ts_language_symbol_name(this[0], typeId); + return name ? UTF8ToString(name) : null; + } + + nodeTypeIsNamed(typeId) { + return C._ts_language_type_is_named_wasm(this[0], typeId) ? true : false; + } + + nodeTypeIsVisible(typeId) { + return C._ts_language_type_is_visible_wasm(this[0], typeId) ? true : false; + } + query(source) { const sourceLength = lengthBytesUTF8(source); const sourceAddress = C._malloc(sourceLength + 1); diff --git a/lib/binding_web/exports.json b/lib/binding_web/exports.json index d0173f3a..b2b4449d 100644 --- a/lib/binding_web/exports.json +++ b/lib/binding_web/exports.json @@ -31,7 +31,10 @@ "_ts_init", "_ts_language_field_count", "_ts_language_field_name_for_id", + "_ts_language_type_is_named_wasm", + "_ts_language_type_is_visible_wasm", "_ts_language_symbol_count", + "_ts_language_symbol_for_name", "_ts_language_symbol_name", "_ts_language_symbol_type", "_ts_language_version", diff --git a/lib/binding_web/test/language-test.js b/lib/binding_web/test/language-test.js new file mode 100644 index 00000000..691a7ae7 --- /dev/null +++ b/lib/binding_web/test/language-test.js @@ -0,0 +1,97 @@ +const { assert } = require("chai"); +let JavaScript; + +describe("Language", () => { + before(async () => ({ JavaScript } = await require("./helper"))); + + describe(".fieldCount", () => { + it("returns a number", () => { + assert.equal(34, JavaScript.fieldCount); + }); + }); + + describe(".fieldIdForName", () => { + it("returns null, if not defined", () => { + const fieldName = "nonExistentFieldName"; + assert.equal(null, JavaScript.fieldIdForName(fieldName)); + }); + + it("returns a number, if defined", () => { + const fieldName = "decorator"; + assert.equal(12, JavaScript.fieldIdForName(fieldName)); + }); + }); + + describe(".fieldNameForId", () => { + it("returns null, if not defined", () => { + const fieldId = -1; + assert.equal(null, JavaScript.fieldNameForId(fieldId)); + }); + + it("returns a string, if defined", () => { + const fieldId = 12; + assert.equal("decorator", JavaScript.fieldNameForId(fieldId)); + }); + }); + + describe(".idForNodeType", () => { + it("returns a number", () => { + const type = "export_statement"; + const named = true; + assert.equal(125, JavaScript.idForNodeType(type, named)); + }); + }); + + describe(".nodeTypeCount", () => { + it("returns a number", () => { + assert.equal(239, JavaScript.nodeTypeCount); + }); + }); + + describe(".nodeTypeForId", () => { + it("returns null, if not defined", () => { + const typeId = -1; + assert.equal(null, JavaScript.nodeTypeForId(typeId)); + }); + + it("returns a string, if not defined", () => { + const typeId = 125; + assert.equal("export_statement", JavaScript.nodeTypeForId(typeId)); + }); + }); + + describe(".nodeTypeIsNamed", () => { + it("returns false, if node type is not named", () => { + const typeId = 4; + assert.equal("*", JavaScript.nodeTypeForId(typeId)); + assert.equal(false, JavaScript.nodeTypeIsNamed(typeId)); + }); + + it("returns true, if node type is named", () => { + const typeId = 125; + assert.equal("export_statement", JavaScript.nodeTypeForId(typeId)); + assert.equal(true, JavaScript.nodeTypeIsNamed(typeId)); + }); + }); + + describe(".nodeTypeIsVisible", () => { + it("returns false, if node type is not visible", () => { + let typeId; + typeId = 100; + assert.equal(false, JavaScript.nodeTypeIsVisible(typeId)); + typeId = 102; + assert.equal(false, JavaScript.nodeTypeIsVisible(typeId)); + }); + + it("returns true, if node type is visible", () => { + const typeId = 101; + assert.equal(true, JavaScript.nodeTypeIsVisible(typeId)); + }); + }); + + describe(".version", () => { + it("returns a number", () => { + assert.equal(12, JavaScript.version); + }); + }); +}); diff --git a/lib/binding_web/tree-sitter-web.d.ts b/lib/binding_web/tree-sitter-web.d.ts index 172d2cd6..2127fa41 100644 --- a/lib/binding_web/tree-sitter-web.d.ts +++ b/lib/binding_web/tree-sitter-web.d.ts @@ -131,9 +131,14 @@ declare module 'web-tree-sitter' { readonly version: number; readonly fieldCount: number; + readonly nodeTypeCount: number; fieldNameForId(fieldId: number): string | null; fieldIdForName(fieldName: string): number | null; + idForNodeType(type: string, named: boolean): number; + nodeTypeForId(typeId: number): string | null; + nodeTypeIsNamed(typeId: number): boolean; + nodeTypeIsVisible(typeId: number): boolean; query(source: string): Query; }