projscan 1.6.2 → 1.8.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/dist/core/applyFix.js +5 -46
- package/dist/core/applyFix.js.map +1 -1
- package/dist/core/embeddings.d.ts +9 -0
- package/dist/core/embeddings.js +45 -5
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/languages/LanguageAdapter.d.ts +1 -1
- package/dist/core/languages/cppAdapter.d.ts +2 -0
- package/dist/core/languages/cppAdapter.js +145 -0
- package/dist/core/languages/cppAdapter.js.map +1 -0
- package/dist/core/languages/cppCallSites.d.ts +13 -0
- package/dist/core/languages/cppCallSites.js +62 -0
- package/dist/core/languages/cppCallSites.js.map +1 -0
- package/dist/core/languages/cppCyclomatic.d.ts +25 -0
- package/dist/core/languages/cppCyclomatic.js +82 -0
- package/dist/core/languages/cppCyclomatic.js.map +1 -0
- package/dist/core/languages/cppExports.d.ts +13 -0
- package/dist/core/languages/cppExports.js +120 -0
- package/dist/core/languages/cppExports.js.map +1 -0
- package/dist/core/languages/cppFunctions.d.ts +30 -0
- package/dist/core/languages/cppFunctions.js +281 -0
- package/dist/core/languages/cppFunctions.js.map +1 -0
- package/dist/core/languages/cppImports.d.ts +25 -0
- package/dist/core/languages/cppImports.js +77 -0
- package/dist/core/languages/cppImports.js.map +1 -0
- package/dist/core/languages/cppManifests.d.ts +18 -0
- package/dist/core/languages/cppManifests.js +41 -0
- package/dist/core/languages/cppManifests.js.map +1 -0
- package/dist/core/languages/kotlinAdapter.d.ts +2 -0
- package/dist/core/languages/kotlinAdapter.js +141 -0
- package/dist/core/languages/kotlinAdapter.js.map +1 -0
- package/dist/core/languages/kotlinCallSites.d.ts +15 -0
- package/dist/core/languages/kotlinCallSites.js +62 -0
- package/dist/core/languages/kotlinCallSites.js.map +1 -0
- package/dist/core/languages/kotlinCyclomatic.d.ts +24 -0
- package/dist/core/languages/kotlinCyclomatic.js +54 -0
- package/dist/core/languages/kotlinCyclomatic.js.map +1 -0
- package/dist/core/languages/kotlinExports.d.ts +13 -0
- package/dist/core/languages/kotlinExports.js +103 -0
- package/dist/core/languages/kotlinExports.js.map +1 -0
- package/dist/core/languages/kotlinFunctions.d.ts +27 -0
- package/dist/core/languages/kotlinFunctions.js +147 -0
- package/dist/core/languages/kotlinFunctions.js.map +1 -0
- package/dist/core/languages/kotlinImports.d.ts +25 -0
- package/dist/core/languages/kotlinImports.js +74 -0
- package/dist/core/languages/kotlinImports.js.map +1 -0
- package/dist/core/languages/kotlinManifests.d.ts +20 -0
- package/dist/core/languages/kotlinManifests.js +46 -0
- package/dist/core/languages/kotlinManifests.js.map +1 -0
- package/dist/core/languages/registry.js +16 -1
- package/dist/core/languages/registry.js.map +1 -1
- package/dist/core/languages/swiftAdapter.d.ts +2 -0
- package/dist/core/languages/swiftAdapter.js +130 -0
- package/dist/core/languages/swiftAdapter.js.map +1 -0
- package/dist/core/languages/swiftCallSites.d.ts +14 -0
- package/dist/core/languages/swiftCallSites.js +60 -0
- package/dist/core/languages/swiftCallSites.js.map +1 -0
- package/dist/core/languages/swiftCyclomatic.d.ts +24 -0
- package/dist/core/languages/swiftCyclomatic.js +54 -0
- package/dist/core/languages/swiftCyclomatic.js.map +1 -0
- package/dist/core/languages/swiftExports.d.ts +13 -0
- package/dist/core/languages/swiftExports.js +95 -0
- package/dist/core/languages/swiftExports.js.map +1 -0
- package/dist/core/languages/swiftFunctions.d.ts +28 -0
- package/dist/core/languages/swiftFunctions.js +162 -0
- package/dist/core/languages/swiftFunctions.js.map +1 -0
- package/dist/core/languages/swiftImports.d.ts +26 -0
- package/dist/core/languages/swiftImports.js +45 -0
- package/dist/core/languages/swiftImports.js.map +1 -0
- package/dist/core/languages/swiftManifests.d.ts +17 -0
- package/dist/core/languages/swiftManifests.js +49 -0
- package/dist/core/languages/swiftManifests.js.map +1 -0
- package/dist/core/languages/treeSitterLoader.js +21 -1
- package/dist/core/languages/treeSitterLoader.js.map +1 -1
- package/dist/core/memory.d.ts +30 -0
- package/dist/core/memory.js +42 -0
- package/dist/core/memory.js.map +1 -1
- package/dist/core/session.d.ts +23 -4
- package/dist/core/session.js +28 -8
- package/dist/core/session.js.map +1 -1
- package/dist/core/taint.d.ts +17 -0
- package/dist/core/taint.js +19 -1
- package/dist/core/taint.js.map +1 -1
- package/dist/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/grammars/tree-sitter-kotlin.wasm +0 -0
- package/dist/grammars/tree-sitter-swift.wasm +0 -0
- package/dist/mcp/server.js +107 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/sessionTouchScanner.js +8 -2
- package/dist/mcp/sessionTouchScanner.js.map +1 -1
- package/dist/mcp/tools/_shared.d.ts +25 -1
- package/dist/mcp/tools/_shared.js.map +1 -1
- package/dist/mcp/tools/costSummary.d.ts +26 -0
- package/dist/mcp/tools/costSummary.js +152 -0
- package/dist/mcp/tools/costSummary.js.map +1 -0
- package/dist/mcp/tools/fixSuggest.js +23 -2
- package/dist/mcp/tools/fixSuggest.js.map +1 -1
- package/dist/mcp/tools/memory.js +37 -4
- package/dist/mcp/tools/memory.js.map +1 -1
- package/dist/mcp/tools/reviewWatch.d.ts +7 -0
- package/dist/mcp/tools/reviewWatch.js +228 -0
- package/dist/mcp/tools/reviewWatch.js.map +1 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/tool-manifest.json +52 -4
- package/dist/utils/atomicWrite.d.ts +26 -0
- package/dist/utils/atomicWrite.js +69 -0
- package/dist/utils/atomicWrite.js.map +1 -0
- package/package.json +6 -2
package/dist/core/applyFix.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
import { atomicWriteFile } from '../utils/atomicWrite.js';
|
|
4
5
|
/**
|
|
5
6
|
* Apply layer (1.6+).
|
|
6
7
|
*
|
|
@@ -181,52 +182,10 @@ async function readIfExists(absPath) {
|
|
|
181
182
|
return null;
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// old shape was predictable to within a few hundred microseconds — on a
|
|
189
|
-
// shared system a local user could pre-create the tmp path as a symlink
|
|
190
|
-
// to an attacker-chosen target before our write landed. Random-UUID
|
|
191
|
-
// eliminates the prediction.
|
|
192
|
-
//
|
|
193
|
-
// 2. Open with the 'wx' flag (O_CREAT | O_EXCL). If the tmp path already
|
|
194
|
-
// exists for any reason (race, leftover, planted symlink), fs.open
|
|
195
|
-
// throws EEXIST instead of following the symlink. Belt-and-suspenders
|
|
196
|
-
// with #1.
|
|
197
|
-
//
|
|
198
|
-
// 3. fsync the file before rename, and best-effort fsync the parent dir
|
|
199
|
-
// after rename. Rename is atomic at the journal-record level on most
|
|
200
|
-
// filesystems, but without fsync the rename can survive a crash with
|
|
201
|
-
// empty tmp content (the file metadata persists, the data doesn't).
|
|
202
|
-
// Parent-dir sync is best-effort because Windows doesn't support it
|
|
203
|
-
// and some filesystems treat it as a no-op.
|
|
204
|
-
const tmp = `${absPath}.projscan-tmp-${randomUUID()}`;
|
|
205
|
-
const handle = await fs.open(tmp, 'wx');
|
|
206
|
-
try {
|
|
207
|
-
await handle.writeFile(content, 'utf-8');
|
|
208
|
-
await handle.sync();
|
|
209
|
-
}
|
|
210
|
-
finally {
|
|
211
|
-
await handle.close();
|
|
212
|
-
}
|
|
213
|
-
await fs.rename(tmp, absPath);
|
|
214
|
-
// Best-effort durable rename. fsync the parent directory so the rename
|
|
215
|
-
// entry survives a crash. Swallow errors: Windows doesn't support
|
|
216
|
-
// directory fsync; some FUSE backends throw EINVAL.
|
|
217
|
-
try {
|
|
218
|
-
const dir = await fs.open(path.dirname(absPath), 'r');
|
|
219
|
-
try {
|
|
220
|
-
await dir.sync();
|
|
221
|
-
}
|
|
222
|
-
finally {
|
|
223
|
-
await dir.close();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
// ignore — best-effort
|
|
228
|
-
}
|
|
229
|
-
}
|
|
185
|
+
// 1.8+ — atomic-write logic moved to src/utils/atomicWrite.ts and reused
|
|
186
|
+
// by session.saveSession. This file keeps the local name as a thin alias
|
|
187
|
+
// so existing call sites don't change shape.
|
|
188
|
+
const atomicWrite = atomicWriteFile;
|
|
230
189
|
function sha256(s) {
|
|
231
190
|
return createHash('sha256').update(s).digest('hex');
|
|
232
191
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyFix.js","sourceRoot":"","sources":["../../src/core/applyFix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"applyFix.js","sourceRoot":"","sources":["../../src/core/applyFix.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,15 @@ export interface EmbedOptions {
|
|
|
20
20
|
* Lightweight; safe to call multiple times.
|
|
21
21
|
*/
|
|
22
22
|
export declare function isSemanticAvailable(): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Test-only: drop all cached pipelines. Lets unit tests verify LRU
|
|
25
|
+
* eviction without each test paying for a real model load.
|
|
26
|
+
*/
|
|
27
|
+
export declare function __resetEmbeddingsCacheForTests(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Test-only: snapshot the model keys currently in the LRU, oldest-first.
|
|
30
|
+
*/
|
|
31
|
+
export declare function __snapshotEmbeddingsCacheForTests(): string[];
|
|
23
32
|
/**
|
|
24
33
|
* Embed a single string → Float32Array of EMBEDDING_DIM floats.
|
|
25
34
|
* Returns null if the peer dep is unavailable.
|
package/dist/core/embeddings.js
CHANGED
|
@@ -12,6 +12,20 @@
|
|
|
12
12
|
export const DEFAULT_MODEL = 'Xenova/all-MiniLM-L6-v2';
|
|
13
13
|
export const EMBEDDING_DIM = 384;
|
|
14
14
|
let cachedModule;
|
|
15
|
+
// 1.8+ — bound the pipeline cache at MAX_CACHED_MODELS to prevent
|
|
16
|
+
// long-running MCP servers from accumulating hundreds of MB of model
|
|
17
|
+
// state on agents that switch models mid-session. Each pipeline holds
|
|
18
|
+
// roughly 200MB of weights when warm; without a bound, an agent
|
|
19
|
+
// requesting `Xenova/all-MiniLM-L6-v2` then `Xenova/all-MiniLM-L12-v2`
|
|
20
|
+
// then a third model retains all three indefinitely. With this LRU
|
|
21
|
+
// bound, the third request evicts the first.
|
|
22
|
+
//
|
|
23
|
+
// `Map` insertion order is the LRU order: oldest entry is the one we
|
|
24
|
+
// drop on overflow. We `delete` + `set` on a hit to bump it to the end.
|
|
25
|
+
//
|
|
26
|
+
// Single-process default (one model in steady state) is unaffected:
|
|
27
|
+
// the bound is 2, and projscan's default-everywhere pipe stays warm.
|
|
28
|
+
const MAX_CACHED_PIPELINES = 2;
|
|
15
29
|
const pipelines = new Map();
|
|
16
30
|
async function tryLoadTransformers() {
|
|
17
31
|
if (cachedModule !== undefined)
|
|
@@ -51,15 +65,41 @@ async function getPipeline(model, onFirstLoad) {
|
|
|
51
65
|
if (!mod)
|
|
52
66
|
return null;
|
|
53
67
|
let existing = pipelines.get(model);
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
});
|
|
68
|
+
if (existing) {
|
|
69
|
+
// Bump on access so the LRU cache treats the recently-used model as
|
|
70
|
+
// hot. Map insertion order = recency.
|
|
71
|
+
pipelines.delete(model);
|
|
59
72
|
pipelines.set(model, existing);
|
|
73
|
+
return existing;
|
|
74
|
+
}
|
|
75
|
+
onFirstLoad?.(`Loading embedding model ${model} (first run downloads ~25MB)...`);
|
|
76
|
+
existing = mod.pipeline('feature-extraction', model, {
|
|
77
|
+
quantized: true,
|
|
78
|
+
});
|
|
79
|
+
pipelines.set(model, existing);
|
|
80
|
+
// Evict the least-recently-used pipeline when over the bound. Map
|
|
81
|
+
// iteration is in insertion order, so the first key is the oldest.
|
|
82
|
+
while (pipelines.size > MAX_CACHED_PIPELINES) {
|
|
83
|
+
const oldest = pipelines.keys().next().value;
|
|
84
|
+
if (oldest === undefined)
|
|
85
|
+
break;
|
|
86
|
+
pipelines.delete(oldest);
|
|
60
87
|
}
|
|
61
88
|
return existing;
|
|
62
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Test-only: drop all cached pipelines. Lets unit tests verify LRU
|
|
92
|
+
* eviction without each test paying for a real model load.
|
|
93
|
+
*/
|
|
94
|
+
export function __resetEmbeddingsCacheForTests() {
|
|
95
|
+
pipelines.clear();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Test-only: snapshot the model keys currently in the LRU, oldest-first.
|
|
99
|
+
*/
|
|
100
|
+
export function __snapshotEmbeddingsCacheForTests() {
|
|
101
|
+
return [...pipelines.keys()];
|
|
102
|
+
}
|
|
63
103
|
/**
|
|
64
104
|
* Embed a single string → Float32Array of EMBEDDING_DIM floats.
|
|
65
105
|
* Returns null if the peer dep is unavailable.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,yBAAyB,CAAC;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAuBjC,IAAI,YAAmD,CAAC;
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FileEntry } from '../../types.js';
|
|
2
2
|
import type { AstResult } from '../ast.js';
|
|
3
|
-
export type LanguageId = 'javascript' | 'python' | 'go' | 'java' | 'ruby' | 'rust' | 'php' | 'csharp';
|
|
3
|
+
export type LanguageId = 'javascript' | 'python' | 'go' | 'java' | 'ruby' | 'rust' | 'php' | 'csharp' | 'kotlin' | 'swift' | 'cpp';
|
|
4
4
|
export interface LanguageResolveContext {
|
|
5
5
|
/** Language-specific root dirs used during import resolution. */
|
|
6
6
|
packageRoots?: string[];
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createParserFor } from './treeSitterLoader.js';
|
|
3
|
+
import { extractCppImports } from './cppImports.js';
|
|
4
|
+
import { extractCppExports } from './cppExports.js';
|
|
5
|
+
import { extractCppCyclomatic } from './cppCyclomatic.js';
|
|
6
|
+
import { extractCppFunctions } from './cppFunctions.js';
|
|
7
|
+
import { extractCppCallSites } from './cppCallSites.js';
|
|
8
|
+
import { detectCppProject } from './cppManifests.js';
|
|
9
|
+
const CPP_EXTENSIONS = new Set(['.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.hxx']);
|
|
10
|
+
const SOURCE_EXTENSIONS = new Set(['.cpp', '.cc', '.cxx', '.c']);
|
|
11
|
+
const MAX_CPP_FILE = 1024 * 1024;
|
|
12
|
+
let parserPromise = null;
|
|
13
|
+
async function getParser() {
|
|
14
|
+
if (!parserPromise)
|
|
15
|
+
parserPromise = createParserFor('tree-sitter-cpp.wasm');
|
|
16
|
+
return parserPromise;
|
|
17
|
+
}
|
|
18
|
+
export const cppAdapter = {
|
|
19
|
+
id: 'cpp',
|
|
20
|
+
extensions: CPP_EXTENSIONS,
|
|
21
|
+
// Only .cpp/.cc/.cxx/.c are "source" for dead-code purposes; headers
|
|
22
|
+
// hold the declarations they consume.
|
|
23
|
+
sourceExtensions: SOURCE_EXTENSIONS,
|
|
24
|
+
barrelBasenames: new Set(),
|
|
25
|
+
maxFileSize: MAX_CPP_FILE,
|
|
26
|
+
async parse(_filePath, content) {
|
|
27
|
+
try {
|
|
28
|
+
const parser = await getParser();
|
|
29
|
+
const tree = parser.parse(content);
|
|
30
|
+
if (!tree || !tree.rootNode) {
|
|
31
|
+
return {
|
|
32
|
+
ok: false,
|
|
33
|
+
reason: 'tree-sitter returned null tree',
|
|
34
|
+
imports: [],
|
|
35
|
+
exports: [],
|
|
36
|
+
callSites: [],
|
|
37
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
38
|
+
cyclomaticComplexity: 0,
|
|
39
|
+
functions: [],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const root = tree.rootNode;
|
|
43
|
+
const imports = extractCppImports(root);
|
|
44
|
+
const exports = extractCppExports(root);
|
|
45
|
+
const cyclomaticComplexity = extractCppCyclomatic(root);
|
|
46
|
+
const callSites = extractCppCallSites(root);
|
|
47
|
+
const functions = extractCppFunctions(root);
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
imports,
|
|
51
|
+
exports,
|
|
52
|
+
callSites,
|
|
53
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
54
|
+
cyclomaticComplexity,
|
|
55
|
+
functions,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
reason: `cpp parse failure: ${msg.slice(0, 120)}`,
|
|
63
|
+
imports: [],
|
|
64
|
+
exports: [],
|
|
65
|
+
callSites: [],
|
|
66
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
67
|
+
cyclomaticComplexity: 0,
|
|
68
|
+
functions: [],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
resolveImport(importingFile, source, graphFiles, context) {
|
|
73
|
+
return resolveCppImport(importingFile, source, graphFiles, context);
|
|
74
|
+
},
|
|
75
|
+
toPackageName(source) {
|
|
76
|
+
if (!source)
|
|
77
|
+
return null;
|
|
78
|
+
// For #include, the "package" is the system header name (`vector`,
|
|
79
|
+
// `iostream`) when angle-bracketed. Quoted includes are project-local
|
|
80
|
+
// and should resolve via resolveImport — but we don't know quoting
|
|
81
|
+
// at this layer, so we conservatively return null for paths that
|
|
82
|
+
// look relative (`./`, `../`, contain `/`) and the bare leaf for
|
|
83
|
+
// angle-bracket-style names.
|
|
84
|
+
if (source.startsWith('./') || source.startsWith('../'))
|
|
85
|
+
return null;
|
|
86
|
+
if (source.includes('/'))
|
|
87
|
+
return source.split('/')[0];
|
|
88
|
+
return source;
|
|
89
|
+
},
|
|
90
|
+
async preparePackageRoots(rootPath, files) {
|
|
91
|
+
const info = await detectCppProject(rootPath, files);
|
|
92
|
+
return {
|
|
93
|
+
packageRoots: info ? info.includeRoots.map((r) => path.relative(rootPath, path.join(rootPath, r)) || '.') : [],
|
|
94
|
+
meta: info ? { cppProject: info } : undefined,
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Resolve a C++ `#include` source to a repo-local file. We try, in order:
|
|
100
|
+
*
|
|
101
|
+
* 1. Relative to the importing file's directory (quoted-include semantics).
|
|
102
|
+
* 2. Each detected include root (e.g., `include/`, `src/`, `lib/`).
|
|
103
|
+
*
|
|
104
|
+
* We return the first hit. Standard-library / third-party headers (e.g.,
|
|
105
|
+
* `<vector>`, `<boost/optional.hpp>`) won't match anything in the graph
|
|
106
|
+
* and resolve to null, which is correct — they're external.
|
|
107
|
+
*/
|
|
108
|
+
function resolveCppImport(importingFile, source, graphFiles, context) {
|
|
109
|
+
if (!source)
|
|
110
|
+
return null;
|
|
111
|
+
const project = context.meta?.cppProject;
|
|
112
|
+
const includeRoots = context.packageRoots ?? project?.includeRoots ?? [];
|
|
113
|
+
// 1) Relative to the importing file. tree-sitter doesn't tell us whether
|
|
114
|
+
// the source was quoted or angle-bracketed, but the resolver works the
|
|
115
|
+
// same way for either: we try the importing file's directory first.
|
|
116
|
+
const importingDir = path.posix.dirname(importingFile);
|
|
117
|
+
const relative = normalizeRelative(importingDir, source);
|
|
118
|
+
if (relative && graphFiles.has(relative))
|
|
119
|
+
return relative;
|
|
120
|
+
// 2) Each include root.
|
|
121
|
+
for (const root of includeRoots) {
|
|
122
|
+
const rootSegs = root === '.' || root === '' ? [] : root.split('/').filter(Boolean);
|
|
123
|
+
const candidate = [...rootSegs, ...source.split('/').filter(Boolean)].join('/');
|
|
124
|
+
if (graphFiles.has(candidate))
|
|
125
|
+
return candidate;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
function normalizeRelative(baseDir, source) {
|
|
130
|
+
// Strip any leading `./`. For `../foo`, walk up the baseDir.
|
|
131
|
+
let dir = baseDir === '.' ? '' : baseDir;
|
|
132
|
+
let rest = source;
|
|
133
|
+
while (rest.startsWith('./'))
|
|
134
|
+
rest = rest.slice(2);
|
|
135
|
+
while (rest.startsWith('../')) {
|
|
136
|
+
if (!dir)
|
|
137
|
+
return null;
|
|
138
|
+
dir = path.posix.dirname(dir);
|
|
139
|
+
if (dir === '.')
|
|
140
|
+
dir = '';
|
|
141
|
+
rest = rest.slice(3);
|
|
142
|
+
}
|
|
143
|
+
return dir ? `${dir}/${rest}` : rest;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=cppAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cppAdapter.js","sourceRoot":"","sources":["../../../src/core/languages/cppAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface TsNode {
|
|
2
|
+
type: string;
|
|
3
|
+
text: string;
|
|
4
|
+
namedChildren: TsNode[];
|
|
5
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Extract called-name from each `call_expression` in a tree-sitter-cpp AST.
|
|
9
|
+
* Mirrors the existing adapter behaviour: dedupe names, strip qualification,
|
|
10
|
+
* so `obj.foo()`, `Foo::bar()`, and `bar()` all surface as just the leaf.
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractCppCallSites(root: TsNode): string[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract called-name from each `call_expression` in a tree-sitter-cpp AST.
|
|
3
|
+
* Mirrors the existing adapter behaviour: dedupe names, strip qualification,
|
|
4
|
+
* so `obj.foo()`, `Foo::bar()`, and `bar()` all surface as just the leaf.
|
|
5
|
+
*/
|
|
6
|
+
export function extractCppCallSites(root) {
|
|
7
|
+
const seen = new Set();
|
|
8
|
+
walk(root, (n) => {
|
|
9
|
+
if (n.type !== 'call_expression')
|
|
10
|
+
return;
|
|
11
|
+
const fn = pickCallee(n);
|
|
12
|
+
if (!fn)
|
|
13
|
+
return;
|
|
14
|
+
const name = bareName(fn);
|
|
15
|
+
if (name)
|
|
16
|
+
seen.add(name);
|
|
17
|
+
});
|
|
18
|
+
return [...seen];
|
|
19
|
+
}
|
|
20
|
+
function pickCallee(node) {
|
|
21
|
+
if (node.childForFieldName) {
|
|
22
|
+
const f = node.childForFieldName('function');
|
|
23
|
+
if (f)
|
|
24
|
+
return f;
|
|
25
|
+
}
|
|
26
|
+
return node.namedChildren[0] ?? null;
|
|
27
|
+
}
|
|
28
|
+
function bareName(node) {
|
|
29
|
+
switch (node.type) {
|
|
30
|
+
case 'identifier':
|
|
31
|
+
case 'field_identifier':
|
|
32
|
+
case 'type_identifier':
|
|
33
|
+
return node.text;
|
|
34
|
+
case 'qualified_identifier': {
|
|
35
|
+
const last = node.namedChildren[node.namedChildren.length - 1];
|
|
36
|
+
return last ? bareName(last) : null;
|
|
37
|
+
}
|
|
38
|
+
case 'field_expression': {
|
|
39
|
+
const f = node.childForFieldName ? node.childForFieldName('field') : null;
|
|
40
|
+
if (f)
|
|
41
|
+
return bareName(f);
|
|
42
|
+
const last = node.namedChildren[node.namedChildren.length - 1];
|
|
43
|
+
return last ? bareName(last) : null;
|
|
44
|
+
}
|
|
45
|
+
case 'template_function': {
|
|
46
|
+
const f = node.childForFieldName ? node.childForFieldName('name') : null;
|
|
47
|
+
return f ? bareName(f) : null;
|
|
48
|
+
}
|
|
49
|
+
case 'call_expression': {
|
|
50
|
+
const inner = pickCallee(node);
|
|
51
|
+
return inner ? bareName(inner) : null;
|
|
52
|
+
}
|
|
53
|
+
default:
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function walk(node, visit) {
|
|
58
|
+
visit(node);
|
|
59
|
+
for (const child of node.namedChildren)
|
|
60
|
+
walk(child, visit);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=cppCallSites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cppCallSites.js","sourceRoot":"","sources":["../../../src/core/languages/cppCallSites.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB;YAAE,OAAO;QACzC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACvC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,YAAY,CAAC;QAClB,KAAK,kBAAkB,CAAC;QACxB,KAAK,iBAAiB;YACpB,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB,KAAK,sBAAsB,CAAC,CAAC,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACtC,CAAC;QACD,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,MAAM,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1E,IAAI,CAAC;gBAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACtC,CAAC;QACD,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACzE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAChC,CAAC;QACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAC/B,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxC,CAAC;QACD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,KAA0B;IACpD,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface TsNode {
|
|
2
|
+
type: string;
|
|
3
|
+
text: string;
|
|
4
|
+
namedChildren: TsNode[];
|
|
5
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* File-level McCabe cyclomatic complexity for a tree-sitter-cpp AST.
|
|
9
|
+
*
|
|
10
|
+
* Decision points in C++:
|
|
11
|
+
* if_statement +1
|
|
12
|
+
* for_statement +1
|
|
13
|
+
* for_range_loop +1
|
|
14
|
+
* while_statement +1
|
|
15
|
+
* do_statement +1
|
|
16
|
+
* try_statement +1
|
|
17
|
+
* catch_clause +1 each
|
|
18
|
+
* case_statement (non-default) +1
|
|
19
|
+
* conditional_expression (`?:`) +1
|
|
20
|
+
* binary_expression `&&` / `||` +1 each
|
|
21
|
+
*
|
|
22
|
+
* `case 1:` and `case 2:` count individually; `default:` does not.
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractCppCyclomatic(root: TsNode): number;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-level McCabe cyclomatic complexity for a tree-sitter-cpp AST.
|
|
3
|
+
*
|
|
4
|
+
* Decision points in C++:
|
|
5
|
+
* if_statement +1
|
|
6
|
+
* for_statement +1
|
|
7
|
+
* for_range_loop +1
|
|
8
|
+
* while_statement +1
|
|
9
|
+
* do_statement +1
|
|
10
|
+
* try_statement +1
|
|
11
|
+
* catch_clause +1 each
|
|
12
|
+
* case_statement (non-default) +1
|
|
13
|
+
* conditional_expression (`?:`) +1
|
|
14
|
+
* binary_expression `&&` / `||` +1 each
|
|
15
|
+
*
|
|
16
|
+
* `case 1:` and `case 2:` count individually; `default:` does not.
|
|
17
|
+
*/
|
|
18
|
+
export function extractCppCyclomatic(root) {
|
|
19
|
+
let decisions = 0;
|
|
20
|
+
walk(root, (n) => {
|
|
21
|
+
if (isDecisionPoint(n))
|
|
22
|
+
decisions++;
|
|
23
|
+
});
|
|
24
|
+
return decisions + 1;
|
|
25
|
+
}
|
|
26
|
+
function isDecisionPoint(n) {
|
|
27
|
+
switch (n.type) {
|
|
28
|
+
case 'if_statement':
|
|
29
|
+
case 'for_statement':
|
|
30
|
+
case 'for_range_loop':
|
|
31
|
+
case 'while_statement':
|
|
32
|
+
case 'do_statement':
|
|
33
|
+
case 'try_statement':
|
|
34
|
+
case 'catch_clause':
|
|
35
|
+
case 'conditional_expression':
|
|
36
|
+
return true;
|
|
37
|
+
case 'case_statement': {
|
|
38
|
+
// tree-sitter-cpp exposes a `value` field for `case X:` and leaves it
|
|
39
|
+
// null for `default:`. Field-based detection is more reliable than
|
|
40
|
+
// text inspection, which can misbehave when comments / whitespace
|
|
41
|
+
// sit between the keyword and the colon.
|
|
42
|
+
if (n.childForFieldName) {
|
|
43
|
+
const value = n.childForFieldName('value');
|
|
44
|
+
if (value)
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
// Fallback for grammar versions without the `value` field: a regular
|
|
48
|
+
// `case` has its label value as the first named child (literal /
|
|
49
|
+
// identifier / expression). The `default` form's first named child
|
|
50
|
+
// is whatever statement follows the colon.
|
|
51
|
+
const first = n.namedChildren[0];
|
|
52
|
+
if (!first)
|
|
53
|
+
return false;
|
|
54
|
+
return !STATEMENT_NODES.has(first.type);
|
|
55
|
+
}
|
|
56
|
+
case 'binary_expression':
|
|
57
|
+
return /(\s|^)(\|\||&&)(\s|$)/.test(n.text);
|
|
58
|
+
default:
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const STATEMENT_NODES = new Set([
|
|
63
|
+
'return_statement',
|
|
64
|
+
'break_statement',
|
|
65
|
+
'continue_statement',
|
|
66
|
+
'expression_statement',
|
|
67
|
+
'compound_statement',
|
|
68
|
+
'if_statement',
|
|
69
|
+
'for_statement',
|
|
70
|
+
'while_statement',
|
|
71
|
+
'do_statement',
|
|
72
|
+
'switch_statement',
|
|
73
|
+
'goto_statement',
|
|
74
|
+
'declaration',
|
|
75
|
+
'labeled_statement',
|
|
76
|
+
]);
|
|
77
|
+
function walk(node, visit) {
|
|
78
|
+
visit(node);
|
|
79
|
+
for (const child of node.namedChildren)
|
|
80
|
+
walk(child, visit);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=cppCyclomatic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cppCyclomatic.js","sourceRoot":"","sources":["../../../src/core/languages/cppCyclomatic.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,eAAe,CAAC,CAAC,CAAC;YAAE,SAAS,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAChC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe,CAAC;QACrB,KAAK,gBAAgB,CAAC;QACtB,KAAK,iBAAiB,CAAC;QACvB,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe,CAAC;QACrB,KAAK,cAAc,CAAC;QACpB,KAAK,wBAAwB;YAC3B,OAAO,IAAI,CAAC;QACd,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,sEAAsE;YACtE,mEAAmE;YACnE,kEAAkE;YAClE,yCAAyC;YACzC,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAC3C,IAAI,KAAK;oBAAE,OAAO,IAAI,CAAC;YACzB,CAAC;YACD,qEAAqE;YACrE,iEAAiE;YACjE,mEAAmE;YACnE,2CAA2C;YAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAC;YACzB,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,mBAAmB;YACtB,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9C;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,kBAAkB;IAClB,iBAAiB;IACjB,oBAAoB;IACpB,sBAAsB;IACtB,oBAAoB;IACpB,cAAc;IACd,eAAe;IACf,iBAAiB;IACjB,cAAc;IACd,kBAAkB;IAClB,gBAAgB;IAChB,aAAa;IACb,mBAAmB;CACpB,CAAC,CAAC;AAEH,SAAS,IAAI,CAAC,IAAY,EAAE,KAA0B;IACpD,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AstExport } from '../ast.js';
|
|
2
|
+
interface TsNode {
|
|
3
|
+
type: string;
|
|
4
|
+
text: string;
|
|
5
|
+
startPosition: {
|
|
6
|
+
row: number;
|
|
7
|
+
column: number;
|
|
8
|
+
};
|
|
9
|
+
namedChildren: TsNode[];
|
|
10
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function extractCppExports(root: TsNode): AstExport[];
|
|
13
|
+
export {};
|