@liendev/parser 0.39.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 (153) hide show
  1. package/dist/ast/chunker.d.ts +30 -0
  2. package/dist/ast/chunker.d.ts.map +1 -0
  3. package/dist/ast/chunker.js +310 -0
  4. package/dist/ast/chunker.js.map +1 -0
  5. package/dist/ast/complexity/cognitive.d.ts +16 -0
  6. package/dist/ast/complexity/cognitive.d.ts.map +1 -0
  7. package/dist/ast/complexity/cognitive.js +137 -0
  8. package/dist/ast/complexity/cognitive.js.map +1 -0
  9. package/dist/ast/complexity/cyclomatic.d.ts +12 -0
  10. package/dist/ast/complexity/cyclomatic.d.ts.map +1 -0
  11. package/dist/ast/complexity/cyclomatic.js +54 -0
  12. package/dist/ast/complexity/cyclomatic.js.map +1 -0
  13. package/dist/ast/complexity/halstead.d.ts +56 -0
  14. package/dist/ast/complexity/halstead.d.ts.map +1 -0
  15. package/dist/ast/complexity/halstead.js +196 -0
  16. package/dist/ast/complexity/halstead.js.map +1 -0
  17. package/dist/ast/complexity/index.d.ts +13 -0
  18. package/dist/ast/complexity/index.d.ts.map +1 -0
  19. package/dist/ast/complexity/index.js +12 -0
  20. package/dist/ast/complexity/index.js.map +1 -0
  21. package/dist/ast/extractors/index.d.ts +35 -0
  22. package/dist/ast/extractors/index.d.ts.map +1 -0
  23. package/dist/ast/extractors/index.js +41 -0
  24. package/dist/ast/extractors/index.js.map +1 -0
  25. package/dist/ast/extractors/symbol-helpers.d.ts +20 -0
  26. package/dist/ast/extractors/symbol-helpers.d.ts.map +1 -0
  27. package/dist/ast/extractors/symbol-helpers.js +58 -0
  28. package/dist/ast/extractors/symbol-helpers.js.map +1 -0
  29. package/dist/ast/extractors/types.d.ts +108 -0
  30. package/dist/ast/extractors/types.d.ts.map +1 -0
  31. package/dist/ast/extractors/types.js +2 -0
  32. package/dist/ast/extractors/types.js.map +1 -0
  33. package/dist/ast/languages/javascript.d.ts +134 -0
  34. package/dist/ast/languages/javascript.d.ts.map +1 -0
  35. package/dist/ast/languages/javascript.js +787 -0
  36. package/dist/ast/languages/javascript.js.map +1 -0
  37. package/dist/ast/languages/php.d.ts +84 -0
  38. package/dist/ast/languages/php.d.ts.map +1 -0
  39. package/dist/ast/languages/php.js +452 -0
  40. package/dist/ast/languages/php.js.map +1 -0
  41. package/dist/ast/languages/python.d.ts +96 -0
  42. package/dist/ast/languages/python.d.ts.map +1 -0
  43. package/dist/ast/languages/python.js +448 -0
  44. package/dist/ast/languages/python.js.map +1 -0
  45. package/dist/ast/languages/registry.d.ts +30 -0
  46. package/dist/ast/languages/registry.d.ts.map +1 -0
  47. package/dist/ast/languages/registry.js +95 -0
  48. package/dist/ast/languages/registry.js.map +1 -0
  49. package/dist/ast/languages/rust.d.ts +113 -0
  50. package/dist/ast/languages/rust.d.ts.map +1 -0
  51. package/dist/ast/languages/rust.js +614 -0
  52. package/dist/ast/languages/rust.js.map +1 -0
  53. package/dist/ast/languages/types.d.ts +52 -0
  54. package/dist/ast/languages/types.d.ts.map +1 -0
  55. package/dist/ast/languages/types.js +2 -0
  56. package/dist/ast/languages/types.js.map +1 -0
  57. package/dist/ast/languages/typescript.d.ts +3 -0
  58. package/dist/ast/languages/typescript.d.ts.map +1 -0
  59. package/dist/ast/languages/typescript.js +134 -0
  60. package/dist/ast/languages/typescript.js.map +1 -0
  61. package/dist/ast/parser.d.ts +29 -0
  62. package/dist/ast/parser.d.ts.map +1 -0
  63. package/dist/ast/parser.js +67 -0
  64. package/dist/ast/parser.js.map +1 -0
  65. package/dist/ast/symbols.d.ts +74 -0
  66. package/dist/ast/symbols.d.ts.map +1 -0
  67. package/dist/ast/symbols.js +171 -0
  68. package/dist/ast/symbols.js.map +1 -0
  69. package/dist/ast/traversers/index.d.ts +19 -0
  70. package/dist/ast/traversers/index.d.ts.map +1 -0
  71. package/dist/ast/traversers/index.js +21 -0
  72. package/dist/ast/traversers/index.js.map +1 -0
  73. package/dist/ast/traversers/types.d.ts +98 -0
  74. package/dist/ast/traversers/types.d.ts.map +1 -0
  75. package/dist/ast/traversers/types.js +2 -0
  76. package/dist/ast/traversers/types.js.map +1 -0
  77. package/dist/ast/types.d.ts +54 -0
  78. package/dist/ast/types.d.ts.map +1 -0
  79. package/dist/ast/types.js +2 -0
  80. package/dist/ast/types.js.map +1 -0
  81. package/dist/chunk-only-index.d.ts +25 -0
  82. package/dist/chunk-only-index.d.ts.map +1 -0
  83. package/dist/chunk-only-index.js +107 -0
  84. package/dist/chunk-only-index.js.map +1 -0
  85. package/dist/chunker.d.ts +12 -0
  86. package/dist/chunker.d.ts.map +1 -0
  87. package/dist/chunker.js +98 -0
  88. package/dist/chunker.js.map +1 -0
  89. package/dist/constants.d.ts +8 -0
  90. package/dist/constants.d.ts.map +1 -0
  91. package/dist/constants.js +11 -0
  92. package/dist/constants.js.map +1 -0
  93. package/dist/content-hash.d.ts +20 -0
  94. package/dist/content-hash.d.ts.map +1 -0
  95. package/dist/content-hash.js +91 -0
  96. package/dist/content-hash.js.map +1 -0
  97. package/dist/dependency-analyzer.d.ts +79 -0
  98. package/dist/dependency-analyzer.d.ts.map +1 -0
  99. package/dist/dependency-analyzer.js +408 -0
  100. package/dist/dependency-analyzer.js.map +1 -0
  101. package/dist/ecosystem-presets.d.ts +32 -0
  102. package/dist/ecosystem-presets.d.ts.map +1 -0
  103. package/dist/ecosystem-presets.js +325 -0
  104. package/dist/ecosystem-presets.js.map +1 -0
  105. package/dist/gitignore.d.ts +22 -0
  106. package/dist/gitignore.d.ts.map +1 -0
  107. package/dist/gitignore.js +128 -0
  108. package/dist/gitignore.js.map +1 -0
  109. package/dist/index.d.ts +32 -0
  110. package/dist/index.d.ts.map +1 -0
  111. package/dist/index.js +68 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/insights/chunk-complexity.d.ts +89 -0
  114. package/dist/insights/chunk-complexity.d.ts.map +1 -0
  115. package/dist/insights/chunk-complexity.js +332 -0
  116. package/dist/insights/chunk-complexity.js.map +1 -0
  117. package/dist/insights/types.d.ts +73 -0
  118. package/dist/insights/types.d.ts.map +1 -0
  119. package/dist/insights/types.js +9 -0
  120. package/dist/insights/types.js.map +1 -0
  121. package/dist/json-template-chunker.d.ts +12 -0
  122. package/dist/json-template-chunker.d.ts.map +1 -0
  123. package/dist/json-template-chunker.js +87 -0
  124. package/dist/json-template-chunker.js.map +1 -0
  125. package/dist/liquid-chunker.d.ts +16 -0
  126. package/dist/liquid-chunker.d.ts.map +1 -0
  127. package/dist/liquid-chunker.js +274 -0
  128. package/dist/liquid-chunker.js.map +1 -0
  129. package/dist/scanner.d.ts +16 -0
  130. package/dist/scanner.d.ts.map +1 -0
  131. package/dist/scanner.js +95 -0
  132. package/dist/scanner.js.map +1 -0
  133. package/dist/symbol-extractor.d.ts +18 -0
  134. package/dist/symbol-extractor.d.ts.map +1 -0
  135. package/dist/symbol-extractor.js +343 -0
  136. package/dist/symbol-extractor.js.map +1 -0
  137. package/dist/test-associations.d.ts +16 -0
  138. package/dist/test-associations.d.ts.map +1 -0
  139. package/dist/test-associations.js +43 -0
  140. package/dist/test-associations.js.map +1 -0
  141. package/dist/types.d.ts +75 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +2 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/utils/path-matching.d.ts +71 -0
  146. package/dist/utils/path-matching.d.ts.map +1 -0
  147. package/dist/utils/path-matching.js +258 -0
  148. package/dist/utils/path-matching.js.map +1 -0
  149. package/dist/utils/repo-id.d.ts +6 -0
  150. package/dist/utils/repo-id.d.ts.map +1 -0
  151. package/dist/utils/repo-id.js +12 -0
  152. package/dist/utils/repo-id.js.map +1 -0
  153. package/package.json +66 -0
@@ -0,0 +1,787 @@
1
+ import JavaScript from 'tree-sitter-javascript';
2
+ import { extractSignature, extractParameters, extractReturnType, } from '../extractors/symbol-helpers.js';
3
+ import { calculateComplexity } from '../complexity/index.js';
4
+ // =============================================================================
5
+ // TRAVERSERS
6
+ // =============================================================================
7
+ /**
8
+ * TypeScript/JavaScript AST traverser
9
+ *
10
+ * Handles TypeScript and JavaScript AST node types and traversal patterns.
11
+ * Both languages share the same AST structure (via tree-sitter-typescript).
12
+ */
13
+ export class TypeScriptTraverser {
14
+ targetNodeTypes = [
15
+ 'function_declaration',
16
+ 'function',
17
+ 'interface_declaration',
18
+ 'method_definition',
19
+ 'lexical_declaration', // For const/let with arrow functions
20
+ 'variable_declaration', // For var with functions
21
+ ];
22
+ containerTypes = [
23
+ 'class_declaration', // We extract methods, not the class itself
24
+ ];
25
+ declarationTypes = [
26
+ 'lexical_declaration', // const/let
27
+ 'variable_declaration', // var
28
+ ];
29
+ functionTypes = ['arrow_function', 'function_expression', 'function'];
30
+ shouldExtractChildren(node) {
31
+ return this.containerTypes.includes(node.type);
32
+ }
33
+ isDeclarationWithFunction(node) {
34
+ return this.declarationTypes.includes(node.type);
35
+ }
36
+ getContainerBody(node) {
37
+ if (node.type === 'class_declaration') {
38
+ return node.childForFieldName('body');
39
+ }
40
+ return null;
41
+ }
42
+ shouldTraverseChildren(node) {
43
+ return (node.type === 'program' || node.type === 'export_statement' || node.type === 'class_body');
44
+ }
45
+ findParentContainerName(node) {
46
+ let current = node.parent;
47
+ while (current) {
48
+ if (current.type === 'class_declaration') {
49
+ const nameNode = current.childForFieldName('name');
50
+ return nameNode?.text;
51
+ }
52
+ current = current.parent;
53
+ }
54
+ return undefined;
55
+ }
56
+ findFunctionInDeclaration(node) {
57
+ const search = (n, depth) => {
58
+ if (depth > 3)
59
+ return null;
60
+ if (this.functionTypes.includes(n.type)) {
61
+ return n;
62
+ }
63
+ for (let i = 0; i < n.childCount; i++) {
64
+ const child = n.child(i);
65
+ if (child) {
66
+ const result = search(child, depth + 1);
67
+ if (result)
68
+ return result;
69
+ }
70
+ }
71
+ return null;
72
+ };
73
+ const functionNode = search(node, 0);
74
+ return {
75
+ hasFunction: functionNode !== null,
76
+ functionNode,
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * JavaScript uses the same traverser as TypeScript
82
+ */
83
+ export class JavaScriptTraverser extends TypeScriptTraverser {
84
+ }
85
+ // =============================================================================
86
+ // EXPORT EXTRACTORS
87
+ // =============================================================================
88
+ /**
89
+ * JavaScript/TypeScript export extractor
90
+ *
91
+ * Handles ES module exports:
92
+ * - Named exports: export { foo, bar }
93
+ * - Declaration exports: export function foo() {}, export const bar = ...
94
+ * - Default exports: export default ...
95
+ * - Re-exports: export { foo } from './module'
96
+ *
97
+ * Handles CommonJS exports:
98
+ * - module.exports = { foo, bar }
99
+ * - module.exports = function/class
100
+ * - exports.foo = ... / module.exports.bar = ...
101
+ */
102
+ export class JavaScriptExportExtractor {
103
+ extractExports(rootNode) {
104
+ const exports = [];
105
+ const seen = new Set();
106
+ const addExport = (name) => {
107
+ if (name && !seen.has(name)) {
108
+ seen.add(name);
109
+ exports.push(name);
110
+ }
111
+ };
112
+ for (let i = 0; i < rootNode.namedChildCount; i++) {
113
+ const child = rootNode.namedChild(i);
114
+ if (child?.type === 'export_statement') {
115
+ this.extractExportStatementSymbols(child, addExport);
116
+ }
117
+ else if (child?.type === 'expression_statement') {
118
+ this.extractCJSExportSymbols(child, addExport);
119
+ }
120
+ }
121
+ return exports;
122
+ }
123
+ extractExportStatementSymbols(node, addExport) {
124
+ const defaultKeyword = node.children.find(c => c.type === 'default');
125
+ if (defaultKeyword) {
126
+ addExport('default');
127
+ }
128
+ const declaration = node.childForFieldName('declaration');
129
+ if (declaration) {
130
+ this.extractDeclarationExports(declaration, addExport);
131
+ }
132
+ for (let i = 0; i < node.namedChildCount; i++) {
133
+ const child = node.namedChild(i);
134
+ if (child?.type === 'export_clause') {
135
+ this.extractExportClauseSymbols(child, addExport);
136
+ }
137
+ }
138
+ }
139
+ extractDeclarationExports(node, addExport) {
140
+ const nameNode = node.childForFieldName('name');
141
+ if (nameNode) {
142
+ addExport(nameNode.text);
143
+ return;
144
+ }
145
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
146
+ for (let i = 0; i < node.namedChildCount; i++) {
147
+ const child = node.namedChild(i);
148
+ if (child?.type === 'variable_declarator') {
149
+ const varName = child.childForFieldName('name');
150
+ if (varName) {
151
+ addExport(varName.text);
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+ extractExportClauseSymbols(node, addExport) {
158
+ for (let i = 0; i < node.namedChildCount; i++) {
159
+ const child = node.namedChild(i);
160
+ if (child?.type === 'export_specifier') {
161
+ const aliasNode = child.childForFieldName('alias');
162
+ const nameNode = child.childForFieldName('name');
163
+ const exported = aliasNode?.text || nameNode?.text;
164
+ if (exported) {
165
+ addExport(exported);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // CommonJS export extraction
172
+ // ---------------------------------------------------------------------------
173
+ isModuleExports(node) {
174
+ return (node.type === 'member_expression' &&
175
+ node.childForFieldName('object')?.text === 'module' &&
176
+ node.childForFieldName('property')?.text === 'exports');
177
+ }
178
+ extractCJSExportSymbols(node, addExport) {
179
+ const expr = node.namedChild(0);
180
+ if (expr?.type !== 'assignment_expression')
181
+ return;
182
+ const left = expr.childForFieldName('left');
183
+ const right = expr.childForFieldName('right');
184
+ if (!left || !right)
185
+ return;
186
+ // module.exports = ...
187
+ if (this.isModuleExports(left)) {
188
+ this.extractModuleExportsValue(right, addExport);
189
+ return;
190
+ }
191
+ // exports.foo = ... or module.exports.bar = ...
192
+ if (left.type !== 'member_expression')
193
+ return;
194
+ const objectNode = left.childForFieldName('object');
195
+ const prop = left.childForFieldName('property');
196
+ if (!prop)
197
+ return;
198
+ const isExportsProperty = objectNode?.text === 'exports' || (objectNode != null && this.isModuleExports(objectNode));
199
+ if (isExportsProperty)
200
+ addExport(prop.text);
201
+ }
202
+ extractModuleExportsValue(node, addExport) {
203
+ // module.exports = { foo, bar, baz: val }
204
+ if (node.type === 'object') {
205
+ this.extractObjectExportProperties(node, addExport);
206
+ return;
207
+ }
208
+ // module.exports = function name() {} or module.exports = class Name {}
209
+ if (node.type === 'function_expression' || node.type === 'class') {
210
+ addExport('default');
211
+ const nameNode = node.childForFieldName('name');
212
+ if (nameNode)
213
+ addExport(nameNode.text);
214
+ return;
215
+ }
216
+ // module.exports = identifier or anything else
217
+ addExport('default');
218
+ }
219
+ extractObjectExportProperties(node, addExport) {
220
+ for (let i = 0; i < node.namedChildCount; i++) {
221
+ const prop = node.namedChild(i);
222
+ if (!prop)
223
+ continue;
224
+ if (prop.type === 'shorthand_property_identifier') {
225
+ addExport(prop.text);
226
+ }
227
+ else if (prop.type === 'pair') {
228
+ const key = prop.childForFieldName('key');
229
+ if (key)
230
+ addExport(key.text);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * TypeScript uses the same export extraction as JavaScript
237
+ */
238
+ export class TypeScriptExportExtractor extends JavaScriptExportExtractor {
239
+ }
240
+ // =============================================================================
241
+ // IMPORT EXTRACTORS
242
+ // =============================================================================
243
+ /**
244
+ * JavaScript/TypeScript import extractor
245
+ *
246
+ * Handles ES module imports:
247
+ * - Named imports: import { foo, bar } from './module'
248
+ * - Default imports: import foo from './module'
249
+ * - Namespace imports: import * as utils from './module'
250
+ * - Re-exports: export { foo } from './module'
251
+ *
252
+ * Handles CommonJS require():
253
+ * - const x = require('module')
254
+ * - const { a, b } = require('module')
255
+ * - const { a: alias } = require('module')
256
+ * - require('./side-effect')
257
+ */
258
+ export class JavaScriptImportExtractor {
259
+ importNodeTypes = [
260
+ 'import_statement',
261
+ 'export_statement',
262
+ 'lexical_declaration',
263
+ 'variable_declaration',
264
+ 'expression_statement',
265
+ ];
266
+ extractImportPath(node) {
267
+ const sourceNode = node.childForFieldName('source');
268
+ if (sourceNode)
269
+ return sourceNode.text.replace(/['"]/g, '');
270
+ // Handle CommonJS require() in variable/lexical declarations
271
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
272
+ const requireInfo = this.processRequireDeclaration(node);
273
+ if (requireInfo?.importPath)
274
+ return requireInfo.importPath;
275
+ }
276
+ return this.extractRequirePath(node);
277
+ }
278
+ processImportSymbols(node) {
279
+ if (node.type === 'import_statement') {
280
+ return this.processImportStatement(node);
281
+ }
282
+ if (node.type === 'export_statement') {
283
+ return this.processReExportStatement(node);
284
+ }
285
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
286
+ return this.processRequireDeclaration(node);
287
+ }
288
+ if (node.type === 'expression_statement') {
289
+ return this.processBareRequire(node);
290
+ }
291
+ return null;
292
+ }
293
+ processImportStatement(node) {
294
+ const sourceNode = node.childForFieldName('source');
295
+ if (!sourceNode)
296
+ return null;
297
+ const importPath = sourceNode.text.replace(/['"]/g, '');
298
+ const symbols = this.extractImportStatementSymbols(node);
299
+ return symbols.length > 0 ? { importPath, symbols } : null;
300
+ }
301
+ processReExportStatement(node) {
302
+ const sourceNode = node.childForFieldName('source');
303
+ if (!sourceNode)
304
+ return null;
305
+ const importPath = sourceNode.text.replace(/['"]/g, '');
306
+ const symbols = [];
307
+ for (let i = 0; i < node.namedChildCount; i++) {
308
+ const child = node.namedChild(i);
309
+ if (child?.type === 'export_clause') {
310
+ symbols.push(...this.extractExportClauseSymbols(child));
311
+ }
312
+ }
313
+ return symbols.length > 0 ? { importPath, symbols } : null;
314
+ }
315
+ extractImportStatementSymbols(node) {
316
+ const symbols = [];
317
+ for (let i = 0; i < node.namedChildCount; i++) {
318
+ const child = node.namedChild(i);
319
+ if (!child)
320
+ continue;
321
+ switch (child.type) {
322
+ case 'identifier':
323
+ symbols.push(child.text);
324
+ break;
325
+ case 'import_clause':
326
+ this.extractImportClauseSymbols(child, symbols);
327
+ break;
328
+ case 'named_imports':
329
+ this.extractNamedImportSymbols(child, symbols);
330
+ break;
331
+ case 'namespace_import':
332
+ this.extractNamespaceImportSymbol(child, symbols);
333
+ break;
334
+ }
335
+ }
336
+ return symbols;
337
+ }
338
+ extractImportClauseSymbols(node, symbols) {
339
+ for (let i = 0; i < node.namedChildCount; i++) {
340
+ const child = node.namedChild(i);
341
+ if (!child)
342
+ continue;
343
+ if (child.type === 'identifier') {
344
+ symbols.push(child.text);
345
+ }
346
+ else if (child.type === 'named_imports') {
347
+ this.extractNamedImportSymbols(child, symbols);
348
+ }
349
+ else if (child.type === 'namespace_import') {
350
+ this.extractNamespaceImportSymbol(child, symbols);
351
+ }
352
+ }
353
+ }
354
+ extractNamespaceImportSymbol(node, symbols) {
355
+ for (let i = 0; i < node.namedChildCount; i++) {
356
+ const child = node.namedChild(i);
357
+ if (child?.type === 'identifier') {
358
+ symbols.push(`* as ${child.text}`);
359
+ return;
360
+ }
361
+ }
362
+ }
363
+ extractNamedImportSymbols(node, symbols) {
364
+ for (let i = 0; i < node.namedChildCount; i++) {
365
+ const child = node.namedChild(i);
366
+ if (!child)
367
+ continue;
368
+ switch (child.type) {
369
+ case 'import_specifier': {
370
+ const aliasNode = child.childForFieldName('alias');
371
+ const nameNode = child.childForFieldName('name');
372
+ const symbol = aliasNode?.text || nameNode?.text || child.text;
373
+ if (symbol && !symbol.includes('{') && !symbol.includes('}')) {
374
+ symbols.push(symbol);
375
+ }
376
+ break;
377
+ }
378
+ case 'identifier':
379
+ symbols.push(child.text);
380
+ break;
381
+ case 'named_imports':
382
+ this.extractNamedImportSymbols(child, symbols);
383
+ break;
384
+ }
385
+ }
386
+ }
387
+ /**
388
+ * Extract original symbol names from an export_clause (for re-exports).
389
+ * Uses original name (not alias) since it maps to the source module's exports.
390
+ */
391
+ extractExportClauseSymbols(clause) {
392
+ const symbols = [];
393
+ for (let j = 0; j < clause.namedChildCount; j++) {
394
+ const specifier = clause.namedChild(j);
395
+ if (specifier?.type !== 'export_specifier')
396
+ continue;
397
+ const nameNode = specifier.childForFieldName('name');
398
+ const symbol = nameNode?.text || specifier.text;
399
+ if (symbol && !symbol.includes('{') && !symbol.includes('}')) {
400
+ symbols.push(symbol);
401
+ }
402
+ }
403
+ return symbols;
404
+ }
405
+ // ---------------------------------------------------------------------------
406
+ // CommonJS require() extraction
407
+ // ---------------------------------------------------------------------------
408
+ findRequireCall(node) {
409
+ // Only match require() as a direct call_expression — not nested inside other expressions
410
+ if (node.type === 'call_expression' && node.childForFieldName('function')?.text === 'require') {
411
+ return node;
412
+ }
413
+ return null;
414
+ }
415
+ getRequirePathFromCall(callNode) {
416
+ const args = callNode.childForFieldName('arguments');
417
+ if (!args)
418
+ return null;
419
+ const firstArg = args.namedChild(0);
420
+ if (!firstArg || firstArg.type !== 'string')
421
+ return null;
422
+ return firstArg.text.replace(/['"]/g, '');
423
+ }
424
+ extractRequirePath(node) {
425
+ // Check the node itself, then its direct named children
426
+ const call = this.findRequireCall(node) ?? this.findRequireCallInChildren(node);
427
+ if (!call)
428
+ return null;
429
+ return this.getRequirePathFromCall(call);
430
+ }
431
+ findRequireCallInChildren(node) {
432
+ for (let i = 0; i < node.namedChildCount; i++) {
433
+ const child = node.namedChild(i);
434
+ if (child) {
435
+ const found = this.findRequireCall(child);
436
+ if (found)
437
+ return found;
438
+ }
439
+ }
440
+ return null;
441
+ }
442
+ processRequireDeclaration(node) {
443
+ // Find the variable_declarator with a require() value
444
+ for (let i = 0; i < node.namedChildCount; i++) {
445
+ const declarator = node.namedChild(i);
446
+ if (declarator?.type !== 'variable_declarator')
447
+ continue;
448
+ const value = declarator.childForFieldName('value');
449
+ if (!value)
450
+ continue;
451
+ const call = this.findRequireCall(value);
452
+ if (!call)
453
+ continue;
454
+ const importPath = this.getRequirePathFromCall(call);
455
+ if (!importPath)
456
+ continue;
457
+ const nameNode = declarator.childForFieldName('name');
458
+ if (!nameNode)
459
+ continue;
460
+ const symbols = this.extractRequireBindingSymbols(nameNode);
461
+ if (symbols.length > 0)
462
+ return { importPath, symbols };
463
+ }
464
+ return null;
465
+ }
466
+ extractRequireBindingSymbols(nameNode) {
467
+ // const express = require('express')
468
+ if (nameNode.type === 'identifier')
469
+ return [nameNode.text];
470
+ // const { Router, json } = require('express')
471
+ if (nameNode.type === 'object_pattern')
472
+ return this.extractObjectPatternSymbols(nameNode);
473
+ return [];
474
+ }
475
+ extractObjectPatternSymbols(node) {
476
+ const symbols = [];
477
+ for (let i = 0; i < node.namedChildCount; i++) {
478
+ const prop = node.namedChild(i);
479
+ if (!prop)
480
+ continue;
481
+ if (prop.type === 'shorthand_property_identifier_pattern') {
482
+ symbols.push(prop.text);
483
+ }
484
+ else if (prop.type === 'pair_pattern') {
485
+ // const { Router: MyRouter } = require('express')
486
+ const value = prop.childForFieldName('value');
487
+ if (value)
488
+ symbols.push(value.text);
489
+ }
490
+ }
491
+ return symbols;
492
+ }
493
+ processBareRequire(node) {
494
+ // require('./polyfill') — side-effect import, no symbols
495
+ const importPath = this.extractRequirePath(node);
496
+ if (!importPath)
497
+ return null;
498
+ return { importPath, symbols: [] };
499
+ }
500
+ }
501
+ /**
502
+ * TypeScript uses the same import extraction as JavaScript
503
+ */
504
+ export class TypeScriptImportExtractor extends JavaScriptImportExtractor {
505
+ }
506
+ // =============================================================================
507
+ // SYMBOL EXTRACTORS
508
+ // =============================================================================
509
+ /**
510
+ * JavaScript/TypeScript symbol extractor
511
+ *
512
+ * Extracts symbol info from function declarations, arrow functions,
513
+ * method definitions, class declarations, and interface declarations.
514
+ *
515
+ * Also handles call site extraction for call_expression and new_expression.
516
+ */
517
+ export class JavaScriptSymbolExtractor {
518
+ symbolNodeTypes = [
519
+ 'function_declaration',
520
+ 'function',
521
+ 'arrow_function',
522
+ 'function_expression',
523
+ 'method_definition',
524
+ 'class_declaration',
525
+ 'interface_declaration',
526
+ ];
527
+ extractSymbol(node, content, parentClass) {
528
+ switch (node.type) {
529
+ case 'function_declaration':
530
+ case 'function':
531
+ return this.extractFunctionInfo(node, content, parentClass);
532
+ case 'arrow_function':
533
+ case 'function_expression':
534
+ return this.extractArrowFunctionInfo(node, content, parentClass);
535
+ case 'method_definition':
536
+ return this.extractMethodInfo(node, content, parentClass);
537
+ case 'class_declaration':
538
+ return this.extractClassInfo(node);
539
+ case 'interface_declaration':
540
+ return this.extractInterfaceInfo(node);
541
+ default:
542
+ return null;
543
+ }
544
+ }
545
+ extractCallSite(node) {
546
+ const line = node.startPosition.row + 1;
547
+ if (node.type === 'call_expression') {
548
+ const functionNode = node.childForFieldName('function');
549
+ if (!functionNode)
550
+ return null;
551
+ const symbol = this.resolveSymbol(functionNode);
552
+ return symbol ? { symbol, line, key: `${symbol}:${line}` } : null;
553
+ }
554
+ if (node.type === 'new_expression') {
555
+ const ctorNode = node.childForFieldName('constructor');
556
+ if (!ctorNode)
557
+ return null;
558
+ const symbol = this.resolveSymbol(ctorNode);
559
+ return symbol ? { symbol, line, key: `${symbol}:${line}` } : null;
560
+ }
561
+ return null;
562
+ }
563
+ resolveSymbol(node) {
564
+ if (node.type === 'identifier')
565
+ return node.text;
566
+ if (node.type === 'member_expression') {
567
+ const propertyNode = node.childForFieldName('property');
568
+ if (propertyNode?.type === 'property_identifier')
569
+ return propertyNode.text;
570
+ }
571
+ return null;
572
+ }
573
+ extractFunctionInfo(node, content, parentClass) {
574
+ const nameNode = node.childForFieldName('name');
575
+ if (!nameNode)
576
+ return null;
577
+ return {
578
+ name: nameNode.text,
579
+ type: parentClass ? 'method' : 'function',
580
+ startLine: node.startPosition.row + 1,
581
+ endLine: node.endPosition.row + 1,
582
+ parentClass,
583
+ signature: extractSignature(node, content),
584
+ parameters: extractParameters(node, content),
585
+ returnType: extractReturnType(node, content),
586
+ complexity: calculateComplexity(node),
587
+ };
588
+ }
589
+ extractArrowFunctionInfo(node, content, parentClass) {
590
+ const parent = node.parent;
591
+ let name = 'anonymous';
592
+ if (parent?.type === 'variable_declarator') {
593
+ const nameNode = parent.childForFieldName('name');
594
+ name = nameNode?.text || 'anonymous';
595
+ }
596
+ return {
597
+ name,
598
+ type: parentClass ? 'method' : 'function',
599
+ startLine: node.startPosition.row + 1,
600
+ endLine: node.endPosition.row + 1,
601
+ parentClass,
602
+ signature: extractSignature(node, content),
603
+ parameters: extractParameters(node, content),
604
+ complexity: calculateComplexity(node),
605
+ };
606
+ }
607
+ extractMethodInfo(node, content, parentClass) {
608
+ const nameNode = node.childForFieldName('name');
609
+ if (!nameNode)
610
+ return null;
611
+ return {
612
+ name: nameNode.text,
613
+ type: 'method',
614
+ startLine: node.startPosition.row + 1,
615
+ endLine: node.endPosition.row + 1,
616
+ parentClass,
617
+ signature: extractSignature(node, content),
618
+ parameters: extractParameters(node, content),
619
+ returnType: extractReturnType(node, content),
620
+ complexity: calculateComplexity(node),
621
+ };
622
+ }
623
+ extractClassInfo(node) {
624
+ const nameNode = node.childForFieldName('name');
625
+ if (!nameNode)
626
+ return null;
627
+ return {
628
+ name: nameNode.text,
629
+ type: 'class',
630
+ startLine: node.startPosition.row + 1,
631
+ endLine: node.endPosition.row + 1,
632
+ signature: `class ${nameNode.text}`,
633
+ };
634
+ }
635
+ extractInterfaceInfo(node) {
636
+ const nameNode = node.childForFieldName('name');
637
+ if (!nameNode)
638
+ return null;
639
+ return {
640
+ name: nameNode.text,
641
+ type: 'interface',
642
+ startLine: node.startPosition.row + 1,
643
+ endLine: node.endPosition.row + 1,
644
+ signature: `interface ${nameNode.text}`,
645
+ };
646
+ }
647
+ }
648
+ /**
649
+ * TypeScript uses the same symbol extraction as JavaScript
650
+ */
651
+ export class TypeScriptSymbolExtractor extends JavaScriptSymbolExtractor {
652
+ }
653
+ // =============================================================================
654
+ // LANGUAGE DEFINITION
655
+ // =============================================================================
656
+ export const javascriptDefinition = {
657
+ id: 'javascript',
658
+ extensions: ['js', 'jsx', 'mjs', 'cjs'],
659
+ grammar: JavaScript,
660
+ traverser: new JavaScriptTraverser(),
661
+ exportExtractor: new JavaScriptExportExtractor(),
662
+ importExtractor: new JavaScriptImportExtractor(),
663
+ symbolExtractor: new JavaScriptSymbolExtractor(),
664
+ complexity: {
665
+ decisionPoints: [
666
+ 'if_statement',
667
+ 'while_statement',
668
+ 'for_statement',
669
+ 'switch_case',
670
+ 'catch_clause',
671
+ 'ternary_expression',
672
+ 'binary_expression',
673
+ 'do_statement',
674
+ 'for_in_statement',
675
+ 'for_of_statement',
676
+ ],
677
+ nestingTypes: [
678
+ 'if_statement',
679
+ 'for_statement',
680
+ 'while_statement',
681
+ 'switch_statement',
682
+ 'catch_clause',
683
+ 'do_statement',
684
+ 'for_in_statement',
685
+ 'for_of_statement',
686
+ ],
687
+ nonNestingTypes: ['else_clause', 'ternary_expression'],
688
+ lambdaTypes: ['arrow_function', 'function_expression'],
689
+ operatorSymbols: new Set([
690
+ '+',
691
+ '-',
692
+ '*',
693
+ '/',
694
+ '%',
695
+ '**',
696
+ '==',
697
+ '===',
698
+ '!=',
699
+ '!==',
700
+ '<',
701
+ '>',
702
+ '<=',
703
+ '>=',
704
+ '&&',
705
+ '||',
706
+ '!',
707
+ '??',
708
+ '=',
709
+ '+=',
710
+ '-=',
711
+ '*=',
712
+ '/=',
713
+ '%=',
714
+ '**=',
715
+ '&&=',
716
+ '||=',
717
+ '??=',
718
+ '&',
719
+ '|',
720
+ '^',
721
+ '~',
722
+ '<<',
723
+ '>>',
724
+ '>>>',
725
+ '&=',
726
+ '|=',
727
+ '^=',
728
+ '<<=',
729
+ '>>=',
730
+ '>>>=',
731
+ '?',
732
+ ':',
733
+ '.',
734
+ '?.',
735
+ '++',
736
+ '--',
737
+ '...',
738
+ '=>',
739
+ '(',
740
+ ')',
741
+ '[',
742
+ ']',
743
+ '{',
744
+ '}',
745
+ ]),
746
+ operatorKeywords: new Set([
747
+ 'if',
748
+ 'else',
749
+ 'for',
750
+ 'while',
751
+ 'do',
752
+ 'switch',
753
+ 'case',
754
+ 'default',
755
+ 'return',
756
+ 'throw',
757
+ 'try',
758
+ 'catch',
759
+ 'finally',
760
+ 'new',
761
+ 'delete',
762
+ 'typeof',
763
+ 'instanceof',
764
+ 'in',
765
+ 'of',
766
+ 'await',
767
+ 'yield',
768
+ 'break',
769
+ 'continue',
770
+ 'const',
771
+ 'let',
772
+ 'var',
773
+ 'function',
774
+ 'class',
775
+ 'extends',
776
+ 'implements',
777
+ 'import',
778
+ 'export',
779
+ 'from',
780
+ 'as',
781
+ ]),
782
+ },
783
+ symbols: {
784
+ callExpressionTypes: ['call_expression', 'new_expression'],
785
+ },
786
+ };
787
+ //# sourceMappingURL=javascript.js.map