aboutsummaryrefslogtreecommitdiff
path: root/bindings/node
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-14 19:59:18 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-14 19:59:33 +0100
commit9b7bda28db0200b628e5f6eb7021a5a717db2e73 (patch)
tree2f477b0fe308da3554fbd0ab807c4c4725715311 /bindings/node
Initial grammar
Diffstat (limited to 'bindings/node')
-rw-r--r--bindings/node/binding.cc19
-rw-r--r--bindings/node/binding_test.js11
-rw-r--r--bindings/node/index.d.ts60
-rw-r--r--bindings/node/index.js37
4 files changed, 127 insertions, 0 deletions
diff --git a/bindings/node/binding.cc b/bindings/node/binding.cc
new file mode 100644
index 0000000..03bd34c
--- /dev/null
+++ b/bindings/node/binding.cc
@@ -0,0 +1,19 @@
+#include <napi.h>
+
+typedef struct TSLanguage TSLanguage;
+
+extern "C" TSLanguage *tree_sitter_wmap();
+
+// "tree-sitter", "language" hashed with BLAKE2
+const napi_type_tag LANGUAGE_TYPE_TAG = {
+ 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
+};
+
+Napi::Object Init(Napi::Env env, Napi::Object exports) {
+ auto language = Napi::External<TSLanguage>::New(env, tree_sitter_wmap());
+ language.TypeTag(&LANGUAGE_TYPE_TAG);
+ exports["language"] = language;
+ return exports;
+}
+
+NODE_API_MODULE(tree_sitter_wmap_binding, Init)
diff --git a/bindings/node/binding_test.js b/bindings/node/binding_test.js
new file mode 100644
index 0000000..7a91a84
--- /dev/null
+++ b/bindings/node/binding_test.js
@@ -0,0 +1,11 @@
+import assert from "node:assert";
+import { test } from "node:test";
+import Parser from "tree-sitter";
+
+test("can load grammar", () => {
+ const parser = new Parser();
+ assert.doesNotReject(async () => {
+ const { default: language } = await import("./index.js");
+ parser.setLanguage(language);
+ });
+});
diff --git a/bindings/node/index.d.ts b/bindings/node/index.d.ts
new file mode 100644
index 0000000..876252a
--- /dev/null
+++ b/bindings/node/index.d.ts
@@ -0,0 +1,60 @@
+type BaseNode = {
+ type: string;
+ named: boolean;
+};
+
+type ChildNode = {
+ multiple: boolean;
+ required: boolean;
+ types: BaseNode[];
+};
+
+type NodeInfo =
+ | (BaseNode & {
+ subtypes: BaseNode[];
+ })
+ | (BaseNode & {
+ fields: { [name: string]: ChildNode };
+ children: ChildNode[];
+ });
+
+/**
+ * The tree-sitter language object for this grammar.
+ *
+ * @see {@linkcode https://tree-sitter.github.io/node-tree-sitter/interfaces/Parser.Language.html Parser.Language}
+ *
+ * @example
+ * import Parser from "tree-sitter";
+ * import Wmap from "tree-sitter-wmap";
+ *
+ * const parser = new Parser();
+ * parser.setLanguage(Wmap);
+ */
+declare const binding: {
+ /**
+ * The inner language object.
+ * @private
+ */
+ language: unknown;
+
+ /**
+ * The content of the `node-types.json` file for this grammar.
+ *
+ * @see {@linkplain https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types Static Node Types}
+ */
+ nodeTypeInfo: NodeInfo[];
+
+ /** The syntax highlighting query for this grammar. */
+ HIGHLIGHTS_QUERY?: string;
+
+ /** The language injection query for this grammar. */
+ INJECTIONS_QUERY?: string;
+
+ /** The local variable query for this grammar. */
+ LOCALS_QUERY?: string;
+
+ /** The symbol tagging query for this grammar. */
+ TAGS_QUERY?: string;
+};
+
+export default binding;
diff --git a/bindings/node/index.js b/bindings/node/index.js
new file mode 100644
index 0000000..efa6bea
--- /dev/null
+++ b/bindings/node/index.js
@@ -0,0 +1,37 @@
+import { readFileSync } from "node:fs";
+import { fileURLToPath } from "node:url";
+
+const root = fileURLToPath(new URL("../..", import.meta.url));
+
+const binding = typeof process.versions.bun === "string"
+ // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time
+ ? await import(`${root}/prebuilds/${process.platform}-${process.arch}/tree-sitter-wmap.node`)
+ : (await import("node-gyp-build")).default(root);
+
+try {
+ const nodeTypes = await import(`${root}/src/node-types.json`, { with: { type: "json" } });
+ binding.nodeTypeInfo = nodeTypes.default;
+} catch { }
+
+const queries = [
+ ["HIGHLIGHTS_QUERY", `${root}/queries/highlights.scm`],
+ ["INJECTIONS_QUERY", `${root}/queries/injections.scm`],
+ ["LOCALS_QUERY", `${root}/queries/locals.scm`],
+ ["TAGS_QUERY", `${root}/queries/tags.scm`],
+];
+
+for (const [prop, path] of queries) {
+ Object.defineProperty(binding, prop, {
+ configurable: true,
+ enumerable: true,
+ get() {
+ delete binding[prop];
+ try {
+ binding[prop] = readFileSync(path, "utf8");
+ } catch { }
+ return binding[prop];
+ }
+ });
+}
+
+export default binding;