@codemap-ai/code-index 1.0.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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/dist/file-discovery.d.ts +36 -0
  3. package/dist/file-discovery.d.ts.map +1 -0
  4. package/dist/file-discovery.js +204 -0
  5. package/dist/index.d.ts +6 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +26 -0
  8. package/dist/language-utils.d.ts +10 -0
  9. package/dist/language-utils.d.ts.map +1 -0
  10. package/dist/language-utils.js +75 -0
  11. package/dist/parsers/dart.d.ts +4 -0
  12. package/dist/parsers/dart.d.ts.map +1 -0
  13. package/dist/parsers/dart.js +353 -0
  14. package/dist/parsers/index.d.ts +11 -0
  15. package/dist/parsers/index.d.ts.map +1 -0
  16. package/dist/parsers/index.js +32 -0
  17. package/dist/parsers/java.d.ts +4 -0
  18. package/dist/parsers/java.d.ts.map +1 -0
  19. package/dist/parsers/java.js +222 -0
  20. package/dist/parsers/kotlin.d.ts +4 -0
  21. package/dist/parsers/kotlin.d.ts.map +1 -0
  22. package/dist/parsers/kotlin.js +221 -0
  23. package/dist/parsers/php.d.ts +4 -0
  24. package/dist/parsers/php.d.ts.map +1 -0
  25. package/dist/parsers/php.js +215 -0
  26. package/dist/parsers/python.d.ts +4 -0
  27. package/dist/parsers/python.d.ts.map +1 -0
  28. package/dist/parsers/python.js +200 -0
  29. package/dist/parsers/shared.d.ts +30 -0
  30. package/dist/parsers/shared.d.ts.map +1 -0
  31. package/dist/parsers/shared.js +200 -0
  32. package/dist/parsers/types.d.ts +93 -0
  33. package/dist/parsers/types.d.ts.map +1 -0
  34. package/dist/parsers/types.js +12 -0
  35. package/dist/parsers/typescript.d.ts +5 -0
  36. package/dist/parsers/typescript.d.ts.map +1 -0
  37. package/dist/parsers/typescript.js +549 -0
  38. package/dist/ts-resolver.d.ts +17 -0
  39. package/dist/ts-resolver.d.ts.map +1 -0
  40. package/dist/ts-resolver.js +110 -0
  41. package/package.json +30 -0
@@ -0,0 +1,549 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseTypeScriptOrJavaScriptFile = parseTypeScriptOrJavaScriptFile;
7
+ const typescript_1 = __importDefault(require("typescript"));
8
+ const shared_js_1 = require("./shared.js");
9
+ function createSourceFile(file) {
10
+ return typescript_1.default.createSourceFile(file.baseName, file.content ?? "", typescript_1.default.ScriptTarget.Latest, true, file.extension === "tsx" || file.extension === "jsx"
11
+ ? typescript_1.default.ScriptKind.TSX
12
+ : typescript_1.default.ScriptKind.TS);
13
+ }
14
+ function getLineCol(sourceFile, pos) {
15
+ const lc = sourceFile.getLineAndCharacterOfPosition(pos);
16
+ return { line: lc.line + 1, col: lc.character };
17
+ }
18
+ // ─── Import/export extraction ─────────────────────────────────────────────────
19
+ function extractImportsWithAst(file, sourceFile, filePathSet, projectImportId, workspacePath, resolverConfigs) {
20
+ const imports = [];
21
+ const exports = [];
22
+ const issues = [];
23
+ const externalSymbols = [];
24
+ function getNodeRange(node) {
25
+ const start = getLineCol(sourceFile, node.getStart(sourceFile));
26
+ const end = getLineCol(sourceFile, node.getEnd());
27
+ return {
28
+ line: start.line,
29
+ col: start.col,
30
+ endLine: end.line,
31
+ endCol: end.col,
32
+ };
33
+ }
34
+ const pushImport = (moduleSpecifier, importKind, isTypeOnly, node, importedNames) => {
35
+ const { line, col, endLine, endCol } = getNodeRange(node);
36
+ const isRelative = moduleSpecifier.startsWith(".");
37
+ const aliasResolution = !isRelative
38
+ ? (0, shared_js_1.resolveTsconfigAliasTargetPath)(workspacePath, file.path, moduleSpecifier, file.language, filePathSet, resolverConfigs)
39
+ : null;
40
+ const resolution = isRelative
41
+ ? (0, shared_js_1.resolveRelativeTargetPath)(file.path, moduleSpecifier, file.language, filePathSet)
42
+ : (aliasResolution ?? { resolvedPath: null, attemptedPath: null });
43
+ const importLocalKey = (0, shared_js_1.buildImportLocalKey)(file.path, importKind, moduleSpecifier, line, col);
44
+ imports.push({
45
+ localKey: importLocalKey,
46
+ moduleSpecifier,
47
+ importKind,
48
+ isTypeOnly,
49
+ importedNames,
50
+ line,
51
+ col,
52
+ endLine,
53
+ endCol,
54
+ resolutionKind: isRelative
55
+ ? resolution.resolvedPath ? "relative_path" : "unresolved"
56
+ : aliasResolution?.resolvedPath ? "tsconfig_alias"
57
+ : aliasResolution?.matched ? "unresolved" : "package",
58
+ targetPathText: resolution.resolvedPath ?? resolution.attemptedPath,
59
+ targetExternalSymbolKey: isRelative || aliasResolution?.matched
60
+ ? null
61
+ : `${file.language?.toLowerCase()}:${moduleSpecifier}`,
62
+ });
63
+ if (!isRelative && !aliasResolution?.matched) {
64
+ externalSymbols.push((0, shared_js_1.createExternalSymbolDraft)(projectImportId, file.language, moduleSpecifier));
65
+ }
66
+ else if (!resolution.resolvedPath) {
67
+ issues.push({
68
+ projectImportId,
69
+ severity: "warning",
70
+ code: "UNRESOLVED_IMPORT",
71
+ message: `Unable to resolve module "${moduleSpecifier}" from ${file.path}`,
72
+ detailJson: { filePath: file.path, moduleSpecifier },
73
+ });
74
+ }
75
+ return importLocalKey;
76
+ };
77
+ function getModuleSpecifier(node) {
78
+ const spec = node.moduleSpecifier;
79
+ if (!spec || !typescript_1.default.isStringLiteral(spec))
80
+ return null;
81
+ return spec.text;
82
+ }
83
+ function extractNamedBindings(clause) {
84
+ return clause.elements.map((el) => {
85
+ // el.name is the local alias; el.propertyName is the original — we want the original
86
+ if ("propertyName" in el && el.propertyName) {
87
+ return el.propertyName.text;
88
+ }
89
+ return el.name.text;
90
+ });
91
+ }
92
+ typescript_1.default.forEachChild(sourceFile, (node) => {
93
+ // import ... from '...'
94
+ if (typescript_1.default.isImportDeclaration(node)) {
95
+ const specifier = getModuleSpecifier(node);
96
+ if (!specifier)
97
+ return;
98
+ const isTypeOnly = node.importClause?.isTypeOnly ?? false;
99
+ const clause = node.importClause;
100
+ const importedNames = [];
101
+ if (clause) {
102
+ // import Foo from '...' — default import, no named
103
+ // import { A, B } from '...'
104
+ if (clause.namedBindings) {
105
+ if (typescript_1.default.isNamedImports(clause.namedBindings)) {
106
+ importedNames.push(...extractNamedBindings(clause.namedBindings));
107
+ }
108
+ // import * as ns — namespace import
109
+ if (typescript_1.default.isNamespaceImport(clause.namedBindings)) {
110
+ const nsName = clause.namedBindings.name.text;
111
+ const localKey = pushImport(specifier, "import", isTypeOnly, node, importedNames);
112
+ // patch namespaceName onto the last pushed import
113
+ const last = imports[imports.length - 1];
114
+ if (last && last.localKey === localKey)
115
+ last.namespaceName = nsName;
116
+ return;
117
+ }
118
+ }
119
+ }
120
+ pushImport(specifier, "import", isTypeOnly, node, importedNames);
121
+ return;
122
+ }
123
+ // export { A } from '...' / export * from '...' / export { A } (local)
124
+ if (typescript_1.default.isExportDeclaration(node)) {
125
+ const specifier = getModuleSpecifier(node);
126
+ const { line, col, endLine, endCol } = getNodeRange(node);
127
+ if (!specifier) {
128
+ // export { A, B } — local, no from
129
+ if (node.exportClause && typescript_1.default.isNamedExports(node.exportClause)) {
130
+ for (const el of node.exportClause.elements) {
131
+ const localName = el.propertyName?.text ?? el.name.text;
132
+ const exportName = el.name.text;
133
+ exports.push({
134
+ exportName,
135
+ exportKind: "named",
136
+ line,
137
+ col,
138
+ endLine,
139
+ endCol,
140
+ symbolLocalKey: (0, shared_js_1.buildLocalSymbolKey)(file.path, "variable", localName),
141
+ });
142
+ }
143
+ }
144
+ return;
145
+ }
146
+ const isTypeOnly = node.isTypeOnly;
147
+ if (node.exportClause && typescript_1.default.isNamedExports(node.exportClause)) {
148
+ // export { A, B } from '...'
149
+ const importLocalKey = pushImport(specifier, "export_from", isTypeOnly, node, []);
150
+ for (const el of node.exportClause.elements) {
151
+ exports.push({
152
+ exportName: el.name.text,
153
+ exportKind: "re_export",
154
+ line,
155
+ col,
156
+ endLine,
157
+ endCol,
158
+ sourceImportLocalKey: importLocalKey,
159
+ targetExternalSymbolKey: specifier.startsWith(".") ? null : `${file.language?.toLowerCase()}:${specifier}`,
160
+ });
161
+ }
162
+ }
163
+ else {
164
+ // export * from '...'
165
+ const importLocalKey = pushImport(specifier, "export_from", isTypeOnly, node, []);
166
+ exports.push({
167
+ exportName: "*",
168
+ exportKind: "wildcard",
169
+ line,
170
+ col,
171
+ endLine,
172
+ endCol,
173
+ sourceImportLocalKey: importLocalKey,
174
+ targetExternalSymbolKey: specifier.startsWith(".") ? null : `${file.language?.toLowerCase()}:${specifier}`,
175
+ });
176
+ }
177
+ return;
178
+ }
179
+ // require('...') and import('...') via CallExpression — walk full subtree
180
+ function walkForCalls(n) {
181
+ if (typescript_1.default.isCallExpression(n)) {
182
+ const expr = n.expression;
183
+ const args = n.arguments;
184
+ if (args.length === 1 && typescript_1.default.isStringLiteral(args[0])) {
185
+ const specifier = args[0].text;
186
+ if (typescript_1.default.isIdentifier(expr) && expr.text === "require") {
187
+ pushImport(specifier, "require", false, n, []);
188
+ }
189
+ else if (expr.kind === typescript_1.default.SyntaxKind.ImportKeyword) {
190
+ pushImport(specifier, "dynamic_import", false, n, []);
191
+ }
192
+ }
193
+ }
194
+ typescript_1.default.forEachChild(n, walkForCalls);
195
+ }
196
+ // Only walk statements that aren't import/export declarations (already handled)
197
+ if (!typescript_1.default.isImportDeclaration(node) && !typescript_1.default.isExportDeclaration(node)) {
198
+ walkForCalls(node);
199
+ }
200
+ });
201
+ return { imports, exports, issues, externalSymbols };
202
+ }
203
+ // ─── Symbol extraction ────────────────────────────────────────────────────────
204
+ function extractSymbolsWithAst(file, sourceFile) {
205
+ const content = file.content ?? "";
206
+ const symbols = [];
207
+ const relationships = [];
208
+ const lines = content.split(/\r?\n/);
209
+ function getSignature(node) {
210
+ const { line } = getLineCol(sourceFile, node.getStart(sourceFile));
211
+ return (lines[line - 1] ?? "").trim().slice(0, 200);
212
+ }
213
+ function getReturnType(node) {
214
+ if (typescript_1.default.isFunctionDeclaration(node) ||
215
+ typescript_1.default.isMethodDeclaration(node) ||
216
+ typescript_1.default.isFunctionExpression(node) ||
217
+ typescript_1.default.isArrowFunction(node)) {
218
+ return node.type ? node.type.getText(sourceFile).slice(0, 200) : null;
219
+ }
220
+ return null;
221
+ }
222
+ function getJSDoc(node) {
223
+ const tags = typescript_1.default.getJSDocCommentsAndTags(node);
224
+ if (tags.length === 0)
225
+ return null;
226
+ const parts = [];
227
+ for (const tag of tags) {
228
+ if (typescript_1.default.isJSDoc(tag) && tag.comment) {
229
+ const text = typeof tag.comment === "string"
230
+ ? tag.comment
231
+ : tag.comment.map((c) => c.text).join("");
232
+ if (text.trim())
233
+ parts.push(text.trim());
234
+ }
235
+ }
236
+ return parts.length > 0 ? parts.join("\n").slice(0, 500) : null;
237
+ }
238
+ function pushSymbol(name, kind, node, isExported, isDefaultExport) {
239
+ const nameStart = content.indexOf(name, node.getStart(sourceFile));
240
+ const { line, col } = nameStart >= 0
241
+ ? getLineCol(sourceFile, nameStart)
242
+ : getLineCol(sourceFile, node.getStart(sourceFile));
243
+ const end = getLineCol(sourceFile, node.getEnd());
244
+ symbols.push({
245
+ localKey: (0, shared_js_1.buildLocalSymbolKey)(file.path, kind, name),
246
+ stableKey: (0, shared_js_1.buildStableSymbolKey)(file.path, kind, name, line),
247
+ displayName: name,
248
+ kind,
249
+ language: file.language,
250
+ signature: getSignature(node),
251
+ returnType: getReturnType(node),
252
+ doc: getJSDoc(node),
253
+ isExported,
254
+ isDefaultExport,
255
+ line,
256
+ col,
257
+ endLine: end.line,
258
+ endCol: end.col,
259
+ });
260
+ }
261
+ // ─── Factory return-object method extraction (heuristic #1 + type-driven #2) ──
262
+ function getReturnedObjectLiteral(body) {
263
+ if (!body)
264
+ return null;
265
+ // Arrow function shorthand: () => ({ ... })
266
+ if (typescript_1.default.isParenthesizedExpression(body)) {
267
+ const inner = body.expression;
268
+ return typescript_1.default.isObjectLiteralExpression(inner) ? inner : null;
269
+ }
270
+ if (typescript_1.default.isObjectLiteralExpression(body))
271
+ return body;
272
+ if (!typescript_1.default.isBlock(body))
273
+ return null;
274
+ // Block body: find the last return statement
275
+ let returnedObj = null;
276
+ for (const stmt of body.statements) {
277
+ if (typescript_1.default.isReturnStatement(stmt) && stmt.expression) {
278
+ const expr = typescript_1.default.isParenthesizedExpression(stmt.expression)
279
+ ? stmt.expression.expression
280
+ : stmt.expression;
281
+ if (typescript_1.default.isObjectLiteralExpression(expr)) {
282
+ returnedObj = expr;
283
+ }
284
+ }
285
+ }
286
+ return returnedObj;
287
+ }
288
+ // Heuristic #2: if the function has a return type annotation that is a TypeLiteral
289
+ // (e.g., ): { foo(): void; bar(): string }), extract allowed method names from it.
290
+ // Returns null if no type annotation or annotation is not a resolvable object type.
291
+ function getAllowedNamesFromReturnType(node) {
292
+ if (!node.type)
293
+ return null;
294
+ // ): { method1(): T; method2(): U }
295
+ if (typescript_1.default.isTypeLiteralNode(node.type)) {
296
+ const names = new Set();
297
+ for (const member of node.type.members) {
298
+ if ((typescript_1.default.isMethodSignature(member) || typescript_1.default.isPropertySignature(member)) &&
299
+ typescript_1.default.isIdentifier(member.name)) {
300
+ names.add(member.name.text);
301
+ }
302
+ }
303
+ return names.size > 0 ? names : null;
304
+ }
305
+ return null;
306
+ }
307
+ function extractReturnObjectMethods(fnNode, parentLocalKey, isParentExported) {
308
+ const body = fnNode.body;
309
+ // Extract inner function declarations defined inside the factory body (private helpers).
310
+ // Use line number as disambiguator so two factories in the same file can have
311
+ // identically-named helpers without a localKey collision.
312
+ const blockBody = body && "statements" in body ? body : null;
313
+ if (blockBody) {
314
+ for (const stmt of blockBody.statements) {
315
+ if (typescript_1.default.isFunctionDeclaration(stmt) && stmt.name) {
316
+ const name = stmt.name.text;
317
+ const { line, col } = getLineCol(sourceFile, stmt.getStart(sourceFile));
318
+ const end = getLineCol(sourceFile, stmt.getEnd());
319
+ const uniqueName = `${name}@${line}`;
320
+ symbols.push({
321
+ localKey: (0, shared_js_1.buildLocalSymbolKey)(file.path, "function", uniqueName),
322
+ stableKey: (0, shared_js_1.buildStableSymbolKey)(file.path, "function", uniqueName, line),
323
+ displayName: name,
324
+ kind: "function",
325
+ language: file.language,
326
+ signature: getSignature(stmt),
327
+ returnType: getReturnType(stmt),
328
+ doc: getJSDoc(stmt),
329
+ isExported: false,
330
+ isDefaultExport: false,
331
+ line,
332
+ col,
333
+ endLine: end.line,
334
+ endCol: end.col,
335
+ parentSymbolLocalKey: parentLocalKey,
336
+ });
337
+ }
338
+ }
339
+ }
340
+ const obj = getReturnedObjectLiteral(body);
341
+ if (!obj)
342
+ return;
343
+ const allowedNames = getAllowedNamesFromReturnType(fnNode);
344
+ for (const prop of obj.properties) {
345
+ let name = null;
346
+ let methodNode = prop;
347
+ let isMethod = false;
348
+ if (typescript_1.default.isMethodDeclaration(prop) && typescript_1.default.isIdentifier(prop.name)) {
349
+ name = prop.name.text;
350
+ isMethod = true;
351
+ }
352
+ else if (typescript_1.default.isPropertyAssignment(prop) && typescript_1.default.isIdentifier(prop.name)) {
353
+ const init = prop.initializer;
354
+ if (typescript_1.default.isArrowFunction(init) || typescript_1.default.isFunctionExpression(init)) {
355
+ name = prop.name.text;
356
+ methodNode = prop;
357
+ isMethod = true;
358
+ }
359
+ }
360
+ else if (typescript_1.default.isShorthandPropertyAssignment(prop)) {
361
+ // { foo } — reference to existing symbol, not a new method definition, skip
362
+ }
363
+ if (!name || !isMethod)
364
+ continue;
365
+ // If type annotation present, only index names that appear in it
366
+ if (allowedNames && !allowedNames.has(name))
367
+ continue;
368
+ const { line, col } = getLineCol(sourceFile, methodNode.getStart(sourceFile));
369
+ const end = getLineCol(sourceFile, methodNode.getEnd());
370
+ symbols.push({
371
+ localKey: (0, shared_js_1.buildLocalSymbolKey)(file.path, "method", name),
372
+ stableKey: (0, shared_js_1.buildStableSymbolKey)(file.path, "method", name, line),
373
+ displayName: name,
374
+ kind: "method",
375
+ language: file.language,
376
+ signature: getSignature(methodNode),
377
+ returnType: getReturnType(typescript_1.default.isMethodDeclaration(prop)
378
+ ? prop
379
+ : typescript_1.default.isPropertyAssignment(prop)
380
+ ? prop.initializer
381
+ : prop),
382
+ doc: getJSDoc(prop),
383
+ isExported: isParentExported,
384
+ isDefaultExport: false,
385
+ line,
386
+ col,
387
+ endLine: end.line,
388
+ endCol: end.col,
389
+ parentSymbolLocalKey: parentLocalKey,
390
+ });
391
+ }
392
+ }
393
+ // ─────────────────────────────────────────────────────────────────────────────
394
+ function visitTopLevel(node) {
395
+ if (typescript_1.default.isExportAssignment(node)) {
396
+ const expr = node.expression;
397
+ if ((typescript_1.default.isFunctionExpression(expr) || typescript_1.default.isArrowFunction(expr)) &&
398
+ typescript_1.default.isIdentifier(expr.name ?? null)) {
399
+ const name = expr.name.text;
400
+ pushSymbol(name, "function", node, true, true);
401
+ }
402
+ return;
403
+ }
404
+ if (!typescript_1.default.isStatement(node))
405
+ return;
406
+ const modifiers = typescript_1.default.canHaveModifiers(node) ? typescript_1.default.getModifiers(node) : undefined;
407
+ const isExported = modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword) ?? false;
408
+ const isDefault = modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.DefaultKeyword) ?? false;
409
+ if (typescript_1.default.isFunctionDeclaration(node) && node.name) {
410
+ const name = node.name.text;
411
+ pushSymbol(name, "function", node, isExported, isDefault);
412
+ const localKey = (0, shared_js_1.buildLocalSymbolKey)(file.path, "function", name);
413
+ extractReturnObjectMethods(node, localKey, isExported);
414
+ return;
415
+ }
416
+ if (typescript_1.default.isClassDeclaration(node) && node.name) {
417
+ const name = node.name.text;
418
+ pushSymbol(name, "class", node, isExported, isDefault);
419
+ const localKey = (0, shared_js_1.buildLocalSymbolKey)(file.path, "class", name);
420
+ for (const clause of node.heritageClauses ?? []) {
421
+ const kind = clause.token === typescript_1.default.SyntaxKind.ExtendsKeyword ? "extends" : "implements";
422
+ for (const type of clause.types) {
423
+ const targetName = type.expression.getText(sourceFile);
424
+ relationships.push({ fromSymbolLocalKey: localKey, toSymbolName: targetName, relationshipKind: kind });
425
+ }
426
+ }
427
+ return;
428
+ }
429
+ if (typescript_1.default.isInterfaceDeclaration(node)) {
430
+ const name = node.name.text;
431
+ pushSymbol(name, "interface", node, isExported, false);
432
+ const localKey = (0, shared_js_1.buildLocalSymbolKey)(file.path, "interface", name);
433
+ for (const clause of node.heritageClauses ?? []) {
434
+ for (const type of clause.types) {
435
+ const targetName = type.expression.getText(sourceFile);
436
+ relationships.push({ fromSymbolLocalKey: localKey, toSymbolName: targetName, relationshipKind: "extends" });
437
+ }
438
+ }
439
+ return;
440
+ }
441
+ if (typescript_1.default.isTypeAliasDeclaration(node)) {
442
+ pushSymbol(node.name.text, "type_alias", node, isExported, false);
443
+ return;
444
+ }
445
+ if (typescript_1.default.isEnumDeclaration(node)) {
446
+ pushSymbol(node.name.text, "enum", node, isExported, false);
447
+ return;
448
+ }
449
+ if (typescript_1.default.isVariableStatement(node) && isExported) {
450
+ for (const decl of node.declarationList.declarations) {
451
+ if (!typescript_1.default.isIdentifier(decl.name))
452
+ continue;
453
+ const name = decl.name.text;
454
+ const isPascalCase = /^[A-Z]/.test(name);
455
+ let kind = "variable";
456
+ if (isPascalCase) {
457
+ kind = "component";
458
+ }
459
+ else if (decl.initializer &&
460
+ (typescript_1.default.isArrowFunction(decl.initializer) || typescript_1.default.isFunctionExpression(decl.initializer))) {
461
+ kind = "function";
462
+ }
463
+ pushSymbol(name, kind, decl, isExported, false);
464
+ if (decl.initializer &&
465
+ (typescript_1.default.isArrowFunction(decl.initializer) || typescript_1.default.isFunctionExpression(decl.initializer))) {
466
+ const localKey = (0, shared_js_1.buildLocalSymbolKey)(file.path, kind, name);
467
+ extractReturnObjectMethods(decl.initializer, localKey, isExported);
468
+ }
469
+ }
470
+ }
471
+ }
472
+ typescript_1.default.forEachChild(sourceFile, visitTopLevel);
473
+ return { symbols, relationships };
474
+ }
475
+ // ─── Call extraction ─────────────────────────────────────────────────────────
476
+ function extractCallsWithAst(file, sourceFile) {
477
+ const calls = [];
478
+ function walk(node) {
479
+ if (typescript_1.default.isCallExpression(node)) {
480
+ const expr = node.expression;
481
+ let calleeName = null;
482
+ if (typescript_1.default.isIdentifier(expr)) {
483
+ calleeName = expr.text;
484
+ }
485
+ else if (typescript_1.default.isPropertyAccessExpression(expr) && typescript_1.default.isIdentifier(expr.name)) {
486
+ calleeName = expr.name.text;
487
+ }
488
+ if (calleeName && calleeName !== "require") {
489
+ const { line, col } = getLineCol(sourceFile, expr.getStart(sourceFile));
490
+ const namespaceName = typescript_1.default.isPropertyAccessExpression(expr) && typescript_1.default.isIdentifier(expr.expression)
491
+ ? expr.expression.text
492
+ : undefined;
493
+ calls.push({ calleeName, namespaceName, line, col, endCol: col + calleeName.length });
494
+ }
495
+ // don't skip children — call args may contain more references
496
+ }
497
+ else if (typescript_1.default.isPropertyAccessExpression(node) && typescript_1.default.isIdentifier(node.expression)) {
498
+ // standalone property access: CACHE_NAMESPACES.foo (not the expression of a call — already handled above)
499
+ const objectName = node.expression.text;
500
+ const { line, col } = getLineCol(sourceFile, node.expression.getStart(sourceFile));
501
+ calls.push({ calleeName: objectName, namespaceName: undefined, line, col, endCol: col + objectName.length });
502
+ }
503
+ else if (typescript_1.default.isIdentifier(node) &&
504
+ !typescript_1.default.isPropertyAccessExpression(node.parent) &&
505
+ !typescript_1.default.isCallExpression(node.parent) &&
506
+ !typescript_1.default.isImportDeclaration(node.parent) &&
507
+ !typescript_1.default.isImportSpecifier(node.parent) &&
508
+ !typescript_1.default.isVariableDeclaration(node.parent) &&
509
+ !typescript_1.default.isParameter(node.parent) &&
510
+ !typescript_1.default.isPropertyAssignment(node.parent) &&
511
+ !typescript_1.default.isShorthandPropertyAssignment(node.parent) &&
512
+ !typescript_1.default.isTypeReferenceNode(node.parent) &&
513
+ !typescript_1.default.isExportSpecifier(node.parent)) {
514
+ // bare identifier reference: CACHE_PREFIX used standalone (array element, argument, etc.)
515
+ const { line, col } = getLineCol(sourceFile, node.getStart(sourceFile));
516
+ calls.push({ calleeName: node.text, namespaceName: undefined, line, col, endCol: col + node.text.length });
517
+ }
518
+ typescript_1.default.forEachChild(node, walk);
519
+ }
520
+ typescript_1.default.forEachChild(sourceFile, walk);
521
+ return calls;
522
+ }
523
+ // ─── Entry point ──────────────────────────────────────────────────────────────
524
+ function parseTypeScriptOrJavaScriptFile(file, filePathSet, projectImportId, workspacePath, resolverConfigs) {
525
+ const sourceFile = createSourceFile(file);
526
+ const { imports, exports, issues, externalSymbols } = extractImportsWithAst(file, sourceFile, filePathSet, projectImportId, workspacePath, resolverConfigs);
527
+ const { symbols: astSymbols, relationships } = extractSymbolsWithAst(file, sourceFile);
528
+ const calls = extractCallsWithAst(file, sourceFile);
529
+ const symbolExports = astSymbols
530
+ .filter((s) => s.isExported)
531
+ .map((s) => ({
532
+ exportName: s.isDefaultExport ? "default" : s.displayName,
533
+ exportKind: s.isDefaultExport ? "default" : "named",
534
+ line: s.line,
535
+ col: s.col,
536
+ endLine: s.endLine,
537
+ endCol: s.endCol,
538
+ symbolLocalKey: s.localKey,
539
+ }));
540
+ return {
541
+ symbols: astSymbols,
542
+ imports,
543
+ exports: [...exports, ...symbolExports],
544
+ relationships,
545
+ calls,
546
+ issues,
547
+ externalSymbols,
548
+ };
549
+ }
@@ -0,0 +1,17 @@
1
+ export interface TypeScriptPathAliasPattern {
2
+ pattern: string;
3
+ hasWildcard: boolean;
4
+ prefix: string;
5
+ suffix: string;
6
+ targets: string[];
7
+ }
8
+ export interface TypeScriptResolverConfig {
9
+ configPath: string;
10
+ configDirPath: string;
11
+ configDirRelativePath: string;
12
+ baseUrlPath: string;
13
+ pathAliases: TypeScriptPathAliasPattern[];
14
+ }
15
+ export declare function normalizeWorkspaceRelativePath(workspacePath: string, targetPath: string): string;
16
+ export declare function loadTypeScriptResolverConfigs(workspacePath: string): Promise<TypeScriptResolverConfig[]>;
17
+ //# sourceMappingURL=ts-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-resolver.d.ts","sourceRoot":"","sources":["../src/ts-resolver.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,0BAA0B,EAAE,CAAC;CAC3C;AAOD,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,UAKnB;AA2CD,wBAAsB,6BAA6B,CACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAwErC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.normalizeWorkspaceRelativePath = normalizeWorkspaceRelativePath;
7
+ exports.loadTypeScriptResolverConfigs = loadTypeScriptResolverConfigs;
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const typescript_1 = __importDefault(require("typescript"));
11
+ const file_discovery_js_1 = require("./file-discovery.js");
12
+ function normalizeWorkspaceRelativePath(workspacePath, targetPath) {
13
+ const relativePath = node_path_1.default.relative(workspacePath, targetPath);
14
+ if (!relativePath)
15
+ return "";
16
+ return (0, file_discovery_js_1.normalizeRepositoryFilePath)(relativePath.split(node_path_1.default.sep).join("/"));
17
+ }
18
+ function readTsConfigFile(configPath) {
19
+ const readResult = typescript_1.default.readConfigFile(configPath, typescript_1.default.sys.readFile);
20
+ if (readResult.error)
21
+ return null;
22
+ return readResult.config;
23
+ }
24
+ async function readTypeScriptCompilerOptionsConfig(configPath, visited = new Set()) {
25
+ if (visited.has(configPath))
26
+ return null;
27
+ visited.add(configPath);
28
+ try {
29
+ const parsed = readTsConfigFile(configPath);
30
+ const configDirPath = node_path_1.default.dirname(configPath);
31
+ let inheritedConfig = null;
32
+ if (parsed?.extends && parsed?.extends.startsWith(".")) {
33
+ const extendsPath = parsed.extends.endsWith(".json")
34
+ ? parsed.extends
35
+ : `${parsed.extends}.json`;
36
+ inheritedConfig = await readTypeScriptCompilerOptionsConfig(node_path_1.default.resolve(configDirPath, extendsPath), visited);
37
+ }
38
+ return {
39
+ baseUrl: parsed?.compilerOptions?.baseUrl ?? inheritedConfig?.baseUrl,
40
+ paths: parsed?.compilerOptions?.paths ?? inheritedConfig?.paths,
41
+ };
42
+ }
43
+ catch (error) {
44
+ console.log(error);
45
+ return null;
46
+ }
47
+ }
48
+ async function loadTypeScriptResolverConfigs(workspacePath) {
49
+ const configRelativePaths = ["tsconfig.json", "jsconfig.json"];
50
+ const discoveredConfigs = new Set();
51
+ async function visit(absolutePath) {
52
+ const entryStats = await (0, promises_1.lstat)(absolutePath);
53
+ if (entryStats.isSymbolicLink())
54
+ return;
55
+ const name = node_path_1.default.basename(absolutePath);
56
+ if (entryStats.isDirectory()) {
57
+ if (file_discovery_js_1.IGNORED_NAMES.has(name))
58
+ return;
59
+ const entries = await (0, promises_1.readdir)(absolutePath, { withFileTypes: true });
60
+ for (const entry of entries) {
61
+ if (entry.isDirectory()) {
62
+ await visit(node_path_1.default.join(absolutePath, entry.name));
63
+ continue;
64
+ }
65
+ if (entry.isFile() && (entry.name === "tsconfig.json" || entry.name === "jsconfig.json")) {
66
+ discoveredConfigs.add(node_path_1.default.join(absolutePath, entry.name));
67
+ }
68
+ }
69
+ }
70
+ }
71
+ for (const relativePath of configRelativePaths) {
72
+ discoveredConfigs.add(node_path_1.default.join(workspacePath, relativePath));
73
+ }
74
+ await visit(workspacePath);
75
+ const resolverConfigs = [];
76
+ for (const configPath of discoveredConfigs) {
77
+ try {
78
+ const compilerOptions = await readTypeScriptCompilerOptionsConfig(configPath);
79
+ if (!compilerOptions?.paths)
80
+ continue;
81
+ const configDirPath = node_path_1.default.dirname(configPath);
82
+ const baseUrlPath = node_path_1.default.resolve(configDirPath, compilerOptions.baseUrl ?? ".");
83
+ const pathAliases = Object.entries(compilerOptions.paths ?? {})
84
+ .filter(([, targets]) => Array.isArray(targets) && targets.length > 0)
85
+ .map(([pattern, targets]) => {
86
+ const wildcardIndex = pattern.indexOf("*");
87
+ return {
88
+ pattern,
89
+ hasWildcard: wildcardIndex >= 0,
90
+ prefix: wildcardIndex >= 0 ? pattern.slice(0, wildcardIndex) : pattern,
91
+ suffix: wildcardIndex >= 0 ? pattern.slice(wildcardIndex + 1) : "",
92
+ targets,
93
+ };
94
+ });
95
+ if (pathAliases.length === 0)
96
+ continue;
97
+ resolverConfigs.push({
98
+ configPath,
99
+ configDirPath,
100
+ configDirRelativePath: normalizeWorkspaceRelativePath(workspacePath, configDirPath),
101
+ baseUrlPath,
102
+ pathAliases,
103
+ });
104
+ }
105
+ catch (error) {
106
+ console.log(`Failed to read TypeScript resolver config at ${configPath}`, error);
107
+ }
108
+ }
109
+ return resolverConfigs.sort((left, right) => right.configDirPath.length - left.configDirPath.length);
110
+ }