@optave/codegraph 3.5.0 → 3.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 +35 -14
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/connection.d.ts +12 -2
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +81 -53
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +38 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +69 -3
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +7 -51
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +7 -5
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +2 -2
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +124 -105
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +164 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +6 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +6 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +306 -292
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -83
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/features/ast.d.ts +2 -0
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +9 -24
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +47 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +118 -62
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +182 -7
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/package.json +13 -7
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/connection.ts +90 -59
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +36 -32
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +71 -3
- package/src/domain/graph/builder/stages/build-edges.ts +10 -75
- package/src/domain/graph/builder/stages/build-structure.ts +9 -7
- package/src/domain/graph/builder/stages/collect-files.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
- package/src/domain/graph/builder/stages/finalize.ts +159 -125
- package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +168 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/go.ts +152 -134
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +6 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +328 -281
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -85
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/features/ast.ts +10 -25
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +51 -4
- package/src/features/cfg.ts +158 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +46 -37
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +189 -7
|
@@ -39,6 +39,12 @@ interface PrecomputedFileData {
|
|
|
39
39
|
// ── Native fast-path ─────────────────────────────────────────────────
|
|
40
40
|
|
|
41
41
|
function tryNativeInsert(ctx: PipelineContext): boolean {
|
|
42
|
+
// Disabled: bulkInsertNodes corrupts the DB when both the JS (better-sqlite3)
|
|
43
|
+
// and Rust (rusqlite) connections are open to the same WAL-mode file.
|
|
44
|
+
// The native path was never operational before — it always crashed on null
|
|
45
|
+
// visibility serialisation. See #696 for the dual-connection fix.
|
|
46
|
+
if (ctx.db) return false;
|
|
47
|
+
|
|
42
48
|
// Use NativeDatabase persistent connection (Phase 6.15+).
|
|
43
49
|
// Standalone napi functions were removed in 6.17 — falls through to JS if nativeDb unavailable.
|
|
44
50
|
if (!ctx.nativeDb?.bulkInsertNodes) return false;
|
|
@@ -52,14 +58,14 @@ function tryNativeInsert(ctx: PipelineContext): boolean {
|
|
|
52
58
|
name: string;
|
|
53
59
|
kind: string;
|
|
54
60
|
line: number;
|
|
55
|
-
endLine?: number
|
|
56
|
-
visibility?: string
|
|
61
|
+
endLine?: number;
|
|
62
|
+
visibility?: string;
|
|
57
63
|
children: Array<{
|
|
58
64
|
name: string;
|
|
59
65
|
kind: string;
|
|
60
66
|
line: number;
|
|
61
|
-
endLine?: number
|
|
62
|
-
visibility?: string
|
|
67
|
+
endLine?: number;
|
|
68
|
+
visibility?: string;
|
|
63
69
|
}>;
|
|
64
70
|
}>;
|
|
65
71
|
exports: Array<{ name: string; kind: string; line: number }>;
|
|
@@ -72,14 +78,14 @@ function tryNativeInsert(ctx: PipelineContext): boolean {
|
|
|
72
78
|
name: def.name,
|
|
73
79
|
kind: def.kind,
|
|
74
80
|
line: def.line,
|
|
75
|
-
endLine: def.endLine ??
|
|
76
|
-
visibility: def.visibility ??
|
|
81
|
+
endLine: def.endLine ?? undefined,
|
|
82
|
+
visibility: def.visibility ?? undefined,
|
|
77
83
|
children: (def.children ?? []).map((c) => ({
|
|
78
84
|
name: c.name,
|
|
79
85
|
kind: c.kind,
|
|
80
86
|
line: c.line,
|
|
81
|
-
endLine: c.endLine ??
|
|
82
|
-
visibility: c.visibility ??
|
|
87
|
+
endLine: c.endLine ?? undefined,
|
|
88
|
+
visibility: c.visibility ?? undefined,
|
|
83
89
|
})),
|
|
84
90
|
})),
|
|
85
91
|
exports: symbols.exports.map((exp) => ({
|
|
@@ -138,7 +144,7 @@ function tryNativeInsert(ctx: PipelineContext): boolean {
|
|
|
138
144
|
fileHashes.push({ file: item.relPath, hash: item.hash, mtime, size });
|
|
139
145
|
}
|
|
140
146
|
|
|
141
|
-
return ctx.nativeDb
|
|
147
|
+
return ctx.nativeDb!.bulkInsertNodes(batches, fileHashes, removed);
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
// ── JS fallback: Phase 1 ────────────────────────────────────────────
|
|
@@ -330,7 +336,7 @@ function updateFileHashes(
|
|
|
330
336
|
// ── Main entry point ────────────────────────────────────────────────
|
|
331
337
|
|
|
332
338
|
export async function insertNodes(ctx: PipelineContext): Promise<void> {
|
|
333
|
-
const {
|
|
339
|
+
const { allSymbols, filesToParse, metadataUpdates, rootDir, removed } = ctx;
|
|
334
340
|
|
|
335
341
|
// Populate fileSymbols before any DB writes (used by later stages)
|
|
336
342
|
for (const [relPath, symbols] of allSymbols) {
|
|
@@ -340,11 +346,16 @@ export async function insertNodes(ctx: PipelineContext): Promise<void> {
|
|
|
340
346
|
const t0 = performance.now();
|
|
341
347
|
|
|
342
348
|
// Try native Rust path first — single transaction, no JS↔C overhead
|
|
343
|
-
if (ctx.engineName === 'native'
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
349
|
+
if (ctx.engineName === 'native') {
|
|
350
|
+
try {
|
|
351
|
+
if (tryNativeInsert(ctx)) {
|
|
352
|
+
ctx.timing.insertMs = performance.now() - t0;
|
|
353
|
+
// Removed-file hash cleanup is handled inside the native call
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
} catch {
|
|
357
|
+
// Native insert failed — fall through to JS implementation
|
|
358
|
+
}
|
|
348
359
|
}
|
|
349
360
|
|
|
350
361
|
// JS fallback
|
|
@@ -355,17 +366,17 @@ export async function insertNodes(ctx: PipelineContext): Promise<void> {
|
|
|
355
366
|
|
|
356
367
|
let upsertHash: SqliteStatement | null;
|
|
357
368
|
try {
|
|
358
|
-
upsertHash = db.prepare(
|
|
369
|
+
upsertHash = ctx.db.prepare(
|
|
359
370
|
'INSERT OR REPLACE INTO file_hashes (file, hash, mtime, size) VALUES (?, ?, ?, ?)',
|
|
360
371
|
);
|
|
361
372
|
} catch {
|
|
362
373
|
upsertHash = null;
|
|
363
374
|
}
|
|
364
375
|
|
|
365
|
-
const insertAll = db.transaction(() => {
|
|
366
|
-
insertDefinitionsAndExports(db, allSymbols);
|
|
367
|
-
insertChildrenAndEdges(db, allSymbols);
|
|
368
|
-
updateFileHashes(db, allSymbols, precomputedData, metadataUpdates, rootDir, upsertHash);
|
|
376
|
+
const insertAll = ctx.db.transaction(() => {
|
|
377
|
+
insertDefinitionsAndExports(ctx.db, allSymbols);
|
|
378
|
+
insertChildrenAndEdges(ctx.db, allSymbols);
|
|
379
|
+
updateFileHashes(ctx.db, allSymbols, precomputedData, metadataUpdates, rootDir, upsertHash);
|
|
369
380
|
});
|
|
370
381
|
|
|
371
382
|
insertAll();
|
|
@@ -373,7 +384,7 @@ export async function insertNodes(ctx: PipelineContext): Promise<void> {
|
|
|
373
384
|
|
|
374
385
|
// Clean up removed file hashes
|
|
375
386
|
if (upsertHash && removed.length > 0) {
|
|
376
|
-
const deleteHash = db.prepare('DELETE FROM file_hashes WHERE file = ?');
|
|
387
|
+
const deleteHash = ctx.db.prepare('DELETE FROM file_hashes WHERE file = ?');
|
|
377
388
|
for (const relPath of removed) {
|
|
378
389
|
deleteHash.run(relPath);
|
|
379
390
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { performance } from 'node:perf_hooks';
|
|
3
|
+
import { debug } from '../../../../infrastructure/logger.js';
|
|
3
4
|
import type { Import } from '../../../../types.js';
|
|
4
5
|
import { parseFilesAuto } from '../../../parser.js';
|
|
5
6
|
import { resolveImportPath, resolveImportsBatch } from '../../resolve.js';
|
|
@@ -132,8 +133,8 @@ export async function resolveImports(ctx: PipelineContext): Promise<void> {
|
|
|
132
133
|
);
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
|
-
} catch {
|
|
136
|
-
|
|
136
|
+
} catch (e: unknown) {
|
|
137
|
+
debug(`Barrel re-parse failed (non-fatal): ${(e as Error).message}`);
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
}
|
|
@@ -117,6 +117,35 @@ function matchSubpathPattern(pattern: string, subpath: string): string | null {
|
|
|
117
117
|
* Resolve a bare specifier through the package.json exports field.
|
|
118
118
|
* Returns an absolute path or null.
|
|
119
119
|
*/
|
|
120
|
+
/** Try to resolve a condition target to a file path in packageDir. */
|
|
121
|
+
function tryResolveTarget(target: string | null, packageDir: string): string | null {
|
|
122
|
+
if (!target) return null;
|
|
123
|
+
const resolved = path.resolve(packageDir, target);
|
|
124
|
+
return fs.existsSync(resolved) ? resolved : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Resolve subpath against a subpath map (object with "." keys). */
|
|
128
|
+
function resolveSubpathMap(
|
|
129
|
+
exports: Record<string, unknown>,
|
|
130
|
+
subpath: string,
|
|
131
|
+
packageDir: string,
|
|
132
|
+
): string | null {
|
|
133
|
+
// Exact match first
|
|
134
|
+
if (subpath in exports) {
|
|
135
|
+
return tryResolveTarget(resolveCondition(exports[subpath]), packageDir);
|
|
136
|
+
}
|
|
137
|
+
// Pattern matching (keys with *)
|
|
138
|
+
for (const [pattern, value] of Object.entries(exports)) {
|
|
139
|
+
if (!pattern.includes('*')) continue;
|
|
140
|
+
const matched = matchSubpathPattern(pattern, subpath);
|
|
141
|
+
if (matched == null) continue;
|
|
142
|
+
const rawTarget = resolveCondition(value);
|
|
143
|
+
if (!rawTarget) continue;
|
|
144
|
+
return tryResolveTarget(rawTarget.replace(/\*/g, matched), packageDir);
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
120
149
|
export function resolveViaExports(specifier: string, rootDir: string): string | null {
|
|
121
150
|
const parsed = parseBareSpecifier(specifier);
|
|
122
151
|
if (!parsed) return null;
|
|
@@ -131,66 +160,25 @@ export function resolveViaExports(specifier: string, rootDir: string): string |
|
|
|
131
160
|
|
|
132
161
|
// Simple string exports: "exports": "./index.js"
|
|
133
162
|
if (typeof exports === 'string') {
|
|
134
|
-
|
|
135
|
-
const resolved = path.resolve(packageDir, exports);
|
|
136
|
-
return fs.existsSync(resolved) ? resolved : null;
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
163
|
+
return subpath === '.' ? tryResolveTarget(exports, packageDir) : null;
|
|
139
164
|
}
|
|
140
165
|
|
|
141
166
|
// Array form at top level
|
|
142
167
|
if (Array.isArray(exports)) {
|
|
143
|
-
|
|
144
|
-
const target = resolveCondition(exports);
|
|
145
|
-
if (target) {
|
|
146
|
-
const resolved = path.resolve(packageDir, target);
|
|
147
|
-
return fs.existsSync(resolved) ? resolved : null;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return null;
|
|
168
|
+
return subpath === '.' ? tryResolveTarget(resolveCondition(exports), packageDir) : null;
|
|
151
169
|
}
|
|
152
170
|
|
|
153
171
|
if (typeof exports !== 'object') return null;
|
|
154
172
|
|
|
155
|
-
// Determine if exports is a conditions object
|
|
156
|
-
// or a subpath map (keys start with ".")
|
|
173
|
+
// Determine if exports is a conditions object or a subpath map
|
|
157
174
|
const keys = Object.keys(exports);
|
|
158
175
|
const isSubpathMap = keys.length > 0 && keys.some((k) => k.startsWith('.'));
|
|
159
176
|
|
|
160
177
|
if (!isSubpathMap) {
|
|
161
|
-
|
|
162
|
-
if (subpath === '.') {
|
|
163
|
-
const target = resolveCondition(exports);
|
|
164
|
-
if (target) {
|
|
165
|
-
const resolved = path.resolve(packageDir, target);
|
|
166
|
-
return fs.existsSync(resolved) ? resolved : null;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return null;
|
|
178
|
+
return subpath === '.' ? tryResolveTarget(resolveCondition(exports), packageDir) : null;
|
|
170
179
|
}
|
|
171
180
|
|
|
172
|
-
|
|
173
|
-
if (subpath in exports) {
|
|
174
|
-
const target = resolveCondition(exports[subpath]);
|
|
175
|
-
if (target) {
|
|
176
|
-
const resolved = path.resolve(packageDir, target);
|
|
177
|
-
return fs.existsSync(resolved) ? resolved : null;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Pattern matching (keys with *)
|
|
182
|
-
for (const [pattern, value] of Object.entries(exports)) {
|
|
183
|
-
if (!pattern.includes('*')) continue;
|
|
184
|
-
const matched = matchSubpathPattern(pattern, subpath);
|
|
185
|
-
if (matched == null) continue;
|
|
186
|
-
const rawTarget = resolveCondition(value);
|
|
187
|
-
if (!rawTarget) continue;
|
|
188
|
-
const target = rawTarget.replace(/\*/g, matched);
|
|
189
|
-
const resolved = path.resolve(packageDir, target);
|
|
190
|
-
if (fs.existsSync(resolved)) return resolved;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return null;
|
|
181
|
+
return resolveSubpathMap(exports as Record<string, unknown>, subpath, packageDir);
|
|
194
182
|
}
|
|
195
183
|
|
|
196
184
|
/** Clear the exports cache (for testing). */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { closeDb, getNodeId as getNodeIdQuery, initSchema, openDb } from '../../db/index.js';
|
|
4
|
-
import { info } from '../../infrastructure/logger.js';
|
|
4
|
+
import { debug, info } from '../../infrastructure/logger.js';
|
|
5
5
|
import { EXTENSIONS, IGNORE_DIRS, normalizePath } from '../../shared/constants.js';
|
|
6
6
|
import { DbError } from '../../shared/errors.js';
|
|
7
7
|
import { createParseTreeCache, getActiveEngine } from '../parser.js';
|
|
@@ -32,12 +32,10 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
32
32
|
ast: false,
|
|
33
33
|
};
|
|
34
34
|
const { name: engineName, version: engineVersion } = getActiveEngine(engineOpts);
|
|
35
|
-
|
|
36
|
-
`Watch mode using ${engineName} engine${engineVersion ? ` (v${engineVersion})` : ''}`,
|
|
37
|
-
);
|
|
35
|
+
info(`Watch mode using ${engineName} engine${engineVersion ? ` (v${engineVersion})` : ''}`);
|
|
38
36
|
|
|
39
37
|
const cache = createParseTreeCache();
|
|
40
|
-
|
|
38
|
+
info(
|
|
41
39
|
cache
|
|
42
40
|
? 'Incremental parsing enabled (native tree cache)'
|
|
43
41
|
: 'Incremental parsing unavailable (full re-parse)',
|
|
@@ -124,8 +122,8 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
124
122
|
}));
|
|
125
123
|
try {
|
|
126
124
|
appendJournalEntries(rootDir, entries);
|
|
127
|
-
} catch {
|
|
128
|
-
|
|
125
|
+
} catch (e: unknown) {
|
|
126
|
+
debug(`Journal write failed (non-fatal): ${(e as Error).message}`);
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
const changeEvents = updates.map((r) =>
|
|
@@ -137,8 +135,8 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
137
135
|
);
|
|
138
136
|
try {
|
|
139
137
|
appendChangeEvents(rootDir, changeEvents);
|
|
140
|
-
} catch {
|
|
141
|
-
|
|
138
|
+
} catch (e: unknown) {
|
|
139
|
+
debug(`Change event write failed (non-fatal): ${(e as Error).message}`);
|
|
142
140
|
}
|
|
143
141
|
}
|
|
144
142
|
|
|
@@ -153,8 +151,8 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
153
151
|
}
|
|
154
152
|
}
|
|
155
153
|
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
info(`Watching ${rootDir} for changes...`);
|
|
155
|
+
info('Press Ctrl+C to stop.');
|
|
158
156
|
|
|
159
157
|
const watcher = fs.watch(rootDir, { recursive: true }, (_eventType, filename) => {
|
|
160
158
|
if (!filename) return;
|
|
@@ -169,7 +167,7 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
169
167
|
});
|
|
170
168
|
|
|
171
169
|
process.on('SIGINT', () => {
|
|
172
|
-
|
|
170
|
+
info('Stopping watcher...');
|
|
173
171
|
watcher.close();
|
|
174
172
|
// Flush any pending file paths to journal before exit
|
|
175
173
|
if (pending.size > 0) {
|
|
@@ -178,8 +176,8 @@ export async function watchProject(rootDir: string, opts: { engine?: string } =
|
|
|
178
176
|
}));
|
|
179
177
|
try {
|
|
180
178
|
appendJournalEntries(rootDir, entries);
|
|
181
|
-
} catch {
|
|
182
|
-
|
|
179
|
+
} catch (e: unknown) {
|
|
180
|
+
debug(`Journal flush on exit failed (non-fatal): ${(e as Error).message}`);
|
|
183
181
|
}
|
|
184
182
|
}
|
|
185
183
|
if (cache) cache.clear();
|
package/src/domain/parser.ts
CHANGED
|
@@ -16,26 +16,38 @@ import type {
|
|
|
16
16
|
|
|
17
17
|
// Re-export all extractors for backward compatibility
|
|
18
18
|
export {
|
|
19
|
+
extractBashSymbols,
|
|
20
|
+
extractCppSymbols,
|
|
19
21
|
extractCSharpSymbols,
|
|
22
|
+
extractCSymbols,
|
|
20
23
|
extractGoSymbols,
|
|
21
24
|
extractHCLSymbols,
|
|
22
25
|
extractJavaSymbols,
|
|
26
|
+
extractKotlinSymbols,
|
|
23
27
|
extractPHPSymbols,
|
|
24
28
|
extractPythonSymbols,
|
|
25
29
|
extractRubySymbols,
|
|
26
30
|
extractRustSymbols,
|
|
31
|
+
extractScalaSymbols,
|
|
32
|
+
extractSwiftSymbols,
|
|
27
33
|
extractSymbols,
|
|
28
34
|
} from '../extractors/index.js';
|
|
29
35
|
|
|
30
36
|
import {
|
|
37
|
+
extractBashSymbols,
|
|
38
|
+
extractCppSymbols,
|
|
31
39
|
extractCSharpSymbols,
|
|
40
|
+
extractCSymbols,
|
|
32
41
|
extractGoSymbols,
|
|
33
42
|
extractHCLSymbols,
|
|
34
43
|
extractJavaSymbols,
|
|
44
|
+
extractKotlinSymbols,
|
|
35
45
|
extractPHPSymbols,
|
|
36
46
|
extractPythonSymbols,
|
|
37
47
|
extractRubySymbols,
|
|
38
48
|
extractRustSymbols,
|
|
49
|
+
extractScalaSymbols,
|
|
50
|
+
extractSwiftSymbols,
|
|
39
51
|
extractSymbols,
|
|
40
52
|
} from '../extractors/index.js';
|
|
41
53
|
|
|
@@ -273,37 +285,38 @@ function resolveEngine(opts: ParseEngineOpts = {}): ResolvedEngine {
|
|
|
273
285
|
* - Backward compat for older native binaries missing js_name annotations
|
|
274
286
|
* - dataflow argFlows/mutations bindingType -> binding wrapper
|
|
275
287
|
*/
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// Backward compat for older binaries missing js_name annotations
|
|
282
|
-
if (r.definitions) {
|
|
283
|
-
for (const d of r.definitions) {
|
|
284
|
-
if (d.endLine === undefined && d.end_line !== undefined) {
|
|
285
|
-
d.endLine = d.end_line;
|
|
286
|
-
}
|
|
288
|
+
/** Patch definition fields for backward compat with older native binaries. */
|
|
289
|
+
function patchDefinitions(definitions: any[]): void {
|
|
290
|
+
for (const d of definitions) {
|
|
291
|
+
if (d.endLine === undefined && d.end_line !== undefined) {
|
|
292
|
+
d.endLine = d.end_line;
|
|
287
293
|
}
|
|
288
294
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Patch import fields for backward compat with older native binaries. */
|
|
298
|
+
function patchImports(imports: any[]): void {
|
|
299
|
+
for (const i of imports) {
|
|
300
|
+
if (i.typeOnly === undefined) i.typeOnly = i.type_only;
|
|
301
|
+
if (i.wildcardReexport === undefined) i.wildcardReexport = i.wildcard_reexport;
|
|
302
|
+
if (i.pythonImport === undefined) i.pythonImport = i.python_import;
|
|
303
|
+
if (i.goImport === undefined) i.goImport = i.go_import;
|
|
304
|
+
if (i.rustUse === undefined) i.rustUse = i.rust_use;
|
|
305
|
+
if (i.javaImport === undefined) i.javaImport = i.java_import;
|
|
306
|
+
if (i.csharpUsing === undefined) i.csharpUsing = i.csharp_using;
|
|
307
|
+
if (i.rubyRequire === undefined) i.rubyRequire = i.ruby_require;
|
|
308
|
+
if (i.phpUse === undefined) i.phpUse = i.php_use;
|
|
309
|
+
if (i.cInclude === undefined) i.cInclude = i.c_include;
|
|
310
|
+
if (i.kotlinImport === undefined) i.kotlinImport = i.kotlin_import;
|
|
311
|
+
if (i.swiftImport === undefined) i.swiftImport = i.swift_import;
|
|
312
|
+
if (i.scalaImport === undefined) i.scalaImport = i.scala_import;
|
|
313
|
+
if (i.bashSource === undefined) i.bashSource = i.bash_source;
|
|
314
|
+
if (i.dynamicImport === undefined) i.dynamicImport = i.dynamic_import;
|
|
302
315
|
}
|
|
316
|
+
}
|
|
303
317
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
// callers can safely access .entries()/.size without null checks.
|
|
318
|
+
/** Normalize native typeMap array to a Map instance. */
|
|
319
|
+
function patchTypeMap(r: any): void {
|
|
307
320
|
if (!r.typeMap) {
|
|
308
321
|
r.typeMap = new Map();
|
|
309
322
|
} else if (!(r.typeMap instanceof Map)) {
|
|
@@ -314,20 +327,31 @@ function patchNativeResult(r: any): ExtractorOutput {
|
|
|
314
327
|
]),
|
|
315
328
|
);
|
|
316
329
|
}
|
|
330
|
+
}
|
|
317
331
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
332
|
+
/** Wrap bindingType into binding object for dataflow argFlows and mutations. */
|
|
333
|
+
function patchDataflow(dataflow: any): void {
|
|
334
|
+
if (dataflow.argFlows) {
|
|
335
|
+
for (const f of dataflow.argFlows) {
|
|
336
|
+
f.binding = f.bindingType ? { type: f.bindingType } : null;
|
|
324
337
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
338
|
+
}
|
|
339
|
+
if (dataflow.mutations) {
|
|
340
|
+
for (const m of dataflow.mutations) {
|
|
341
|
+
m.binding = m.bindingType ? { type: m.bindingType } : null;
|
|
329
342
|
}
|
|
330
343
|
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function patchNativeResult(r: any): ExtractorOutput {
|
|
347
|
+
// lineCount: napi(js_name) emits "lineCount"; older binaries may emit "line_count"
|
|
348
|
+
r.lineCount = r.lineCount ?? r.line_count ?? null;
|
|
349
|
+
r._lineCount = r.lineCount;
|
|
350
|
+
|
|
351
|
+
if (r.definitions) patchDefinitions(r.definitions);
|
|
352
|
+
if (r.imports) patchImports(r.imports);
|
|
353
|
+
patchTypeMap(r);
|
|
354
|
+
if (r.dataflow) patchDataflow(r.dataflow);
|
|
331
355
|
|
|
332
356
|
return r;
|
|
333
357
|
}
|
|
@@ -414,6 +438,48 @@ export const LANGUAGE_REGISTRY: LanguageRegistryEntry[] = [
|
|
|
414
438
|
extractor: extractPHPSymbols,
|
|
415
439
|
required: false,
|
|
416
440
|
},
|
|
441
|
+
{
|
|
442
|
+
id: 'c',
|
|
443
|
+
extensions: ['.c', '.h'],
|
|
444
|
+
grammarFile: 'tree-sitter-c.wasm',
|
|
445
|
+
extractor: extractCSymbols,
|
|
446
|
+
required: false,
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
id: 'cpp',
|
|
450
|
+
extensions: ['.cpp', '.cc', '.cxx', '.hpp'],
|
|
451
|
+
grammarFile: 'tree-sitter-cpp.wasm',
|
|
452
|
+
extractor: extractCppSymbols,
|
|
453
|
+
required: false,
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: 'kotlin',
|
|
457
|
+
extensions: ['.kt', '.kts'],
|
|
458
|
+
grammarFile: 'tree-sitter-kotlin.wasm',
|
|
459
|
+
extractor: extractKotlinSymbols,
|
|
460
|
+
required: false,
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: 'swift',
|
|
464
|
+
extensions: ['.swift'],
|
|
465
|
+
grammarFile: 'tree-sitter-swift.wasm',
|
|
466
|
+
extractor: extractSwiftSymbols,
|
|
467
|
+
required: false,
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
id: 'scala',
|
|
471
|
+
extensions: ['.scala'],
|
|
472
|
+
grammarFile: 'tree-sitter-scala.wasm',
|
|
473
|
+
extractor: extractScalaSymbols,
|
|
474
|
+
required: false,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
id: 'bash',
|
|
478
|
+
extensions: ['.sh', '.bash'],
|
|
479
|
+
grammarFile: 'tree-sitter-bash.wasm',
|
|
480
|
+
extractor: extractBashSymbols,
|
|
481
|
+
required: false,
|
|
482
|
+
},
|
|
417
483
|
];
|
|
418
484
|
|
|
419
485
|
const _extToLang: Map<string, LanguageRegistryEntry> = new Map();
|
|
@@ -522,73 +588,48 @@ export async function parseFileAuto(
|
|
|
522
588
|
return extracted ? extracted.symbols : null;
|
|
523
589
|
}
|
|
524
590
|
|
|
525
|
-
/**
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
)
|
|
533
|
-
|
|
534
|
-
const result = new Map<string, ExtractorOutput>();
|
|
591
|
+
/** Backfill typeMap via WASM for files missing type-map data from native engine. */
|
|
592
|
+
async function backfillTypeMapBatch(
|
|
593
|
+
needsTypeMap: { filePath: string; relPath: string }[],
|
|
594
|
+
result: Map<string, ExtractorOutput>,
|
|
595
|
+
): Promise<void> {
|
|
596
|
+
const tsFiles = needsTypeMap.filter(({ filePath }) =>
|
|
597
|
+
TS_BACKFILL_EXTS.has(path.extname(filePath)),
|
|
598
|
+
);
|
|
599
|
+
if (tsFiles.length === 0) return;
|
|
535
600
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const relPath = path.relative(rootDir, r.file).split(path.sep).join('/');
|
|
548
|
-
result.set(relPath, patched);
|
|
549
|
-
if (patched.typeMap.size === 0) {
|
|
550
|
-
needsTypeMap.push({ filePath: r.file, relPath });
|
|
601
|
+
const parsers = await createParsers();
|
|
602
|
+
for (const { filePath, relPath } of tsFiles) {
|
|
603
|
+
let extracted: WasmExtractResult | null | undefined;
|
|
604
|
+
try {
|
|
605
|
+
const code = fs.readFileSync(filePath, 'utf-8');
|
|
606
|
+
extracted = wasmExtractSymbols(parsers, filePath, code);
|
|
607
|
+
if (extracted?.symbols && extracted.symbols.typeMap.size > 0) {
|
|
608
|
+
const symbols = result.get(relPath);
|
|
609
|
+
if (!symbols) continue;
|
|
610
|
+
symbols.typeMap = extracted.symbols.typeMap;
|
|
611
|
+
symbols._typeMapBackfilled = true;
|
|
551
612
|
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if (tsFiles.length > 0) {
|
|
561
|
-
const parsers = await createParsers();
|
|
562
|
-
for (const { filePath, relPath } of tsFiles) {
|
|
563
|
-
let extracted: WasmExtractResult | null | undefined;
|
|
564
|
-
try {
|
|
565
|
-
const code = fs.readFileSync(filePath, 'utf-8');
|
|
566
|
-
extracted = wasmExtractSymbols(parsers, filePath, code);
|
|
567
|
-
if (extracted?.symbols && extracted.symbols.typeMap.size > 0) {
|
|
568
|
-
const symbols = result.get(relPath);
|
|
569
|
-
if (!symbols) continue;
|
|
570
|
-
symbols.typeMap = extracted.symbols.typeMap;
|
|
571
|
-
symbols._typeMapBackfilled = true;
|
|
572
|
-
}
|
|
573
|
-
} catch (e) {
|
|
574
|
-
debug(`batchExtract: typeMap backfill failed: ${toErrorMessage(e)}`);
|
|
575
|
-
} finally {
|
|
576
|
-
// Free the WASM tree to prevent memory accumulation across repeated builds
|
|
577
|
-
if (extracted?.tree && typeof extracted.tree.delete === 'function') {
|
|
578
|
-
try {
|
|
579
|
-
extracted.tree.delete();
|
|
580
|
-
} catch (e) {
|
|
581
|
-
debug(`batchExtract: WASM tree cleanup failed: ${toErrorMessage(e)}`);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
613
|
+
} catch (e) {
|
|
614
|
+
debug(`batchExtract: typeMap backfill failed: ${toErrorMessage(e)}`);
|
|
615
|
+
} finally {
|
|
616
|
+
if (extracted?.tree && typeof extracted.tree.delete === 'function') {
|
|
617
|
+
try {
|
|
618
|
+
extracted.tree.delete();
|
|
619
|
+
} catch (e) {
|
|
620
|
+
debug(`batchExtract: WASM tree cleanup failed: ${toErrorMessage(e)}`);
|
|
585
621
|
}
|
|
586
622
|
}
|
|
587
623
|
}
|
|
588
|
-
return result;
|
|
589
624
|
}
|
|
625
|
+
}
|
|
590
626
|
|
|
591
|
-
|
|
627
|
+
/** Parse files via WASM engine, returning a Map<relPath, symbols>. */
|
|
628
|
+
async function parseFilesWasm(
|
|
629
|
+
filePaths: string[],
|
|
630
|
+
rootDir: string,
|
|
631
|
+
): Promise<Map<string, ExtractorOutput>> {
|
|
632
|
+
const result = new Map<string, ExtractorOutput>();
|
|
592
633
|
const parsers = await createParsers();
|
|
593
634
|
for (const filePath of filePaths) {
|
|
594
635
|
let code: string;
|
|
@@ -610,6 +651,36 @@ export async function parseFilesAuto(
|
|
|
610
651
|
return result;
|
|
611
652
|
}
|
|
612
653
|
|
|
654
|
+
/**
|
|
655
|
+
* Parse multiple files in bulk and return a Map<relPath, symbols>.
|
|
656
|
+
*/
|
|
657
|
+
export async function parseFilesAuto(
|
|
658
|
+
filePaths: string[],
|
|
659
|
+
rootDir: string,
|
|
660
|
+
opts: ParseEngineOpts = {},
|
|
661
|
+
): Promise<Map<string, ExtractorOutput>> {
|
|
662
|
+
const { native } = resolveEngine(opts);
|
|
663
|
+
|
|
664
|
+
if (!native) return parseFilesWasm(filePaths, rootDir);
|
|
665
|
+
|
|
666
|
+
const result = new Map<string, ExtractorOutput>();
|
|
667
|
+
const nativeResults = native.parseFiles(filePaths, rootDir, !!opts.dataflow, opts.ast !== false);
|
|
668
|
+
const needsTypeMap: { filePath: string; relPath: string }[] = [];
|
|
669
|
+
for (const r of nativeResults) {
|
|
670
|
+
if (!r) continue;
|
|
671
|
+
const patched = patchNativeResult(r);
|
|
672
|
+
const relPath = path.relative(rootDir, r.file).split(path.sep).join('/');
|
|
673
|
+
result.set(relPath, patched);
|
|
674
|
+
if (patched.typeMap.size === 0) {
|
|
675
|
+
needsTypeMap.push({ filePath: r.file, relPath });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (needsTypeMap.length > 0) {
|
|
679
|
+
await backfillTypeMapBatch(needsTypeMap, result);
|
|
680
|
+
}
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
|
|
613
684
|
/**
|
|
614
685
|
* Report which engine is active.
|
|
615
686
|
*/
|