projscan 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,9 +6,9 @@
6
6
  [![license](https://img.shields.io/npm/l/projscan.svg)](https://github.com/abhiyoheswaran1/projscan/blob/main/LICENSE)
7
7
  [![node](https://img.shields.io/node/v/projscan.svg)](https://nodejs.org)
8
8
 
9
- **Instant codebase insights doctor, x-ray, and architecture map for any repository.**
9
+ **Agent-first code intelligence.** An MCP server that lets AI coding agents (Claude Code, Cursor, Windsurf) query your codebase — with a CLI for humans on the side.
10
10
 
11
- [Install](#install) · [Quick Start](#quick-start) · [Commands](#commands) · [Full Guide](docs/GUIDE.md) · [Roadmap](docs/ROADMAP.md)
11
+ [AI Agent Quick Start](#ai-agent-integration-mcp) · [CLI Quick Start](#quick-start) · [Commands](#commands) · [Full Guide](docs/GUIDE.md) · [Roadmap](docs/ROADMAP.md)
12
12
 
13
13
  <img src="docs/hero.png" alt="projscan banner" width="600">
14
14
 
@@ -18,16 +18,13 @@
18
18
 
19
19
  ## Why?
20
20
 
21
- Every time you clone a new repo, join a new team, or revisit an old project, you face the same questions:
21
+ AI coding agents are becoming the primary interface to code. Today, when you ask your agent *"which files implement auth?"* or *"what breaks if I bump React from 18 to 19?"* — it either guesses from names, or it shells out to grep and reads raw output not built for it.
22
22
 
23
- - What language and framework is this?
24
- - Is there linting? Testing? Formatting?
25
- - What's the project structure?
26
- - Are the dependencies healthy?
23
+ **projscan is the first code-intelligence tool built for agents, not for humans.** Your agent gets a fast, AST-accurate, context-budget-aware view of your codebase through 13 structured MCP tools. It can query the import graph, find symbol definitions, preview upgrades, rank hotspots — without loading the file tree into its context.
27
24
 
28
- Answering these manually takes 10-30 minutes of poking through config files and directories.
25
+ Humans get the same thing through the CLI.
29
26
 
30
- **projscan answers all of this in one command, in under 2 seconds.**
27
+ **Everything is offline-first. Zero network calls. No API keys.**
31
28
 
32
29
  ```bash
33
30
  npx projscan
@@ -388,27 +385,7 @@ Coverage is also automatically joined into `projscan hotspots` when one of those
388
385
 
389
386
  ## AI Agent Integration (MCP)
390
387
 
391
- **`projscan mcp`** starts an [MCP](https://modelcontextprotocol.io) server over stdio so AI coding agents can query projscan during a session.
392
-
393
- **Tools** (11):
394
- - `projscan_analyze` — full project report
395
- - `projscan_doctor` — health score + issues
396
- - `projscan_hotspots` — risk-ranked files (with `limit`, `since` args)
397
- - `projscan_file` — per-file risk + ownership + related issues
398
- - `projscan_explain` — per-file purpose, imports, exports, smells
399
- - `projscan_structure` — directory tree
400
- - `projscan_dependencies` — package audit
401
- - `projscan_outdated` — declared-vs-installed drift
402
- - `projscan_audit` — npm audit, normalized
403
- - `projscan_upgrade` — offline upgrade preview with CHANGELOG + importers
404
- - `projscan_coverage` — coverage × hotspots, "scariest untested files"
405
-
406
- **Prompts** (2, parameterized with live project data):
407
- - `prioritize_refactoring` — ranked plan grounded in current hotspots
408
- - `investigate_file` — senior-engineer brief for a specific file
409
-
410
- **Resources** (3, readable on demand):
411
- - `projscan://health` · `projscan://hotspots` · `projscan://structure`
388
+ **This is the primary way to use projscan.** `projscan mcp` starts an [MCP](https://modelcontextprotocol.io) server over stdio so AI coding agents can query your codebase with real structural accuracy — not regex, not grep.
412
389
 
413
390
  ### Claude Code
414
391
 
@@ -418,8 +395,6 @@ claude mcp add projscan -- npx projscan mcp
418
395
 
419
396
  ### Cursor / Windsurf / any MCP client
420
397
 
421
- Add to your MCP config:
422
-
423
398
  ```json
424
399
  {
425
400
  "mcpServers": {
@@ -431,7 +406,54 @@ Add to your MCP config:
431
406
  }
432
407
  ```
433
408
 
434
- Now your agent can ask *"what are the riskiest files in this repo?"* and get a grounded answer, or run `projscan_doctor` before proposing an edit.
409
+ ### What agents can ask
410
+
411
+ - *"Who imports `src/auth/jwt.ts`?"* → `projscan_graph { file, direction: "importers" }`
412
+ - *"Where is `runAudit` defined?"* → `projscan_search { query: "runAudit", scope: "symbols" }`
413
+ - *"Which files implement auth?"* → `projscan_search { query: "auth", scope: "content" }`
414
+ - *"What are the scariest untested files?"* → `projscan_coverage`
415
+ - *"What breaks if I bump chalk to 6?"* → `projscan_upgrade { package: "chalk" }`
416
+ - *"Where should I refactor first?"* → `projscan_hotspots`
417
+
418
+ ### The 13 MCP tools
419
+
420
+ **Structural (0.6.0 — new, agent-native):**
421
+ - **`projscan_graph`** — query the AST-based code graph. Directions: `imports`, `exports`, `importers`, `symbol_defs`, `package_importers`. Millisecond responses on a warm cache.
422
+ - **`projscan_search`** — fast search across `symbols` (exported names), `files` (path substring), or `content` (source substring with line + excerpt). Replaces the temptation to shell out to grep.
423
+
424
+ **Analysis:**
425
+ - `projscan_analyze` — full project report
426
+ - `projscan_doctor` — health score + issues
427
+ - `projscan_hotspots` — risk-ranked files (churn × complexity × issues × ownership × coverage)
428
+ - `projscan_file` — per-file risk + ownership + related issues
429
+ - `projscan_explain` — per-file purpose, imports, exports, smells
430
+ - `projscan_structure` — directory tree
431
+ - `projscan_coverage` — scariest untested files (coverage × hotspots)
432
+
433
+ **Dependencies:**
434
+ - `projscan_dependencies` — declared deps, risks
435
+ - `projscan_outdated` — declared-vs-installed drift (offline)
436
+ - `projscan_audit` — normalized `npm audit`
437
+ - `projscan_upgrade` — upgrade preview (CHANGELOG + importers, offline)
438
+
439
+ ### Context-window budgeting
440
+
441
+ **Every MCP tool accepts an optional `max_tokens` argument.** Set it and projscan serializes the result, and — if over budget — truncates the largest array field record-by-record until it fits. Responses include a `_budget` sidecar when truncated so your agent knows it got a partial view.
442
+
443
+ ```json
444
+ { "name": "projscan_hotspots", "arguments": { "limit": 100, "max_tokens": 800 } }
445
+ ```
446
+
447
+ ### Incremental index cache
448
+
449
+ projscan caches parsed ASTs at `.projscan-cache/graph.json` (auto-gitignored). First run populates it; subsequent runs re-parse only files whose `mtime` changed. Agent queries on a warm cache are milliseconds, not seconds.
450
+
451
+ ### Prompts (2, parameterized with live project data)
452
+ - `prioritize_refactoring` — ranked plan grounded in current hotspots
453
+ - `investigate_file` — senior-engineer brief for a specific file
454
+
455
+ ### Resources (3, readable on demand)
456
+ - `projscan://health` · `projscan://hotspots` · `projscan://structure`
435
457
 
436
458
  ## Use Cases
437
459
 
@@ -0,0 +1,34 @@
1
+ export type SymbolKind = 'function' | 'class' | 'variable' | 'type' | 'interface' | 'enum' | 'default' | 'unknown';
2
+ export interface AstImport {
3
+ source: string;
4
+ kind: 'static' | 'dynamic' | 'require' | 'reexport';
5
+ specifiers: string[];
6
+ typeOnly: boolean;
7
+ line: number;
8
+ }
9
+ export interface AstExport {
10
+ name: string;
11
+ kind: SymbolKind;
12
+ typeOnly: boolean;
13
+ line: number;
14
+ }
15
+ export interface AstResult {
16
+ ok: boolean;
17
+ reason?: string;
18
+ imports: AstImport[];
19
+ exports: AstExport[];
20
+ callSites: string[];
21
+ lineCount: number;
22
+ }
23
+ /** Is this a file we should try to AST-parse at all? */
24
+ export declare function isParseable(filePath: string): boolean;
25
+ /**
26
+ * Parse a source file and extract imports, exports, and call sites.
27
+ *
28
+ * Uses @babel/parser with generous options so we accept real-world code:
29
+ * TypeScript, JSX, decorators, top-level await, class properties, etc.
30
+ *
31
+ * Failures return ok:false with a reason — callers decide whether to fall
32
+ * back to regex or skip the file. Never throws.
33
+ */
34
+ export declare function parseSource(filePath: string, content: string): AstResult;
@@ -0,0 +1,270 @@
1
+ import { parse } from '@babel/parser';
2
+ import path from 'node:path';
3
+ const EMPTY = {
4
+ ok: false,
5
+ reason: 'unparsed',
6
+ imports: [],
7
+ exports: [],
8
+ callSites: [],
9
+ lineCount: 0,
10
+ };
11
+ const SOURCE_EXTENSIONS = new Set([
12
+ '.ts',
13
+ '.tsx',
14
+ '.js',
15
+ '.jsx',
16
+ '.mjs',
17
+ '.cjs',
18
+ '.mts',
19
+ '.cts',
20
+ ]);
21
+ /** Is this a file we should try to AST-parse at all? */
22
+ export function isParseable(filePath) {
23
+ return SOURCE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
24
+ }
25
+ /**
26
+ * Parse a source file and extract imports, exports, and call sites.
27
+ *
28
+ * Uses @babel/parser with generous options so we accept real-world code:
29
+ * TypeScript, JSX, decorators, top-level await, class properties, etc.
30
+ *
31
+ * Failures return ok:false with a reason — callers decide whether to fall
32
+ * back to regex or skip the file. Never throws.
33
+ */
34
+ export function parseSource(filePath, content) {
35
+ if (!isParseable(filePath)) {
36
+ return { ...EMPTY, reason: 'non-source extension' };
37
+ }
38
+ const ext = path.extname(filePath).toLowerCase();
39
+ const isTypeScript = ext === '.ts' || ext === '.tsx' || ext === '.mts' || ext === '.cts';
40
+ const isJSX = ext === '.tsx' || ext === '.jsx';
41
+ const plugins = [];
42
+ if (isTypeScript)
43
+ plugins.push('typescript');
44
+ if (isJSX)
45
+ plugins.push('jsx');
46
+ plugins.push('decorators-legacy', 'dynamicImport', 'topLevelAwait');
47
+ let ast;
48
+ try {
49
+ ast = parse(content, {
50
+ sourceType: 'module',
51
+ allowImportExportEverywhere: true,
52
+ allowAwaitOutsideFunction: true,
53
+ allowReturnOutsideFunction: true,
54
+ allowSuperOutsideMethod: true,
55
+ errorRecovery: true,
56
+ plugins,
57
+ });
58
+ }
59
+ catch (err) {
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ return { ...EMPTY, reason: `parse error: ${msg.slice(0, 120)}` };
62
+ }
63
+ const imports = [];
64
+ const exports = [];
65
+ const callSites = [];
66
+ for (const node of ast.program.body) {
67
+ visitTopLevel(node, imports, exports);
68
+ }
69
+ // Second pass: extract dynamic imports + call sites. Walk the whole tree
70
+ // (cheap — we already have the AST in memory).
71
+ walk(ast.program, (n) => {
72
+ if (n.type === 'CallExpression') {
73
+ const callee = n.callee;
74
+ if (callee.type === 'Identifier') {
75
+ callSites.push(callee.name);
76
+ }
77
+ else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
78
+ callSites.push(callee.property.name);
79
+ }
80
+ else if (callee.type === 'Import' && n.arguments[0] && n.arguments[0].type === 'StringLiteral') {
81
+ imports.push({
82
+ source: n.arguments[0].value,
83
+ kind: 'dynamic',
84
+ specifiers: [],
85
+ typeOnly: false,
86
+ line: n.loc?.start.line ?? 0,
87
+ });
88
+ }
89
+ // CommonJS require()
90
+ if (callee.type === 'Identifier' &&
91
+ callee.name === 'require' &&
92
+ n.arguments[0] &&
93
+ n.arguments[0].type === 'StringLiteral') {
94
+ imports.push({
95
+ source: n.arguments[0].value,
96
+ kind: 'require',
97
+ specifiers: [],
98
+ typeOnly: false,
99
+ line: n.loc?.start.line ?? 0,
100
+ });
101
+ }
102
+ }
103
+ });
104
+ return {
105
+ ok: true,
106
+ imports,
107
+ exports,
108
+ callSites: [...new Set(callSites)],
109
+ lineCount: content ? content.split('\n').length : 0,
110
+ };
111
+ }
112
+ function visitTopLevel(node, imports, exports) {
113
+ switch (node.type) {
114
+ case 'ImportDeclaration': {
115
+ imports.push(importFromNode(node));
116
+ return;
117
+ }
118
+ case 'ExportNamedDeclaration': {
119
+ collectNamedExport(node, exports, imports);
120
+ return;
121
+ }
122
+ case 'ExportDefaultDeclaration': {
123
+ exports.push({
124
+ name: 'default',
125
+ kind: 'default',
126
+ typeOnly: false,
127
+ line: node.loc?.start.line ?? 0,
128
+ });
129
+ return;
130
+ }
131
+ case 'ExportAllDeclaration': {
132
+ const source = node.source.value;
133
+ imports.push({
134
+ source,
135
+ kind: 'reexport',
136
+ specifiers: [],
137
+ typeOnly: Boolean(node.exportKind === 'type'),
138
+ line: node.loc?.start.line ?? 0,
139
+ });
140
+ return;
141
+ }
142
+ default:
143
+ return;
144
+ }
145
+ }
146
+ function importFromNode(node) {
147
+ const specifiers = node.specifiers.map((s) => {
148
+ if (s.type === 'ImportDefaultSpecifier')
149
+ return 'default';
150
+ if (s.type === 'ImportNamespaceSpecifier')
151
+ return '*';
152
+ if (s.type === 'ImportSpecifier') {
153
+ const imported = s.imported;
154
+ if (imported.type === 'Identifier')
155
+ return imported.name;
156
+ return imported.value;
157
+ }
158
+ return '';
159
+ });
160
+ return {
161
+ source: node.source.value,
162
+ kind: 'static',
163
+ specifiers: specifiers.filter(Boolean),
164
+ typeOnly: node.importKind === 'type',
165
+ line: node.loc?.start.line ?? 0,
166
+ };
167
+ }
168
+ function collectNamedExport(node, exports, imports) {
169
+ // Re-export: export { X } from 'source'
170
+ if (node.source) {
171
+ imports.push({
172
+ source: node.source.value,
173
+ kind: 'reexport',
174
+ specifiers: node.specifiers.map((s) => {
175
+ if (s.type === 'ExportSpecifier') {
176
+ const exported = s.exported;
177
+ return exported.type === 'Identifier' ? exported.name : exported.value;
178
+ }
179
+ return '';
180
+ }).filter(Boolean),
181
+ typeOnly: node.exportKind === 'type',
182
+ line: node.loc?.start.line ?? 0,
183
+ });
184
+ }
185
+ // Inline declaration: export function foo() {} / export const x = ... / etc.
186
+ if (node.declaration) {
187
+ const typeOnly = node.exportKind === 'type';
188
+ const line = node.declaration.loc?.start.line ?? node.loc?.start.line ?? 0;
189
+ switch (node.declaration.type) {
190
+ case 'FunctionDeclaration': {
191
+ const name = node.declaration.id?.name;
192
+ if (name)
193
+ exports.push({ name, kind: 'function', typeOnly, line });
194
+ return;
195
+ }
196
+ case 'ClassDeclaration': {
197
+ const name = node.declaration.id?.name;
198
+ if (name)
199
+ exports.push({ name, kind: 'class', typeOnly, line });
200
+ return;
201
+ }
202
+ case 'VariableDeclaration': {
203
+ for (const decl of node.declaration.declarations) {
204
+ if (decl.id.type === 'Identifier') {
205
+ exports.push({ name: decl.id.name, kind: 'variable', typeOnly, line });
206
+ }
207
+ }
208
+ return;
209
+ }
210
+ case 'TSInterfaceDeclaration': {
211
+ const name = node.declaration.id.name;
212
+ exports.push({ name, kind: 'interface', typeOnly: true, line });
213
+ return;
214
+ }
215
+ case 'TSTypeAliasDeclaration': {
216
+ const name = node.declaration.id.name;
217
+ exports.push({ name, kind: 'type', typeOnly: true, line });
218
+ return;
219
+ }
220
+ case 'TSEnumDeclaration': {
221
+ const name = node.declaration.id.name;
222
+ exports.push({ name, kind: 'enum', typeOnly, line });
223
+ return;
224
+ }
225
+ default:
226
+ return;
227
+ }
228
+ }
229
+ // Named re-export of local symbols: export { foo, bar }
230
+ for (const spec of node.specifiers) {
231
+ if (spec.type !== 'ExportSpecifier')
232
+ continue;
233
+ const exported = spec.exported;
234
+ const name = exported.type === 'Identifier' ? exported.name : exported.value;
235
+ exports.push({
236
+ name,
237
+ kind: 'unknown',
238
+ typeOnly: node.exportKind === 'type',
239
+ line: spec.loc?.start.line ?? node.loc?.start.line ?? 0,
240
+ });
241
+ }
242
+ }
243
+ /**
244
+ * Lightweight AST walker. We only care about recursing through node properties
245
+ * to find CallExpressions (for call sites + dynamic imports + require).
246
+ * Avoids the full babel-traverse dependency.
247
+ */
248
+ function walk(node, visit) {
249
+ if (!node || typeof node !== 'object')
250
+ return;
251
+ visit(node);
252
+ for (const key of Object.keys(node)) {
253
+ if (key === 'loc' || key === 'range' || key === 'leadingComments' || key === 'trailingComments')
254
+ continue;
255
+ const child = node[key];
256
+ if (!child)
257
+ continue;
258
+ if (Array.isArray(child)) {
259
+ for (const item of child) {
260
+ if (item && typeof item === 'object' && 'type' in item) {
261
+ walk(item, visit);
262
+ }
263
+ }
264
+ }
265
+ else if (typeof child === 'object' && 'type' in child) {
266
+ walk(child, visit);
267
+ }
268
+ }
269
+ }
270
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/core/ast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { FileEntry } from '../types.js';
2
+ import { type AstImport, type AstExport } from './ast.js';
3
+ export interface GraphFile {
4
+ relativePath: string;
5
+ imports: AstImport[];
6
+ exports: AstExport[];
7
+ callSites: string[];
8
+ lineCount: number;
9
+ mtimeMs: number;
10
+ parseOk: boolean;
11
+ parseReason?: string;
12
+ }
13
+ export interface CodeGraph {
14
+ /** per-file parse results, keyed by relativePath */
15
+ files: Map<string, GraphFile>;
16
+ /** package name → relativePaths that import it */
17
+ packageImporters: Map<string, Set<string>>;
18
+ /** relativePath → relativePaths that import it (local resolution) */
19
+ localImporters: Map<string, Set<string>>;
20
+ /** symbol name → relativePaths that export it */
21
+ symbolDefs: Map<string, Set<string>>;
22
+ /** scanned file count */
23
+ scannedFiles: number;
24
+ }
25
+ export declare function buildCodeGraph(rootPath: string, files: FileEntry[], previousGraph?: CodeGraph): Promise<CodeGraph>;
26
+ /**
27
+ * Convert an import specifier to a bare package name.
28
+ */
29
+ export declare function toPackageName(specifier: string): string | null;
30
+ export declare function packagesUsed(graph: CodeGraph): Set<string>;
31
+ export declare function filesImportingPackage(graph: CodeGraph, pkg: string): string[];
32
+ export declare function filesImportingFile(graph: CodeGraph, relativePath: string): string[];
33
+ export declare function filesDefiningSymbol(graph: CodeGraph, name: string): string[];
34
+ export declare function importersOf(graph: CodeGraph, relativePath: string): string[];
35
+ export declare function exportsOf(graph: CodeGraph, relativePath: string): AstExport[];
36
+ export declare function importsOf(graph: CodeGraph, relativePath: string): AstImport[];
@@ -0,0 +1,167 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { parseSource, isParseable } from './ast.js';
4
+ const NODE_BUILTINS = new Set([
5
+ 'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console', 'constants', 'crypto',
6
+ 'dgram', 'dns', 'domain', 'events', 'fs', 'fs/promises', 'http', 'http2', 'https', 'inspector',
7
+ 'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline',
8
+ 'repl', 'stream', 'string_decoder', 'sys', 'timers', 'tls', 'trace_events', 'tty', 'url', 'util',
9
+ 'v8', 'vm', 'wasi', 'worker_threads', 'zlib',
10
+ ]);
11
+ const RESOLUTION_EXTS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts'];
12
+ const MAX_FILE_SIZE = 1024 * 1024;
13
+ export async function buildCodeGraph(rootPath, files, previousGraph) {
14
+ const parseable = files.filter((f) => isParseable(f.relativePath) && f.sizeBytes <= MAX_FILE_SIZE);
15
+ const graphFiles = new Map();
16
+ const packageImporters = new Map();
17
+ const localImporters = new Map();
18
+ const symbolDefs = new Map();
19
+ // Parse each file (with mtime-based reuse if we have a previous graph)
20
+ await Promise.all(parseable.map(async (file) => {
21
+ const absolutePath = path.isAbsolute(file.absolutePath)
22
+ ? file.absolutePath
23
+ : path.resolve(rootPath, file.relativePath);
24
+ let mtimeMs;
25
+ try {
26
+ const stat = await fs.stat(absolutePath);
27
+ mtimeMs = stat.mtimeMs;
28
+ }
29
+ catch {
30
+ return;
31
+ }
32
+ const cached = previousGraph?.files.get(file.relativePath);
33
+ if (cached && cached.mtimeMs === mtimeMs) {
34
+ graphFiles.set(file.relativePath, cached);
35
+ return;
36
+ }
37
+ let content;
38
+ try {
39
+ content = await fs.readFile(absolutePath, 'utf-8');
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ const result = parseSource(file.relativePath, content);
45
+ graphFiles.set(file.relativePath, {
46
+ relativePath: file.relativePath,
47
+ imports: result.imports,
48
+ exports: result.exports,
49
+ callSites: result.callSites,
50
+ lineCount: result.lineCount,
51
+ mtimeMs,
52
+ parseOk: result.ok,
53
+ parseReason: result.reason,
54
+ });
55
+ }));
56
+ // Build derived indexes after all parsing is done
57
+ for (const [importingFile, entry] of graphFiles) {
58
+ const importingDir = path.posix.dirname(importingFile);
59
+ for (const imp of entry.imports) {
60
+ const pkg = toPackageName(imp.source);
61
+ if (pkg) {
62
+ if (!packageImporters.has(pkg))
63
+ packageImporters.set(pkg, new Set());
64
+ packageImporters.get(pkg).add(importingFile);
65
+ }
66
+ else if (imp.source.startsWith('.') || imp.source.startsWith('/')) {
67
+ const resolved = resolveRelative(importingDir, imp.source, graphFiles);
68
+ if (resolved) {
69
+ if (!localImporters.has(resolved))
70
+ localImporters.set(resolved, new Set());
71
+ localImporters.get(resolved).add(importingFile);
72
+ }
73
+ }
74
+ }
75
+ for (const exp of entry.exports) {
76
+ if (!exp.name)
77
+ continue;
78
+ if (!symbolDefs.has(exp.name))
79
+ symbolDefs.set(exp.name, new Set());
80
+ symbolDefs.get(exp.name).add(importingFile);
81
+ }
82
+ }
83
+ return {
84
+ files: graphFiles,
85
+ packageImporters,
86
+ localImporters,
87
+ symbolDefs,
88
+ scannedFiles: graphFiles.size,
89
+ };
90
+ }
91
+ /**
92
+ * Convert an import specifier to a bare package name.
93
+ */
94
+ export function toPackageName(specifier) {
95
+ if (!specifier)
96
+ return null;
97
+ if (specifier.startsWith('.') || specifier.startsWith('/'))
98
+ return null;
99
+ if (specifier.startsWith('node:'))
100
+ return null;
101
+ if (NODE_BUILTINS.has(specifier))
102
+ return null;
103
+ if (specifier.startsWith('@')) {
104
+ const segments = specifier.split('/');
105
+ if (segments.length < 2)
106
+ return null;
107
+ return `${segments[0]}/${segments[1]}`;
108
+ }
109
+ return specifier.split('/')[0];
110
+ }
111
+ /**
112
+ * Resolve a relative import to a file in the graph, or null if no match.
113
+ * Supports:
114
+ * - direct hit (./foo.ts → foo.ts)
115
+ * - extension inference (./foo → foo.ts)
116
+ * - barrel index (./foo → foo/index.ts)
117
+ * - .js that resolves to .ts under NodeNext
118
+ */
119
+ function resolveRelative(importingDir, specifier, graphFiles) {
120
+ const base = path.posix.normalize(path.posix.join(importingDir, specifier));
121
+ if (graphFiles.has(base))
122
+ return base;
123
+ for (const ext of RESOLUTION_EXTS) {
124
+ if (graphFiles.has(base + ext))
125
+ return base + ext;
126
+ }
127
+ for (const ext of RESOLUTION_EXTS) {
128
+ const barrel = `${base}/index${ext}`;
129
+ if (graphFiles.has(barrel))
130
+ return barrel;
131
+ }
132
+ // .js → .ts fallback (NodeNext)
133
+ if (base.endsWith('.js')) {
134
+ const trimmed = base.slice(0, -3);
135
+ if (graphFiles.has(`${trimmed}.ts`))
136
+ return `${trimmed}.ts`;
137
+ if (graphFiles.has(`${trimmed}.tsx`))
138
+ return `${trimmed}.tsx`;
139
+ }
140
+ return null;
141
+ }
142
+ // ── Query API ──────────────────────────────────────────────
143
+ export function packagesUsed(graph) {
144
+ return new Set(graph.packageImporters.keys());
145
+ }
146
+ export function filesImportingPackage(graph, pkg) {
147
+ const set = graph.packageImporters.get(pkg);
148
+ return set ? [...set].sort() : [];
149
+ }
150
+ export function filesImportingFile(graph, relativePath) {
151
+ const set = graph.localImporters.get(relativePath);
152
+ return set ? [...set].sort() : [];
153
+ }
154
+ export function filesDefiningSymbol(graph, name) {
155
+ const set = graph.symbolDefs.get(name);
156
+ return set ? [...set].sort() : [];
157
+ }
158
+ export function importersOf(graph, relativePath) {
159
+ return filesImportingFile(graph, relativePath);
160
+ }
161
+ export function exportsOf(graph, relativePath) {
162
+ return graph.files.get(relativePath)?.exports ?? [];
163
+ }
164
+ export function importsOf(graph, relativePath) {
165
+ return graph.files.get(relativePath)?.imports ?? [];
166
+ }
167
+ //# sourceMappingURL=codeGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeGraph.js","sourceRoot":"","sources":["../../src/core/codeGraph.ts"],"names":[],"mappings":"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"}