@opensip-cli/tree-sitter 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/__tests__/query.test.d.ts +14 -0
- package/dist/__tests__/query.test.d.ts.map +1 -0
- package/dist/__tests__/query.test.js +133 -0
- package/dist/__tests__/query.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +7 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +24 -2
- package/dist/lifecycle.js.map +1 -1
- package/dist/query.d.ts +107 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +120 -0
- package/dist/query.js.map +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@ This package is published for the CLI and advanced plugin authors; most users sh
|
|
|
23
23
|
## Documentation
|
|
24
24
|
|
|
25
25
|
- 📚 Project docs: https://opensip.ai/docs/opensip-cli/
|
|
26
|
-
- 🧭 Package catalog (what every package does): https://github.com/opensip-ai/opensip-cli/blob/v0.1.
|
|
27
|
-
- 📦 Source: https://github.com/opensip-ai/opensip-cli/tree/v0.1.
|
|
26
|
+
- 🧭 Package catalog (what every package does): https://github.com/opensip-ai/opensip-cli/blob/v0.1.9/docs/public/70-reference/02-package-catalog.md
|
|
27
|
+
- 📦 Source: https://github.com/opensip-ai/opensip-cli/tree/v0.1.9/packages/tree-sitter
|
|
28
28
|
|
|
29
29
|
## License
|
|
30
30
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the shared `createTreeSitterQuery` factory (ADR-0010, M10).
|
|
3
|
+
*
|
|
4
|
+
* The tree-sitter package ships no grammar (the `.wasm` lives in each `lang-*`
|
|
5
|
+
* adapter), so these tests drive the factory over a hand-built minimal `Node`
|
|
6
|
+
* mock that implements only the surface the factory + `nodes.ts` helpers touch:
|
|
7
|
+
* `type`, `text`, `startPosition`, `namedChildren`, and `childForFieldName`.
|
|
8
|
+
* The per-language extractors are supplied by the config under test, so the
|
|
9
|
+
* generic traversal/assembly is exercised end-to-end. Each `lang-*` adapter
|
|
10
|
+
* additionally exercises the factory through its real grammar in its own
|
|
11
|
+
* `query.test.ts`.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=query.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/query.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the shared `createTreeSitterQuery` factory (ADR-0010, M10).
|
|
3
|
+
*
|
|
4
|
+
* The tree-sitter package ships no grammar (the `.wasm` lives in each `lang-*`
|
|
5
|
+
* adapter), so these tests drive the factory over a hand-built minimal `Node`
|
|
6
|
+
* mock that implements only the surface the factory + `nodes.ts` helpers touch:
|
|
7
|
+
* `type`, `text`, `startPosition`, `namedChildren`, and `childForFieldName`.
|
|
8
|
+
* The per-language extractors are supplied by the config under test, so the
|
|
9
|
+
* generic traversal/assembly is exercised end-to-end. Each `lang-*` adapter
|
|
10
|
+
* additionally exercises the factory through its real grammar in its own
|
|
11
|
+
* `query.test.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, expect, it } from 'vitest';
|
|
14
|
+
import { createTreeSitterQuery, stripSurroundingQuotes } from '../query.js';
|
|
15
|
+
class MockNode {
|
|
16
|
+
type;
|
|
17
|
+
text;
|
|
18
|
+
startPosition;
|
|
19
|
+
namedChildren;
|
|
20
|
+
namedChildCount;
|
|
21
|
+
fields;
|
|
22
|
+
constructor(spec) {
|
|
23
|
+
this.type = spec.type;
|
|
24
|
+
this.text = spec.text ?? '';
|
|
25
|
+
this.startPosition = { row: spec.row ?? 0, column: spec.column ?? 0 };
|
|
26
|
+
this.namedChildren = spec.children ?? [];
|
|
27
|
+
this.namedChildCount = this.namedChildren.length;
|
|
28
|
+
this.fields = spec.fields ?? {};
|
|
29
|
+
}
|
|
30
|
+
childForFieldName(name) {
|
|
31
|
+
return this.fields[name] ?? null;
|
|
32
|
+
}
|
|
33
|
+
namedChild(i) {
|
|
34
|
+
return this.namedChildren[i] ?? null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// The mock implements only the Node surface the factory + nodes.ts touch; cast
|
|
38
|
+
// at construction so call sites see a real `Node`.
|
|
39
|
+
function node(spec) {
|
|
40
|
+
return new MockNode(spec);
|
|
41
|
+
}
|
|
42
|
+
/** Wrap a root node as a ParsedFile (only `.tree.rootNode` is read). */
|
|
43
|
+
function asTree(root) {
|
|
44
|
+
return { tree: { rootNode: root }, source: '' };
|
|
45
|
+
}
|
|
46
|
+
const baseConfig = {
|
|
47
|
+
functions: { nodeTypes: new Set(['fn']) },
|
|
48
|
+
calls: {
|
|
49
|
+
nodeTypes: new Set(['call']),
|
|
50
|
+
calleeName: (n) => n.childForFieldName('name')?.text ?? null,
|
|
51
|
+
},
|
|
52
|
+
imports: {
|
|
53
|
+
nodeTypes: new Set(['import']),
|
|
54
|
+
extract: (n) => [{ specifier: n.text, names: [n.text.split('.').pop() ?? n.text] }],
|
|
55
|
+
},
|
|
56
|
+
strings: { nodeTypes: new Set(['str']) },
|
|
57
|
+
};
|
|
58
|
+
describe('stripSurroundingQuotes', () => {
|
|
59
|
+
it('strips matched double, single, and backtick quotes', () => {
|
|
60
|
+
expect(stripSurroundingQuotes('"abc"')).toBe('abc');
|
|
61
|
+
expect(stripSurroundingQuotes("'abc'")).toBe('abc');
|
|
62
|
+
expect(stripSurroundingQuotes('`abc`')).toBe('abc');
|
|
63
|
+
});
|
|
64
|
+
it('leaves unquoted / mismatched / too-short text untouched', () => {
|
|
65
|
+
expect(stripSurroundingQuotes('abc')).toBe('abc');
|
|
66
|
+
expect(stripSurroundingQuotes('"abc')).toBe('"abc');
|
|
67
|
+
expect(stripSurroundingQuotes('"')).toBe('"');
|
|
68
|
+
expect(stripSurroundingQuotes('')).toBe('');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('createTreeSitterQuery', () => {
|
|
72
|
+
it('findFunctions returns each function node with its name (null when absent)', () => {
|
|
73
|
+
const named = node({ type: 'fn', row: 1, fields: { name: node({ type: 'id', text: 'foo' }) } });
|
|
74
|
+
const anon = node({ type: 'fn', row: 2 });
|
|
75
|
+
const root = node({ type: 'root', children: [named, anon] });
|
|
76
|
+
const q = createTreeSitterQuery(baseConfig);
|
|
77
|
+
const fns = q.findFunctions(asTree(root));
|
|
78
|
+
expect(fns.map((f) => f.name)).toEqual(['foo', null]);
|
|
79
|
+
expect(fns[0].location).toEqual({ file: '', line: 2, column: 0 });
|
|
80
|
+
expect(fns[0].node).toBe(named);
|
|
81
|
+
});
|
|
82
|
+
it('findFunctions honours a custom nameOf', () => {
|
|
83
|
+
const fn = node({ type: 'fn', text: 'lambda' });
|
|
84
|
+
const root = node({ type: 'root', children: [fn] });
|
|
85
|
+
const q = createTreeSitterQuery({
|
|
86
|
+
...baseConfig,
|
|
87
|
+
functions: { nodeTypes: new Set(['fn']), nameOf: () => null },
|
|
88
|
+
});
|
|
89
|
+
expect(q.findFunctions(asTree(root))[0].name).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
it('findImports expands each import node into targets', () => {
|
|
92
|
+
const imp = node({ type: 'import', text: 'a.b.C', row: 3, column: 2 });
|
|
93
|
+
const root = node({ type: 'root', children: [imp] });
|
|
94
|
+
const q = createTreeSitterQuery(baseConfig);
|
|
95
|
+
const imports = q.findImports(asTree(root));
|
|
96
|
+
expect(imports).toEqual([
|
|
97
|
+
{ specifier: 'a.b.C', names: ['C'], location: { file: '', line: 4, column: 2 } },
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
it('findCallsTo matches the leaf callee name', () => {
|
|
101
|
+
const call1 = node({ type: 'call', fields: { name: node({ type: 'id', text: 'foo' }) } });
|
|
102
|
+
const call2 = node({ type: 'call', fields: { name: node({ type: 'id', text: 'bar' }) } });
|
|
103
|
+
const root = node({ type: 'root', children: [call1, call2] });
|
|
104
|
+
const q = createTreeSitterQuery(baseConfig);
|
|
105
|
+
expect(q.findCallsTo(asTree(root), 'foo')).toEqual([call1]);
|
|
106
|
+
expect(q.findCallsTo(asTree(root), 'absent')).toEqual([]);
|
|
107
|
+
});
|
|
108
|
+
it('findStringLiterals uses the default quote-stripping value extractor', () => {
|
|
109
|
+
const str = node({ type: 'str', text: '"hello"', row: 0, column: 5 });
|
|
110
|
+
const root = node({ type: 'root', children: [str] });
|
|
111
|
+
const q = createTreeSitterQuery(baseConfig);
|
|
112
|
+
expect(q.findStringLiterals(asTree(root))).toEqual([
|
|
113
|
+
{ value: 'hello', location: { file: '', line: 1, column: 5 } },
|
|
114
|
+
]);
|
|
115
|
+
});
|
|
116
|
+
it('findStringLiterals honours a custom stringValue', () => {
|
|
117
|
+
const str = node({ type: 'str', text: 'RAW' });
|
|
118
|
+
const root = node({ type: 'root', children: [str] });
|
|
119
|
+
const q = createTreeSitterQuery({
|
|
120
|
+
...baseConfig,
|
|
121
|
+
strings: { nodeTypes: new Set(['str']), stringValue: (n) => `<${n.text}>` },
|
|
122
|
+
});
|
|
123
|
+
expect(q.findStringLiterals(asTree(root))[0].value).toBe('<RAW>');
|
|
124
|
+
});
|
|
125
|
+
it('getLocation / getText read position and text from the node', () => {
|
|
126
|
+
const n = node({ type: 'x', text: 'body', row: 7, column: 3 });
|
|
127
|
+
const q = createTreeSitterQuery(baseConfig);
|
|
128
|
+
const tree = asTree(node({ type: 'root' }));
|
|
129
|
+
expect(q.getLocation(tree, n)).toEqual({ file: '', line: 8, column: 3 });
|
|
130
|
+
expect(q.getText(tree, n)).toBe('body');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=query.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.test.js","sourceRoot":"","sources":["../../src/__tests__/query.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -15,7 +15,13 @@
|
|
|
15
15
|
* adapter's own top-level `await loadGrammar(<wasm>)`.
|
|
16
16
|
*/
|
|
17
17
|
import { Parser, Language, type Tree } from 'web-tree-sitter';
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Load a tree-sitter grammar from a `.wasm` path (adapter module top level).
|
|
20
|
+
*
|
|
21
|
+
* @throws {Error} When the web-tree-sitter runtime failed to initialize (the
|
|
22
|
+
* contained `Parser.init()` above) — lang-* adapters catch this and degrade
|
|
23
|
+
* that language to "unavailable" rather than crashing the CLI.
|
|
24
|
+
*/
|
|
19
25
|
export declare function loadGrammar(wasmPath: string): Promise<Language>;
|
|
20
26
|
/**
|
|
21
27
|
* Create a parser bound to `grammar`. Adapters create one per grammar at
|
package/dist/lifecycle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAmB9D;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAIrE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAItD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEvE"}
|
package/dist/lifecycle.js
CHANGED
|
@@ -18,9 +18,31 @@ import { Parser, Language } from 'web-tree-sitter';
|
|
|
18
18
|
// One-time WASM runtime init. Top-level await — every consumer statically
|
|
19
19
|
// imports this module — guarantees the runtime is ready before any adapter's
|
|
20
20
|
// `loadGrammar(<wasm>)` (which also runs at module top level).
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Contained: if the WASM runtime fails to initialize (a broken/incompatible
|
|
22
|
+
// web-tree-sitter build), this module still LOADS — `loadGrammar` then throws,
|
|
23
|
+
// and each lang-* adapter degrades its language to "unavailable" rather than
|
|
24
|
+
// crashing the whole CLI on import.
|
|
25
|
+
let runtimeReady = false;
|
|
26
|
+
/* v8 ignore start -- runtime-init failure is environment-dependent; not reproducible under the test runner */
|
|
27
|
+
try {
|
|
28
|
+
await Parser.init();
|
|
29
|
+
runtimeReady = true;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* @swallow-ok runtime init failed → loadGrammar throws → adapters degrade per-language */
|
|
33
|
+
}
|
|
34
|
+
/* v8 ignore stop */
|
|
35
|
+
/**
|
|
36
|
+
* Load a tree-sitter grammar from a `.wasm` path (adapter module top level).
|
|
37
|
+
*
|
|
38
|
+
* @throws {Error} When the web-tree-sitter runtime failed to initialize (the
|
|
39
|
+
* contained `Parser.init()` above) — lang-* adapters catch this and degrade
|
|
40
|
+
* that language to "unavailable" rather than crashing the CLI.
|
|
41
|
+
*/
|
|
23
42
|
export async function loadGrammar(wasmPath) {
|
|
43
|
+
/* v8 ignore next -- only reachable when Parser.init() failed above */
|
|
44
|
+
if (!runtimeReady)
|
|
45
|
+
throw new Error('web-tree-sitter runtime is not initialized');
|
|
24
46
|
return Language.load(wasmPath);
|
|
25
47
|
}
|
|
26
48
|
/**
|
package/dist/lifecycle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAa,MAAM,iBAAiB,CAAC;AAE9D,0EAA0E;AAC1E,6EAA6E;AAC7E,+DAA+D;AAC/D,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAa,MAAM,iBAAiB,CAAC;AAE9D,0EAA0E;AAC1E,6EAA6E;AAC7E,+DAA+D;AAC/D,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,oCAAoC;AACpC,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,8GAA8G;AAC9G,IAAI,CAAC;IACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACpB,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC;AAAC,MAAM,CAAC;IACP,0FAA0F;AAC5F,CAAC;AACD,oBAAoB;AAEpB;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,sEAAsE;IACtE,IAAI,CAAC,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IACjF,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,OAAiB;IAC5C,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,MAAc;IACxD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC"}
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createTreeSitterQuery` — the shared, grammar-agnostic implementation of
|
|
3
|
+
* core's {@link LanguageQueryAPI} for every tree-sitter `lang-*` adapter
|
|
4
|
+
* (ADR-0010, M10). The traversal is written once here; each adapter supplies a
|
|
5
|
+
* tiny {@link TreeSitterQueryConfig} naming its grammar's node types plus the
|
|
6
|
+
* handful of extractors a grammar genuinely differs on (callee name, import
|
|
7
|
+
* shape, string value).
|
|
8
|
+
*
|
|
9
|
+
* The query operates over the adapter's parse result — a {@link ParsedFile}
|
|
10
|
+
* (`{ tree, source }`), the same value `adapter.parse()` returns — so it slots
|
|
11
|
+
* straight onto `LanguageAdapter<ParsedFile, Node>.query` exactly the way
|
|
12
|
+
* `typescriptQuery` slots onto `LanguageAdapter<ts.SourceFile, ts.Node>`.
|
|
13
|
+
*
|
|
14
|
+
* The semantics mirror `lang-typescript`'s reference `typescriptQuery` so the
|
|
15
|
+
* equivalence cross-language checks expect holds:
|
|
16
|
+
*
|
|
17
|
+
* - `findFunctions` — every function/method/lambda declaration node,
|
|
18
|
+
* `name` via the grammar `name` field (`null` for
|
|
19
|
+
* anonymous lambdas/closures), matching TS's mix of
|
|
20
|
+
* function declarations + arrow/method nodes.
|
|
21
|
+
* - `findImports` — one {@link Import} per import target. `names` is
|
|
22
|
+
* populated where the grammar exposes named imports
|
|
23
|
+
* (Rust `use a::{x, y}`, Python `from m import x`);
|
|
24
|
+
* empty where the language has no named-import concept
|
|
25
|
+
* (Go/Java import a whole package/type by path — the
|
|
26
|
+
* faithful equivalent, not a silent gap).
|
|
27
|
+
* - `findCallsTo` — call/macro/invocation nodes whose *leaf* callee name
|
|
28
|
+
* equals `name` (the same leaf-name match TS uses for
|
|
29
|
+
* `foo()` and `obj.bar()`), via the per-grammar
|
|
30
|
+
* `calleeName` extractor.
|
|
31
|
+
* - `findStringLiterals`— every string-literal node, value via the per-grammar
|
|
32
|
+
* `stringValue` extractor (default strips one matching
|
|
33
|
+
* pair of surrounding quotes).
|
|
34
|
+
* - `getLocation` / `getText` — `{ file, line(1-based), column(0-based) }` and
|
|
35
|
+
* `node.text`, matching the TS shapes.
|
|
36
|
+
*
|
|
37
|
+
* Faithful-equivalent note: a tree-sitter `Tree` carries no source filename
|
|
38
|
+
* (unlike a `ts.SourceFile`, whose `fileName` `typescriptQuery` uses), so
|
|
39
|
+
* `Location.file` is the empty string. Cross-language checks key on
|
|
40
|
+
* `line`/`column`/`value`, not on `file`.
|
|
41
|
+
*
|
|
42
|
+
* Traversal uses the package's {@link walkNodes} (named descendants only —
|
|
43
|
+
* punctuation/anonymous tokens are never functions, calls, imports, or string
|
|
44
|
+
* literals, so visiting them would only waste cycles).
|
|
45
|
+
*/
|
|
46
|
+
import type { Node, ParsedFile } from './types.js';
|
|
47
|
+
import type { LanguageQueryAPI } from '@opensip-cli/core/languages';
|
|
48
|
+
export type { GenericFunction, Import, LanguageQueryAPI, Location, } from '@opensip-cli/core/languages';
|
|
49
|
+
/**
|
|
50
|
+
* One import target extracted from an import-declaration node. A single node
|
|
51
|
+
* can yield several (e.g. Go's grouped `import ( … )`, Rust's `use a::{x, y}`),
|
|
52
|
+
* so {@link TreeSitterQueryConfig.imports.extract} returns an array.
|
|
53
|
+
*/
|
|
54
|
+
export interface ExtractedImport {
|
|
55
|
+
/** The import specifier as written (module path / crate path), no quotes. */
|
|
56
|
+
readonly specifier: string;
|
|
57
|
+
/** Named imports where the grammar supports them; empty otherwise. */
|
|
58
|
+
readonly names: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
/** Per-language grammar configuration for {@link createTreeSitterQuery}. */
|
|
61
|
+
export interface TreeSitterQueryConfig {
|
|
62
|
+
readonly functions: {
|
|
63
|
+
/** Grammar node types that declare a callable (function/method/lambda). */
|
|
64
|
+
readonly nodeTypes: ReadonlySet<string>;
|
|
65
|
+
/**
|
|
66
|
+
* The declared name of a function node, or `null` for anonymous shapes.
|
|
67
|
+
* Defaults to {@link nameOf} (reads the grammar `name` field).
|
|
68
|
+
*/
|
|
69
|
+
readonly nameOf?: (node: Node) => string | null;
|
|
70
|
+
};
|
|
71
|
+
readonly calls: {
|
|
72
|
+
/** Grammar node types for a call/invocation (call_expression, call, …). */
|
|
73
|
+
readonly nodeTypes: ReadonlySet<string>;
|
|
74
|
+
/**
|
|
75
|
+
* The leaf callee name of a call node, or `null` when the shape isn't a
|
|
76
|
+
* simple named call (e.g. an index/computed callee). Mirrors each graph
|
|
77
|
+
* adapter's `extractCallTargetName`.
|
|
78
|
+
*/
|
|
79
|
+
readonly calleeName: (node: Node) => string | null;
|
|
80
|
+
};
|
|
81
|
+
readonly imports: {
|
|
82
|
+
/** Grammar node types for an import/use declaration. */
|
|
83
|
+
readonly nodeTypes: ReadonlySet<string>;
|
|
84
|
+
/** Expand one import-declaration node into zero or more import targets. */
|
|
85
|
+
readonly extract: (node: Node) => readonly ExtractedImport[];
|
|
86
|
+
};
|
|
87
|
+
readonly strings: {
|
|
88
|
+
/** Grammar node types for a string literal. */
|
|
89
|
+
readonly nodeTypes: ReadonlySet<string>;
|
|
90
|
+
/**
|
|
91
|
+
* The literal's value. Defaults to {@link stripSurroundingQuotes} over
|
|
92
|
+
* `node.text` (handles the common `"…"` / `'…'` / backtick cases).
|
|
93
|
+
* Named `stringValue` (not `valueOf`) to avoid colliding with
|
|
94
|
+
* `Object.prototype.valueOf` in structural assignability.
|
|
95
|
+
*/
|
|
96
|
+
readonly stringValue?: (node: Node) => string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Strip one matched pair of surrounding `"`, `'`, or backtick quotes. */
|
|
100
|
+
export declare function stripSurroundingQuotes(text: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* Build a {@link LanguageQueryAPI} over a {@link ParsedFile} from a per-language
|
|
103
|
+
* {@link TreeSitterQueryConfig}. The result is assignable to
|
|
104
|
+
* `LanguageAdapter<ParsedFile, Node>.query`.
|
|
105
|
+
*/
|
|
106
|
+
export declare function createTreeSitterQuery(config: TreeSitterQueryConfig): LanguageQueryAPI<ParsedFile, Node>;
|
|
107
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAGV,gBAAgB,EAEjB,MAAM,6BAA6B,CAAC;AAKrC,YAAY,EACV,eAAe,EACf,MAAM,EACN,gBAAgB,EAChB,QAAQ,GACT,MAAM,6BAA6B,CAAC;AAErC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE;QAClB,2EAA2E;QAC3E,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC;;;WAGG;QACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;KACjD,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE;QACd,2EAA2E;QAC3E,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC;;;;WAIG;QACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;KACpD,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE;QAChB,wDAAwD;QACxD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC,2EAA2E;QAC3E,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,eAAe,EAAE,CAAC;KAC9D,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE;QAChB,+CAA+C;QAC/C,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC;;;;;WAKG;QACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;KAC/C,CAAC;CACH;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS3D;AAUD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC5B,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,CAmDpC"}
|
package/dist/query.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createTreeSitterQuery` — the shared, grammar-agnostic implementation of
|
|
3
|
+
* core's {@link LanguageQueryAPI} for every tree-sitter `lang-*` adapter
|
|
4
|
+
* (ADR-0010, M10). The traversal is written once here; each adapter supplies a
|
|
5
|
+
* tiny {@link TreeSitterQueryConfig} naming its grammar's node types plus the
|
|
6
|
+
* handful of extractors a grammar genuinely differs on (callee name, import
|
|
7
|
+
* shape, string value).
|
|
8
|
+
*
|
|
9
|
+
* The query operates over the adapter's parse result — a {@link ParsedFile}
|
|
10
|
+
* (`{ tree, source }`), the same value `adapter.parse()` returns — so it slots
|
|
11
|
+
* straight onto `LanguageAdapter<ParsedFile, Node>.query` exactly the way
|
|
12
|
+
* `typescriptQuery` slots onto `LanguageAdapter<ts.SourceFile, ts.Node>`.
|
|
13
|
+
*
|
|
14
|
+
* The semantics mirror `lang-typescript`'s reference `typescriptQuery` so the
|
|
15
|
+
* equivalence cross-language checks expect holds:
|
|
16
|
+
*
|
|
17
|
+
* - `findFunctions` — every function/method/lambda declaration node,
|
|
18
|
+
* `name` via the grammar `name` field (`null` for
|
|
19
|
+
* anonymous lambdas/closures), matching TS's mix of
|
|
20
|
+
* function declarations + arrow/method nodes.
|
|
21
|
+
* - `findImports` — one {@link Import} per import target. `names` is
|
|
22
|
+
* populated where the grammar exposes named imports
|
|
23
|
+
* (Rust `use a::{x, y}`, Python `from m import x`);
|
|
24
|
+
* empty where the language has no named-import concept
|
|
25
|
+
* (Go/Java import a whole package/type by path — the
|
|
26
|
+
* faithful equivalent, not a silent gap).
|
|
27
|
+
* - `findCallsTo` — call/macro/invocation nodes whose *leaf* callee name
|
|
28
|
+
* equals `name` (the same leaf-name match TS uses for
|
|
29
|
+
* `foo()` and `obj.bar()`), via the per-grammar
|
|
30
|
+
* `calleeName` extractor.
|
|
31
|
+
* - `findStringLiterals`— every string-literal node, value via the per-grammar
|
|
32
|
+
* `stringValue` extractor (default strips one matching
|
|
33
|
+
* pair of surrounding quotes).
|
|
34
|
+
* - `getLocation` / `getText` — `{ file, line(1-based), column(0-based) }` and
|
|
35
|
+
* `node.text`, matching the TS shapes.
|
|
36
|
+
*
|
|
37
|
+
* Faithful-equivalent note: a tree-sitter `Tree` carries no source filename
|
|
38
|
+
* (unlike a `ts.SourceFile`, whose `fileName` `typescriptQuery` uses), so
|
|
39
|
+
* `Location.file` is the empty string. Cross-language checks key on
|
|
40
|
+
* `line`/`column`/`value`, not on `file`.
|
|
41
|
+
*
|
|
42
|
+
* Traversal uses the package's {@link walkNodes} (named descendants only —
|
|
43
|
+
* punctuation/anonymous tokens are never functions, calls, imports, or string
|
|
44
|
+
* literals, so visiting them would only waste cycles).
|
|
45
|
+
*/
|
|
46
|
+
import { getColumn, getLineNumber, nameOf, walkNodes } from './nodes.js';
|
|
47
|
+
/** Strip one matched pair of surrounding `"`, `'`, or backtick quotes. */
|
|
48
|
+
export function stripSurroundingQuotes(text) {
|
|
49
|
+
if (text.length >= 2) {
|
|
50
|
+
const first = text[0];
|
|
51
|
+
const last = text.at(-1);
|
|
52
|
+
if ((first === '"' || first === "'" || first === '`') && last === first) {
|
|
53
|
+
return text.slice(1, -1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
// tree-sitter trees carry no source path; Location.file is empty (see the
|
|
59
|
+
// factory docstring). Checks key on line/column/value, not file.
|
|
60
|
+
const NO_FILE = '';
|
|
61
|
+
function locationOf(node) {
|
|
62
|
+
return { file: NO_FILE, line: getLineNumber(node), column: getColumn(node) };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build a {@link LanguageQueryAPI} over a {@link ParsedFile} from a per-language
|
|
66
|
+
* {@link TreeSitterQueryConfig}. The result is assignable to
|
|
67
|
+
* `LanguageAdapter<ParsedFile, Node>.query`.
|
|
68
|
+
*/
|
|
69
|
+
export function createTreeSitterQuery(config) {
|
|
70
|
+
const functionName = config.functions.nameOf ?? nameOf;
|
|
71
|
+
const stringValue = config.strings.stringValue ?? ((node) => stripSurroundingQuotes(node.text));
|
|
72
|
+
return {
|
|
73
|
+
findFunctions(tree) {
|
|
74
|
+
const out = [];
|
|
75
|
+
walkNodes(tree.tree.rootNode, (node) => {
|
|
76
|
+
if (config.functions.nodeTypes.has(node.type)) {
|
|
77
|
+
out.push({ name: functionName(node), location: locationOf(node), node });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return out;
|
|
81
|
+
},
|
|
82
|
+
findImports(tree) {
|
|
83
|
+
const out = [];
|
|
84
|
+
walkNodes(tree.tree.rootNode, (node) => {
|
|
85
|
+
if (!config.imports.nodeTypes.has(node.type))
|
|
86
|
+
return;
|
|
87
|
+
const location = locationOf(node);
|
|
88
|
+
for (const imp of config.imports.extract(node)) {
|
|
89
|
+
out.push({ specifier: imp.specifier, names: imp.names, location });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return out;
|
|
93
|
+
},
|
|
94
|
+
findCallsTo(tree, name) {
|
|
95
|
+
const out = [];
|
|
96
|
+
walkNodes(tree.tree.rootNode, (node) => {
|
|
97
|
+
if (config.calls.nodeTypes.has(node.type) && config.calls.calleeName(node) === name) {
|
|
98
|
+
out.push(node);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return out;
|
|
102
|
+
},
|
|
103
|
+
findStringLiterals(tree) {
|
|
104
|
+
const out = [];
|
|
105
|
+
walkNodes(tree.tree.rootNode, (node) => {
|
|
106
|
+
if (config.strings.nodeTypes.has(node.type)) {
|
|
107
|
+
out.push({ value: stringValue(node), location: locationOf(node) });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return out;
|
|
111
|
+
},
|
|
112
|
+
getLocation(_tree, node) {
|
|
113
|
+
return locationOf(node);
|
|
114
|
+
},
|
|
115
|
+
getText(_tree, node) {
|
|
116
|
+
return node.text;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensip-cli/tree-sitter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Grammar-agnostic tree-sitter substrate (parser lifecycle + node accessors) shared by lang-* and the graph adapters",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"NOTICE"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"web-tree-sitter": "0.26.9"
|
|
35
|
+
"web-tree-sitter": "0.26.9",
|
|
36
|
+
"@opensip-cli/core": "0.1.9"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/node": "^24.13.2",
|