@kerebron/tree-sitter 0.4.6
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/LICENSE +23 -0
- package/README.md +4 -0
- package/esm/_dnt.polyfills.d.ts +101 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +127 -0
- package/esm/deno-tree-sitter/main/extended/base_node.d.ts +48 -0
- package/esm/deno-tree-sitter/main/extended/base_node.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/base_node.js +154 -0
- package/esm/deno-tree-sitter/main/extended/node_extended.d.ts +237 -0
- package/esm/deno-tree-sitter/main/extended/node_extended.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/node_extended.js +665 -0
- package/esm/deno-tree-sitter/main/extended/parser.d.ts +37 -0
- package/esm/deno-tree-sitter/main/extended/parser.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/parser.js +86 -0
- package/esm/deno-tree-sitter/main/extended/soft_node.d.ts +15 -0
- package/esm/deno-tree-sitter/main/extended/soft_node.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/soft_node.js +32 -0
- package/esm/deno-tree-sitter/main/extended/soft_text_node.d.ts +10 -0
- package/esm/deno-tree-sitter/main/extended/soft_text_node.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/soft_text_node.js +10 -0
- package/esm/deno-tree-sitter/main/extended/whitespace_node.d.ts +10 -0
- package/esm/deno-tree-sitter/main/extended/whitespace_node.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extended/whitespace_node.js +10 -0
- package/esm/deno-tree-sitter/main/extras/misc.d.ts +2 -0
- package/esm/deno-tree-sitter/main/extras/misc.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/extras/misc.js +13 -0
- package/esm/deno-tree-sitter/main/tree_sitter/bindings.d.ts +14 -0
- package/esm/deno-tree-sitter/main/tree_sitter/bindings.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/bindings.js +21 -0
- package/esm/deno-tree-sitter/main/tree_sitter/constants.d.ts +60 -0
- package/esm/deno-tree-sitter/main/tree_sitter/constants.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/constants.js +66 -0
- package/esm/deno-tree-sitter/main/tree_sitter/language.d.ts +137 -0
- package/esm/deno-tree-sitter/main/tree_sitter/language.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/language.js +296 -0
- package/esm/deno-tree-sitter/main/tree_sitter/lookahead_iterator.d.ts +41 -0
- package/esm/deno-tree-sitter/main/tree_sitter/lookahead_iterator.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/lookahead_iterator.js +75 -0
- package/esm/deno-tree-sitter/main/tree_sitter/marshal.d.ts +85 -0
- package/esm/deno-tree-sitter/main/tree_sitter/marshal.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/marshal.js +173 -0
- package/esm/deno-tree-sitter/main/tree_sitter/node.d.ts +260 -0
- package/esm/deno-tree-sitter/main/tree_sitter/node.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/node.js +592 -0
- package/esm/deno-tree-sitter/main/tree_sitter/parser.d.ts +124 -0
- package/esm/deno-tree-sitter/main/tree_sitter/parser.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/parser.js +272 -0
- package/esm/deno-tree-sitter/main/tree_sitter/query.d.ts +134 -0
- package/esm/deno-tree-sitter/main/tree_sitter/query.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/query.js +670 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree.d.ts +49 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree.js +145 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree_cursor.d.ts +165 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree_cursor.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter/tree_cursor.js +305 -0
- package/esm/deno-tree-sitter/main/tree_sitter_wasm.d.ts +3 -0
- package/esm/deno-tree-sitter/main/tree_sitter_wasm.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/tree_sitter_wasm.js +0 -0
- package/esm/deno-tree-sitter/main/wasm_loader.d.ts +29 -0
- package/esm/deno-tree-sitter/main/wasm_loader.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/wasm_loader.js +1709 -0
- package/esm/deno-tree-sitter/main/wasm_loader_with_defaults.d.ts +3 -0
- package/esm/deno-tree-sitter/main/wasm_loader_with_defaults.d.ts.map +1 -0
- package/esm/deno-tree-sitter/main/wasm_loader_with_defaults.js +8 -0
- package/esm/mod.d.ts +8 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +8 -0
- package/esm/package.json +3 -0
- package/package.json +16 -0
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
import { Node } from "../tree_sitter/node.js";
|
|
2
|
+
import { Parser } from "../tree_sitter/parser.js";
|
|
3
|
+
import { BaseNode, _shadows } from "./base_node.js";
|
|
4
|
+
import { WhitespaceNode } from "./whitespace_node.js";
|
|
5
|
+
import { SoftTextNode } from "./soft_text_node.js";
|
|
6
|
+
import { Query, QueryError } from "../tree_sitter/query.js";
|
|
7
|
+
import { _getQueryCaptureTargets } from "../extras/misc.js";
|
|
8
|
+
import { Tree } from "../tree_sitter/tree.js";
|
|
9
|
+
// NOTE: the tree override is in here because it has a circular type dependency on HardNode
|
|
10
|
+
const realRootNodeGetter = Object.getOwnPropertyDescriptor(Tree.prototype, "rootNode").get;
|
|
11
|
+
//
|
|
12
|
+
// complicated override in order to make the root node pretend to contain soft nodes (ex: leading and trailing whitespace)
|
|
13
|
+
//
|
|
14
|
+
// hard because a normal change to .startIndex/.endIndex breaks internal methods, so we have to selectively choose who sees the real/faked .startIndex/.endIndex
|
|
15
|
+
Object.defineProperty(Tree.prototype, "rootNode", {
|
|
16
|
+
get() {
|
|
17
|
+
const rootNode = realRootNodeGetter.call(this);
|
|
18
|
+
const rootShadow = {};
|
|
19
|
+
Object.setPrototypeOf(rootShadow, Object.getPrototypeOf(rootNode));
|
|
20
|
+
const descriptors = Object.assign(Object.getOwnPropertyDescriptors(Node.prototype), Object.getOwnPropertyDescriptors(rootNode));
|
|
21
|
+
const newDescriptors = {};
|
|
22
|
+
for (const [key, setting] of Object.entries(descriptors)) {
|
|
23
|
+
if (key == "startIndex" || key == "startPosition") {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
else if (key == "text" || key == "replaceInnards") {
|
|
27
|
+
// use the faked .startIndex for these methods/getters
|
|
28
|
+
newDescriptors[key] = setting;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// use the real .startIndex for these methods/getters (get it from the real thing)
|
|
32
|
+
// (otherwise stuff breaks when there is a whitespace prefix)
|
|
33
|
+
newDescriptors[key] = {
|
|
34
|
+
get: () => {
|
|
35
|
+
const output = rootNode[key];
|
|
36
|
+
if (typeof output == "function") {
|
|
37
|
+
return (...args) => output.apply(rootNode, args);
|
|
38
|
+
}
|
|
39
|
+
return output;
|
|
40
|
+
},
|
|
41
|
+
set: (value) => rootNode[key] = value,
|
|
42
|
+
enumerable: setting.enumerable,
|
|
43
|
+
configurable: setting.configurable,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
Object.setPrototypeOf(rootShadow, Node.prototype);
|
|
48
|
+
Object.defineProperties(rootShadow, newDescriptors);
|
|
49
|
+
rootShadow.startIndex = 0;
|
|
50
|
+
rootShadow.startPosition = { row: 0, column: 0 };
|
|
51
|
+
// if the original file is just whitespace or non-matched text, then fill it with soft nodes even though it'd normally have no children
|
|
52
|
+
if (rootShadow.children.length == 0 && rootShadow.endIndex != 0) {
|
|
53
|
+
rootShadow._children = _childrenWithSoftNodes(rootShadow, [{ startIndex: rootShadow.endIndex, endIndex: rootShadow.endIndex, endPosition: rootShadow.endPosition }], rootNode.tree.codeString).slice(0, -1);
|
|
54
|
+
}
|
|
55
|
+
_shadows[rootNode.id] = rootShadow;
|
|
56
|
+
return rootShadow;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// this only exists to help with type hints
|
|
60
|
+
export class ExtendedTree extends Tree {
|
|
61
|
+
constructor() {
|
|
62
|
+
super(...arguments);
|
|
63
|
+
/** @type {HardNode} */
|
|
64
|
+
Object.defineProperty(this, "rootNode", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
configurable: true,
|
|
67
|
+
writable: true,
|
|
68
|
+
value: void 0
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// this only exists to help with type hints
|
|
73
|
+
class Position {
|
|
74
|
+
constructor() {
|
|
75
|
+
/** @type {number} */
|
|
76
|
+
Object.defineProperty(this, "row", {
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: true,
|
|
79
|
+
writable: true,
|
|
80
|
+
value: void 0
|
|
81
|
+
});
|
|
82
|
+
/** @type {number} */
|
|
83
|
+
Object.defineProperty(this, "column", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: void 0
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const originalDescriptors = Object.getOwnPropertyDescriptors(Node.prototype);
|
|
92
|
+
const originalChildrenGetter = originalDescriptors.children.get;
|
|
93
|
+
const originalEndIndex = originalDescriptors.endIndex.get;
|
|
94
|
+
const originalEndPosition = originalDescriptors.endPosition.get;
|
|
95
|
+
const originalParent = originalDescriptors.parent.get;
|
|
96
|
+
const originalTextGetter = originalDescriptors.text.get;
|
|
97
|
+
const originalEquals = originalDescriptors.equals.value;
|
|
98
|
+
const originalToString = originalDescriptors.toString.value;
|
|
99
|
+
export class HardNode extends BaseNode {
|
|
100
|
+
constructor() {
|
|
101
|
+
super(...arguments);
|
|
102
|
+
/** @internal */
|
|
103
|
+
Object.defineProperty(this, "_children", {
|
|
104
|
+
enumerable: true,
|
|
105
|
+
configurable: true,
|
|
106
|
+
writable: true,
|
|
107
|
+
value: void 0
|
|
108
|
+
});
|
|
109
|
+
/** @internal */
|
|
110
|
+
Object.defineProperty(this, "_fields", {
|
|
111
|
+
enumerable: true,
|
|
112
|
+
configurable: true,
|
|
113
|
+
writable: true,
|
|
114
|
+
value: void 0
|
|
115
|
+
});
|
|
116
|
+
/** @internal */
|
|
117
|
+
Object.defineProperty(this, "_depth", {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
configurable: true,
|
|
120
|
+
writable: true,
|
|
121
|
+
value: void 0
|
|
122
|
+
});
|
|
123
|
+
/** @type {number} */
|
|
124
|
+
Object.defineProperty(this, "id", {
|
|
125
|
+
enumerable: true,
|
|
126
|
+
configurable: true,
|
|
127
|
+
writable: true,
|
|
128
|
+
value: void 0
|
|
129
|
+
});
|
|
130
|
+
/** @type {number} */
|
|
131
|
+
Object.defineProperty(this, "startIndex", {
|
|
132
|
+
enumerable: true,
|
|
133
|
+
configurable: true,
|
|
134
|
+
writable: true,
|
|
135
|
+
value: void 0
|
|
136
|
+
});
|
|
137
|
+
/** @type {Position} */
|
|
138
|
+
Object.defineProperty(this, "startPosition", {
|
|
139
|
+
enumerable: true,
|
|
140
|
+
configurable: true,
|
|
141
|
+
writable: true,
|
|
142
|
+
value: void 0
|
|
143
|
+
});
|
|
144
|
+
/** @type {ExtendedTree} */
|
|
145
|
+
Object.defineProperty(this, "tree", {
|
|
146
|
+
enumerable: true,
|
|
147
|
+
configurable: true,
|
|
148
|
+
writable: true,
|
|
149
|
+
value: void 0
|
|
150
|
+
});
|
|
151
|
+
/** @type {string} */
|
|
152
|
+
Object.defineProperty(this, "type", {
|
|
153
|
+
enumerable: true,
|
|
154
|
+
configurable: true,
|
|
155
|
+
writable: true,
|
|
156
|
+
value: void 0
|
|
157
|
+
});
|
|
158
|
+
/** @type {Boolean} */
|
|
159
|
+
Object.defineProperty(this, "isExtra", {
|
|
160
|
+
enumerable: true,
|
|
161
|
+
configurable: true,
|
|
162
|
+
writable: true,
|
|
163
|
+
value: void 0
|
|
164
|
+
});
|
|
165
|
+
/** @type {Boolean} */
|
|
166
|
+
Object.defineProperty(this, "isError", {
|
|
167
|
+
enumerable: true,
|
|
168
|
+
configurable: true,
|
|
169
|
+
writable: true,
|
|
170
|
+
value: void 0
|
|
171
|
+
});
|
|
172
|
+
/** @type {Boolean} */
|
|
173
|
+
Object.defineProperty(this, "isMissing", {
|
|
174
|
+
enumerable: true,
|
|
175
|
+
configurable: true,
|
|
176
|
+
writable: true,
|
|
177
|
+
value: void 0
|
|
178
|
+
});
|
|
179
|
+
/** @type {Boolean} */
|
|
180
|
+
Object.defineProperty(this, "hasChanges", {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
configurable: true,
|
|
183
|
+
writable: true,
|
|
184
|
+
value: void 0
|
|
185
|
+
});
|
|
186
|
+
/** @type {Boolean} */
|
|
187
|
+
Object.defineProperty(this, "hasError", {
|
|
188
|
+
enumerable: true,
|
|
189
|
+
configurable: true,
|
|
190
|
+
writable: true,
|
|
191
|
+
value: void 0
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* @param {HardNode} other -
|
|
195
|
+
* @returns {Boolean} output -
|
|
196
|
+
*/
|
|
197
|
+
Object.defineProperty(this, "equals", {
|
|
198
|
+
enumerable: true,
|
|
199
|
+
configurable: true,
|
|
200
|
+
writable: true,
|
|
201
|
+
value: originalEquals
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/** @type {HardNode} */
|
|
205
|
+
get parent() {
|
|
206
|
+
const rawParent = originalParent.call(this);
|
|
207
|
+
return _shadows[rawParent?.id] || rawParent;
|
|
208
|
+
}
|
|
209
|
+
/** @type {string} */
|
|
210
|
+
get text() {
|
|
211
|
+
return originalTextGetter.call(_shadows[this.id] || this);
|
|
212
|
+
}
|
|
213
|
+
/** @type {Number} */
|
|
214
|
+
get endIndex() {
|
|
215
|
+
if (this.depth == 0) {
|
|
216
|
+
return this.tree.codeString.length;
|
|
217
|
+
}
|
|
218
|
+
return originalEndIndex.call(this);
|
|
219
|
+
}
|
|
220
|
+
/** @type {Position} */
|
|
221
|
+
get endPosition() {
|
|
222
|
+
if (this.depth == 0) {
|
|
223
|
+
const rowIndex = (this.tree.codeString.match(/\n/g) || []).length;
|
|
224
|
+
const columnIndex = this.tree.codeString.match(new RegExp(`^(?:.*\\r?\\n){${rowIndex}}(.*)`))[1].length;
|
|
225
|
+
return { row: rowIndex, column: columnIndex };
|
|
226
|
+
}
|
|
227
|
+
return originalEndPosition.call(this);
|
|
228
|
+
}
|
|
229
|
+
/** @type {Array<HardNode|SoftNode>} */
|
|
230
|
+
get children() {
|
|
231
|
+
if (!this._children) {
|
|
232
|
+
// will set this._children
|
|
233
|
+
this._children = originalChildrenGetter.call(this);
|
|
234
|
+
// add soft nodes if needed
|
|
235
|
+
if (this.tree._enableSoftNodes) {
|
|
236
|
+
this._children = _childrenWithSoftNodes(this, this._children || [], this.tree.codeString);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return this._children || [];
|
|
240
|
+
}
|
|
241
|
+
set children(value) {
|
|
242
|
+
this._children = value;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Yields each child
|
|
246
|
+
*
|
|
247
|
+
* @generator
|
|
248
|
+
* @yields {HardNode} The current child or grandchild in the structure.
|
|
249
|
+
*/
|
|
250
|
+
*traverse(arg = { _parentNodes: [] }) {
|
|
251
|
+
const { _parentNodes } = arg;
|
|
252
|
+
const parentNodes = [this, ..._parentNodes];
|
|
253
|
+
if (this.children?.length == 0) {
|
|
254
|
+
yield [_parentNodes, this, "-"];
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
yield [_parentNodes, this, "->"];
|
|
258
|
+
for (const each of this.children || []) {
|
|
259
|
+
if (each instanceof Node) {
|
|
260
|
+
for (const eachInner of each.traverse({ _parentNodes: parentNodes })) {
|
|
261
|
+
yield eachInner;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
yield [parentNodes, each, "-"];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
yield [_parentNodes, this, "<-"];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* A generator function that flattens the hierarchical structure of `children` and their descendants.
|
|
273
|
+
* It yields each child and their flattened descendants recursively.
|
|
274
|
+
*
|
|
275
|
+
* @param {Function} opts.filter - A function to filter the flattened elements.
|
|
276
|
+
* @param {Boolean} opts.includeSelf -
|
|
277
|
+
* @generator
|
|
278
|
+
* @yields {HardNode} The current child or grandchild in the structure.
|
|
279
|
+
*/
|
|
280
|
+
*iterFlattened({ filter, includeSelf = false } = {}) {
|
|
281
|
+
if (includeSelf) {
|
|
282
|
+
yield this;
|
|
283
|
+
}
|
|
284
|
+
if (typeof filter == "function") {
|
|
285
|
+
for (const each of this.children || []) {
|
|
286
|
+
if (filter(each)) {
|
|
287
|
+
yield each;
|
|
288
|
+
}
|
|
289
|
+
for (const eachGrandChild of each.iterFlattened({ filter })) {
|
|
290
|
+
yield eachGrandChild;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
for (const each of this.children || []) {
|
|
296
|
+
yield each;
|
|
297
|
+
for (const eachGrandChild of each.iterFlattened({ filter })) {
|
|
298
|
+
yield eachGrandChild;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** @internal */
|
|
304
|
+
iterFlatten() {
|
|
305
|
+
throw Error(`did you mean iterFlattened instead of iterFlatten?`);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Flattens the structure of `children` using the provided filter function.
|
|
309
|
+
* This method returns an array containing the flattened elements.
|
|
310
|
+
*
|
|
311
|
+
* @param {Function} opts.filter - A function to filter the flattened elements.
|
|
312
|
+
* @param {Boolean} opts.includeSelf -
|
|
313
|
+
* @returns {Array} An array containing the flattened elements that pass the filter.
|
|
314
|
+
*/
|
|
315
|
+
flattened({ filter, includeSelf = false } = {}) {
|
|
316
|
+
return [...this.iterFlattened({ filter, includeSelf })];
|
|
317
|
+
}
|
|
318
|
+
/** @internal */
|
|
319
|
+
flatten() {
|
|
320
|
+
throw Error(`did you mean flattened instead of flatten?`);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Query
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```js
|
|
327
|
+
* import { createParser } from "https://deno.land/x/deno_tree_sitter/main/main.js"
|
|
328
|
+
* import javascript from "https://github.com/jeff-hykin/common_tree_sitter_languages/raw/4d8a6d34d7f6263ff570f333cdcf5ded6be89e3d/main/javascript.js"
|
|
329
|
+
* const parser = await createParser(javascript) // path or Uint8Array
|
|
330
|
+
* const tree = parser.parse('let a = 1;let b = 1;let c = 1;')
|
|
331
|
+
*
|
|
332
|
+
* tree.rootNode.query(`(identifier) @blahBlahBlah`, {matchLimit: 2})
|
|
333
|
+
* // returns:
|
|
334
|
+
* [
|
|
335
|
+
* {
|
|
336
|
+
* pattern: 0,
|
|
337
|
+
* captures: [
|
|
338
|
+
* {
|
|
339
|
+
* name: "blahBlahBlah",
|
|
340
|
+
* node: {
|
|
341
|
+
* type: "identifier",
|
|
342
|
+
* typeId: 1,
|
|
343
|
+
* startPosition: { row: 0, column: 4 },
|
|
344
|
+
* startIndex: 4,
|
|
345
|
+
* endPosition: { row: 0, column: 5 },
|
|
346
|
+
* endIndex: 5,
|
|
347
|
+
* indent: undefined,
|
|
348
|
+
* hasChildren: false,
|
|
349
|
+
* children: []
|
|
350
|
+
* }
|
|
351
|
+
* }
|
|
352
|
+
* ]
|
|
353
|
+
* },
|
|
354
|
+
* {
|
|
355
|
+
* pattern: 0,
|
|
356
|
+
* captures: [
|
|
357
|
+
* {
|
|
358
|
+
* name: "blahBlahBlah",
|
|
359
|
+
* node: {
|
|
360
|
+
* type: "identifier",
|
|
361
|
+
* typeId: 1,
|
|
362
|
+
* startPosition: { row: 0, column: 14 },
|
|
363
|
+
* startIndex: 14,
|
|
364
|
+
* endPosition: { row: 0, column: 15 },
|
|
365
|
+
* endIndex: 15,
|
|
366
|
+
* indent: undefined,
|
|
367
|
+
* hasChildren: false,
|
|
368
|
+
* children: []
|
|
369
|
+
* }
|
|
370
|
+
* }
|
|
371
|
+
* ]
|
|
372
|
+
* },
|
|
373
|
+
* {
|
|
374
|
+
* pattern: 0,
|
|
375
|
+
* captures: [
|
|
376
|
+
* {
|
|
377
|
+
* name: "blahBlahBlah",
|
|
378
|
+
* node: {
|
|
379
|
+
* type: "identifier",
|
|
380
|
+
* typeId: 1,
|
|
381
|
+
* startPosition: { row: 0, column: 24 },
|
|
382
|
+
* startIndex: 24,
|
|
383
|
+
* endPosition: { row: 0, column: 25 },
|
|
384
|
+
* endIndex: 25,
|
|
385
|
+
* indent: undefined,
|
|
386
|
+
* hasChildren: false,
|
|
387
|
+
* children: []
|
|
388
|
+
* }
|
|
389
|
+
* }
|
|
390
|
+
* ]
|
|
391
|
+
* }
|
|
392
|
+
* ]
|
|
393
|
+
* ```
|
|
394
|
+
*
|
|
395
|
+
* @param {String} queryString - see https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
|
|
396
|
+
* @param options.matchLimit - max number of results
|
|
397
|
+
* @param options.startPosition - {row: Number, column: number}
|
|
398
|
+
* @param options.endPosition - {row: Number, column: number}
|
|
399
|
+
* @param options.maxResultDepth - depth relative to the current node (1 = direct children, 2 = grandchildren, etc)
|
|
400
|
+
* @returns {[Object]} output
|
|
401
|
+
*
|
|
402
|
+
*/
|
|
403
|
+
query(queryString, options) {
|
|
404
|
+
const { matchLimit, startPosition, endPosition, maxResultDepth } = options || {};
|
|
405
|
+
const realMaxResultDepth = maxResultDepth == null ? Infinity : maxResultDepth;
|
|
406
|
+
let query;
|
|
407
|
+
try {
|
|
408
|
+
query = new Query(this.tree.language, queryString);
|
|
409
|
+
}
|
|
410
|
+
catch (error) {
|
|
411
|
+
if (error instanceof QueryError) {
|
|
412
|
+
error.message = `${error.message} in the following query: ${JSON.stringify(queryString)}`;
|
|
413
|
+
}
|
|
414
|
+
throw error;
|
|
415
|
+
}
|
|
416
|
+
const result = query.matches(this, startPosition || this.startPosition, endPosition || this.endPosition, matchLimit);
|
|
417
|
+
const results = result.filter((each) => each.captures.every((each) => each.node.depth - this.depth <= realMaxResultDepth));
|
|
418
|
+
const codeOrCallback = this.tree.codeString;
|
|
419
|
+
// without this soft nodes will be missing
|
|
420
|
+
for (const eachResult of results) {
|
|
421
|
+
for (const eachCapture of eachResult.captures) {
|
|
422
|
+
eachCapture.node.children = _childrenWithSoftNodes(eachCapture.node, eachCapture.node.children, codeOrCallback);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return result.filter((each) => each.captures.every((each) => each.node.depth - this.depth <= realMaxResultDepth));
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* quickQuery
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```js
|
|
432
|
+
* import { createParser } from "https://deno.land/x/deno_tree_sitter/main/main.js"
|
|
433
|
+
* import javascript from "https://github.com/jeff-hykin/common_tree_sitter_languages/raw/676ffa3b93768b8ac628fd5c61656f7dc41ba413/main/javascript.js"
|
|
434
|
+
* const parser = await createParser(javascript) // path or Uint8Array
|
|
435
|
+
* const tree = parser.parse('let a = 1;let b = 1;let c = 1;')
|
|
436
|
+
* // ex1: no capture names
|
|
437
|
+
* const nodes = tree.rootNode.quickQuery(
|
|
438
|
+
* `(identifier)`, {matchLimit: 2}
|
|
439
|
+
* )
|
|
440
|
+
* // ex2: with capture names
|
|
441
|
+
* const groups = tree.rootNode.quickQuery(
|
|
442
|
+
* `'(binding (attrpath) @myKey (list_expression) @myList ("\\"")? @optionalThing )`
|
|
443
|
+
* )
|
|
444
|
+
* groups[0].myKey // node
|
|
445
|
+
* groups[0].myList // node
|
|
446
|
+
* groups[0].optionalThing // node or null
|
|
447
|
+
* groups[0][0] // node (the whole match)
|
|
448
|
+
* ```
|
|
449
|
+
*
|
|
450
|
+
* @param {String} queryString - see https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
|
|
451
|
+
* @param options.matchLimit - max number of results
|
|
452
|
+
* @param options.startPosition - {row: Number, column: number}
|
|
453
|
+
* @param options.endPosition - {row: Number, column: number}
|
|
454
|
+
* @param options.maxResultDepth - depth relative to the current node (1 = direct children, 2 = grandchildren, etc)
|
|
455
|
+
* @returns {Array<HardNode|Record<any, HardNode>>} nodesOrObjsOfNodes
|
|
456
|
+
*/
|
|
457
|
+
quickQuery(queryString, options) {
|
|
458
|
+
const possibleCaptureTargets = _getQueryCaptureTargets(queryString);
|
|
459
|
+
//
|
|
460
|
+
// get a base capture name
|
|
461
|
+
//
|
|
462
|
+
let baseCaptureName = "_";
|
|
463
|
+
while (possibleCaptureTargets.includes(baseCaptureName)) {
|
|
464
|
+
// append until it doesn't conflict
|
|
465
|
+
baseCaptureName = `${baseCaptureName}_`;
|
|
466
|
+
}
|
|
467
|
+
// add the base capture always
|
|
468
|
+
queryString = `${queryString} @${baseCaptureName}`;
|
|
469
|
+
const output = this.query(queryString, options).map((each) => {
|
|
470
|
+
const nodesByCaptureName = Object.fromEntries(each.captures.map((each) => [each.name, each.node]));
|
|
471
|
+
// no capture targets means just return the base
|
|
472
|
+
if (possibleCaptureTargets.length == 0) {
|
|
473
|
+
return nodesByCaptureName[baseCaptureName];
|
|
474
|
+
// return named targets
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
// 0 is not allowed as a capture name, so it will never conflict
|
|
478
|
+
nodesByCaptureName[0] = nodesByCaptureName[baseCaptureName];
|
|
479
|
+
delete nodesByCaptureName[baseCaptureName];
|
|
480
|
+
return nodesByCaptureName;
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
return output;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* quickQueryFirst
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```js
|
|
490
|
+
* import { createParser } from "https://deno.land/x/deno_tree_sitter/main/main.js"
|
|
491
|
+
* import javascript from "https://github.com/jeff-hykin/common_tree_sitter_languages/raw/4d8a6d34d7f6263ff570f333cdcf5ded6be89e3d/main/javascript.js"
|
|
492
|
+
* const parser = await createParser(javascript) // path or Uint8Array
|
|
493
|
+
* const tree = parser.parse('let a = 1;let b = 1;let c = 1;')
|
|
494
|
+
*
|
|
495
|
+
* // ex1: no capture names
|
|
496
|
+
* const node = tree.rootNode.quickQueryFirst(`(identifier)`)
|
|
497
|
+
*
|
|
498
|
+
* // ex2: with capture names
|
|
499
|
+
* const { myKey, myList, optionalThing } = tree.rootNode.quickQueryFirst(
|
|
500
|
+
* `'(binding (attrpath) @myKey (list_expression) @myList ("\\"")? @optionalThing )`
|
|
501
|
+
* )
|
|
502
|
+
* myKey // node
|
|
503
|
+
* myList // node
|
|
504
|
+
* optionalThing // node or null
|
|
505
|
+
* ```
|
|
506
|
+
*
|
|
507
|
+
* @param {String} queryString - see https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
|
|
508
|
+
* @param options.startPosition - {row: Number, column: number}
|
|
509
|
+
* @param options.endPosition - {row: Number, column: number}
|
|
510
|
+
* @param options.maxResultDepth - depth relative to the current node (1 = direct children, 2 = grandchildren, etc)
|
|
511
|
+
* @returns {HardNode|Record<any,HardNode>|null} nodeOrObjOfNodes
|
|
512
|
+
*/
|
|
513
|
+
quickQueryFirst(queryString, options) {
|
|
514
|
+
return this.quickQuery(queryString, { ...options, matchLimit: 1 })[0];
|
|
515
|
+
}
|
|
516
|
+
get fields() {
|
|
517
|
+
if (!this._fields) {
|
|
518
|
+
this._fields = {};
|
|
519
|
+
let index = -1;
|
|
520
|
+
for (let each of this.children || []) {
|
|
521
|
+
// skip soft nodes
|
|
522
|
+
if (each.typeId <= 0) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
index++;
|
|
526
|
+
const name = this.fieldNameForChild(index);
|
|
527
|
+
if (name) {
|
|
528
|
+
this._fields[name] = each;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
return this._fields;
|
|
533
|
+
}
|
|
534
|
+
get fieldNames() {
|
|
535
|
+
return Object.keys(this.fields);
|
|
536
|
+
}
|
|
537
|
+
getQueryForSelf() {
|
|
538
|
+
let current = this;
|
|
539
|
+
let chunks = [];
|
|
540
|
+
while (current) {
|
|
541
|
+
if (current.type) {
|
|
542
|
+
if (current.isNamed) {
|
|
543
|
+
if (current.type.match(/^([a-zA-Z0-9.\-_\$]+)$/)) {
|
|
544
|
+
chunks.push(current.type);
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
chunks.push(JSON.stringify(current.type));
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
// TODO: this might not always be correct. Probably should be JSON.stringify(current.text) but theres a risk of .text being massive
|
|
552
|
+
chunks.push(JSON.stringify(current.type));
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
current = current.parent;
|
|
556
|
+
}
|
|
557
|
+
return "(" + chunks.reverse().join(" (") + ")".repeat(chunks.length);
|
|
558
|
+
}
|
|
559
|
+
/** @returns {string} */
|
|
560
|
+
asLispString() {
|
|
561
|
+
return originalToString.call(this);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
// patch Node with all HardNode properties
|
|
565
|
+
const descriptors = Object.getOwnPropertyDescriptors(HardNode.prototype);
|
|
566
|
+
delete descriptors.constructor;
|
|
567
|
+
Object.defineProperties(Node.prototype, descriptors);
|
|
568
|
+
// force it to inherit from BaseNode
|
|
569
|
+
Object.setPrototypeOf(Node.prototype, BaseNode.prototype);
|
|
570
|
+
export { Node };
|
|
571
|
+
// helper
|
|
572
|
+
export const _childrenWithSoftNodes = (node, children, string) => {
|
|
573
|
+
if (children?.length > 0) {
|
|
574
|
+
const newChildren = [];
|
|
575
|
+
const childrenCopy = [...children];
|
|
576
|
+
let firstChild = childrenCopy.shift();
|
|
577
|
+
// helper
|
|
578
|
+
const handleGaps = (gapText, getReferencePoint, parentNode) => {
|
|
579
|
+
const { index, position } = getReferencePoint();
|
|
580
|
+
let start = index;
|
|
581
|
+
let startPosition = position;
|
|
582
|
+
const chunks = gapText.split(/(?<!\s)(?=\s+)/g);
|
|
583
|
+
let colOffset = startPosition.column;
|
|
584
|
+
let rowOffset = startPosition.row;
|
|
585
|
+
for (const eachGap of chunks) {
|
|
586
|
+
if (eachGap.length == 0) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
const end = start + eachGap.length;
|
|
590
|
+
if (eachGap.match(/^\s/)) {
|
|
591
|
+
const rowOffsetBefore = rowOffset;
|
|
592
|
+
const colOffsetBefore = colOffset;
|
|
593
|
+
rowOffset += (eachGap.match(/\n/g) || []).length;
|
|
594
|
+
// reset column offset on new row
|
|
595
|
+
if (rowOffsetBefore != rowOffset) {
|
|
596
|
+
colOffset = eachGap.split("\n").slice(-1)[0].length;
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
colOffset += eachGap.length;
|
|
600
|
+
}
|
|
601
|
+
newChildren.push(new WhitespaceNode({
|
|
602
|
+
tree: node.tree,
|
|
603
|
+
parent: parentNode,
|
|
604
|
+
getReferencePoint,
|
|
605
|
+
text: eachGap,
|
|
606
|
+
_startIndexOffset: start - index,
|
|
607
|
+
_startRowOffset: rowOffsetBefore - position.row,
|
|
608
|
+
_startColOffset: colOffsetBefore - position.column,
|
|
609
|
+
_endIndexOffset: end - index,
|
|
610
|
+
_endRowOffset: rowOffset - position.row,
|
|
611
|
+
_endColOffset: colOffset - position.column,
|
|
612
|
+
children: [],
|
|
613
|
+
}));
|
|
614
|
+
// sometimes the gap isn't always whitespace
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
const colOffsetBefore = colOffset;
|
|
618
|
+
colOffset += eachGap.length;
|
|
619
|
+
newChildren.push(new SoftTextNode({
|
|
620
|
+
tree: node.tree,
|
|
621
|
+
parent: parentNode,
|
|
622
|
+
getReferencePoint,
|
|
623
|
+
text: eachGap,
|
|
624
|
+
_startIndexOffset: start - index,
|
|
625
|
+
_startRowOffset: rowOffset - position.row,
|
|
626
|
+
_startColOffset: colOffsetBefore - position.column,
|
|
627
|
+
_endIndexOffset: end - index,
|
|
628
|
+
_endRowOffset: rowOffset - position.row,
|
|
629
|
+
_endColOffset: colOffset - position.column,
|
|
630
|
+
children: [],
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
start = end;
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
// preceding whitespace
|
|
637
|
+
if (node.startIndex != firstChild.startIndex) {
|
|
638
|
+
const gapText = string.slice(node.startIndex, firstChild.startIndex);
|
|
639
|
+
const thisNode = node;
|
|
640
|
+
// whitespace and non-whitespace chunks
|
|
641
|
+
handleGaps(gapText, () => ({ index: thisNode.startIndex, position: thisNode.startPosition }), node);
|
|
642
|
+
}
|
|
643
|
+
// firstChild.indent = indent
|
|
644
|
+
newChildren.push(firstChild);
|
|
645
|
+
// gaps between sibilings
|
|
646
|
+
let prevChild = firstChild;
|
|
647
|
+
for (const eachSecondaryNode of childrenCopy) {
|
|
648
|
+
if (prevChild.endIndex != eachSecondaryNode.startIndex) {
|
|
649
|
+
const gapText = string.slice(prevChild.endIndex, eachSecondaryNode.startIndex);
|
|
650
|
+
const thisChild = prevChild;
|
|
651
|
+
handleGaps(gapText, () => ({ index: thisChild.endIndex, position: thisChild.endPosition }), node);
|
|
652
|
+
}
|
|
653
|
+
// eachSecondaryNode.indent = indent
|
|
654
|
+
newChildren.push(eachSecondaryNode);
|
|
655
|
+
prevChild = eachSecondaryNode;
|
|
656
|
+
}
|
|
657
|
+
// gap between last child and parent
|
|
658
|
+
if (prevChild.endIndex != node.endIndex) {
|
|
659
|
+
const gapText = string.slice(prevChild.endIndex, node.endIndex);
|
|
660
|
+
const thisChild = prevChild;
|
|
661
|
+
handleGaps(gapText, () => ({ index: thisChild.endIndex, position: thisChild.endPosition }), node);
|
|
662
|
+
}
|
|
663
|
+
return newChildren;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates and returns a new parser instance, loading a language from a WebAssembly binary or file path.
|
|
3
|
+
* Optionally, the parser can be configured to disable soft nodes.
|
|
4
|
+
*
|
|
5
|
+
* @async
|
|
6
|
+
* @param {Uint8Array|string} wasmUint8ArrayOrFilePath - The WebAssembly binary as a `Uint8Array` or a file path to load the language.
|
|
7
|
+
* @param {Object} [options] - Optional configuration options.
|
|
8
|
+
* @param {boolean} [options.disableSoftNodes=false] - Whether to disable soft nodes in the parser (default is `false`).
|
|
9
|
+
* @returns {Promise<ExtendedParser>} A promise that resolves to the created parser instance.
|
|
10
|
+
*/
|
|
11
|
+
export function createParser(wasmUint8ArrayOrFilePath: Uint8Array | string, { disableSoftNodes, moduleOptions }?: {
|
|
12
|
+
disableSoftNodes?: boolean | undefined;
|
|
13
|
+
}): Promise<ExtendedParser>;
|
|
14
|
+
declare class ExtendedParser extends Parser {
|
|
15
|
+
/**
|
|
16
|
+
* Parse a slice of UTF8 text.
|
|
17
|
+
*
|
|
18
|
+
* @param {string | ParseCallback} callback - Source code to parse
|
|
19
|
+
*
|
|
20
|
+
* @param {Tree | null} [oldTree] - A previous syntax tree parsed from the same document. If the text of the
|
|
21
|
+
* document has changed since `oldTree` was created, then you must edit `oldTree` to match
|
|
22
|
+
* the new text using {@link Tree#edit}.
|
|
23
|
+
*
|
|
24
|
+
* @param {ParseOptions} [options] - Options for parsing the text.
|
|
25
|
+
* This can be used to set the included ranges, or a progress callback.
|
|
26
|
+
*
|
|
27
|
+
* @returns {ExtendedTree | null} A {@link Tree} if parsing succeeded, or `null` if:
|
|
28
|
+
* - The parser has not yet had a language assigned with {@link Parser#setLanguage}.
|
|
29
|
+
* - The progress callback returned true.
|
|
30
|
+
*/
|
|
31
|
+
parse(inputString: any, oldTree?: Tree | null, options?: ParseOptions): ExtendedTree | null;
|
|
32
|
+
}
|
|
33
|
+
import { Parser } from "../tree_sitter/parser.js";
|
|
34
|
+
import { Tree } from "../tree_sitter/tree.js";
|
|
35
|
+
import { ExtendedTree } from "./node_extended.js";
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=parser.d.ts.map
|