@optave/codegraph 3.9.1 → 3.9.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 +95 -14
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +64 -0
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +5 -17
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/structure.d.ts.map +1 -1
- package/dist/cli/commands/structure.js +18 -1
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/db/connection.d.ts +2 -0
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +2 -2
- 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/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +5 -15
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts +5 -5
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +6 -16
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +12 -0
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/diff-impact.js +20 -1
- package/dist/domain/analysis/diff-impact.js.map +1 -1
- package/dist/domain/analysis/fn-impact.js +2 -2
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/implementations.d.ts.map +1 -1
- package/dist/domain/analysis/implementations.js +3 -13
- package/dist/domain/analysis/implementations.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +4 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js +4 -0
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/native-db-proxy.d.ts +24 -0
- package/dist/domain/graph/builder/native-db-proxy.d.ts.map +1 -0
- package/dist/domain/graph/builder/native-db-proxy.js +91 -0
- package/dist/domain/graph/builder/native-db-proxy.js.map +1 -0
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +148 -79
- 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 +15 -2
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +2 -2
- package/dist/domain/graph/builder/stages/build-structure.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 +6 -28
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +1 -1
- 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 +16 -12
- 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 +2 -3
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +11 -4
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/queries.d.ts +1 -1
- package/dist/domain/queries.d.ts.map +1 -1
- package/dist/domain/queries.js +1 -1
- package/dist/domain/queries.js.map +1 -1
- package/dist/features/ast.js +2 -2
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +3 -2
- package/dist/features/audit.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +3 -5
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +2 -1
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +52 -6
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +7 -0
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/flow.d.ts.map +1 -1
- package/dist/features/flow.js +2 -1
- package/dist/features/flow.js.map +1 -1
- package/dist/features/manifesto.d.ts.map +1 -1
- package/dist/features/manifesto.js +15 -1
- package/dist/features/manifesto.js.map +1 -1
- package/dist/infrastructure/config.d.ts +1 -0
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +1 -0
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/update-check.d.ts +1 -1
- package/dist/infrastructure/update-check.js +3 -3
- package/dist/infrastructure/update-check.js.map +1 -1
- package/dist/presentation/batch.d.ts.map +1 -1
- package/dist/presentation/batch.js +1 -0
- package/dist/presentation/batch.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +1 -1
- package/dist/presentation/structure.js.map +1 -1
- package/dist/shared/normalize.d.ts +12 -0
- package/dist/shared/normalize.d.ts.map +1 -1
- package/dist/shared/normalize.js +4 -0
- package/dist/shared/normalize.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/ast-analysis/engine.ts +83 -0
- package/src/cli/commands/batch.ts +5 -26
- package/src/cli/commands/structure.ts +21 -1
- package/src/db/connection.ts +2 -2
- package/src/db/index.ts +2 -0
- package/src/domain/analysis/context.ts +5 -15
- package/src/domain/analysis/dependencies.ts +6 -16
- package/src/domain/analysis/diff-impact.ts +28 -1
- package/src/domain/analysis/fn-impact.ts +2 -2
- package/src/domain/analysis/implementations.ts +3 -13
- package/src/domain/graph/builder/context.ts +4 -0
- package/src/domain/graph/builder/native-db-proxy.ts +104 -0
- package/src/domain/graph/builder/pipeline.ts +171 -84
- package/src/domain/graph/builder/stages/build-edges.ts +15 -2
- package/src/domain/graph/builder/stages/build-structure.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +11 -33
- package/src/domain/graph/builder/stages/finalize.ts +1 -1
- package/src/domain/graph/builder/stages/insert-nodes.ts +17 -14
- package/src/domain/graph/builder/stages/resolve-imports.ts +2 -3
- package/src/domain/parser.ts +12 -4
- package/src/domain/queries.ts +1 -1
- package/src/features/ast.ts +2 -2
- package/src/features/audit.ts +3 -2
- package/src/features/boundaries.ts +3 -5
- package/src/features/branch-compare.ts +2 -3
- package/src/features/cfg.ts +51 -6
- package/src/features/complexity.ts +7 -0
- package/src/features/flow.ts +2 -1
- package/src/features/manifesto.ts +15 -1
- package/src/infrastructure/config.ts +1 -0
- package/src/infrastructure/update-check.ts +3 -3
- package/src/presentation/batch.ts +1 -0
- package/src/presentation/structure.ts +2 -2
- package/src/shared/normalize.ts +10 -0
- package/src/types.ts +2 -0
package/src/domain/parser.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Tree } from 'web-tree-sitter';
|
|
|
5
5
|
import { Language, Parser, Query } from 'web-tree-sitter';
|
|
6
6
|
import { debug, warn } from '../infrastructure/logger.js';
|
|
7
7
|
import { getNative, getNativePackageVersion, loadNative } from '../infrastructure/native.js';
|
|
8
|
-
import { toErrorMessage } from '../shared/errors.js';
|
|
8
|
+
import { ParseError, toErrorMessage } from '../shared/errors.js';
|
|
9
9
|
import type {
|
|
10
10
|
EngineMode,
|
|
11
11
|
ExtractorOutput,
|
|
@@ -188,7 +188,11 @@ async function doLoadLanguage(entry: LanguageRegistryEntry): Promise<void> {
|
|
|
188
188
|
_queryCache.set(entry.id, new Query(lang, patterns.join('\n')));
|
|
189
189
|
}
|
|
190
190
|
} catch (e: unknown) {
|
|
191
|
-
if (entry.required)
|
|
191
|
+
if (entry.required)
|
|
192
|
+
throw new ParseError(`Required parser ${entry.id} failed to initialize`, {
|
|
193
|
+
file: entry.grammarFile,
|
|
194
|
+
cause: e as Error,
|
|
195
|
+
});
|
|
192
196
|
warn(
|
|
193
197
|
`${entry.id} parser failed to initialize: ${(e as Error).message}. ${entry.id} files will be skipped.`,
|
|
194
198
|
);
|
|
@@ -776,7 +780,7 @@ export async function parseFileAuto(
|
|
|
776
780
|
const { native } = resolveEngine(opts);
|
|
777
781
|
|
|
778
782
|
if (native) {
|
|
779
|
-
const result = native.parseFile(filePath, source,
|
|
783
|
+
const result = native.parseFile(filePath, source, true, true);
|
|
780
784
|
if (!result) return null;
|
|
781
785
|
const patched = patchNativeResult(result);
|
|
782
786
|
// Always backfill typeMap for TS/TSX from WASM — native parser's type
|
|
@@ -874,7 +878,11 @@ export async function parseFilesAuto(
|
|
|
874
878
|
if (!native) return parseFilesWasm(filePaths, rootDir);
|
|
875
879
|
|
|
876
880
|
const result = new Map<string, ExtractorOutput>();
|
|
877
|
-
|
|
881
|
+
// Always extract all analysis data (dataflow + AST nodes) during native parse.
|
|
882
|
+
// This eliminates the need for any downstream WASM re-parse or native standalone calls.
|
|
883
|
+
const nativeResults = native.parseFilesFull
|
|
884
|
+
? native.parseFilesFull(filePaths, rootDir)
|
|
885
|
+
: native.parseFiles(filePaths, rootDir, true, true);
|
|
878
886
|
const needsTypeMap: { filePath: string; relPath: string }[] = [];
|
|
879
887
|
for (const r of nativeResults) {
|
|
880
888
|
if (!r) continue;
|
package/src/domain/queries.ts
CHANGED
|
@@ -22,7 +22,7 @@ export {
|
|
|
22
22
|
VALID_ROLES,
|
|
23
23
|
} from '../shared/kinds.js';
|
|
24
24
|
// ── Shared utilities ─────────────────────────────────────────────────────
|
|
25
|
-
export { kindIcon, normalizeSymbol } from '../shared/normalize.js';
|
|
25
|
+
export { kindIcon, normalizeSymbol, toSymbolRef } from '../shared/normalize.js';
|
|
26
26
|
export { briefData } from './analysis/brief.js';
|
|
27
27
|
export { contextData, explainData } from './analysis/context.js';
|
|
28
28
|
export { fileDepsData, filePathData, fnDepsData, pathData } from './analysis/dependencies.js';
|
package/src/features/ast.ts
CHANGED
|
@@ -115,8 +115,8 @@ function tryNativeBulkInsert(
|
|
|
115
115
|
receiver: n.receiver ?? '',
|
|
116
116
|
})),
|
|
117
117
|
});
|
|
118
|
-
} else if (symbols.
|
|
119
|
-
return false; // needs JS fallback
|
|
118
|
+
} else if (symbols._tree) {
|
|
119
|
+
return false; // has WASM tree not yet processed — needs JS fallback
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
package/src/features/audit.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { loadConfig } from '../infrastructure/config.js';
|
|
|
7
7
|
import { debug } from '../infrastructure/logger.js';
|
|
8
8
|
import { isTestFile } from '../infrastructure/test-filter.js';
|
|
9
9
|
import { toErrorMessage } from '../shared/errors.js';
|
|
10
|
+
import { toSymbolRef } from '../shared/normalize.js';
|
|
10
11
|
import type { BetterSqlite3Database, CodegraphConfig } from '../types.js';
|
|
11
12
|
import { RULE_DEFS } from './manifesto.js';
|
|
12
13
|
|
|
@@ -317,7 +318,7 @@ function enrichSymbol(
|
|
|
317
318
|
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
318
319
|
)
|
|
319
320
|
.all(nodeId) as SymbolRef[]
|
|
320
|
-
).map(
|
|
321
|
+
).map(toSymbolRef);
|
|
321
322
|
|
|
322
323
|
callers = (
|
|
323
324
|
db
|
|
@@ -327,7 +328,7 @@ function enrichSymbol(
|
|
|
327
328
|
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
328
329
|
)
|
|
329
330
|
.all(nodeId) as SymbolRef[]
|
|
330
|
-
).map(
|
|
331
|
+
).map(toSymbolRef);
|
|
331
332
|
if (noTests) callers = callers.filter((c) => !isTestFile(c.file));
|
|
332
333
|
|
|
333
334
|
const testCallerRows = db
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { debug } from '../infrastructure/logger.js';
|
|
2
1
|
import { isTestFile } from '../infrastructure/test-filter.js';
|
|
2
|
+
import { BoundaryError } from '../shared/errors.js';
|
|
3
3
|
import type { BetterSqlite3Database } from '../types.js';
|
|
4
4
|
|
|
5
5
|
// ─── Glob-to-Regex ───────────────────────────────────────────────────
|
|
@@ -269,8 +269,7 @@ export function evaluateBoundaries(
|
|
|
269
269
|
|
|
270
270
|
const { valid, errors } = validateBoundaryConfig(boundaryConfig);
|
|
271
271
|
if (!valid) {
|
|
272
|
-
|
|
273
|
-
return { violations: [], violationCount: 0 };
|
|
272
|
+
throw new BoundaryError(`Invalid boundary configuration: ${errors.join('; ')}`);
|
|
274
273
|
}
|
|
275
274
|
|
|
276
275
|
const modules = resolveModules(boundaryConfig);
|
|
@@ -297,8 +296,7 @@ export function evaluateBoundaries(
|
|
|
297
296
|
)
|
|
298
297
|
.all() as Array<{ source: string; target: string }>;
|
|
299
298
|
} catch (err) {
|
|
300
|
-
|
|
301
|
-
return { violations: [], violationCount: 0 };
|
|
299
|
+
throw new BoundaryError('Boundary evaluation failed', { cause: err as Error });
|
|
302
300
|
}
|
|
303
301
|
|
|
304
302
|
if (opts.noTests) {
|
|
@@ -9,6 +9,7 @@ import { debug } from '../infrastructure/logger.js';
|
|
|
9
9
|
import { getNative, isNativeAvailable } from '../infrastructure/native.js';
|
|
10
10
|
import { isTestFile } from '../infrastructure/test-filter.js';
|
|
11
11
|
import { toErrorMessage } from '../shared/errors.js';
|
|
12
|
+
import { toSymbolRef } from '../shared/normalize.js';
|
|
12
13
|
import type { EngineMode, NativeDatabase } from '../types.js';
|
|
13
14
|
|
|
14
15
|
// ─── Git Helpers ────────────────────────────────────────────────────────
|
|
@@ -255,9 +256,7 @@ function loadCallersFromDb(
|
|
|
255
256
|
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
256
257
|
visited.add(c.id);
|
|
257
258
|
nextFrontier.push(c.id);
|
|
258
|
-
allCallers.add(
|
|
259
|
-
JSON.stringify({ name: c.name, kind: c.kind, file: c.file, line: c.line }),
|
|
260
|
-
);
|
|
259
|
+
allCallers.add(JSON.stringify(toSymbolRef(c)));
|
|
261
260
|
}
|
|
262
261
|
}
|
|
263
262
|
}
|
package/src/features/cfg.ts
CHANGED
|
@@ -369,7 +369,7 @@ export async function buildCFGData(
|
|
|
369
369
|
db: BetterSqlite3Database,
|
|
370
370
|
fileSymbols: Map<string, FileSymbols>,
|
|
371
371
|
rootDir: string,
|
|
372
|
-
|
|
372
|
+
engineOpts?: {
|
|
373
373
|
nativeDb?: { bulkInsertCfg?(entries: Array<Record<string, unknown>>): number };
|
|
374
374
|
suspendJsDb?: () => void;
|
|
375
375
|
resumeJsDb?: () => void;
|
|
@@ -379,11 +379,56 @@ export async function buildCFGData(
|
|
|
379
379
|
// skip WASM parser init, tree parsing, and JS visitor entirely — just persist.
|
|
380
380
|
const allNative = allCfgNative(fileSymbols);
|
|
381
381
|
|
|
382
|
-
//
|
|
383
|
-
// The
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
382
|
+
// ── Native bulk-insert fast path ──────────────────────────────────────
|
|
383
|
+
// The Rust bulkInsertCfg handles delete-before-insert atomically on a
|
|
384
|
+
// single rusqlite connection, so there is no dual-connection WAL conflict.
|
|
385
|
+
const nativeDb = engineOpts?.nativeDb;
|
|
386
|
+
if (allNative && nativeDb?.bulkInsertCfg) {
|
|
387
|
+
const entries: Array<Record<string, unknown>> = [];
|
|
388
|
+
for (const [relPath, symbols] of fileSymbols) {
|
|
389
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
390
|
+
if (!CFG_EXTENSIONS.has(ext)) continue;
|
|
391
|
+
|
|
392
|
+
for (const def of symbols.definitions) {
|
|
393
|
+
if (def.kind !== 'function' && def.kind !== 'method') continue;
|
|
394
|
+
if (!def.line) continue;
|
|
395
|
+
|
|
396
|
+
const nodeId = getFunctionNodeId(db, def.name, relPath, def.line);
|
|
397
|
+
if (!nodeId) continue;
|
|
398
|
+
|
|
399
|
+
const cfg = def.cfg as { blocks?: CfgBuildBlock[]; edges?: CfgBuildEdge[] } | undefined;
|
|
400
|
+
if (!cfg?.blocks?.length) continue;
|
|
401
|
+
|
|
402
|
+
entries.push({
|
|
403
|
+
nodeId,
|
|
404
|
+
blocks: cfg.blocks.map((b) => ({
|
|
405
|
+
index: b.index,
|
|
406
|
+
blockType: b.type,
|
|
407
|
+
startLine: b.startLine ?? undefined,
|
|
408
|
+
endLine: b.endLine ?? undefined,
|
|
409
|
+
label: b.label ?? undefined,
|
|
410
|
+
})),
|
|
411
|
+
edges: (cfg.edges || []).map((e) => ({
|
|
412
|
+
sourceIndex: e.sourceIndex,
|
|
413
|
+
targetIndex: e.targetIndex,
|
|
414
|
+
kind: e.kind,
|
|
415
|
+
})),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (entries.length > 0) {
|
|
421
|
+
let inserted = 0;
|
|
422
|
+
try {
|
|
423
|
+
engineOpts?.suspendJsDb?.();
|
|
424
|
+
inserted = nativeDb.bulkInsertCfg(entries);
|
|
425
|
+
} finally {
|
|
426
|
+
engineOpts?.resumeJsDb?.();
|
|
427
|
+
}
|
|
428
|
+
info(`CFG (native bulk): ${inserted} functions analyzed`);
|
|
429
|
+
}
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
387
432
|
|
|
388
433
|
const extToLang = buildExtToLangMap();
|
|
389
434
|
let parsers: unknown = null;
|
|
@@ -545,6 +545,10 @@ function collectNativeBulkRows(
|
|
|
545
545
|
const rows: Array<Record<string, unknown>> = [];
|
|
546
546
|
|
|
547
547
|
for (const [relPath, symbols] of fileSymbols) {
|
|
548
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
549
|
+
const langId = symbols._langId || '';
|
|
550
|
+
const langSupported = COMPLEXITY_EXTENSIONS.has(ext) || COMPLEXITY_RULES.has(langId);
|
|
551
|
+
|
|
548
552
|
for (const def of symbols.definitions) {
|
|
549
553
|
if (def.kind !== 'function' && def.kind !== 'method') continue;
|
|
550
554
|
if (!def.line) continue;
|
|
@@ -554,6 +558,9 @@ function collectNativeBulkRows(
|
|
|
554
558
|
// of the native bulk-insert path for every TypeScript codebase (#846).
|
|
555
559
|
if (!def.complexity) {
|
|
556
560
|
if (def.name.includes('.') || !def.endLine || def.endLine <= def.line) continue;
|
|
561
|
+
// Languages without complexity rules will never have data — skip them
|
|
562
|
+
// rather than bailing out of the entire native bulk path.
|
|
563
|
+
if (!langSupported) continue;
|
|
557
564
|
return null; // genuine function body missing complexity — needs JS fallback
|
|
558
565
|
}
|
|
559
566
|
const nodeId = getFunctionNodeId(db, def.name, relPath, def.line);
|
package/src/features/flow.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { openReadonlyOrFail } from '../db/index.js';
|
|
9
9
|
import { CORE_SYMBOL_KINDS, findMatchingNodes } from '../domain/queries.js';
|
|
10
10
|
import { isTestFile } from '../infrastructure/test-filter.js';
|
|
11
|
+
import { toSymbolRef } from '../shared/normalize.js';
|
|
11
12
|
import { paginateResult } from '../shared/paginate.js';
|
|
12
13
|
import { FRAMEWORK_ENTRY_PREFIXES } from './structure.js';
|
|
13
14
|
|
|
@@ -175,7 +176,7 @@ function bfsCallees(
|
|
|
175
176
|
|
|
176
177
|
visited.add(c.id);
|
|
177
178
|
nextFrontier.push(c.id);
|
|
178
|
-
const nodeInfo: NodeInfo =
|
|
179
|
+
const nodeInfo: NodeInfo = toSymbolRef(c);
|
|
179
180
|
levelNodes.push(nodeInfo);
|
|
180
181
|
nodeDepths.set(c.id, d);
|
|
181
182
|
idToNode.set(c.id, nodeInfo);
|
|
@@ -5,6 +5,7 @@ import { loadConfig } from '../infrastructure/config.js';
|
|
|
5
5
|
import { debug } from '../infrastructure/logger.js';
|
|
6
6
|
import { paginateResult } from '../shared/paginate.js';
|
|
7
7
|
import type { BetterSqlite3Database, CodegraphConfig, ThresholdRule } from '../types.js';
|
|
8
|
+
import type { BoundaryViolation } from './boundaries.js';
|
|
8
9
|
import { evaluateBoundaries } from './boundaries.js';
|
|
9
10
|
|
|
10
11
|
// ─── Rule Definitions ─────────────────────────────────────────────────
|
|
@@ -416,7 +417,20 @@ function evaluateBoundaryRules(
|
|
|
416
417
|
return;
|
|
417
418
|
}
|
|
418
419
|
|
|
419
|
-
|
|
420
|
+
let result: { violations: BoundaryViolation[]; violationCount: number };
|
|
421
|
+
try {
|
|
422
|
+
result = evaluateBoundaries(db, boundaryConfig, { noTests: opts.noTests || false });
|
|
423
|
+
} catch (e: unknown) {
|
|
424
|
+
debug(`boundary check failed: ${(e as Error).message}`);
|
|
425
|
+
ruleResults.push({
|
|
426
|
+
name: 'boundaries',
|
|
427
|
+
level: 'graph',
|
|
428
|
+
status: 'warn',
|
|
429
|
+
thresholds: effectiveThresholds,
|
|
430
|
+
violationCount: 0,
|
|
431
|
+
});
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
420
434
|
const hasBoundaryViolations = result.violationCount > 0;
|
|
421
435
|
|
|
422
436
|
if (!hasBoundaryViolations) {
|
|
@@ -18,11 +18,11 @@ interface UpdateCache {
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Minimal semver comparison. Returns -1, 0, or 1.
|
|
21
|
-
*
|
|
21
|
+
* Strips pre-release suffixes (e.g. "3.9.3-dev.6" → "3.9.3") before comparing.
|
|
22
22
|
*/
|
|
23
23
|
export function semverCompare(a: string, b: string): -1 | 0 | 1 {
|
|
24
|
-
const pa = a.split('.').map(Number);
|
|
25
|
-
const pb = b.split('.').map(Number);
|
|
24
|
+
const pa = a.replace(/-.*$/, '').split('.').map(Number);
|
|
25
|
+
const pb = b.replace(/-.*$/, '').split('.').map(Number);
|
|
26
26
|
for (let i = 0; i < 3; i++) {
|
|
27
27
|
const na = pa[i] || 0;
|
|
28
28
|
const nb = pb[i] || 0;
|
|
@@ -75,7 +75,7 @@ export function formatHotspots(data: HotspotsResult): string {
|
|
|
75
75
|
|
|
76
76
|
interface ModuleBoundaryEntry {
|
|
77
77
|
directory: string;
|
|
78
|
-
cohesion: number;
|
|
78
|
+
cohesion: number | null;
|
|
79
79
|
fileCount: number;
|
|
80
80
|
symbolCount: number;
|
|
81
81
|
fanIn: number;
|
|
@@ -95,7 +95,7 @@ export function formatModuleBoundaries(data: ModuleBoundariesResult): string {
|
|
|
95
95
|
const lines = [`\nModule boundaries (cohesion >= ${data.threshold}, ${data.count} modules):\n`];
|
|
96
96
|
for (const m of data.modules) {
|
|
97
97
|
lines.push(
|
|
98
|
-
` ${m.directory}/ cohesion=${m.cohesion.toFixed(2)} (${m.fileCount} files, ${m.symbolCount} symbols)`,
|
|
98
|
+
` ${m.directory}/ cohesion=${m.cohesion !== null ? m.cohesion.toFixed(2) : 'n/a'} (${m.fileCount} files, ${m.symbolCount} symbols)`,
|
|
99
99
|
);
|
|
100
100
|
lines.push(` Incoming: ${m.fanIn} edges Outgoing: ${m.fanOut} edges`);
|
|
101
101
|
if (m.files.length > 0) {
|
package/src/shared/normalize.ts
CHANGED
|
@@ -19,6 +19,16 @@ export function getFileHash(db: DbHandle, file: string): string | null {
|
|
|
19
19
|
return row ? row.hash : null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** Pick the 4-field symbol reference from any row that carries at least {name, kind, file, line}. */
|
|
23
|
+
export function toSymbolRef(row: { name: string; kind: string; file: string; line: number }): {
|
|
24
|
+
name: string;
|
|
25
|
+
kind: string;
|
|
26
|
+
file: string;
|
|
27
|
+
line: number;
|
|
28
|
+
} {
|
|
29
|
+
return { name: row.name, kind: row.kind, file: row.file, line: row.line };
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
export function kindIcon(kind: string): string {
|
|
23
33
|
switch (kind) {
|
|
24
34
|
case 'function':
|
package/src/types.ts
CHANGED
|
@@ -1085,6 +1085,7 @@ export interface CodegraphConfig {
|
|
|
1085
1085
|
incremental: boolean;
|
|
1086
1086
|
dbPath: string;
|
|
1087
1087
|
driftThreshold: number;
|
|
1088
|
+
smallFilesThreshold: number;
|
|
1088
1089
|
};
|
|
1089
1090
|
|
|
1090
1091
|
query: {
|
|
@@ -1873,6 +1874,7 @@ export type StmtCache<TRow = unknown> = WeakMap<BetterSqlite3Database, SqliteSta
|
|
|
1873
1874
|
export interface NativeAddon {
|
|
1874
1875
|
parseFile(filePath: string, source: string, dataflow: boolean, ast: boolean): unknown;
|
|
1875
1876
|
parseFiles(files: string[], rootDir: string, dataflow: boolean, ast: boolean): unknown[];
|
|
1877
|
+
parseFilesFull?(files: string[], rootDir: string): unknown[];
|
|
1876
1878
|
resolveImport(fromFile: string, importSource: string, rootDir: string, aliases: unknown): string;
|
|
1877
1879
|
resolveImports(
|
|
1878
1880
|
items: Array<{ fromFile: string; importSource: string }>,
|