pi-lens 3.8.65 → 3.8.67
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/CHANGELOG.md +59 -0
- package/README.md +0 -1
- package/dist/clients/actionable-warnings-logger.js +11 -36
- package/dist/clients/ast-grep-tool-logger.js +11 -36
- package/dist/clients/biome-client.js +10 -2
- package/dist/clients/bootstrap.js +1 -3
- package/dist/clients/cascade-logger.js +7 -12
- package/dist/clients/complexity-client.js +397 -623
- package/dist/clients/dead-code-logger.js +11 -22
- package/dist/clients/dependency-checker.js +15 -2
- package/dist/clients/deps/vscode-jsonrpc.js +1 -1
- package/dist/clients/diagnostic-logger.js +7 -31
- package/dist/clients/dispatch/auxiliary-lsp.js +38 -0
- package/dist/clients/dispatch/dispatcher.js +4 -39
- package/dist/clients/dispatch/fact-runner.js +9 -57
- package/dist/clients/dispatch/facts/comment-facts.js +12 -25
- package/dist/clients/dispatch/facts/function-facts.js +161 -132
- package/dist/clients/dispatch/facts/import-facts.js +164 -117
- package/dist/clients/dispatch/facts/tree-sitter-facts.js +34 -0
- package/dist/clients/dispatch/facts/try-catch-facts.js +62 -68
- package/dist/clients/dispatch/inline-suppressions.js +61 -0
- package/dist/clients/dispatch/integration.js +94 -32
- package/dist/clients/dispatch/plan.js +0 -49
- package/dist/clients/dispatch/priorities.js +0 -1
- package/dist/clients/dispatch/rules/cors-wildcard.js +54 -0
- package/dist/clients/dispatch/rules/high-import-coupling.js +37 -0
- package/dist/clients/dispatch/rules/no-commented-credentials.js +52 -0
- package/dist/clients/dispatch/runners/index.js +2 -7
- package/dist/clients/dispatch/runners/lsp.js +18 -6
- package/dist/clients/dispatch/runners/tree-sitter.js +11 -64
- package/dist/clients/dispatch/runners/utils/runner-helpers.js +28 -33
- package/dist/clients/dispatch/tool-profile.js +0 -1
- package/dist/clients/dispatch/types.js +1 -1
- package/dist/clients/formatters.js +10 -0
- package/dist/clients/git-guard.js +1 -1
- package/dist/clients/grammar-source.js +65 -2
- package/dist/clients/jscpd-client.js +8 -2
- package/dist/clients/language-policy.js +2 -2
- package/dist/clients/latency-logger.js +10 -15
- package/dist/clients/lsp/client.js +74 -11
- package/dist/clients/lsp/config.js +61 -3
- package/dist/clients/lsp/index.js +43 -3
- package/dist/clients/lsp/launch.js +3 -32
- package/dist/clients/mcp/session.js +0 -1
- package/dist/clients/module-report.js +16 -5
- package/dist/clients/ndjson-logger.js +150 -0
- package/dist/clients/package-manager.js +65 -0
- package/dist/clients/pipeline.js +25 -41
- package/dist/clients/project-diagnostics/extractors.js +85 -0
- package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +44 -0
- package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +25 -0
- package/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +34 -0
- package/dist/clients/project-diagnostics/runner-adapters/jscpd.js +38 -0
- package/dist/clients/project-diagnostics/runner-adapters/madge.js +47 -0
- package/dist/clients/project-diagnostics/runner-adapters/trivy.js +31 -0
- package/dist/clients/project-diagnostics/scanner.js +11 -10
- package/dist/clients/read-guard-logger.js +11 -36
- package/dist/clients/review-graph/builder.js +337 -27
- package/dist/clients/review-graph/git-identity.js +150 -0
- package/dist/clients/review-graph/service.js +3 -3
- package/dist/clients/runtime-coordinator.js +83 -0
- package/dist/clients/runtime-session.js +28 -2
- package/dist/clients/runtime-tool-result.js +10 -2
- package/dist/clients/runtime-turn.js +25 -7
- package/dist/clients/sg-runner.js +15 -0
- package/dist/clients/test-runner-client.js +12 -6
- package/dist/clients/tree-sitter-cache.js +47 -14
- package/dist/clients/tree-sitter-client.js +9 -1
- package/dist/clients/tree-sitter-logger.js +7 -12
- package/dist/clients/tree-sitter-query-loader.js +1 -0
- package/dist/clients/tree-sitter-shared.js +113 -0
- package/dist/clients/tree-sitter-symbol-extractor.js +19 -12
- package/dist/index.js +4 -22
- package/dist/tools/lens-diagnostics.js +254 -20
- package/grammars/tree-sitter-yaml.wasm +0 -0
- package/grammars/tree-sitter-yaml.wasm.json +3 -3
- package/package.json +4 -3
- package/rules/ast-grep-rules/rule-tests/no-init-return-test.yml +15 -0
- package/rules/ast-grep-rules/rules/no-init-return.yml +11 -5
- package/rules/tree-sitter-queries/python/python-assert-production.yml +4 -0
- package/scripts/download-grammars.js +29 -4
- package/scripts/grammars.lock.json +14 -2
- package/scripts/install-selftest.mjs +8 -7
- package/dist/clients/deps/typescript.js +0 -15
- package/dist/clients/dispatch/rules/quality-rules.js +0 -297
- package/dist/clients/dispatch/rules/sonar-rules.js +0 -493
- package/dist/clients/dispatch/runners/biome.js +0 -69
- package/dist/clients/dispatch/runners/python-slop.js +0 -106
- package/dist/clients/dispatch/runners/ts-lsp.js +0 -109
- package/dist/clients/runner-tracker.js +0 -153
- package/dist/clients/ts-service.js +0 -130
- package/dist/clients/type-coverage-client.js +0 -128
- package/dist/clients/typescript-client.js +0 -509
- package/dist/commands/booboo.js +0 -1412
- package/rules/python-slop-rules/.sgconfig.yml +0 -4
- package/rules/python-slop-rules/rules/slop-rules.yml +0 -647
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { extractFactsFromTree, firstChildOfType, walk, } from "./tree-sitter-facts.js";
|
|
2
2
|
const BOUNDARY_PREFIXES = [
|
|
3
3
|
"fetch",
|
|
4
4
|
"fs.",
|
|
@@ -9,139 +9,177 @@ const BOUNDARY_PREFIXES = [
|
|
|
9
9
|
"req.",
|
|
10
10
|
"res.",
|
|
11
11
|
];
|
|
12
|
+
const FUNCTION_TYPES = new Set([
|
|
13
|
+
"function_declaration",
|
|
14
|
+
"method_definition",
|
|
15
|
+
"function_expression",
|
|
16
|
+
"arrow_function",
|
|
17
|
+
]);
|
|
18
|
+
// Decision points for McCabe complexity (matches the old ts.SyntaxKind set).
|
|
19
|
+
const COMPLEXITY_TYPES = new Set([
|
|
20
|
+
"if_statement",
|
|
21
|
+
"for_statement",
|
|
22
|
+
"for_in_statement", // for…of and for…in both parse to for_in_statement
|
|
23
|
+
"while_statement",
|
|
24
|
+
"do_statement",
|
|
25
|
+
"switch_case", // `case` only — `default` (switch_default) is not counted
|
|
26
|
+
"catch_clause",
|
|
27
|
+
"ternary_expression",
|
|
28
|
+
]);
|
|
29
|
+
// Control structures that increase nesting depth (matches the old set).
|
|
30
|
+
const NESTING_TYPES = new Set([
|
|
31
|
+
"if_statement",
|
|
32
|
+
"for_statement",
|
|
33
|
+
"for_in_statement",
|
|
34
|
+
"while_statement",
|
|
35
|
+
"do_statement",
|
|
36
|
+
"switch_statement",
|
|
37
|
+
"try_statement",
|
|
38
|
+
]);
|
|
39
|
+
const LOGICAL_OPERATORS = new Set(["&&", "||", "??"]);
|
|
40
|
+
/** Named children excluding comments — i.e. the "real" statements/args/expressions. */
|
|
41
|
+
function namedChildren(node) {
|
|
42
|
+
return (node.children ?? []).filter((c) => c && c.isNamed && c.type !== "comment");
|
|
43
|
+
}
|
|
44
|
+
/** First named, non-comment child (e.g. a return statement's returned expression). */
|
|
45
|
+
function firstNamedChild(node) {
|
|
46
|
+
return namedChildren(node)[0];
|
|
47
|
+
}
|
|
48
|
+
function getBody(node) {
|
|
49
|
+
// Only block-bodied functions get a summary (expression-bodied arrows have no
|
|
50
|
+
// statement_block — matching the old `!ts.isBlock(body)` skip).
|
|
51
|
+
return firstChildOfType(node, "statement_block");
|
|
52
|
+
}
|
|
53
|
+
function getParameters(node) {
|
|
54
|
+
const fp = firstChildOfType(node, "formal_parameters");
|
|
55
|
+
if (!fp)
|
|
56
|
+
return [];
|
|
57
|
+
return (fp.children ?? []).filter((c) => c &&
|
|
58
|
+
(c.type === "required_parameter" ||
|
|
59
|
+
c.type === "optional_parameter" ||
|
|
60
|
+
c.type === "rest_pattern"));
|
|
61
|
+
}
|
|
62
|
+
function parameterName(param) {
|
|
63
|
+
return firstNamedChild(param)?.text ?? "";
|
|
64
|
+
}
|
|
12
65
|
function getFunctionName(node) {
|
|
13
|
-
if (
|
|
14
|
-
return node
|
|
66
|
+
if (node.type === "function_declaration") {
|
|
67
|
+
return firstChildOfType(node, "identifier")?.text ?? "<anonymous>";
|
|
15
68
|
}
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
69
|
+
if (node.type === "method_definition") {
|
|
70
|
+
// The name is the child just before formal_parameters (property_identifier /
|
|
71
|
+
// private / computed / string / number); skip async/get/set modifiers.
|
|
72
|
+
const kids = node.children ?? [];
|
|
73
|
+
const paramsIdx = kids.findIndex((c) => c?.type === "formal_parameters");
|
|
74
|
+
for (let i = paramsIdx - 1; i >= 0; i -= 1) {
|
|
75
|
+
const t = kids[i]?.type;
|
|
76
|
+
if (t === "property_identifier" ||
|
|
77
|
+
t === "private_property_identifier" ||
|
|
78
|
+
t === "computed_property_name" ||
|
|
79
|
+
t === "string" ||
|
|
80
|
+
t === "number") {
|
|
81
|
+
return kids[i].text;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return "<anonymous>";
|
|
20
85
|
}
|
|
21
|
-
if (
|
|
86
|
+
if (node.type === "arrow_function" || node.type === "function_expression") {
|
|
87
|
+
// Name comes from the binding site (like the old parent-based lookup):
|
|
88
|
+
// `const f = () => …` / `{ prop: () => … }`.
|
|
22
89
|
const parent = node.parent;
|
|
23
|
-
if (
|
|
24
|
-
|
|
90
|
+
if (parent?.type === "variable_declarator") {
|
|
91
|
+
const id = firstChildOfType(parent, "identifier");
|
|
92
|
+
if (id)
|
|
93
|
+
return id.text;
|
|
25
94
|
}
|
|
26
|
-
if (
|
|
27
|
-
|
|
95
|
+
else if (parent?.type === "pair") {
|
|
96
|
+
const key = (parent.children ?? [])[0];
|
|
97
|
+
if (key)
|
|
98
|
+
return key.text;
|
|
28
99
|
}
|
|
29
100
|
return "<anonymous>";
|
|
30
101
|
}
|
|
31
102
|
return "<unknown>";
|
|
32
103
|
}
|
|
33
104
|
function isCallPassThrough(stmt, paramNames) {
|
|
34
|
-
if (
|
|
105
|
+
if (stmt.type !== "return_statement")
|
|
35
106
|
return { pass: false };
|
|
36
|
-
const expr = stmt
|
|
37
|
-
if (!
|
|
107
|
+
const expr = firstNamedChild(stmt);
|
|
108
|
+
if (!expr || expr.type !== "call_expression")
|
|
38
109
|
return { pass: false };
|
|
39
|
-
const
|
|
110
|
+
const argsNode = firstChildOfType(expr, "arguments");
|
|
111
|
+
const args = argsNode ? namedChildren(argsNode).map((a) => a.text) : [];
|
|
40
112
|
if (args.length !== paramNames.length)
|
|
41
113
|
return { pass: false };
|
|
42
114
|
for (let i = 0; i < args.length; i += 1) {
|
|
43
115
|
if (args[i] !== paramNames[i])
|
|
44
116
|
return { pass: false };
|
|
45
117
|
}
|
|
46
|
-
return { pass: true, target: expr.
|
|
118
|
+
return { pass: true, target: (expr.children ?? [])[0]?.text };
|
|
47
119
|
}
|
|
48
120
|
function calcCyclomaticComplexity(body) {
|
|
49
121
|
let cc = 1;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
case ts.SyntaxKind.WhileStatement:
|
|
57
|
-
case ts.SyntaxKind.DoStatement:
|
|
58
|
-
case ts.SyntaxKind.CaseClause:
|
|
59
|
-
case ts.SyntaxKind.CatchClause:
|
|
60
|
-
case ts.SyntaxKind.ConditionalExpression:
|
|
122
|
+
walk(body, (node) => {
|
|
123
|
+
if (COMPLEXITY_TYPES.has(node.type)) {
|
|
124
|
+
cc++;
|
|
125
|
+
}
|
|
126
|
+
else if (node.type === "binary_expression") {
|
|
127
|
+
if ((node.children ?? []).some((c) => LOGICAL_OPERATORS.has(c?.type))) {
|
|
61
128
|
cc++;
|
|
62
|
-
break;
|
|
63
|
-
case ts.SyntaxKind.BinaryExpression: {
|
|
64
|
-
const op = node.operatorToken.kind;
|
|
65
|
-
if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
66
|
-
op === ts.SyntaxKind.BarBarToken ||
|
|
67
|
-
op === ts.SyntaxKind.QuestionQuestionToken)
|
|
68
|
-
cc++;
|
|
69
|
-
break;
|
|
70
129
|
}
|
|
71
130
|
}
|
|
72
|
-
|
|
73
|
-
};
|
|
74
|
-
walk(body);
|
|
131
|
+
});
|
|
75
132
|
return cc;
|
|
76
133
|
}
|
|
77
134
|
function calcMaxNestingDepth(body) {
|
|
78
135
|
let maxDepth = 0;
|
|
79
|
-
const
|
|
80
|
-
switch (node.kind) {
|
|
81
|
-
case ts.SyntaxKind.IfStatement:
|
|
82
|
-
case ts.SyntaxKind.ForStatement:
|
|
83
|
-
case ts.SyntaxKind.ForInStatement:
|
|
84
|
-
case ts.SyntaxKind.ForOfStatement:
|
|
85
|
-
case ts.SyntaxKind.WhileStatement:
|
|
86
|
-
case ts.SyntaxKind.DoStatement:
|
|
87
|
-
case ts.SyntaxKind.SwitchStatement:
|
|
88
|
-
case ts.SyntaxKind.TryStatement:
|
|
89
|
-
return true;
|
|
90
|
-
default:
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
const walk = (node, depth) => {
|
|
136
|
+
const walkDepth = (node, depth) => {
|
|
95
137
|
if (depth > maxDepth)
|
|
96
138
|
maxDepth = depth;
|
|
97
|
-
const next =
|
|
98
|
-
|
|
139
|
+
const next = NESTING_TYPES.has(node.type) ? depth + 1 : depth;
|
|
140
|
+
for (const child of node.children ?? []) {
|
|
141
|
+
if (child)
|
|
142
|
+
walkDepth(child, next);
|
|
143
|
+
}
|
|
99
144
|
};
|
|
100
|
-
|
|
145
|
+
// Start at the body's children at depth 0 (the body block itself isn't counted).
|
|
146
|
+
for (const child of body.children ?? []) {
|
|
147
|
+
if (child)
|
|
148
|
+
walkDepth(child, 0);
|
|
149
|
+
}
|
|
101
150
|
return maxDepth;
|
|
102
151
|
}
|
|
103
152
|
function collectOutgoingCalls(body) {
|
|
104
153
|
const calls = new Set();
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
const callee = node.
|
|
154
|
+
walk(body, (node) => {
|
|
155
|
+
if (node.type === "call_expression") {
|
|
156
|
+
const callee = (node.children ?? [])[0]?.text ?? "";
|
|
108
157
|
if (callee.length < 80)
|
|
109
158
|
calls.add(callee);
|
|
110
159
|
}
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
walk(body);
|
|
160
|
+
});
|
|
114
161
|
return [...calls];
|
|
115
162
|
}
|
|
116
163
|
function hasAwaitInNode(node) {
|
|
117
164
|
let found = false;
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
return;
|
|
121
|
-
if (ts.isAwaitExpression(n)) {
|
|
165
|
+
walk(node, (n) => {
|
|
166
|
+
if (n.type === "await_expression")
|
|
122
167
|
found = true;
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
ts.forEachChild(n, walk);
|
|
126
|
-
};
|
|
127
|
-
walk(node);
|
|
168
|
+
});
|
|
128
169
|
return found;
|
|
129
170
|
}
|
|
130
171
|
function hasReturnAwaitCall(node) {
|
|
131
172
|
let found = false;
|
|
132
|
-
|
|
133
|
-
if (
|
|
173
|
+
walk(node, (n) => {
|
|
174
|
+
if (n.type !== "return_statement")
|
|
134
175
|
return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
ts.isAwaitExpression(n.expression) &&
|
|
138
|
-
ts.isCallExpression(n.expression.expression)) {
|
|
139
|
-
found = true;
|
|
176
|
+
const ret = firstNamedChild(n);
|
|
177
|
+
if (ret?.type !== "await_expression")
|
|
140
178
|
return;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
179
|
+
const awaited = firstNamedChild(ret);
|
|
180
|
+
if (awaited?.type === "call_expression")
|
|
181
|
+
found = true;
|
|
182
|
+
});
|
|
145
183
|
return found;
|
|
146
184
|
}
|
|
147
185
|
export const functionFactProvider = {
|
|
@@ -151,54 +189,45 @@ export const functionFactProvider = {
|
|
|
151
189
|
appliesTo(ctx) {
|
|
152
190
|
return /\.tsx?$/.test(ctx.filePath);
|
|
153
191
|
},
|
|
154
|
-
run(ctx, store) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
async run(ctx, store) {
|
|
193
|
+
await extractFactsFromTree(ctx, store, { "file.functionSummaries": [] }, (root) => {
|
|
194
|
+
const summaries = [];
|
|
195
|
+
const addSummary = (node) => {
|
|
196
|
+
const body = getBody(node);
|
|
197
|
+
if (!body)
|
|
198
|
+
return;
|
|
199
|
+
const params = getParameters(node);
|
|
200
|
+
const paramNames = params.map(parameterName);
|
|
201
|
+
const statements = namedChildren(body);
|
|
202
|
+
const statementCount = statements.length;
|
|
203
|
+
const passThrough = statementCount === 1
|
|
204
|
+
? isCallPassThrough(statements[0], paramNames)
|
|
205
|
+
: { pass: false };
|
|
206
|
+
const target = passThrough.target ?? "";
|
|
207
|
+
const lowerTarget = target.toLowerCase();
|
|
208
|
+
const isBoundaryWrapper = BOUNDARY_PREFIXES.some((prefix) => lowerTarget.startsWith(prefix));
|
|
209
|
+
summaries.push({
|
|
210
|
+
name: getFunctionName(node),
|
|
211
|
+
line: node.startPosition.row + 1,
|
|
212
|
+
column: node.startPosition.column + 1,
|
|
213
|
+
isAsync: Boolean(firstChildOfType(node, "async")),
|
|
214
|
+
hasAwait: hasAwaitInNode(body),
|
|
215
|
+
hasReturnAwaitCall: hasReturnAwaitCall(body),
|
|
216
|
+
statementCount,
|
|
217
|
+
parameterCount: params.length,
|
|
218
|
+
isPassThroughWrapper: passThrough.pass,
|
|
219
|
+
passThroughTarget: passThrough.target,
|
|
220
|
+
isBoundaryWrapper,
|
|
221
|
+
cyclomaticComplexity: calcCyclomaticComplexity(body),
|
|
222
|
+
maxNestingDepth: calcMaxNestingDepth(body),
|
|
223
|
+
outgoingCalls: collectOutgoingCalls(body),
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
walk(root, (node) => {
|
|
227
|
+
if (FUNCTION_TYPES.has(node.type))
|
|
228
|
+
addSummary(node);
|
|
190
229
|
});
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (ts.isFunctionDeclaration(node) ||
|
|
194
|
-
ts.isMethodDeclaration(node) ||
|
|
195
|
-
ts.isFunctionExpression(node) ||
|
|
196
|
-
ts.isArrowFunction(node)) {
|
|
197
|
-
addSummary(node);
|
|
198
|
-
}
|
|
199
|
-
ts.forEachChild(node, visit);
|
|
200
|
-
};
|
|
201
|
-
visit(sourceFile);
|
|
202
|
-
store.setFileFact(ctx.filePath, "file.functionSummaries", summaries);
|
|
230
|
+
return { "file.functionSummaries": summaries };
|
|
231
|
+
});
|
|
203
232
|
},
|
|
204
233
|
};
|