projscan 1.7.0 → 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/cppFunctions.js +40 -1
- package/dist/core/languages/cppFunctions.js.map +1 -1
- package/dist/core/languages/registry.js +2 -0
- 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 +2 -0
- package/dist/core/languages/treeSitterLoader.js.map +1 -1
- package/dist/core/session.d.ts +18 -4
- package/dist/core/session.js +20 -5
- 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-swift.wasm +0 -0
- package/dist/mcp/server.js +60 -1
- package/dist/mcp/server.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.js +12 -3
- package/dist/mcp/tools/costSummary.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 +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/tool-manifest.json +37 -3
- 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 +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swiftCyclomatic.js","sourceRoot":"","sources":["../../../src/core/languages/swiftCyclomatic.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,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,iBAAiB,CAAC;QACvB,KAAK,eAAe,CAAC;QACrB,KAAK,iBAAiB,CAAC;QACvB,KAAK,wBAAwB,CAAC;QAC9B,KAAK,cAAc,CAAC;QACpB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc,CAAC;QACpB,KAAK,wBAAwB,CAAC;QAC9B,KAAK,wBAAwB;YAC3B,OAAO,IAAI,CAAC;QACd,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;YACvG,OAAO,CAAC,SAAS,CAAC;QACpB,CAAC;QACD;YACE,OAAO,KAAK,CAAC;IACjB,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,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 extractSwiftExports(root: TsNode): AstExport[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract Swift top-level declarations as exports. Swift's default
|
|
3
|
+
* visibility is `internal` (visible within the module). For graph
|
|
4
|
+
* purposes we treat everything that is NOT explicitly `private` or
|
|
5
|
+
* `fileprivate` as exported — module-internal symbols still participate
|
|
6
|
+
* in cross-file resolution within the module.
|
|
7
|
+
*
|
|
8
|
+
* Kinds:
|
|
9
|
+
* func foo() → function
|
|
10
|
+
* class Foo / struct Foo → class
|
|
11
|
+
* protocol Foo → interface
|
|
12
|
+
* enum Color → enum
|
|
13
|
+
* typealias Bar = ... → type
|
|
14
|
+
* let / var x → variable
|
|
15
|
+
* actor Foo → class
|
|
16
|
+
*/
|
|
17
|
+
const EXPORT_NODE_TO_KIND = {
|
|
18
|
+
function_declaration: 'function',
|
|
19
|
+
class_declaration: 'class',
|
|
20
|
+
protocol_declaration: 'interface',
|
|
21
|
+
typealias_declaration: 'type',
|
|
22
|
+
property_declaration: 'variable',
|
|
23
|
+
};
|
|
24
|
+
export function extractSwiftExports(root) {
|
|
25
|
+
const exports = [];
|
|
26
|
+
for (const child of root.namedChildren) {
|
|
27
|
+
visitTopLevel(child, exports);
|
|
28
|
+
}
|
|
29
|
+
return exports;
|
|
30
|
+
}
|
|
31
|
+
function visitTopLevel(node, out) {
|
|
32
|
+
if (node.type === 'class_declaration') {
|
|
33
|
+
if (isHidden(node))
|
|
34
|
+
return;
|
|
35
|
+
const name = nameOf(node);
|
|
36
|
+
if (!name)
|
|
37
|
+
return;
|
|
38
|
+
const head = headerText(node);
|
|
39
|
+
let kind = 'class';
|
|
40
|
+
if (/\benum\b/.test(head))
|
|
41
|
+
kind = 'enum';
|
|
42
|
+
out.push({ name, kind, typeOnly: false, line: node.startPosition.row + 1 });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const kind = EXPORT_NODE_TO_KIND[node.type];
|
|
46
|
+
if (!kind) {
|
|
47
|
+
for (const c of node.namedChildren)
|
|
48
|
+
visitTopLevel(c, out);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (isHidden(node))
|
|
52
|
+
return;
|
|
53
|
+
const name = nameOf(node);
|
|
54
|
+
if (!name)
|
|
55
|
+
return;
|
|
56
|
+
out.push({ name, kind, typeOnly: false, line: node.startPosition.row + 1 });
|
|
57
|
+
}
|
|
58
|
+
function headerText(node) {
|
|
59
|
+
const idx = node.text.indexOf('{');
|
|
60
|
+
return idx >= 0 ? node.text.slice(0, idx) : node.text;
|
|
61
|
+
}
|
|
62
|
+
function isHidden(node) {
|
|
63
|
+
for (const c of node.namedChildren) {
|
|
64
|
+
if (c.type === 'modifiers' || c.type === 'modifier_list') {
|
|
65
|
+
for (const m of c.namedChildren) {
|
|
66
|
+
const t = m.text.trim();
|
|
67
|
+
if (t === 'private' || t === 'fileprivate')
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (c.type === 'visibility_modifier') {
|
|
72
|
+
const t = c.text.trim();
|
|
73
|
+
if (t === 'private' || t === 'fileprivate')
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
function nameOf(node) {
|
|
80
|
+
if (node.childForFieldName) {
|
|
81
|
+
const id = node.childForFieldName('name');
|
|
82
|
+
if (id && id.text)
|
|
83
|
+
return id.text;
|
|
84
|
+
}
|
|
85
|
+
for (const c of node.namedChildren) {
|
|
86
|
+
if (c.type === 'simple_identifier' || c.type === 'identifier' || c.type === 'type_identifier') {
|
|
87
|
+
return c.text;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const m = /\b(let|var)\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(node.text);
|
|
91
|
+
if (m)
|
|
92
|
+
return m[2];
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=swiftExports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swiftExports.js","sourceRoot":"","sources":["../../../src/core/languages/swiftExports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { FunctionInfo } from '../ast.js';
|
|
2
|
+
interface TsNode {
|
|
3
|
+
type: string;
|
|
4
|
+
text: string;
|
|
5
|
+
startPosition: {
|
|
6
|
+
row: number;
|
|
7
|
+
column: number;
|
|
8
|
+
};
|
|
9
|
+
endPosition: {
|
|
10
|
+
row: number;
|
|
11
|
+
column: number;
|
|
12
|
+
};
|
|
13
|
+
namedChildren: TsNode[];
|
|
14
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Per-function McCabe CC for Swift. Walks `function_declaration` nodes
|
|
18
|
+
* (top-level + class/struct/protocol/extension methods). Methods inside
|
|
19
|
+
* `class Foo { func m() }` are named `Foo.m`. Closures and trailing-closure
|
|
20
|
+
* blocks aren't extracted as separate functions; their decision points
|
|
21
|
+
* fold into the enclosing function (matches projscan's convention for
|
|
22
|
+
* Rust closures and Go func literals).
|
|
23
|
+
*
|
|
24
|
+
* `switch` cases each count as +1; the `default` arm does not. Optional
|
|
25
|
+
* chaining (`?.`) and nil-coalescing (`??`) are NOT counted.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractSwiftFunctions(root: TsNode): FunctionInfo[];
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const SWIFT_DECISION_NODES = new Set([
|
|
2
|
+
'if_statement',
|
|
3
|
+
'guard_statement',
|
|
4
|
+
'for_statement',
|
|
5
|
+
'while_statement',
|
|
6
|
+
'repeat_while_statement',
|
|
7
|
+
'do_statement',
|
|
8
|
+
'catch_block',
|
|
9
|
+
'catch_clause',
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* Per-function McCabe CC for Swift. Walks `function_declaration` nodes
|
|
13
|
+
* (top-level + class/struct/protocol/extension methods). Methods inside
|
|
14
|
+
* `class Foo { func m() }` are named `Foo.m`. Closures and trailing-closure
|
|
15
|
+
* blocks aren't extracted as separate functions; their decision points
|
|
16
|
+
* fold into the enclosing function (matches projscan's convention for
|
|
17
|
+
* Rust closures and Go func literals).
|
|
18
|
+
*
|
|
19
|
+
* `switch` cases each count as +1; the `default` arm does not. Optional
|
|
20
|
+
* chaining (`?.`) and nil-coalescing (`??`) are NOT counted.
|
|
21
|
+
*/
|
|
22
|
+
export function extractSwiftFunctions(root) {
|
|
23
|
+
const out = [];
|
|
24
|
+
walk(root, null, out);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
function walk(node, ownerName, out) {
|
|
28
|
+
if (node.type === 'class_declaration' ||
|
|
29
|
+
node.type === 'protocol_declaration' ||
|
|
30
|
+
node.type === 'extension_declaration') {
|
|
31
|
+
const name = nameOfDecl(node) ?? ownerName;
|
|
32
|
+
const body = bodyOf(node);
|
|
33
|
+
if (body) {
|
|
34
|
+
for (const child of body.namedChildren)
|
|
35
|
+
walk(child, name, out);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (node.type === 'function_declaration' ||
|
|
40
|
+
node.type === 'init_declaration' ||
|
|
41
|
+
node.type === 'deinit_declaration' ||
|
|
42
|
+
node.type === 'subscript_declaration') {
|
|
43
|
+
let baseName;
|
|
44
|
+
if (node.type === 'init_declaration')
|
|
45
|
+
baseName = 'init';
|
|
46
|
+
else if (node.type === 'deinit_declaration')
|
|
47
|
+
baseName = 'deinit';
|
|
48
|
+
else if (node.type === 'subscript_declaration')
|
|
49
|
+
baseName = 'subscript';
|
|
50
|
+
else
|
|
51
|
+
baseName = nameOfDecl(node) ?? '<anonymous>';
|
|
52
|
+
const fnName = ownerName ? `${ownerName}.${baseName}` : baseName;
|
|
53
|
+
const line = node.startPosition.row + 1;
|
|
54
|
+
const endLine = node.endPosition.row + 1;
|
|
55
|
+
const { cc, callSites } = analyzeBody(node);
|
|
56
|
+
out.push({ name: fnName, line, endLine, cyclomaticComplexity: cc, callSites });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
for (const child of node.namedChildren)
|
|
60
|
+
walk(child, ownerName, out);
|
|
61
|
+
}
|
|
62
|
+
function nameOfDecl(node) {
|
|
63
|
+
if (node.childForFieldName) {
|
|
64
|
+
const id = node.childForFieldName('name');
|
|
65
|
+
if (id && id.text)
|
|
66
|
+
return id.text;
|
|
67
|
+
}
|
|
68
|
+
for (const c of node.namedChildren) {
|
|
69
|
+
if (c.type === 'simple_identifier' || c.type === 'identifier' || c.type === 'type_identifier') {
|
|
70
|
+
return c.text;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function bodyOf(node) {
|
|
76
|
+
if (node.childForFieldName) {
|
|
77
|
+
const b = node.childForFieldName('body');
|
|
78
|
+
if (b)
|
|
79
|
+
return b;
|
|
80
|
+
}
|
|
81
|
+
for (const c of node.namedChildren) {
|
|
82
|
+
if (c.type === 'class_body' ||
|
|
83
|
+
c.type === 'protocol_body' ||
|
|
84
|
+
c.type === 'function_body' ||
|
|
85
|
+
c.type === 'extension_body') {
|
|
86
|
+
return c;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function analyzeBody(fnNode) {
|
|
92
|
+
let count = 0;
|
|
93
|
+
const calls = new Set();
|
|
94
|
+
const body = bodyOf(fnNode);
|
|
95
|
+
if (!body)
|
|
96
|
+
return { cc: 1, callSites: [] };
|
|
97
|
+
walkSkipNested(body, (n) => {
|
|
98
|
+
if (SWIFT_DECISION_NODES.has(n.type)) {
|
|
99
|
+
count++;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (n.type === 'switch_entry') {
|
|
103
|
+
// The default arm has no value child (no case_label patterns) — non-
|
|
104
|
+
// default arms always carry one or more case_label / case_pattern
|
|
105
|
+
// children. Mirrors the kotlin/cpp structural-detection approach.
|
|
106
|
+
const isDefault = !n.namedChildren.some((c) => c.type === 'switch_pattern' || c.type === 'case_label');
|
|
107
|
+
if (!isDefault)
|
|
108
|
+
count++;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (n.type === 'conjunction_expression' || n.type === 'disjunction_expression') {
|
|
112
|
+
count++;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (n.type === 'call_expression') {
|
|
116
|
+
const fn = n.childForFieldName ? n.childForFieldName('function') : n.namedChildren[0] ?? null;
|
|
117
|
+
const name = bareName(fn);
|
|
118
|
+
if (name)
|
|
119
|
+
calls.add(name);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return { cc: count + 1, callSites: [...calls] };
|
|
123
|
+
}
|
|
124
|
+
function bareName(node) {
|
|
125
|
+
if (!node)
|
|
126
|
+
return null;
|
|
127
|
+
switch (node.type) {
|
|
128
|
+
case 'simple_identifier':
|
|
129
|
+
case 'identifier':
|
|
130
|
+
case 'type_identifier':
|
|
131
|
+
return node.text;
|
|
132
|
+
case 'navigation_expression': {
|
|
133
|
+
const last = node.namedChildren[node.namedChildren.length - 1];
|
|
134
|
+
return last ? bareName(last) : null;
|
|
135
|
+
}
|
|
136
|
+
case 'navigation_suffix': {
|
|
137
|
+
for (const c of node.namedChildren) {
|
|
138
|
+
const n = bareName(c);
|
|
139
|
+
if (n)
|
|
140
|
+
return n;
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
default:
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function walkSkipNested(node, visit) {
|
|
149
|
+
visit(node);
|
|
150
|
+
for (const child of node.namedChildren) {
|
|
151
|
+
if (child.type === 'function_declaration' ||
|
|
152
|
+
child.type === 'init_declaration' ||
|
|
153
|
+
child.type === 'class_declaration' ||
|
|
154
|
+
child.type === 'protocol_declaration' ||
|
|
155
|
+
child.type === 'lambda_literal' ||
|
|
156
|
+
child.type === 'closure_expression') {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
walkSkipNested(child, visit);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=swiftFunctions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swiftFunctions.js","sourceRoot":"","sources":["../../../src/core/languages/swiftFunctions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AstImport } 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
|
+
/**
|
|
13
|
+
* Extract Swift `import` statements from a tree-sitter-swift AST.
|
|
14
|
+
*
|
|
15
|
+
* Handled forms:
|
|
16
|
+
* import Foundation → source = "Foundation"
|
|
17
|
+
* import struct Foo.Bar → source = "Foo.Bar"
|
|
18
|
+
* import class Foo.Bar.Baz → source = "Foo.Bar.Baz"
|
|
19
|
+
* @testable import MyModule → source = "MyModule"
|
|
20
|
+
* @_implementationOnly import Private → source = "Private"
|
|
21
|
+
*
|
|
22
|
+
* Swift modules don't expose individual symbols at import time the way
|
|
23
|
+
* JS named imports do; the import binds the whole module / submodule.
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractSwiftImports(root: TsNode): AstImport[];
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract Swift `import` statements from a tree-sitter-swift AST.
|
|
3
|
+
*
|
|
4
|
+
* Handled forms:
|
|
5
|
+
* import Foundation → source = "Foundation"
|
|
6
|
+
* import struct Foo.Bar → source = "Foo.Bar"
|
|
7
|
+
* import class Foo.Bar.Baz → source = "Foo.Bar.Baz"
|
|
8
|
+
* @testable import MyModule → source = "MyModule"
|
|
9
|
+
* @_implementationOnly import Private → source = "Private"
|
|
10
|
+
*
|
|
11
|
+
* Swift modules don't expose individual symbols at import time the way
|
|
12
|
+
* JS named imports do; the import binds the whole module / submodule.
|
|
13
|
+
*/
|
|
14
|
+
export function extractSwiftImports(root) {
|
|
15
|
+
const imports = [];
|
|
16
|
+
walk(root, (n) => {
|
|
17
|
+
if (n.type !== 'import_declaration')
|
|
18
|
+
return;
|
|
19
|
+
const source = readImportPath(n);
|
|
20
|
+
if (!source)
|
|
21
|
+
return;
|
|
22
|
+
imports.push({
|
|
23
|
+
source,
|
|
24
|
+
kind: 'static',
|
|
25
|
+
specifiers: [],
|
|
26
|
+
typeOnly: false,
|
|
27
|
+
line: n.startPosition.row + 1,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return imports;
|
|
31
|
+
}
|
|
32
|
+
function readImportPath(node) {
|
|
33
|
+
const text = node.text.trim();
|
|
34
|
+
let body = text.replace(/^\s*(@[A-Za-z_][\w]*\s*)+/, '');
|
|
35
|
+
body = body.replace(/^\s*import\b/, '').trim();
|
|
36
|
+
body = body.replace(/^(typealias|struct|class|enum|protocol|let|var|func)\b\s*/, '');
|
|
37
|
+
const m = /^[A-Za-z_][\w.]*/.exec(body);
|
|
38
|
+
return m ? m[0] : '';
|
|
39
|
+
}
|
|
40
|
+
function walk(node, visit) {
|
|
41
|
+
visit(node);
|
|
42
|
+
for (const child of node.namedChildren)
|
|
43
|
+
walk(child, visit);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=swiftImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swiftImports.js","sourceRoot":"","sources":["../../../src/core/languages/swiftImports.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,CAAC,CAAC,IAAI,KAAK,oBAAoB;YAAE,OAAO;QAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE;YACd,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;IACzD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,2DAA2D,EAC3D,EAAE,CACH,CAAC;IACF,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvB,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,17 @@
|
|
|
1
|
+
import type { FileEntry } from '../../types.js';
|
|
2
|
+
export interface SwiftProjectInfo {
|
|
3
|
+
/**
|
|
4
|
+
* Detected Swift source roots. For SwiftPM projects this is typically
|
|
5
|
+
* `Sources/<Module>` per declared target; we fall back to the conventional
|
|
6
|
+
* `Sources/` and the repo root when no Package.swift exists.
|
|
7
|
+
*/
|
|
8
|
+
packageRoots: string[];
|
|
9
|
+
/** Did we see a Package.swift / .xcodeproj manifest? Used for diagnostics only. */
|
|
10
|
+
hasManifest: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Detect Swift source roots. We don't parse Package.swift; instead we
|
|
14
|
+
* survey the .swift file paths and pick whichever conventional roots
|
|
15
|
+
* actually contain Swift sources.
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectSwiftProject(rootPath: string, files: FileEntry[]): Promise<SwiftProjectInfo | null>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const COMMON_SWIFT_ROOTS = ['Sources', 'Tests', '.'];
|
|
4
|
+
/**
|
|
5
|
+
* Detect Swift source roots. We don't parse Package.swift; instead we
|
|
6
|
+
* survey the .swift file paths and pick whichever conventional roots
|
|
7
|
+
* actually contain Swift sources.
|
|
8
|
+
*/
|
|
9
|
+
export async function detectSwiftProject(rootPath, files) {
|
|
10
|
+
const swiftFiles = files.filter((f) => f.relativePath.endsWith('.swift'));
|
|
11
|
+
if (swiftFiles.length === 0)
|
|
12
|
+
return null;
|
|
13
|
+
const hasManifest = await hasSwiftManifest(rootPath);
|
|
14
|
+
const packageRoots = [];
|
|
15
|
+
for (const candidate of COMMON_SWIFT_ROOTS) {
|
|
16
|
+
if (candidate === '.') {
|
|
17
|
+
if (swiftFiles.some((f) => !f.relativePath.includes('/')))
|
|
18
|
+
packageRoots.push('.');
|
|
19
|
+
}
|
|
20
|
+
else if (swiftFiles.some((f) => f.relativePath.startsWith(candidate + '/'))) {
|
|
21
|
+
packageRoots.push(candidate);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (packageRoots.length === 0)
|
|
25
|
+
packageRoots.push('.');
|
|
26
|
+
return { packageRoots, hasManifest };
|
|
27
|
+
}
|
|
28
|
+
async function hasSwiftManifest(rootPath) {
|
|
29
|
+
const candidates = ['Package.swift', 'Package.resolved'];
|
|
30
|
+
for (const c of candidates) {
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(path.join(rootPath, c));
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// try next
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const entries = await fs.readdir(rootPath, { withFileTypes: true });
|
|
41
|
+
if (entries.some((e) => e.isDirectory() && e.name.endsWith('.xcodeproj')))
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// ignore
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=swiftManifests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swiftManifests.js","sourceRoot":"","sources":["../../../src/core/languages/swiftManifests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAc7B,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,KAAkB;IAElB,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;QAC3C,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YACtB,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpF,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9E,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IAC9C,MAAM,UAAU,GAAG,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,WAAW;QACb,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACzF,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -33,6 +33,7 @@ function grammarDirs() {
|
|
|
33
33
|
// ensureBuiltWasm). At test time (vitest running off src/) the wasm
|
|
34
34
|
// sits inside the package directory, so probe it there too.
|
|
35
35
|
const nodeModulesKotlin = path.join(repoRoot, 'node_modules', 'tree-sitter-kotlin');
|
|
36
|
+
const nodeModulesSwift = path.join(repoRoot, 'node_modules', 'tree-sitter-swift');
|
|
36
37
|
const nodeModulesCpp = path.join(repoRoot, 'node_modules', 'tree-sitter-cpp');
|
|
37
38
|
return [
|
|
38
39
|
distDir,
|
|
@@ -45,6 +46,7 @@ function grammarDirs() {
|
|
|
45
46
|
nodeModulesPhp,
|
|
46
47
|
nodeModulesCSharp,
|
|
47
48
|
nodeModulesKotlin,
|
|
49
|
+
nodeModulesSwift,
|
|
48
50
|
nodeModulesCpp,
|
|
49
51
|
];
|
|
50
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"treeSitterLoader.js","sourceRoot":"","sources":["../../../src/core/languages/treeSitterLoader.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"treeSitterLoader.js","sourceRoot":"","sources":["../../../src/core/languages/treeSitterLoader.ts"],"names":[],"mappings":"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"}
|
package/dist/core/session.d.ts
CHANGED
|
@@ -86,10 +86,24 @@ export declare function recordEvent(session: Session, kind: string, data?: Recor
|
|
|
86
86
|
* Persist the session to disk. Best-effort; failures are swallowed so
|
|
87
87
|
* a transient write error doesn't break the calling tool.
|
|
88
88
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
89
|
+
* 1.8+ — uses atomicWriteFile (tmp + fsync + rename + parent-dir fsync)
|
|
90
|
+
* instead of a naive fs.writeFile. Two reasons:
|
|
91
|
+
*
|
|
92
|
+
* 1. Crash safety. A naive writeFile can leave the file truncated to
|
|
93
|
+
* zero bytes if the process is killed mid-write — and on next
|
|
94
|
+
* startup the corrupt file is treated as a new session, losing the
|
|
95
|
+
* touched-file map and event log.
|
|
96
|
+
*
|
|
97
|
+
* 2. Concurrent processes. The previous "last-write-wins" comment was
|
|
98
|
+
* true at the *file* level: two writers could clobber each other.
|
|
99
|
+
* With atomic rename the in-flight tmp paths are unique (random
|
|
100
|
+
* UUID suffix), so the only collision point is the rename — which
|
|
101
|
+
* is atomic at the journal-record level on every supported FS.
|
|
102
|
+
* Either A wins or B wins; neither sees a half-written read.
|
|
103
|
+
*
|
|
104
|
+
* The session payload is JSON; we still don't merge concurrent writes
|
|
105
|
+
* (one writer's view may shadow another's recent touches by a few
|
|
106
|
+
* seconds), but corruption is no longer possible.
|
|
93
107
|
*/
|
|
94
108
|
export declare function saveSession(rootPath: string, session: Session): Promise<void>;
|
|
95
109
|
/**
|
package/dist/core/session.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { atomicWriteFile } from '../utils/atomicWrite.js';
|
|
4
5
|
/**
|
|
5
6
|
* Session — durable cross-invocation state for projscan (1.4+).
|
|
6
7
|
*
|
|
@@ -121,17 +122,31 @@ export function recordEvent(session, kind, data) {
|
|
|
121
122
|
* Persist the session to disk. Best-effort; failures are swallowed so
|
|
122
123
|
* a transient write error doesn't break the calling tool.
|
|
123
124
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
125
|
+
* 1.8+ — uses atomicWriteFile (tmp + fsync + rename + parent-dir fsync)
|
|
126
|
+
* instead of a naive fs.writeFile. Two reasons:
|
|
127
|
+
*
|
|
128
|
+
* 1. Crash safety. A naive writeFile can leave the file truncated to
|
|
129
|
+
* zero bytes if the process is killed mid-write — and on next
|
|
130
|
+
* startup the corrupt file is treated as a new session, losing the
|
|
131
|
+
* touched-file map and event log.
|
|
132
|
+
*
|
|
133
|
+
* 2. Concurrent processes. The previous "last-write-wins" comment was
|
|
134
|
+
* true at the *file* level: two writers could clobber each other.
|
|
135
|
+
* With atomic rename the in-flight tmp paths are unique (random
|
|
136
|
+
* UUID suffix), so the only collision point is the rename — which
|
|
137
|
+
* is atomic at the journal-record level on every supported FS.
|
|
138
|
+
* Either A wins or B wins; neither sees a half-written read.
|
|
139
|
+
*
|
|
140
|
+
* The session payload is JSON; we still don't merge concurrent writes
|
|
141
|
+
* (one writer's view may shadow another's recent touches by a few
|
|
142
|
+
* seconds), but corruption is no longer possible.
|
|
128
143
|
*/
|
|
129
144
|
export async function saveSession(rootPath, session) {
|
|
130
145
|
try {
|
|
131
146
|
const dir = path.join(rootPath, SESSION_DIR);
|
|
132
147
|
await fs.mkdir(dir, { recursive: true });
|
|
133
148
|
const filePath = sessionFilePath(rootPath);
|
|
134
|
-
await
|
|
149
|
+
await atomicWriteFile(filePath, JSON.stringify(session, null, 2));
|
|
135
150
|
}
|
|
136
151
|
catch {
|
|
137
152
|
// Swallow — sessions are best-effort.
|
package/dist/core/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
|
package/dist/core/taint.d.ts
CHANGED
|
@@ -80,6 +80,23 @@ export interface TaintReport {
|
|
|
80
80
|
/** The effective sources/sinks list used for this run (after merging defaults + config). */
|
|
81
81
|
effectiveSources: string[];
|
|
82
82
|
effectiveSinks: string[];
|
|
83
|
+
/**
|
|
84
|
+
* 1.8+ — true when the BFS hit MAX_DEPTH for at least one source with
|
|
85
|
+
* a non-empty frontier still pending. When set, the agent should know
|
|
86
|
+
* that flows deeper than MAX_DEPTH may exist but weren't reported.
|
|
87
|
+
* Pairs with `truncatedSources` so a follow-up scan can re-target.
|
|
88
|
+
*/
|
|
89
|
+
truncated?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* 1.8+ — function names whose BFS exited at MAX_DEPTH with the
|
|
92
|
+
* frontier non-empty. Empty when no truncation occurred.
|
|
93
|
+
*/
|
|
94
|
+
truncatedSources?: string[];
|
|
95
|
+
/**
|
|
96
|
+
* 1.8+ — the depth cap actually used. Surfacing this lets agents
|
|
97
|
+
* notice when projscan's defaults shift between releases.
|
|
98
|
+
*/
|
|
99
|
+
maxDepth?: number;
|
|
83
100
|
}
|
|
84
101
|
/**
|
|
85
102
|
* Compute taint flows over the given code graph. Per-function callSites
|