Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. See [commit

## [3.0.3](https://github.com/optave/codegraph/compare/v3.0.2...v3.0.3) (2026-03-04)

> **Note:** 3.0.2 was an internal/unpublished version used during development.

### Performance

* **ast:** use single transaction for AST node insertion — astMs drops from ~3600ms to ~350ms (native) and ~547ms (WASM), reducing overall native build from 24.9 to 8.5 ms/file ([#333](https://github.com/optave/codegraph/pull/333))
* **builder:** skip `ensureWasmTrees` when native engine provides complete CFG + dataflow data ([#344](https://github.com/optave/codegraph/pull/344))

### Bug Fixes

* **native:** fix function-scoped `const` declarations being incorrectly extracted as top-level constants ([#344](https://github.com/optave/codegraph/pull/344))

## [3.0.2](https://github.com/optave/codegraph/compare/v3.0.1...v3.0.2) (2026-03-04)

Expand Down
47 changes: 39 additions & 8 deletions src/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1317,16 +1317,47 @@ export async function buildGraph(rootDir, opts = {}) {
_t.complexityMs = performance.now() - _t.complexity0;

// Pre-parse files missing WASM trees (native builds) so CFG + dataflow
// share a single parse pass instead of each creating parsers independently
// share a single parse pass instead of each creating parsers independently.
// Skip entirely when native engine already provides CFG + dataflow data.
if (opts.cfg !== false || opts.dataflow !== false) {
_t.wasmPre0 = performance.now();
try {
const { ensureWasmTrees } = await import('./parser.js');
await ensureWasmTrees(astComplexitySymbols, rootDir);
} catch (err) {
debug(`WASM pre-parse failed: ${err.message}`);
const needsCfg = opts.cfg !== false;
const needsDataflow = opts.dataflow !== false;

let needsWasmTrees = false;
for (const [, symbols] of astComplexitySymbols) {
if (symbols._tree) continue; // already has a tree
// CFG: need tree if any function/method def lacks native CFG
if (needsCfg) {
const fnDefs = (symbols.definitions || []).filter(
(d) => (d.kind === 'function' || d.kind === 'method') && d.line,
);
if (
fnDefs.length > 0 &&
!fnDefs.every((d) => d.cfg === null || Array.isArray(d.cfg?.blocks))
) {
needsWasmTrees = true;
break;
}
}
// Dataflow: need tree if file lacks native dataflow
if (needsDataflow && !symbols.dataflow) {
needsWasmTrees = true;
break;
}
}

if (needsWasmTrees) {
_t.wasmPre0 = performance.now();
try {
const { ensureWasmTrees } = await import('./parser.js');
await ensureWasmTrees(astComplexitySymbols, rootDir);
} catch (err) {
debug(`WASM pre-parse failed: ${err.message}`);
}
_t.wasmPreMs = performance.now() - _t.wasmPre0;
} else {
_t.wasmPreMs = 0;
}
_t.wasmPreMs = performance.now() - _t.wasmPre0;
}

// CFG analysis (skip with --no-cfg)
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/build-parity.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ function readGraph(dbPath) {
// Exclude constant nodes — the native engine has a known scope bug where it
// extracts local `const` variables inside functions as top-level constants,
// while WASM correctly limits constant extraction to program-level declarations.
// TODO: Remove kind != 'constant' exclusion once native binary >= 3.0.4 ships
// Fix: crates/codegraph-core/src/extractors/javascript.rs (find_parent_of_types guard)
const nodes = db
.prepare(
"SELECT name, kind, file, line FROM nodes WHERE kind != 'constant' ORDER BY name, kind, file, line",
Expand Down