@optave/codegraph 3.1.1 → 3.1.3
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 +6 -6
- package/package.json +7 -7
- package/src/ast-analysis/engine.js +365 -0
- package/src/ast-analysis/metrics.js +118 -0
- package/src/ast-analysis/visitor-utils.js +176 -0
- package/src/ast-analysis/visitor.js +162 -0
- package/src/ast-analysis/visitors/ast-store-visitor.js +150 -0
- package/src/ast-analysis/visitors/cfg-visitor.js +792 -0
- package/src/ast-analysis/visitors/complexity-visitor.js +243 -0
- package/src/ast-analysis/visitors/dataflow-visitor.js +358 -0
- package/src/ast.js +13 -140
- package/src/audit.js +2 -87
- package/src/batch.js +0 -25
- package/src/boundaries.js +1 -1
- package/src/branch-compare.js +1 -96
- package/src/builder.js +60 -178
- package/src/cfg.js +89 -883
- package/src/check.js +1 -84
- package/src/cli.js +31 -22
- package/src/cochange.js +1 -39
- package/src/commands/audit.js +88 -0
- package/src/commands/batch.js +26 -0
- package/src/commands/branch-compare.js +97 -0
- package/src/commands/cfg.js +55 -0
- package/src/commands/check.js +82 -0
- package/src/commands/cochange.js +37 -0
- package/src/commands/communities.js +69 -0
- package/src/commands/complexity.js +77 -0
- package/src/commands/dataflow.js +110 -0
- package/src/commands/flow.js +70 -0
- package/src/commands/manifesto.js +77 -0
- package/src/commands/owners.js +52 -0
- package/src/commands/query.js +21 -0
- package/src/commands/sequence.js +33 -0
- package/src/commands/structure.js +64 -0
- package/src/commands/triage.js +49 -0
- package/src/communities.js +12 -83
- package/src/complexity.js +43 -357
- package/src/cycles.js +1 -1
- package/src/dataflow.js +12 -665
- package/src/db/repository/build-stmts.js +104 -0
- package/src/db/repository/cached-stmt.js +19 -0
- package/src/db/repository/cfg.js +72 -0
- package/src/db/repository/cochange.js +54 -0
- package/src/db/repository/complexity.js +20 -0
- package/src/db/repository/dataflow.js +17 -0
- package/src/db/repository/edges.js +281 -0
- package/src/db/repository/embeddings.js +51 -0
- package/src/db/repository/graph-read.js +59 -0
- package/src/db/repository/index.js +43 -0
- package/src/db/repository/nodes.js +247 -0
- package/src/db.js +40 -1
- package/src/embedder.js +14 -34
- package/src/export.js +1 -1
- package/src/extractors/javascript.js +130 -5
- package/src/flow.js +2 -70
- package/src/index.js +30 -20
- package/src/{result-formatter.js → infrastructure/result-formatter.js} +1 -1
- package/src/kinds.js +1 -0
- package/src/manifesto.js +0 -76
- package/src/native.js +31 -9
- package/src/owners.js +1 -56
- package/src/parser.js +53 -2
- package/src/queries-cli.js +1 -1
- package/src/queries.js +79 -280
- package/src/sequence.js +5 -44
- package/src/structure.js +16 -75
- package/src/triage.js +1 -54
- package/src/viewer.js +1 -1
- package/src/watcher.js +7 -4
- package/src/db/repository.js +0 -134
- /package/src/{test-filter.js → infrastructure/test-filter.js} +0 -0
package/src/index.js
CHANGED
|
@@ -8,13 +8,11 @@
|
|
|
8
8
|
// AST node queries
|
|
9
9
|
export { AST_NODE_KINDS, astQuery, astQueryData } from './ast.js';
|
|
10
10
|
// Audit (composite report)
|
|
11
|
-
export {
|
|
11
|
+
export { auditData } from './audit.js';
|
|
12
12
|
// Batch querying
|
|
13
13
|
export {
|
|
14
14
|
BATCH_COMMANDS,
|
|
15
|
-
batch,
|
|
16
15
|
batchData,
|
|
17
|
-
batchQuery,
|
|
18
16
|
multiBatchData,
|
|
19
17
|
splitTargets,
|
|
20
18
|
} from './batch.js';
|
|
@@ -29,13 +27,12 @@ export {
|
|
|
29
27
|
buildCFGData,
|
|
30
28
|
buildFunctionCFG,
|
|
31
29
|
CFG_RULES,
|
|
32
|
-
cfg,
|
|
33
30
|
cfgData,
|
|
34
31
|
cfgToDOT,
|
|
35
32
|
cfgToMermaid,
|
|
36
33
|
} from './cfg.js';
|
|
37
34
|
// Check (CI validation predicates)
|
|
38
|
-
export {
|
|
35
|
+
export { checkData } from './check.js';
|
|
39
36
|
// Co-change analysis
|
|
40
37
|
export {
|
|
41
38
|
analyzeCoChanges,
|
|
@@ -45,12 +42,23 @@ export {
|
|
|
45
42
|
computeCoChanges,
|
|
46
43
|
scanGitHistory,
|
|
47
44
|
} from './cochange.js';
|
|
45
|
+
export { audit } from './commands/audit.js';
|
|
46
|
+
export { batch, batchQuery } from './commands/batch.js';
|
|
47
|
+
export { cfg } from './commands/cfg.js';
|
|
48
|
+
export { check } from './commands/check.js';
|
|
49
|
+
export { communities } from './commands/communities.js';
|
|
50
|
+
export { complexity } from './commands/complexity.js';
|
|
51
|
+
export { dataflow } from './commands/dataflow.js';
|
|
52
|
+
export { manifesto } from './commands/manifesto.js';
|
|
53
|
+
export { owners } from './commands/owners.js';
|
|
54
|
+
export { sequence } from './commands/sequence.js';
|
|
55
|
+
export { formatHotspots, formatModuleBoundaries, formatStructure } from './commands/structure.js';
|
|
56
|
+
export { triage } from './commands/triage.js';
|
|
48
57
|
// Community detection
|
|
49
|
-
export {
|
|
58
|
+
export { communitiesData, communitySummaryForStats } from './communities.js';
|
|
50
59
|
// Complexity metrics
|
|
51
60
|
export {
|
|
52
61
|
COMPLEXITY_RULES,
|
|
53
|
-
complexity,
|
|
54
62
|
complexityData,
|
|
55
63
|
computeFunctionComplexity,
|
|
56
64
|
computeHalsteadMetrics,
|
|
@@ -69,7 +77,6 @@ export { findCycles, formatCycles } from './cycles.js';
|
|
|
69
77
|
// Dataflow analysis
|
|
70
78
|
export {
|
|
71
79
|
buildDataflowEdges,
|
|
72
|
-
dataflow,
|
|
73
80
|
dataflowData,
|
|
74
81
|
dataflowImpactData,
|
|
75
82
|
dataflowPathData,
|
|
@@ -123,18 +130,28 @@ export {
|
|
|
123
130
|
} from './export.js';
|
|
124
131
|
// Execution flow tracing
|
|
125
132
|
export { entryPointType, flowData, listEntryPointsData } from './flow.js';
|
|
133
|
+
// Result formatting
|
|
134
|
+
export { outputResult } from './infrastructure/result-formatter.js';
|
|
135
|
+
// Test file detection
|
|
136
|
+
export { isTestFile, TEST_PATTERN } from './infrastructure/test-filter.js';
|
|
126
137
|
// Logger
|
|
127
138
|
export { setVerbose } from './logger.js';
|
|
128
139
|
// Manifesto rule engine
|
|
129
|
-
export {
|
|
140
|
+
export { manifestoData, RULE_DEFS } from './manifesto.js';
|
|
130
141
|
// Native engine
|
|
131
142
|
export { isNativeAvailable } from './native.js';
|
|
132
143
|
// Ownership (CODEOWNERS)
|
|
133
|
-
export { matchOwners,
|
|
144
|
+
export { matchOwners, ownersData, ownersForFiles, parseCodeowners } from './owners.js';
|
|
134
145
|
// Pagination utilities
|
|
135
146
|
export { MCP_DEFAULTS, MCP_MAX_LIMIT, paginate, paginateResult, printNdjson } from './paginate.js';
|
|
136
147
|
// Unified parser API
|
|
137
|
-
export {
|
|
148
|
+
export {
|
|
149
|
+
disposeParsers,
|
|
150
|
+
getActiveEngine,
|
|
151
|
+
isWasmAvailable,
|
|
152
|
+
parseFileAuto,
|
|
153
|
+
parseFilesAuto,
|
|
154
|
+
} from './parser.js';
|
|
138
155
|
// Query functions (data-returning)
|
|
139
156
|
export {
|
|
140
157
|
ALL_SYMBOL_KINDS,
|
|
@@ -198,10 +215,8 @@ export {
|
|
|
198
215
|
saveRegistry,
|
|
199
216
|
unregisterRepo,
|
|
200
217
|
} from './registry.js';
|
|
201
|
-
// Result formatting
|
|
202
|
-
export { outputResult } from './result-formatter.js';
|
|
203
218
|
// Sequence diagram generation
|
|
204
|
-
export {
|
|
219
|
+
export { sequenceData, sequenceToMermaid } from './sequence.js';
|
|
205
220
|
// Snapshot management
|
|
206
221
|
export {
|
|
207
222
|
snapshotDelete,
|
|
@@ -216,17 +231,12 @@ export {
|
|
|
216
231
|
buildStructure,
|
|
217
232
|
classifyNodeRoles,
|
|
218
233
|
FRAMEWORK_ENTRY_PREFIXES,
|
|
219
|
-
formatHotspots,
|
|
220
|
-
formatModuleBoundaries,
|
|
221
|
-
formatStructure,
|
|
222
234
|
hotspotsData,
|
|
223
235
|
moduleBoundariesData,
|
|
224
236
|
structureData,
|
|
225
237
|
} from './structure.js';
|
|
226
|
-
// Test file detection
|
|
227
|
-
export { isTestFile, TEST_PATTERN } from './test-filter.js';
|
|
228
238
|
// Triage — composite risk audit
|
|
229
|
-
export {
|
|
239
|
+
export { triageData } from './triage.js';
|
|
230
240
|
// Interactive HTML viewer
|
|
231
241
|
export { generatePlotHTML, loadPlotConfig } from './viewer.js';
|
|
232
242
|
// Watch mode
|
package/src/kinds.js
CHANGED
package/src/manifesto.js
CHANGED
|
@@ -4,7 +4,6 @@ import { findCycles } from './cycles.js';
|
|
|
4
4
|
import { openReadonlyOrFail } from './db.js';
|
|
5
5
|
import { debug } from './logger.js';
|
|
6
6
|
import { paginateResult } from './paginate.js';
|
|
7
|
-
import { outputResult } from './result-formatter.js';
|
|
8
7
|
|
|
9
8
|
// ─── Rule Definitions ─────────────────────────────────────────────────
|
|
10
9
|
|
|
@@ -428,78 +427,3 @@ export function manifestoData(customDbPath, opts = {}) {
|
|
|
428
427
|
db.close();
|
|
429
428
|
}
|
|
430
429
|
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* CLI formatter — prints manifesto results and exits with code 1 on failure.
|
|
434
|
-
*/
|
|
435
|
-
export function manifesto(customDbPath, opts = {}) {
|
|
436
|
-
const data = manifestoData(customDbPath, opts);
|
|
437
|
-
|
|
438
|
-
if (outputResult(data, 'violations', opts)) {
|
|
439
|
-
if (!data.passed) process.exit(1);
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
console.log('\n# Manifesto Rules\n');
|
|
444
|
-
|
|
445
|
-
// Rules table
|
|
446
|
-
console.log(
|
|
447
|
-
` ${'Rule'.padEnd(20)} ${'Level'.padEnd(10)} ${'Status'.padEnd(8)} ${'Warn'.padStart(6)} ${'Fail'.padStart(6)} ${'Violations'.padStart(11)}`,
|
|
448
|
-
);
|
|
449
|
-
console.log(
|
|
450
|
-
` ${'─'.repeat(20)} ${'─'.repeat(10)} ${'─'.repeat(8)} ${'─'.repeat(6)} ${'─'.repeat(6)} ${'─'.repeat(11)}`,
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
for (const rule of data.rules) {
|
|
454
|
-
const warn = rule.thresholds.warn != null ? String(rule.thresholds.warn) : '—';
|
|
455
|
-
const fail = rule.thresholds.fail != null ? String(rule.thresholds.fail) : '—';
|
|
456
|
-
const statusIcon = rule.status === 'pass' ? 'pass' : rule.status === 'warn' ? 'WARN' : 'FAIL';
|
|
457
|
-
console.log(
|
|
458
|
-
` ${rule.name.padEnd(20)} ${rule.level.padEnd(10)} ${statusIcon.padEnd(8)} ${warn.padStart(6)} ${fail.padStart(6)} ${String(rule.violationCount).padStart(11)}`,
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Summary
|
|
463
|
-
const s = data.summary;
|
|
464
|
-
console.log(
|
|
465
|
-
`\n ${s.total} rules | ${s.passed} passed | ${s.warned} warned | ${s.failed} failed | ${s.violationCount} violations`,
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
// Violations detail
|
|
469
|
-
if (data.violations.length > 0) {
|
|
470
|
-
const failViolations = data.violations.filter((v) => v.level === 'fail');
|
|
471
|
-
const warnViolations = data.violations.filter((v) => v.level === 'warn');
|
|
472
|
-
|
|
473
|
-
if (failViolations.length > 0) {
|
|
474
|
-
console.log(`\n## Failures (${failViolations.length})\n`);
|
|
475
|
-
for (const v of failViolations.slice(0, 20)) {
|
|
476
|
-
const loc = v.line ? `${v.file}:${v.line}` : v.file;
|
|
477
|
-
console.log(
|
|
478
|
-
` [FAIL] ${v.rule}: ${v.name} (${v.value}) at ${loc} — threshold ${v.threshold}`,
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
if (failViolations.length > 20) {
|
|
482
|
-
console.log(` ... and ${failViolations.length - 20} more`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (warnViolations.length > 0) {
|
|
487
|
-
console.log(`\n## Warnings (${warnViolations.length})\n`);
|
|
488
|
-
for (const v of warnViolations.slice(0, 20)) {
|
|
489
|
-
const loc = v.line ? `${v.file}:${v.line}` : v.file;
|
|
490
|
-
console.log(
|
|
491
|
-
` [WARN] ${v.rule}: ${v.name} (${v.value}) at ${loc} — threshold ${v.threshold}`,
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
if (warnViolations.length > 20) {
|
|
495
|
-
console.log(` ... and ${warnViolations.length - 20} more`);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
console.log();
|
|
501
|
-
|
|
502
|
-
if (!data.passed) {
|
|
503
|
-
process.exit(1);
|
|
504
|
-
}
|
|
505
|
-
}
|
package/src/native.js
CHANGED
|
@@ -11,6 +11,7 @@ import os from 'node:os';
|
|
|
11
11
|
|
|
12
12
|
let _cached; // undefined = not yet tried, null = failed, object = module
|
|
13
13
|
let _loadError = null;
|
|
14
|
+
const _require = createRequire(import.meta.url);
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Detect whether the current Linux environment uses glibc or musl.
|
|
@@ -18,7 +19,7 @@ let _loadError = null;
|
|
|
18
19
|
*/
|
|
19
20
|
function detectLibc() {
|
|
20
21
|
try {
|
|
21
|
-
const { readdirSync } =
|
|
22
|
+
const { readdirSync } = _require('node:fs');
|
|
22
23
|
const files = readdirSync('/lib');
|
|
23
24
|
if (files.some((f) => f.startsWith('ld-musl-') && f.endsWith('.so.1'))) {
|
|
24
25
|
return 'musl';
|
|
@@ -38,6 +39,17 @@ const PLATFORM_PACKAGES = {
|
|
|
38
39
|
'win32-x64': '@optave/codegraph-win32-x64-msvc',
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the platform-specific npm package name for the native addon.
|
|
44
|
+
* Returns null if the current platform is not supported.
|
|
45
|
+
*/
|
|
46
|
+
function resolvePlatformPackage() {
|
|
47
|
+
const platform = os.platform();
|
|
48
|
+
const arch = os.arch();
|
|
49
|
+
const key = platform === 'linux' ? `${platform}-${arch}-${detectLibc()}` : `${platform}-${arch}`;
|
|
50
|
+
return PLATFORM_PACKAGES[key] || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
/**
|
|
42
54
|
* Try to load the native napi addon.
|
|
43
55
|
* Returns the module on success, null on failure.
|
|
@@ -45,21 +57,16 @@ const PLATFORM_PACKAGES = {
|
|
|
45
57
|
export function loadNative() {
|
|
46
58
|
if (_cached !== undefined) return _cached;
|
|
47
59
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const platform = os.platform();
|
|
51
|
-
const arch = os.arch();
|
|
52
|
-
const key = platform === 'linux' ? `${platform}-${arch}-${detectLibc()}` : `${platform}-${arch}`;
|
|
53
|
-
const pkg = PLATFORM_PACKAGES[key];
|
|
60
|
+
const pkg = resolvePlatformPackage();
|
|
54
61
|
if (pkg) {
|
|
55
62
|
try {
|
|
56
|
-
_cached =
|
|
63
|
+
_cached = _require(pkg);
|
|
57
64
|
return _cached;
|
|
58
65
|
} catch (err) {
|
|
59
66
|
_loadError = err;
|
|
60
67
|
}
|
|
61
68
|
} else {
|
|
62
|
-
_loadError = new Error(`Unsupported platform: ${
|
|
69
|
+
_loadError = new Error(`Unsupported platform: ${os.platform()}-${os.arch()}`);
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
_cached = null;
|
|
@@ -73,6 +80,21 @@ export function isNativeAvailable() {
|
|
|
73
80
|
return loadNative() !== null;
|
|
74
81
|
}
|
|
75
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Read the version from the platform-specific npm package.json.
|
|
85
|
+
* Returns null if the package is not installed or has no version.
|
|
86
|
+
*/
|
|
87
|
+
export function getNativePackageVersion() {
|
|
88
|
+
const pkg = resolvePlatformPackage();
|
|
89
|
+
if (!pkg) return null;
|
|
90
|
+
try {
|
|
91
|
+
const pkgJson = _require(`${pkg}/package.json`);
|
|
92
|
+
return pkgJson.version || null;
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
76
98
|
/**
|
|
77
99
|
* Return the native module or throw if not available.
|
|
78
100
|
*/
|
package/src/owners.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { findDbPath, openReadonlyOrFail } from './db.js';
|
|
4
|
-
import {
|
|
5
|
-
import { isTestFile } from './test-filter.js';
|
|
4
|
+
import { isTestFile } from './infrastructure/test-filter.js';
|
|
6
5
|
|
|
7
6
|
// ─── CODEOWNERS Parsing ──────────────────────────────────────────────
|
|
8
7
|
|
|
@@ -303,57 +302,3 @@ export function ownersData(customDbPath, opts = {}) {
|
|
|
303
302
|
db.close();
|
|
304
303
|
}
|
|
305
304
|
}
|
|
306
|
-
|
|
307
|
-
// ─── CLI Display ─────────────────────────────────────────────────────
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* CLI display function for the `owners` command.
|
|
311
|
-
* @param {string} [customDbPath]
|
|
312
|
-
* @param {object} [opts]
|
|
313
|
-
*/
|
|
314
|
-
export function owners(customDbPath, opts = {}) {
|
|
315
|
-
const data = ownersData(customDbPath, opts);
|
|
316
|
-
if (outputResult(data, null, opts)) return;
|
|
317
|
-
|
|
318
|
-
if (!data.codeownersFile) {
|
|
319
|
-
console.log('No CODEOWNERS file found.');
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
console.log(`\nCODEOWNERS: ${data.codeownersFile}\n`);
|
|
324
|
-
|
|
325
|
-
const s = data.summary;
|
|
326
|
-
console.log(
|
|
327
|
-
` Coverage: ${s.coveragePercent}% (${s.ownedFiles}/${s.totalFiles} files owned, ${s.ownerCount} owners)\n`,
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
if (s.byOwner.length > 0) {
|
|
331
|
-
console.log(' Owners:\n');
|
|
332
|
-
for (const o of s.byOwner) {
|
|
333
|
-
console.log(` ${o.owner} ${o.fileCount} files`);
|
|
334
|
-
}
|
|
335
|
-
console.log();
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (data.files.length > 0 && opts.owner) {
|
|
339
|
-
console.log(` Files owned by ${opts.owner}:\n`);
|
|
340
|
-
for (const f of data.files) {
|
|
341
|
-
console.log(` ${f.file}`);
|
|
342
|
-
}
|
|
343
|
-
console.log();
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (data.boundaries.length > 0) {
|
|
347
|
-
console.log(` Cross-owner boundaries: ${data.boundaries.length} edges\n`);
|
|
348
|
-
const shown = data.boundaries.slice(0, 30);
|
|
349
|
-
for (const b of shown) {
|
|
350
|
-
const srcOwner = b.from.owners.join(', ') || '(unowned)';
|
|
351
|
-
const tgtOwner = b.to.owners.join(', ') || '(unowned)';
|
|
352
|
-
console.log(` ${b.from.name} [${srcOwner}] -> ${b.to.name} [${tgtOwner}]`);
|
|
353
|
-
}
|
|
354
|
-
if (data.boundaries.length > 30) {
|
|
355
|
-
console.log(` ... and ${data.boundaries.length - 30} more`);
|
|
356
|
-
}
|
|
357
|
-
console.log();
|
|
358
|
-
}
|
|
359
|
-
}
|
package/src/parser.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { Language, Parser, Query } from 'web-tree-sitter';
|
|
5
5
|
import { warn } from './logger.js';
|
|
6
|
-
import { getNative, loadNative } from './native.js';
|
|
6
|
+
import { getNative, getNativePackageVersion, loadNative } from './native.js';
|
|
7
7
|
|
|
8
8
|
// Re-export all extractors for backward compatibility
|
|
9
9
|
export {
|
|
@@ -41,6 +41,9 @@ let _initialized = false;
|
|
|
41
41
|
// Memoized parsers — avoids reloading WASM grammars on every createParsers() call
|
|
42
42
|
let _cachedParsers = null;
|
|
43
43
|
|
|
44
|
+
// Cached Language objects — WASM-backed, must be .delete()'d explicitly
|
|
45
|
+
let _cachedLanguages = null;
|
|
46
|
+
|
|
44
47
|
// Query cache for JS/TS/TSX extractors (populated during createParsers)
|
|
45
48
|
const _queryCache = new Map();
|
|
46
49
|
|
|
@@ -77,12 +80,14 @@ export async function createParsers() {
|
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
const parsers = new Map();
|
|
83
|
+
const languages = new Map();
|
|
80
84
|
for (const entry of LANGUAGE_REGISTRY) {
|
|
81
85
|
try {
|
|
82
86
|
const lang = await Language.load(grammarPath(entry.grammarFile));
|
|
83
87
|
const parser = new Parser();
|
|
84
88
|
parser.setLanguage(lang);
|
|
85
89
|
parsers.set(entry.id, parser);
|
|
90
|
+
languages.set(entry.id, lang);
|
|
86
91
|
// Compile and cache tree-sitter Query for JS/TS/TSX extractors
|
|
87
92
|
if (entry.extractor === extractSymbols && !_queryCache.has(entry.id)) {
|
|
88
93
|
const isTS = entry.id === 'typescript' || entry.id === 'tsx';
|
|
@@ -100,9 +105,47 @@ export async function createParsers() {
|
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
_cachedParsers = parsers;
|
|
108
|
+
_cachedLanguages = languages;
|
|
103
109
|
return parsers;
|
|
104
110
|
}
|
|
105
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Dispose all cached WASM parsers and queries to free WASM linear memory.
|
|
114
|
+
* Call this between repeated builds in the same process (e.g. benchmarks)
|
|
115
|
+
* to prevent memory accumulation that can cause segfaults.
|
|
116
|
+
*/
|
|
117
|
+
export function disposeParsers() {
|
|
118
|
+
if (_cachedParsers) {
|
|
119
|
+
for (const [, parser] of _cachedParsers) {
|
|
120
|
+
if (parser && typeof parser.delete === 'function') {
|
|
121
|
+
try {
|
|
122
|
+
parser.delete();
|
|
123
|
+
} catch {}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
_cachedParsers = null;
|
|
127
|
+
}
|
|
128
|
+
for (const [, query] of _queryCache) {
|
|
129
|
+
if (query && typeof query.delete === 'function') {
|
|
130
|
+
try {
|
|
131
|
+
query.delete();
|
|
132
|
+
} catch {}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
_queryCache.clear();
|
|
136
|
+
if (_cachedLanguages) {
|
|
137
|
+
for (const [, lang] of _cachedLanguages) {
|
|
138
|
+
if (lang && typeof lang.delete === 'function') {
|
|
139
|
+
try {
|
|
140
|
+
lang.delete();
|
|
141
|
+
} catch {}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_cachedLanguages = null;
|
|
145
|
+
}
|
|
146
|
+
_initialized = false;
|
|
147
|
+
}
|
|
148
|
+
|
|
106
149
|
export function getParser(parsers, filePath) {
|
|
107
150
|
const ext = path.extname(filePath);
|
|
108
151
|
const entry = _extToLang.get(ext);
|
|
@@ -214,6 +257,7 @@ function patchNativeResult(r) {
|
|
|
214
257
|
if (i.csharpUsing === undefined) i.csharpUsing = i.csharp_using;
|
|
215
258
|
if (i.rubyRequire === undefined) i.rubyRequire = i.ruby_require;
|
|
216
259
|
if (i.phpUse === undefined) i.phpUse = i.php_use;
|
|
260
|
+
if (i.dynamicImport === undefined) i.dynamicImport = i.dynamic_import;
|
|
217
261
|
}
|
|
218
262
|
}
|
|
219
263
|
|
|
@@ -429,11 +473,18 @@ export async function parseFilesAuto(filePaths, rootDir, opts = {}) {
|
|
|
429
473
|
*/
|
|
430
474
|
export function getActiveEngine(opts = {}) {
|
|
431
475
|
const { name, native } = resolveEngine(opts);
|
|
432
|
-
|
|
476
|
+
let version = native
|
|
433
477
|
? typeof native.engineVersion === 'function'
|
|
434
478
|
? native.engineVersion()
|
|
435
479
|
: null
|
|
436
480
|
: null;
|
|
481
|
+
// Prefer platform package.json version over binary-embedded version
|
|
482
|
+
// to handle stale binaries that weren't recompiled during a release
|
|
483
|
+
if (native) {
|
|
484
|
+
try {
|
|
485
|
+
version = getNativePackageVersion() ?? version;
|
|
486
|
+
} catch {}
|
|
487
|
+
}
|
|
437
488
|
return { name, version };
|
|
438
489
|
}
|
|
439
490
|
|
package/src/queries-cli.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import path from 'node:path';
|
|
10
|
+
import { outputResult } from './infrastructure/result-formatter.js';
|
|
10
11
|
import {
|
|
11
12
|
childrenData,
|
|
12
13
|
contextData,
|
|
@@ -26,7 +27,6 @@ import {
|
|
|
26
27
|
statsData,
|
|
27
28
|
whereData,
|
|
28
29
|
} from './queries.js';
|
|
29
|
-
import { outputResult } from './result-formatter.js';
|
|
30
30
|
|
|
31
31
|
// ─── symbolPath ─────────────────────────────────────────────────────────
|
|
32
32
|
|