@kerebron/tree-sitter 0.5.4 → 0.6.0

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