@ctxo/lang-typescript 0.7.0-alpha.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alper Hankendi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,44 @@
1
+ import { ILanguageAdapter, SymbolKind, SymbolNode, GraphEdge, ComplexityMetrics, CtxoLanguagePlugin } from '@ctxo/plugin-api';
2
+
3
+ declare class TsMorphAdapter implements ILanguageAdapter {
4
+ readonly extensions: readonly [".ts", ".tsx", ".js", ".jsx"];
5
+ readonly tier: "full";
6
+ private readonly project;
7
+ private symbolRegistry;
8
+ private projectPreloaded;
9
+ constructor();
10
+ isSupported(filePath: string): boolean;
11
+ setSymbolRegistry(registry: Map<string, SymbolKind>): void;
12
+ loadProjectSources(files: Map<string, string>): void;
13
+ clearProjectSources(): void;
14
+ extractSymbols(filePath: string, source: string): Promise<SymbolNode[]>;
15
+ extractEdges(filePath: string, source: string): Promise<GraphEdge[]>;
16
+ extractComplexity(filePath: string, source: string): Promise<ComplexityMetrics[]>;
17
+ private extractFunctions;
18
+ private extractClasses;
19
+ private extractInterfaces;
20
+ private extractTypeAliases;
21
+ private extractVariables;
22
+ private extractImportEdges;
23
+ private extractInheritanceEdges;
24
+ private extractCallEdges;
25
+ private extractReferenceEdges;
26
+ private emitUsesEdges;
27
+ private resolveLocalCallTarget;
28
+ private resolveThisMethodCall;
29
+ private parseSource;
30
+ private cleanupSourceFile;
31
+ private buildSymbolId;
32
+ private resolveRelativeImport;
33
+ private resolveImportTarget;
34
+ private resolveSymbolReference;
35
+ private inferSymbolKind;
36
+ private normalizeFilePath;
37
+ private getExportedSymbolIds;
38
+ private isExported;
39
+ private countCyclomaticComplexity;
40
+ }
41
+
42
+ declare const plugin: CtxoLanguagePlugin;
43
+
44
+ export { TsMorphAdapter, plugin as default, plugin };
package/dist/index.js ADDED
@@ -0,0 +1,592 @@
1
+ // src/ts-morph-adapter.ts
2
+ import {
3
+ Project,
4
+ SyntaxKind,
5
+ Node,
6
+ ScriptTarget
7
+ } from "ts-morph";
8
+ import { extname, dirname, join, normalize } from "path";
9
+ import {
10
+ SYMBOL_KINDS
11
+ } from "@ctxo/plugin-api";
12
+ var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
13
+ var TsMorphAdapter = class {
14
+ extensions = SUPPORTED_EXTENSIONS;
15
+ tier = "full";
16
+ project;
17
+ symbolRegistry = /* @__PURE__ */ new Map();
18
+ projectPreloaded = false;
19
+ constructor() {
20
+ this.project = new Project({
21
+ compilerOptions: {
22
+ target: ScriptTarget.ES2022,
23
+ allowJs: true,
24
+ jsx: 2,
25
+ // React
26
+ skipLibCheck: true
27
+ },
28
+ useInMemoryFileSystem: true
29
+ });
30
+ }
31
+ isSupported(filePath) {
32
+ const ext = extname(filePath).toLowerCase();
33
+ return SUPPORTED_EXTENSIONS.includes(ext);
34
+ }
35
+ setSymbolRegistry(registry) {
36
+ this.symbolRegistry = registry;
37
+ }
38
+ loadProjectSources(files) {
39
+ for (const [filePath, source] of files) {
40
+ try {
41
+ const existing = this.project.getSourceFile(filePath);
42
+ if (existing) this.project.removeSourceFile(existing);
43
+ this.project.createSourceFile(filePath, source, { overwrite: true });
44
+ } catch (err) {
45
+ console.error(`[ctxo:ts-morph] Failed to preload ${filePath}: ${err.message}`);
46
+ }
47
+ }
48
+ this.projectPreloaded = true;
49
+ }
50
+ clearProjectSources() {
51
+ for (const sf of this.project.getSourceFiles()) {
52
+ this.project.removeSourceFile(sf);
53
+ }
54
+ this.projectPreloaded = false;
55
+ }
56
+ async extractSymbols(filePath, source) {
57
+ const sourceFile = this.parseSource(filePath, source);
58
+ if (!sourceFile) return [];
59
+ try {
60
+ const symbols = [];
61
+ this.extractFunctions(sourceFile, filePath, symbols);
62
+ this.extractClasses(sourceFile, filePath, symbols);
63
+ this.extractInterfaces(sourceFile, filePath, symbols);
64
+ this.extractTypeAliases(sourceFile, filePath, symbols);
65
+ this.extractVariables(sourceFile, filePath, symbols);
66
+ return symbols;
67
+ } catch (err) {
68
+ console.error(`[ctxo:ts-morph] Symbol extraction failed for ${filePath}: ${err.message}`);
69
+ return [];
70
+ } finally {
71
+ this.cleanupSourceFile(filePath);
72
+ }
73
+ }
74
+ async extractEdges(filePath, source) {
75
+ const sourceFile = this.parseSource(filePath, source);
76
+ if (!sourceFile) return [];
77
+ try {
78
+ const edges = [];
79
+ this.extractImportEdges(sourceFile, filePath, edges);
80
+ this.extractInheritanceEdges(sourceFile, filePath, edges);
81
+ this.extractCallEdges(sourceFile, filePath, edges);
82
+ this.extractReferenceEdges(sourceFile, filePath, edges);
83
+ return edges;
84
+ } catch (err) {
85
+ console.error(`[ctxo:ts-morph] Edge extraction failed for ${filePath}: ${err.message}`);
86
+ return [];
87
+ } finally {
88
+ if (!this.projectPreloaded) {
89
+ this.cleanupSourceFile(filePath);
90
+ }
91
+ }
92
+ }
93
+ async extractComplexity(filePath, source) {
94
+ const sourceFile = this.parseSource(filePath, source);
95
+ if (!sourceFile) return [];
96
+ try {
97
+ const metrics = [];
98
+ for (const fn of sourceFile.getFunctions()) {
99
+ if (!this.isExported(fn)) continue;
100
+ const name = fn.getName();
101
+ if (!name) continue;
102
+ const symbolId = this.buildSymbolId(filePath, name, "function");
103
+ metrics.push({ symbolId, cyclomatic: this.countCyclomaticComplexity(fn) });
104
+ }
105
+ for (const cls of sourceFile.getClasses()) {
106
+ const className = cls.getName();
107
+ if (!className || !this.isExported(cls)) continue;
108
+ for (const method of cls.getMethods()) {
109
+ const methodName = method.getName();
110
+ const symbolId = this.buildSymbolId(filePath, `${className}.${methodName}`, "method");
111
+ metrics.push({ symbolId, cyclomatic: this.countCyclomaticComplexity(method) });
112
+ }
113
+ }
114
+ return metrics;
115
+ } catch (err) {
116
+ console.error(`[ctxo:ts-morph] Complexity extraction failed for ${filePath}: ${err.message}`);
117
+ return [];
118
+ } finally {
119
+ this.cleanupSourceFile(filePath);
120
+ }
121
+ }
122
+ // ── Symbol Extraction ───────────────────────────────────────
123
+ extractFunctions(sourceFile, filePath, symbols) {
124
+ for (const fn of sourceFile.getFunctions()) {
125
+ if (!this.isExported(fn)) continue;
126
+ const name = fn.getName();
127
+ if (!name) continue;
128
+ symbols.push({
129
+ symbolId: this.buildSymbolId(filePath, name, "function"),
130
+ name,
131
+ kind: "function",
132
+ startLine: fn.getStartLineNumber() - 1,
133
+ endLine: fn.getEndLineNumber() - 1,
134
+ startOffset: fn.getStart(),
135
+ endOffset: fn.getEnd()
136
+ });
137
+ }
138
+ }
139
+ extractClasses(sourceFile, filePath, symbols) {
140
+ for (const cls of sourceFile.getClasses()) {
141
+ const name = cls.getName();
142
+ if (!name || !this.isExported(cls)) continue;
143
+ symbols.push({
144
+ symbolId: this.buildSymbolId(filePath, name, "class"),
145
+ name,
146
+ kind: "class",
147
+ startLine: cls.getStartLineNumber() - 1,
148
+ endLine: cls.getEndLineNumber() - 1,
149
+ startOffset: cls.getStart(),
150
+ endOffset: cls.getEnd()
151
+ });
152
+ for (const method of cls.getMethods()) {
153
+ const methodName = method.getName();
154
+ symbols.push({
155
+ symbolId: this.buildSymbolId(filePath, `${name}.${methodName}`, "method"),
156
+ name: `${name}.${methodName}`,
157
+ kind: "method",
158
+ startLine: method.getStartLineNumber() - 1,
159
+ endLine: method.getEndLineNumber() - 1,
160
+ startOffset: method.getStart(),
161
+ endOffset: method.getEnd()
162
+ });
163
+ }
164
+ }
165
+ }
166
+ extractInterfaces(sourceFile, filePath, symbols) {
167
+ for (const iface of sourceFile.getInterfaces()) {
168
+ if (!this.isExported(iface)) continue;
169
+ const name = iface.getName();
170
+ symbols.push({
171
+ symbolId: this.buildSymbolId(filePath, name, "interface"),
172
+ name,
173
+ kind: "interface",
174
+ startLine: iface.getStartLineNumber() - 1,
175
+ endLine: iface.getEndLineNumber() - 1,
176
+ startOffset: iface.getStart(),
177
+ endOffset: iface.getEnd()
178
+ });
179
+ }
180
+ }
181
+ extractTypeAliases(sourceFile, filePath, symbols) {
182
+ for (const typeAlias of sourceFile.getTypeAliases()) {
183
+ if (!this.isExported(typeAlias)) continue;
184
+ const name = typeAlias.getName();
185
+ symbols.push({
186
+ symbolId: this.buildSymbolId(filePath, name, "type"),
187
+ name,
188
+ kind: "type",
189
+ startLine: typeAlias.getStartLineNumber() - 1,
190
+ endLine: typeAlias.getEndLineNumber() - 1,
191
+ startOffset: typeAlias.getStart(),
192
+ endOffset: typeAlias.getEnd()
193
+ });
194
+ }
195
+ }
196
+ extractVariables(sourceFile, filePath, symbols) {
197
+ for (const stmt of sourceFile.getVariableStatements()) {
198
+ if (!this.isExported(stmt)) continue;
199
+ for (const decl of stmt.getDeclarations()) {
200
+ const name = decl.getName();
201
+ symbols.push({
202
+ symbolId: this.buildSymbolId(filePath, name, "variable"),
203
+ name,
204
+ kind: "variable",
205
+ startLine: stmt.getStartLineNumber() - 1,
206
+ endLine: stmt.getEndLineNumber() - 1,
207
+ startOffset: decl.getStart(),
208
+ endOffset: decl.getEnd()
209
+ });
210
+ }
211
+ }
212
+ }
213
+ // ── Edge Extraction ─────────────────────────────────────────
214
+ extractImportEdges(sourceFile, filePath, edges) {
215
+ const fileSymbolId = this.buildSymbolId(filePath, sourceFile.getBaseName().replace(/\.[^.]+$/, ""), "variable");
216
+ const fromSymbols = this.getExportedSymbolIds(sourceFile, filePath);
217
+ const fromSymbol = fromSymbols.length > 0 ? fromSymbols[0] : fileSymbolId;
218
+ for (const imp of sourceFile.getImportDeclarations()) {
219
+ const moduleSpecifier = imp.getModuleSpecifierValue();
220
+ if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) {
221
+ continue;
222
+ }
223
+ const normalizedTarget = this.resolveRelativeImport(filePath, moduleSpecifier);
224
+ const isTypeOnly = imp.isTypeOnly();
225
+ for (const named of imp.getNamedImports()) {
226
+ const importedName = named.getName();
227
+ const edge = {
228
+ from: fromSymbol,
229
+ to: this.resolveImportTarget(normalizedTarget, importedName),
230
+ kind: "imports"
231
+ };
232
+ if (isTypeOnly || named.isTypeOnly()) edge.typeOnly = true;
233
+ edges.push(edge);
234
+ }
235
+ const defaultImport = imp.getDefaultImport();
236
+ if (defaultImport) {
237
+ const edge = {
238
+ from: fromSymbol,
239
+ to: this.resolveImportTarget(normalizedTarget, defaultImport.getText()),
240
+ kind: "imports"
241
+ };
242
+ if (isTypeOnly) edge.typeOnly = true;
243
+ edges.push(edge);
244
+ }
245
+ const nsImport = imp.getNamespaceImport();
246
+ if (nsImport) {
247
+ const edge = {
248
+ from: fromSymbol,
249
+ to: this.buildSymbolId(normalizedTarget, nsImport.getText(), "variable"),
250
+ kind: "imports"
251
+ };
252
+ if (isTypeOnly) edge.typeOnly = true;
253
+ edges.push(edge);
254
+ }
255
+ }
256
+ }
257
+ extractInheritanceEdges(sourceFile, filePath, edges) {
258
+ for (const cls of sourceFile.getClasses()) {
259
+ const className = cls.getName();
260
+ if (!className || !this.isExported(cls)) continue;
261
+ const classSymbolId = this.buildSymbolId(filePath, className, "class");
262
+ const baseClass = cls.getExtends();
263
+ if (baseClass) {
264
+ const baseName = baseClass.getExpression().getText().replace(/<.*>$/, "");
265
+ edges.push({
266
+ from: classSymbolId,
267
+ to: this.resolveSymbolReference(sourceFile, baseName, "class"),
268
+ kind: "extends"
269
+ });
270
+ }
271
+ for (const impl of cls.getImplements()) {
272
+ const ifaceName = impl.getExpression().getText().replace(/<.*>$/, "");
273
+ edges.push({
274
+ from: classSymbolId,
275
+ to: this.resolveSymbolReference(sourceFile, ifaceName, "interface"),
276
+ kind: "implements"
277
+ });
278
+ }
279
+ }
280
+ }
281
+ extractCallEdges(sourceFile, filePath, edges) {
282
+ for (const fn of sourceFile.getFunctions()) {
283
+ if (!this.isExported(fn)) continue;
284
+ const fnName = fn.getName();
285
+ if (!fnName) continue;
286
+ const fnSymbolId = this.buildSymbolId(filePath, fnName, "function");
287
+ for (const call of fn.getDescendantsOfKind(SyntaxKind.CallExpression)) {
288
+ const calledName = call.getExpression().getText().split(".").pop();
289
+ if (!calledName || calledName === fnName) continue;
290
+ const resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);
291
+ if (resolved) {
292
+ edges.push({ from: fnSymbolId, to: resolved, kind: "calls" });
293
+ }
294
+ }
295
+ for (const newExpr of fn.getDescendantsOfKind(SyntaxKind.NewExpression)) {
296
+ const calledName = newExpr.getExpression().getText().split(".").pop();
297
+ if (!calledName) continue;
298
+ const resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);
299
+ if (resolved) {
300
+ edges.push({ from: fnSymbolId, to: resolved, kind: "calls" });
301
+ }
302
+ }
303
+ }
304
+ for (const cls of sourceFile.getClasses()) {
305
+ const className = cls.getName();
306
+ if (!className || !this.isExported(cls)) continue;
307
+ for (const method of cls.getMethods()) {
308
+ const methodName = method.getName();
309
+ const methodSymbolId = this.buildSymbolId(filePath, `${className}.${methodName}`, "method");
310
+ for (const call of method.getDescendantsOfKind(SyntaxKind.CallExpression)) {
311
+ const calledText = call.getExpression().getText();
312
+ const calledName = calledText.split(".").pop();
313
+ if (!calledName || calledName === methodName) continue;
314
+ let resolved;
315
+ if (calledText.startsWith("this.")) {
316
+ resolved = this.resolveThisMethodCall(sourceFile, filePath, className, calledName);
317
+ } else {
318
+ resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);
319
+ }
320
+ if (resolved) {
321
+ edges.push({ from: methodSymbolId, to: resolved, kind: "calls" });
322
+ }
323
+ }
324
+ for (const newExpr of method.getDescendantsOfKind(SyntaxKind.NewExpression)) {
325
+ const calledText = newExpr.getExpression().getText();
326
+ const calledName = calledText.split(".").pop();
327
+ if (!calledName) continue;
328
+ let resolved;
329
+ if (calledText.startsWith("this.")) {
330
+ resolved = this.resolveThisMethodCall(sourceFile, filePath, className, calledName);
331
+ } else {
332
+ resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);
333
+ }
334
+ if (resolved) {
335
+ edges.push({ from: methodSymbolId, to: resolved, kind: "calls" });
336
+ }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ extractReferenceEdges(sourceFile, filePath, edges) {
342
+ const importMap = /* @__PURE__ */ new Map();
343
+ for (const imp of sourceFile.getImportDeclarations()) {
344
+ const mod = imp.getModuleSpecifierValue();
345
+ if (!mod.startsWith(".") && !mod.startsWith("/")) continue;
346
+ const targetFile = this.resolveRelativeImport(filePath, mod);
347
+ for (const named of imp.getNamedImports()) {
348
+ importMap.set(named.getName(), this.resolveImportTarget(targetFile, named.getName()));
349
+ }
350
+ const defaultImport = imp.getDefaultImport();
351
+ if (defaultImport) {
352
+ importMap.set(defaultImport.getText(), this.resolveImportTarget(targetFile, defaultImport.getText()));
353
+ }
354
+ }
355
+ if (importMap.size === 0) return;
356
+ for (const fn of sourceFile.getFunctions()) {
357
+ if (!this.isExported(fn)) continue;
358
+ const fnName = fn.getName();
359
+ if (!fnName) continue;
360
+ const fromId = this.buildSymbolId(filePath, fnName, "function");
361
+ this.emitUsesEdges(fn, fromId, importMap, edges);
362
+ }
363
+ for (const cls of sourceFile.getClasses()) {
364
+ if (!this.isExported(cls)) continue;
365
+ const className = cls.getName();
366
+ if (!className) continue;
367
+ const classId = this.buildSymbolId(filePath, className, "class");
368
+ this.emitUsesEdges(cls, classId, importMap, edges);
369
+ }
370
+ }
371
+ emitUsesEdges(node, fromId, importMap, edges) {
372
+ const seen = /* @__PURE__ */ new Set();
373
+ for (const id of node.getDescendantsOfKind(SyntaxKind.Identifier)) {
374
+ const name = id.getText();
375
+ if (seen.has(name)) continue;
376
+ const target = importMap.get(name);
377
+ if (target) {
378
+ seen.add(name);
379
+ edges.push({ from: fromId, to: target, kind: "uses" });
380
+ }
381
+ }
382
+ }
383
+ resolveLocalCallTarget(sourceFile, filePath, calledName) {
384
+ for (const imp of sourceFile.getImportDeclarations()) {
385
+ const moduleSpecifier = imp.getModuleSpecifierValue();
386
+ if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) continue;
387
+ for (const named of imp.getNamedImports()) {
388
+ if (named.getName() === calledName) {
389
+ const targetFile = this.resolveRelativeImport(filePath, moduleSpecifier);
390
+ return this.resolveImportTarget(targetFile, calledName);
391
+ }
392
+ }
393
+ }
394
+ for (const fn of sourceFile.getFunctions()) {
395
+ if (fn.getName() === calledName) {
396
+ return this.buildSymbolId(filePath, calledName, "function");
397
+ }
398
+ }
399
+ return void 0;
400
+ }
401
+ resolveThisMethodCall(sourceFile, filePath, className, calledName) {
402
+ for (const cls of sourceFile.getClasses()) {
403
+ if (cls.getName() !== className) continue;
404
+ for (const method of cls.getMethods()) {
405
+ if (method.getName() === calledName) {
406
+ return this.buildSymbolId(filePath, `${className}.${calledName}`, "method");
407
+ }
408
+ }
409
+ }
410
+ return void 0;
411
+ }
412
+ // ── Helpers ─────────────────────────────────────────────────
413
+ parseSource(filePath, source) {
414
+ try {
415
+ const existing = this.project.getSourceFile(filePath);
416
+ if (existing && this.projectPreloaded) {
417
+ return existing;
418
+ }
419
+ if (existing) {
420
+ this.project.removeSourceFile(existing);
421
+ }
422
+ return this.project.createSourceFile(filePath, source, { overwrite: true });
423
+ } catch (err) {
424
+ console.error(`[ctxo:ts-morph] Parse failed for ${filePath}: ${err.message}`);
425
+ return void 0;
426
+ }
427
+ }
428
+ cleanupSourceFile(filePath) {
429
+ const existing = this.project.getSourceFile(filePath);
430
+ if (existing) {
431
+ this.project.removeSourceFile(existing);
432
+ }
433
+ }
434
+ buildSymbolId(filePath, name, kind) {
435
+ return `${filePath}::${name}::${kind}`;
436
+ }
437
+ resolveRelativeImport(fromFile, moduleSpecifier) {
438
+ const fromDir = dirname(fromFile);
439
+ let resolved = normalize(join(fromDir, moduleSpecifier)).replace(/\\/g, "/");
440
+ if (resolved.endsWith(".js")) {
441
+ resolved = resolved.slice(0, -3) + ".ts";
442
+ } else if (resolved.endsWith(".jsx")) {
443
+ resolved = resolved.slice(0, -4) + ".tsx";
444
+ } else if (!extname(resolved)) {
445
+ resolved += ".ts";
446
+ }
447
+ return resolved;
448
+ }
449
+ resolveImportTarget(targetFile, name) {
450
+ const prefix = `${targetFile}::${name}::`;
451
+ for (const kind2 of SYMBOL_KINDS) {
452
+ if (this.symbolRegistry.has(`${prefix}${kind2}`)) {
453
+ return `${prefix}${kind2}`;
454
+ }
455
+ }
456
+ const targetSourceFile = this.project.getSourceFile(targetFile);
457
+ if (targetSourceFile) {
458
+ for (const fn of targetSourceFile.getFunctions()) {
459
+ if (fn.getName() === name && this.isExported(fn)) {
460
+ return this.buildSymbolId(targetFile, name, "function");
461
+ }
462
+ }
463
+ for (const cls of targetSourceFile.getClasses()) {
464
+ if (cls.getName() === name && this.isExported(cls)) {
465
+ return this.buildSymbolId(targetFile, name, "class");
466
+ }
467
+ }
468
+ for (const iface of targetSourceFile.getInterfaces()) {
469
+ if (iface.getName() === name && this.isExported(iface)) {
470
+ return this.buildSymbolId(targetFile, name, "interface");
471
+ }
472
+ }
473
+ for (const t of targetSourceFile.getTypeAliases()) {
474
+ if (t.getName() === name && this.isExported(t)) {
475
+ return this.buildSymbolId(targetFile, name, "type");
476
+ }
477
+ }
478
+ }
479
+ const kind = this.inferSymbolKind(name);
480
+ return `${targetFile}::${name}::${kind}`;
481
+ }
482
+ resolveSymbolReference(sourceFile, name, defaultKind) {
483
+ for (const imp of sourceFile.getImportDeclarations()) {
484
+ const moduleSpecifier = imp.getModuleSpecifierValue();
485
+ if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) continue;
486
+ for (const named of imp.getNamedImports()) {
487
+ if (named.getName() === name) {
488
+ const resolved = imp.getModuleSpecifierSourceFile()?.getFilePath();
489
+ if (resolved) {
490
+ return `${this.normalizeFilePath(resolved)}::${name}::${defaultKind}`;
491
+ }
492
+ const sourceDir = dirname(this.normalizeFilePath(sourceFile.getFilePath()));
493
+ const resolvedPath = normalize(join(sourceDir, moduleSpecifier)).replace(/\\/g, "/").replace(/\.jsx$/, ".tsx").replace(/\.js$/, ".ts");
494
+ return `${resolvedPath}::${name}::${defaultKind}`;
495
+ }
496
+ }
497
+ }
498
+ return `${sourceFile.getFilePath()}::${name}::${defaultKind}`;
499
+ }
500
+ inferSymbolKind(name) {
501
+ if (/^I[A-Z]/.test(name) && name.length > 2) return "interface";
502
+ if (/^[A-Z][A-Z_0-9]+$/.test(name)) return "variable";
503
+ if (/^[A-Z]/.test(name)) return "class";
504
+ return "function";
505
+ }
506
+ normalizeFilePath(filePath) {
507
+ return filePath.replace(/^\//, "");
508
+ }
509
+ getExportedSymbolIds(sourceFile, filePath) {
510
+ const ids = [];
511
+ for (const fn of sourceFile.getFunctions()) {
512
+ if (!this.isExported(fn)) continue;
513
+ const name = fn.getName();
514
+ if (name) ids.push(this.buildSymbolId(filePath, name, "function"));
515
+ }
516
+ for (const cls of sourceFile.getClasses()) {
517
+ if (!this.isExported(cls)) continue;
518
+ const name = cls.getName();
519
+ if (name) ids.push(this.buildSymbolId(filePath, name, "class"));
520
+ }
521
+ for (const iface of sourceFile.getInterfaces()) {
522
+ if (!this.isExported(iface)) continue;
523
+ ids.push(this.buildSymbolId(filePath, iface.getName(), "interface"));
524
+ }
525
+ for (const t of sourceFile.getTypeAliases()) {
526
+ if (!this.isExported(t)) continue;
527
+ ids.push(this.buildSymbolId(filePath, t.getName(), "type"));
528
+ }
529
+ for (const stmt of sourceFile.getVariableStatements()) {
530
+ if (!this.isExported(stmt)) continue;
531
+ for (const decl of stmt.getDeclarations()) {
532
+ ids.push(this.buildSymbolId(filePath, decl.getName(), "variable"));
533
+ }
534
+ }
535
+ return ids;
536
+ }
537
+ isExported(node) {
538
+ if (Node.isExportable(node)) {
539
+ return node.isExported();
540
+ }
541
+ return false;
542
+ }
543
+ countCyclomaticComplexity(node) {
544
+ let complexity = 1;
545
+ node.forEachDescendant((child) => {
546
+ switch (child.getKind()) {
547
+ case SyntaxKind.IfStatement:
548
+ case SyntaxKind.ConditionalExpression:
549
+ case SyntaxKind.ForStatement:
550
+ case SyntaxKind.ForInStatement:
551
+ case SyntaxKind.ForOfStatement:
552
+ case SyntaxKind.WhileStatement:
553
+ case SyntaxKind.DoStatement:
554
+ case SyntaxKind.CaseClause:
555
+ case SyntaxKind.CatchClause:
556
+ case SyntaxKind.BinaryExpression: {
557
+ const text = child.getText();
558
+ if (child.getKind() === SyntaxKind.BinaryExpression) {
559
+ if (text.includes("&&") || text.includes("||") || text.includes("??")) {
560
+ complexity++;
561
+ }
562
+ } else {
563
+ complexity++;
564
+ }
565
+ break;
566
+ }
567
+ }
568
+ });
569
+ return complexity;
570
+ }
571
+ };
572
+
573
+ // src/index.ts
574
+ var VERSION = "0.7.0-alpha.0";
575
+ var plugin = {
576
+ apiVersion: "1",
577
+ id: "typescript",
578
+ name: "TypeScript / JavaScript (ts-morph)",
579
+ version: VERSION,
580
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
581
+ tier: "full",
582
+ createAdapter(_ctx) {
583
+ return new TsMorphAdapter();
584
+ }
585
+ };
586
+ var index_default = plugin;
587
+ export {
588
+ TsMorphAdapter,
589
+ index_default as default,
590
+ plugin
591
+ };
592
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ts-morph-adapter.ts","../src/index.ts"],"sourcesContent":["import {\n Project,\n SyntaxKind,\n Node,\n type SourceFile,\n type FunctionDeclaration,\n type MethodDeclaration,\n ScriptTarget,\n} from 'ts-morph';\nimport { extname, dirname, join, normalize } from 'node:path';\nimport {\n type SymbolNode,\n type GraphEdge,\n type ComplexityMetrics,\n type SymbolKind,\n type ILanguageAdapter,\n SYMBOL_KINDS,\n} from '@ctxo/plugin-api';\n\nconst SUPPORTED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'] as const;\n\nexport class TsMorphAdapter implements ILanguageAdapter {\n readonly extensions = SUPPORTED_EXTENSIONS;\n readonly tier = 'full' as const;\n\n private readonly project: Project;\n private symbolRegistry = new Map<string, SymbolKind>();\n private projectPreloaded = false;\n\n constructor() {\n this.project = new Project({\n compilerOptions: {\n target: ScriptTarget.ES2022,\n allowJs: true,\n jsx: 2, // React\n skipLibCheck: true,\n },\n useInMemoryFileSystem: true,\n });\n }\n\n isSupported(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return (SUPPORTED_EXTENSIONS as readonly string[]).includes(ext);\n }\n\n setSymbolRegistry(registry: Map<string, SymbolKind>): void {\n this.symbolRegistry = registry;\n }\n\n loadProjectSources(files: Map<string, string>): void {\n for (const [filePath, source] of files) {\n try {\n const existing = this.project.getSourceFile(filePath);\n if (existing) this.project.removeSourceFile(existing);\n this.project.createSourceFile(filePath, source, { overwrite: true });\n } catch (err) {\n console.error(`[ctxo:ts-morph] Failed to preload ${filePath}: ${(err as Error).message}`);\n }\n }\n this.projectPreloaded = true;\n }\n\n clearProjectSources(): void {\n for (const sf of this.project.getSourceFiles()) {\n this.project.removeSourceFile(sf);\n }\n this.projectPreloaded = false;\n }\n\n async extractSymbols(filePath: string, source: string): Promise<SymbolNode[]> {\n const sourceFile = this.parseSource(filePath, source);\n if (!sourceFile) return [];\n\n try {\n const symbols: SymbolNode[] = [];\n\n this.extractFunctions(sourceFile, filePath, symbols);\n this.extractClasses(sourceFile, filePath, symbols);\n this.extractInterfaces(sourceFile, filePath, symbols);\n this.extractTypeAliases(sourceFile, filePath, symbols);\n this.extractVariables(sourceFile, filePath, symbols);\n\n return symbols;\n } catch (err) {\n console.error(`[ctxo:ts-morph] Symbol extraction failed for ${filePath}: ${(err as Error).message}`);\n return [];\n } finally {\n this.cleanupSourceFile(filePath);\n }\n }\n\n async extractEdges(filePath: string, source: string): Promise<GraphEdge[]> {\n const sourceFile = this.parseSource(filePath, source);\n if (!sourceFile) return [];\n\n try {\n const edges: GraphEdge[] = [];\n\n this.extractImportEdges(sourceFile, filePath, edges);\n this.extractInheritanceEdges(sourceFile, filePath, edges);\n this.extractCallEdges(sourceFile, filePath, edges);\n this.extractReferenceEdges(sourceFile, filePath, edges);\n\n return edges;\n } catch (err) {\n console.error(`[ctxo:ts-morph] Edge extraction failed for ${filePath}: ${(err as Error).message}`);\n return [];\n } finally {\n if (!this.projectPreloaded) {\n this.cleanupSourceFile(filePath);\n }\n }\n }\n\n async extractComplexity(filePath: string, source: string): Promise<ComplexityMetrics[]> {\n const sourceFile = this.parseSource(filePath, source);\n if (!sourceFile) return [];\n\n try {\n const metrics: ComplexityMetrics[] = [];\n\n for (const fn of sourceFile.getFunctions()) {\n if (!this.isExported(fn)) continue;\n const name = fn.getName();\n if (!name) continue;\n const symbolId = this.buildSymbolId(filePath, name, 'function');\n metrics.push({ symbolId, cyclomatic: this.countCyclomaticComplexity(fn) });\n }\n\n for (const cls of sourceFile.getClasses()) {\n const className = cls.getName();\n if (!className || !this.isExported(cls)) continue;\n\n for (const method of cls.getMethods()) {\n const methodName = method.getName();\n const symbolId = this.buildSymbolId(filePath, `${className}.${methodName}`, 'method');\n metrics.push({ symbolId, cyclomatic: this.countCyclomaticComplexity(method) });\n }\n }\n\n return metrics;\n } catch (err) {\n console.error(`[ctxo:ts-morph] Complexity extraction failed for ${filePath}: ${(err as Error).message}`);\n return [];\n } finally {\n this.cleanupSourceFile(filePath);\n }\n }\n\n // ── Symbol Extraction ───────────────────────────────────────\n\n private extractFunctions(\n sourceFile: SourceFile,\n filePath: string,\n symbols: SymbolNode[],\n ): void {\n for (const fn of sourceFile.getFunctions()) {\n if (!this.isExported(fn)) continue;\n const name = fn.getName();\n if (!name) continue;\n\n symbols.push({\n symbolId: this.buildSymbolId(filePath, name, 'function'),\n name,\n kind: 'function',\n startLine: fn.getStartLineNumber() - 1,\n endLine: fn.getEndLineNumber() - 1,\n startOffset: fn.getStart(),\n endOffset: fn.getEnd(),\n });\n }\n }\n\n private extractClasses(\n sourceFile: SourceFile,\n filePath: string,\n symbols: SymbolNode[],\n ): void {\n for (const cls of sourceFile.getClasses()) {\n const name = cls.getName();\n if (!name || !this.isExported(cls)) continue;\n\n symbols.push({\n symbolId: this.buildSymbolId(filePath, name, 'class'),\n name,\n kind: 'class',\n startLine: cls.getStartLineNumber() - 1,\n endLine: cls.getEndLineNumber() - 1,\n startOffset: cls.getStart(),\n endOffset: cls.getEnd(),\n });\n\n // Extract methods\n for (const method of cls.getMethods()) {\n const methodName = method.getName();\n symbols.push({\n symbolId: this.buildSymbolId(filePath, `${name}.${methodName}`, 'method'),\n name: `${name}.${methodName}`,\n kind: 'method',\n startLine: method.getStartLineNumber() - 1,\n endLine: method.getEndLineNumber() - 1,\n startOffset: method.getStart(),\n endOffset: method.getEnd(),\n });\n }\n }\n }\n\n private extractInterfaces(\n sourceFile: SourceFile,\n filePath: string,\n symbols: SymbolNode[],\n ): void {\n for (const iface of sourceFile.getInterfaces()) {\n if (!this.isExported(iface)) continue;\n const name = iface.getName();\n\n symbols.push({\n symbolId: this.buildSymbolId(filePath, name, 'interface'),\n name,\n kind: 'interface',\n startLine: iface.getStartLineNumber() - 1,\n endLine: iface.getEndLineNumber() - 1,\n startOffset: iface.getStart(),\n endOffset: iface.getEnd(),\n });\n }\n }\n\n private extractTypeAliases(\n sourceFile: SourceFile,\n filePath: string,\n symbols: SymbolNode[],\n ): void {\n for (const typeAlias of sourceFile.getTypeAliases()) {\n if (!this.isExported(typeAlias)) continue;\n const name = typeAlias.getName();\n\n symbols.push({\n symbolId: this.buildSymbolId(filePath, name, 'type'),\n name,\n kind: 'type',\n startLine: typeAlias.getStartLineNumber() - 1,\n endLine: typeAlias.getEndLineNumber() - 1,\n startOffset: typeAlias.getStart(),\n endOffset: typeAlias.getEnd(),\n });\n }\n }\n\n private extractVariables(\n sourceFile: SourceFile,\n filePath: string,\n symbols: SymbolNode[],\n ): void {\n for (const stmt of sourceFile.getVariableStatements()) {\n if (!this.isExported(stmt)) continue;\n\n for (const decl of stmt.getDeclarations()) {\n const name = decl.getName();\n\n symbols.push({\n symbolId: this.buildSymbolId(filePath, name, 'variable'),\n name,\n kind: 'variable',\n startLine: stmt.getStartLineNumber() - 1,\n endLine: stmt.getEndLineNumber() - 1,\n startOffset: decl.getStart(),\n endOffset: decl.getEnd(),\n });\n }\n }\n }\n\n // ── Edge Extraction ─────────────────────────────────────────\n\n private extractImportEdges(\n sourceFile: SourceFile,\n filePath: string,\n edges: GraphEdge[],\n ): void {\n // BUG-1 FIX: use sourceFile directly instead of project lookup (file may be cleaned up)\n const fileSymbolId = this.buildSymbolId(filePath, sourceFile.getBaseName().replace(/\\.[^.]+$/, ''), 'variable');\n const fromSymbols = this.getExportedSymbolIds(sourceFile, filePath);\n const fromSymbol = fromSymbols.length > 0 ? fromSymbols[0]! : fileSymbolId;\n\n for (const imp of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = imp.getModuleSpecifierValue();\n\n // Only track local imports (relative paths)\n if (!moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/')) {\n continue;\n }\n\n // Resolve relative import to project-relative path\n const normalizedTarget = this.resolveRelativeImport(filePath, moduleSpecifier);\n\n // SCHEMA-40 FIX: detect type-only imports\n const isTypeOnly = imp.isTypeOnly();\n\n for (const named of imp.getNamedImports()) {\n const importedName = named.getName();\n const edge: GraphEdge = {\n from: fromSymbol,\n to: this.resolveImportTarget(normalizedTarget, importedName),\n kind: 'imports',\n };\n if (isTypeOnly || named.isTypeOnly()) edge.typeOnly = true;\n edges.push(edge);\n }\n\n const defaultImport = imp.getDefaultImport();\n if (defaultImport) {\n const edge: GraphEdge = {\n from: fromSymbol,\n to: this.resolveImportTarget(normalizedTarget, defaultImport.getText()),\n kind: 'imports',\n };\n if (isTypeOnly) edge.typeOnly = true;\n edges.push(edge);\n }\n\n // GAP-3 FIX: namespace imports (import * as X from './mod')\n const nsImport = imp.getNamespaceImport();\n if (nsImport) {\n const edge: GraphEdge = {\n from: fromSymbol,\n to: this.buildSymbolId(normalizedTarget, nsImport.getText(), 'variable'),\n kind: 'imports',\n };\n if (isTypeOnly) edge.typeOnly = true;\n edges.push(edge);\n }\n }\n }\n\n private extractInheritanceEdges(\n sourceFile: SourceFile,\n filePath: string,\n edges: GraphEdge[],\n ): void {\n for (const cls of sourceFile.getClasses()) {\n const className = cls.getName();\n if (!className || !this.isExported(cls)) continue;\n\n const classSymbolId = this.buildSymbolId(filePath, className, 'class');\n\n // extends\n const baseClass = cls.getExtends();\n if (baseClass) {\n // BUG-17 FIX: strip generic type arguments (Base<string> → Base)\n const baseName = baseClass.getExpression().getText().replace(/<.*>$/, '');\n edges.push({\n from: classSymbolId,\n to: this.resolveSymbolReference(sourceFile, baseName, 'class'),\n kind: 'extends',\n });\n }\n\n // implements\n for (const impl of cls.getImplements()) {\n // BUG-18 FIX: strip generic type arguments (IRepo<User> → IRepo)\n const ifaceName = impl.getExpression().getText().replace(/<.*>$/, '');\n edges.push({\n from: classSymbolId,\n to: this.resolveSymbolReference(sourceFile, ifaceName, 'interface'),\n kind: 'implements',\n });\n }\n }\n }\n\n private extractCallEdges(\n sourceFile: SourceFile,\n filePath: string,\n edges: GraphEdge[],\n ): void {\n // Extract function call edges from exported functions and methods\n for (const fn of sourceFile.getFunctions()) {\n if (!this.isExported(fn)) continue;\n const fnName = fn.getName();\n if (!fnName) continue;\n\n const fnSymbolId = this.buildSymbolId(filePath, fnName, 'function');\n\n for (const call of fn.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n const calledName = call.getExpression().getText().split('.').pop();\n if (!calledName || calledName === fnName) continue;\n\n const resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);\n if (resolved) {\n edges.push({ from: fnSymbolId, to: resolved, kind: 'calls' });\n }\n }\n\n // GAP-11 FIX: constructor calls (new Foo())\n for (const newExpr of fn.getDescendantsOfKind(SyntaxKind.NewExpression)) {\n const calledName = newExpr.getExpression().getText().split('.').pop();\n if (!calledName) continue;\n\n const resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);\n if (resolved) {\n edges.push({ from: fnSymbolId, to: resolved, kind: 'calls' });\n }\n }\n }\n\n // Extract calls from class methods\n for (const cls of sourceFile.getClasses()) {\n const className = cls.getName();\n if (!className || !this.isExported(cls)) continue;\n\n for (const method of cls.getMethods()) {\n const methodName = method.getName();\n const methodSymbolId = this.buildSymbolId(filePath, `${className}.${methodName}`, 'method');\n\n for (const call of method.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n const calledText = call.getExpression().getText();\n const calledName = calledText.split('.').pop();\n if (!calledName || calledName === methodName) continue;\n\n let resolved: string | undefined;\n if (calledText.startsWith('this.')) {\n resolved = this.resolveThisMethodCall(sourceFile, filePath, className, calledName);\n } else {\n resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);\n }\n if (resolved) {\n edges.push({ from: methodSymbolId, to: resolved, kind: 'calls' });\n }\n }\n\n // GAP-11 FIX: constructor calls from methods (new Foo())\n for (const newExpr of method.getDescendantsOfKind(SyntaxKind.NewExpression)) {\n const calledText = newExpr.getExpression().getText();\n const calledName = calledText.split('.').pop();\n if (!calledName) continue;\n\n let resolved: string | undefined;\n if (calledText.startsWith('this.')) {\n resolved = this.resolveThisMethodCall(sourceFile, filePath, className, calledName);\n } else {\n resolved = this.resolveLocalCallTarget(sourceFile, filePath, calledName);\n }\n if (resolved) {\n edges.push({ from: methodSymbolId, to: resolved, kind: 'calls' });\n }\n }\n }\n }\n }\n\n private extractReferenceEdges(\n sourceFile: SourceFile,\n filePath: string,\n edges: GraphEdge[],\n ): void {\n // Build map of all named imports from local modules: importedName → resolved symbolId\n const importMap = new Map<string, string>();\n for (const imp of sourceFile.getImportDeclarations()) {\n const mod = imp.getModuleSpecifierValue();\n if (!mod.startsWith('.') && !mod.startsWith('/')) continue;\n const targetFile = this.resolveRelativeImport(filePath, mod);\n for (const named of imp.getNamedImports()) {\n importMap.set(named.getName(), this.resolveImportTarget(targetFile, named.getName()));\n }\n const defaultImport = imp.getDefaultImport();\n if (defaultImport) {\n importMap.set(defaultImport.getText(), this.resolveImportTarget(targetFile, defaultImport.getText()));\n }\n }\n if (importMap.size === 0) return;\n\n // Scan each exported symbol's body for identifier references to imports\n for (const fn of sourceFile.getFunctions()) {\n if (!this.isExported(fn)) continue;\n const fnName = fn.getName();\n if (!fnName) continue;\n const fromId = this.buildSymbolId(filePath, fnName, 'function');\n this.emitUsesEdges(fn, fromId, importMap, edges);\n }\n\n for (const cls of sourceFile.getClasses()) {\n if (!this.isExported(cls)) continue;\n const className = cls.getName();\n if (!className) continue;\n\n // Class-level references (property types, constructor params)\n const classId = this.buildSymbolId(filePath, className, 'class');\n this.emitUsesEdges(cls, classId, importMap, edges);\n }\n }\n\n private emitUsesEdges(\n node: Node,\n fromId: string,\n importMap: Map<string, string>,\n edges: GraphEdge[],\n ): void {\n const seen = new Set<string>();\n for (const id of node.getDescendantsOfKind(SyntaxKind.Identifier)) {\n const name = id.getText();\n if (seen.has(name)) continue;\n const target = importMap.get(name);\n if (target) {\n seen.add(name);\n edges.push({ from: fromId, to: target, kind: 'uses' });\n }\n }\n }\n\n private resolveLocalCallTarget(\n sourceFile: SourceFile,\n filePath: string,\n calledName: string,\n ): string | undefined {\n // Check if the called name is imported from a local module\n for (const imp of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = imp.getModuleSpecifierValue();\n if (!moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/')) continue;\n\n for (const named of imp.getNamedImports()) {\n if (named.getName() === calledName) {\n const targetFile = this.resolveRelativeImport(filePath, moduleSpecifier);\n return this.resolveImportTarget(targetFile, calledName);\n }\n }\n }\n\n // Check if it's a locally defined function in the same file\n for (const fn of sourceFile.getFunctions()) {\n if (fn.getName() === calledName) {\n return this.buildSymbolId(filePath, calledName, 'function');\n }\n }\n\n return undefined;\n }\n\n private resolveThisMethodCall(\n sourceFile: SourceFile,\n filePath: string,\n className: string,\n calledName: string,\n ): string | undefined {\n for (const cls of sourceFile.getClasses()) {\n if (cls.getName() !== className) continue;\n for (const method of cls.getMethods()) {\n if (method.getName() === calledName) {\n return this.buildSymbolId(filePath, `${className}.${calledName}`, 'method');\n }\n }\n }\n return undefined;\n }\n\n // ── Helpers ─────────────────────────────────────────────────\n\n private parseSource(filePath: string, source: string): SourceFile | undefined {\n try {\n const existing = this.project.getSourceFile(filePath);\n if (existing && this.projectPreloaded) {\n return existing;\n }\n if (existing) {\n this.project.removeSourceFile(existing);\n }\n return this.project.createSourceFile(filePath, source, { overwrite: true });\n } catch (err) {\n console.error(`[ctxo:ts-morph] Parse failed for ${filePath}: ${(err as Error).message}`);\n return undefined;\n }\n }\n\n private cleanupSourceFile(filePath: string): void {\n const existing = this.project.getSourceFile(filePath);\n if (existing) {\n this.project.removeSourceFile(existing);\n }\n }\n\n private buildSymbolId(filePath: string, name: string, kind: SymbolKind): string {\n return `${filePath}::${name}::${kind}`;\n }\n\n private resolveRelativeImport(fromFile: string, moduleSpecifier: string): string {\n // Convert relative import like '../types.js' to project-relative 'src/core/types.ts'\n const fromDir = dirname(fromFile);\n let resolved = normalize(join(fromDir, moduleSpecifier)).replace(/\\\\/g, '/');\n\n // Strip .js extension (TypeScript imports use .js but source files are .ts)\n if (resolved.endsWith('.js')) {\n resolved = resolved.slice(0, -3) + '.ts';\n } else if (resolved.endsWith('.jsx')) {\n resolved = resolved.slice(0, -4) + '.tsx';\n } else if (!extname(resolved)) {\n resolved += '.ts';\n }\n\n return resolved;\n }\n\n private resolveImportTarget(targetFile: string, name: string): string {\n // BUG-8/9 FIX: check symbol registry first (populated from Phase 1 of indexing)\n const prefix = `${targetFile}::${name}::`;\n for (const kind of SYMBOL_KINDS) {\n if (this.symbolRegistry.has(`${prefix}${kind}`)) {\n return `${prefix}${kind}`;\n }\n }\n\n // Try to find the symbol in the already-parsed project to get the correct kind\n const targetSourceFile = this.project.getSourceFile(targetFile);\n if (targetSourceFile) {\n for (const fn of targetSourceFile.getFunctions()) {\n if (fn.getName() === name && this.isExported(fn)) {\n return this.buildSymbolId(targetFile, name, 'function');\n }\n }\n for (const cls of targetSourceFile.getClasses()) {\n if (cls.getName() === name && this.isExported(cls)) {\n return this.buildSymbolId(targetFile, name, 'class');\n }\n }\n for (const iface of targetSourceFile.getInterfaces()) {\n if (iface.getName() === name && this.isExported(iface)) {\n return this.buildSymbolId(targetFile, name, 'interface');\n }\n }\n for (const t of targetSourceFile.getTypeAliases()) {\n if (t.getName() === name && this.isExported(t)) {\n return this.buildSymbolId(targetFile, name, 'type');\n }\n }\n }\n // Fallback: infer kind from naming conventions\n const kind = this.inferSymbolKind(name);\n return `${targetFile}::${name}::${kind}`;\n }\n\n private resolveSymbolReference(\n sourceFile: SourceFile,\n name: string,\n defaultKind: SymbolKind,\n ): string {\n // Check if the name is imported\n for (const imp of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = imp.getModuleSpecifierValue();\n if (!moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/')) continue;\n\n for (const named of imp.getNamedImports()) {\n if (named.getName() === name) {\n const resolved = imp.getModuleSpecifierSourceFile()?.getFilePath();\n if (resolved) {\n return `${this.normalizeFilePath(resolved)}::${name}::${defaultKind}`;\n }\n // Fallback: resolve relative module specifier manually\n const sourceDir = dirname(this.normalizeFilePath(sourceFile.getFilePath()));\n const resolvedPath = normalize(join(sourceDir, moduleSpecifier))\n .replace(/\\\\/g, '/')\n .replace(/\\.jsx$/, '.tsx')\n .replace(/\\.js$/, '.ts');\n return `${resolvedPath}::${name}::${defaultKind}`;\n }\n }\n }\n\n // Assume it's in the same file\n return `${sourceFile.getFilePath()}::${name}::${defaultKind}`;\n }\n\n private inferSymbolKind(name: string): SymbolKind {\n // Interface: starts with I followed by uppercase (IStoragePort, IGitPort)\n if (/^I[A-Z]/.test(name) && name.length > 2) return 'interface';\n // All caps with underscores: variable/constant (MAX_AMOUNT, EDGE_KINDS)\n if (/^[A-Z][A-Z_0-9]+$/.test(name)) return 'variable';\n // PascalCase: could be class, interface, or type — default to class\n if (/^[A-Z]/.test(name)) return 'class';\n // camelCase: function\n return 'function';\n }\n\n private normalizeFilePath(filePath: string): string {\n // Remove leading / from in-memory file system paths\n return filePath.replace(/^\\//, '');\n }\n\n private getExportedSymbolIds(sourceFile: SourceFile, filePath: string): string[] {\n const ids: string[] = [];\n for (const fn of sourceFile.getFunctions()) {\n if (!this.isExported(fn)) continue;\n const name = fn.getName();\n if (name) ids.push(this.buildSymbolId(filePath, name, 'function'));\n }\n for (const cls of sourceFile.getClasses()) {\n if (!this.isExported(cls)) continue;\n const name = cls.getName();\n if (name) ids.push(this.buildSymbolId(filePath, name, 'class'));\n }\n for (const iface of sourceFile.getInterfaces()) {\n if (!this.isExported(iface)) continue;\n ids.push(this.buildSymbolId(filePath, iface.getName(), 'interface'));\n }\n for (const t of sourceFile.getTypeAliases()) {\n if (!this.isExported(t)) continue;\n ids.push(this.buildSymbolId(filePath, t.getName(), 'type'));\n }\n for (const stmt of sourceFile.getVariableStatements()) {\n if (!this.isExported(stmt)) continue;\n for (const decl of stmt.getDeclarations()) {\n ids.push(this.buildSymbolId(filePath, decl.getName(), 'variable'));\n }\n }\n return ids;\n }\n\n private isExported(node: Node): boolean {\n if (Node.isExportable(node)) {\n return node.isExported();\n }\n return false;\n }\n\n private countCyclomaticComplexity(node: FunctionDeclaration | MethodDeclaration): number {\n let complexity = 1;\n\n node.forEachDescendant((child) => {\n switch (child.getKind()) {\n case SyntaxKind.IfStatement:\n case SyntaxKind.ConditionalExpression:\n case SyntaxKind.ForStatement:\n case SyntaxKind.ForInStatement:\n case SyntaxKind.ForOfStatement:\n case SyntaxKind.WhileStatement:\n case SyntaxKind.DoStatement:\n case SyntaxKind.CaseClause:\n case SyntaxKind.CatchClause:\n case SyntaxKind.BinaryExpression: {\n const text = child.getText();\n if (child.getKind() === SyntaxKind.BinaryExpression) {\n if (text.includes('&&') || text.includes('||') || text.includes('??')) {\n complexity++;\n }\n } else {\n complexity++;\n }\n break;\n }\n }\n });\n\n return complexity;\n }\n}\n","import type { CtxoLanguagePlugin, PluginContext, ILanguageAdapter } from '@ctxo/plugin-api';\nimport { TsMorphAdapter } from './ts-morph-adapter.js';\n\nexport { TsMorphAdapter } from './ts-morph-adapter.js';\n\nconst VERSION = '0.7.0-alpha.0';\n\nexport const plugin: CtxoLanguagePlugin = {\n apiVersion: '1',\n id: 'typescript',\n name: 'TypeScript / JavaScript (ts-morph)',\n version: VERSION,\n extensions: ['.ts', '.tsx', '.js', '.jsx'],\n tier: 'full',\n createAdapter(_ctx: PluginContext): ILanguageAdapter {\n return new TsMorphAdapter();\n },\n};\n\nexport default plugin;\n"],"mappings":"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","names":["kind"]}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@ctxo/lang-typescript",
3
+ "version": "0.7.0-alpha.0",
4
+ "description": "Ctxo TypeScript/JavaScript language plugin (ts-morph, full tier)",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "files": [
19
+ "dist/",
20
+ "README.md"
21
+ ],
22
+ "keywords": [
23
+ "ctxo",
24
+ "ctxo-plugin",
25
+ "language-plugin",
26
+ "typescript",
27
+ "javascript",
28
+ "ts-morph"
29
+ ],
30
+ "author": "Alper Hankendi",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "ts-morph": "^27.0.2"
34
+ },
35
+ "peerDependencies": {
36
+ "@ctxo/plugin-api": "^0.7.0-alpha.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.15.3",
40
+ "tsup": "^8.4.0",
41
+ "typescript": "^5.8.3",
42
+ "vitest": "^3.1.3",
43
+ "@ctxo/plugin-api": "0.7.0-alpha.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "typecheck": "tsc --noEmit",
48
+ "test": "vitest run",
49
+ "test:unit": "vitest run"
50
+ }
51
+ }