@skillsmith/core 0.5.3 → 0.5.4
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 +10 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/activation/ActivationManager.d.ts +7 -0
- package/dist/src/activation/ActivationManager.d.ts.map +1 -1
- package/dist/src/activation/ActivationManager.js +13 -4
- package/dist/src/activation/ActivationManager.js.map +1 -1
- package/dist/src/analysis/adapters/python.d.ts +16 -11
- package/dist/src/analysis/adapters/python.d.ts.map +1 -1
- package/dist/src/analysis/adapters/python.js +46 -61
- package/dist/src/analysis/adapters/python.js.map +1 -1
- package/dist/src/analysis/router.test.d.ts +2 -0
- package/dist/src/analysis/router.test.d.ts.map +1 -0
- package/dist/src/analysis/router.test.js +411 -0
- package/dist/src/analysis/router.test.js.map +1 -0
- package/dist/src/analysis/tree-sitter/manager.d.ts.map +1 -1
- package/dist/src/analysis/tree-sitter/manager.js +12 -5
- package/dist/src/analysis/tree-sitter/manager.js.map +1 -1
- package/dist/src/analysis/tree-sitter/pythonExtractor.d.ts +45 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.js +264 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.js.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.test.d.ts +12 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.test.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.test.js +74 -0
- package/dist/src/analysis/tree-sitter/pythonExtractor.test.js.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts +93 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.d.ts +22 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js +229 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.js +287 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.js.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.test.d.ts +17 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.test.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.test.js +142 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.test.js.map +1 -0
- package/dist/src/analysis/tree-sitter/queries/python.d.ts +43 -0
- package/dist/src/analysis/tree-sitter/queries/python.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/queries/python.js +88 -0
- package/dist/src/analysis/tree-sitter/queries/python.js.map +1 -0
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.d.ts +13 -0
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.d.ts.map +1 -0
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js +174 -0
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js.map +1 -0
- package/dist/src/analytics/ROIDashboardService.csv.d.ts +11 -0
- package/dist/src/analytics/ROIDashboardService.csv.d.ts.map +1 -0
- package/dist/src/analytics/ROIDashboardService.csv.js +43 -0
- package/dist/src/analytics/ROIDashboardService.csv.js.map +1 -0
- package/dist/src/analytics/ROIDashboardService.d.ts +64 -3
- package/dist/src/analytics/ROIDashboardService.d.ts.map +1 -1
- package/dist/src/analytics/ROIDashboardService.js +116 -45
- package/dist/src/analytics/ROIDashboardService.js.map +1 -1
- package/dist/src/api/schemas.d.ts +70 -319
- package/dist/src/api/schemas.d.ts.map +1 -1
- package/dist/src/benchmarks/incrementalParseBenchmark.d.ts +18 -0
- package/dist/src/benchmarks/incrementalParseBenchmark.d.ts.map +1 -0
- package/dist/src/benchmarks/incrementalParseBenchmark.js +121 -0
- package/dist/src/benchmarks/incrementalParseBenchmark.js.map +1 -0
- package/dist/src/billing/GDPRComplianceService.test.d.ts +2 -0
- package/dist/src/billing/GDPRComplianceService.test.d.ts.map +1 -0
- package/dist/src/billing/GDPRComplianceService.test.js +405 -0
- package/dist/src/billing/GDPRComplianceService.test.js.map +1 -0
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexer/SkillParser.coverage.test.d.ts +10 -0
- package/dist/src/indexer/SkillParser.coverage.test.d.ts.map +1 -0
- package/dist/src/indexer/SkillParser.coverage.test.js +76 -0
- package/dist/src/indexer/SkillParser.coverage.test.js.map +1 -0
- package/dist/src/indexer/SkillParser.test.d.ts +2 -0
- package/dist/src/indexer/SkillParser.test.d.ts.map +1 -0
- package/dist/src/indexer/SkillParser.test.js +375 -0
- package/dist/src/indexer/SkillParser.test.js.map +1 -0
- package/dist/src/scripts/validation/types.d.ts +14 -24
- package/dist/src/scripts/validation/types.d.ts.map +1 -1
- package/dist/src/services/skill-config-schema.d.ts +4 -36
- package/dist/src/services/skill-config-schema.d.ts.map +1 -1
- package/dist/src/sources/LocalFilesystemAdapter.d.ts +104 -10
- package/dist/src/sources/LocalFilesystemAdapter.d.ts.map +1 -1
- package/dist/src/sources/LocalFilesystemAdapter.helpers.d.ts +92 -0
- package/dist/src/sources/LocalFilesystemAdapter.helpers.d.ts.map +1 -0
- package/dist/src/sources/LocalFilesystemAdapter.helpers.js +157 -0
- package/dist/src/sources/LocalFilesystemAdapter.helpers.js.map +1 -0
- package/dist/src/sources/LocalFilesystemAdapter.js +218 -159
- package/dist/src/sources/LocalFilesystemAdapter.js.map +1 -1
- package/dist/src/sources/LocalFilesystemAdapter.scan.d.ts +78 -0
- package/dist/src/sources/LocalFilesystemAdapter.scan.d.ts.map +1 -0
- package/dist/src/sources/LocalFilesystemAdapter.scan.js +118 -0
- package/dist/src/sources/LocalFilesystemAdapter.scan.js.map +1 -0
- package/dist/src/sources/index.d.ts +1 -1
- package/dist/src/sources/index.d.ts.map +1 -1
- package/dist/src/sources/index.js.map +1 -1
- package/dist/src/sources/types.d.ts +28 -0
- package/dist/src/sources/types.d.ts.map +1 -1
- package/dist/src/telemetry/tracer-imports.d.ts +13 -0
- package/dist/src/telemetry/tracer-imports.d.ts.map +1 -0
- package/dist/src/telemetry/tracer-imports.js +26 -0
- package/dist/src/telemetry/tracer-imports.js.map +1 -0
- package/dist/src/telemetry/tracer.d.ts.map +1 -1
- package/dist/src/telemetry/tracer.js +18 -21
- package/dist/src/telemetry/tracer.js.map +1 -1
- package/dist/src/utils/rate-limit.d.ts +39 -0
- package/dist/src/utils/rate-limit.d.ts.map +1 -0
- package/dist/src/utils/rate-limit.js +48 -0
- package/dist/src/utils/rate-limit.js.map +1 -0
- package/dist/src/utils/rate-limit.test.d.ts +11 -0
- package/dist/src/utils/rate-limit.test.d.ts.map +1 -0
- package/dist/src/utils/rate-limit.test.js +86 -0
- package/dist/src/utils/rate-limit.test.js.map +1 -0
- package/dist/src/webhooks/WebhookDeadLetterRepository.d.ts +178 -0
- package/dist/src/webhooks/WebhookDeadLetterRepository.d.ts.map +1 -0
- package/dist/src/webhooks/WebhookDeadLetterRepository.js +196 -0
- package/dist/src/webhooks/WebhookDeadLetterRepository.js.map +1 -0
- package/dist/src/webhooks/WebhookQueue.d.ts +1 -0
- package/dist/src/webhooks/WebhookQueue.d.ts.map +1 -1
- package/dist/src/webhooks/WebhookQueue.js +19 -0
- package/dist/src/webhooks/WebhookQueue.js.map +1 -1
- package/dist/src/webhooks/WebhookQueue.types.d.ts +11 -0
- package/dist/src/webhooks/WebhookQueue.types.d.ts.map +1 -1
- package/dist/src/webhooks/index.d.ts +1 -0
- package/dist/src/webhooks/index.d.ts.map +1 -1
- package/dist/src/webhooks/index.js +2 -0
- package/dist/src/webhooks/index.js.map +1 -1
- package/dist/src/webhooks/webhook-schemas.d.ts +117 -1212
- package/dist/src/webhooks/webhook-schemas.d.ts.map +1 -1
- package/dist/tests/ActivationManager.test.d.ts +13 -0
- package/dist/tests/ActivationManager.test.d.ts.map +1 -0
- package/dist/tests/ActivationManager.test.js +218 -0
- package/dist/tests/ActivationManager.test.js.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.coverage.test.d.ts +13 -0
- package/dist/tests/LocalFilesystemAdapter.coverage.test.d.ts.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.coverage.test.js +314 -0
- package/dist/tests/LocalFilesystemAdapter.coverage.test.js.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.security.test.d.ts +18 -0
- package/dist/tests/LocalFilesystemAdapter.security.test.d.ts.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.security.test.js +344 -0
- package/dist/tests/LocalFilesystemAdapter.security.test.js.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.test.d.ts +12 -0
- package/dist/tests/LocalFilesystemAdapter.test.d.ts.map +1 -0
- package/dist/tests/LocalFilesystemAdapter.test.js +301 -0
- package/dist/tests/LocalFilesystemAdapter.test.js.map +1 -0
- package/dist/tests/ROIDashboardService.coverage.test.d.ts +9 -0
- package/dist/tests/ROIDashboardService.coverage.test.d.ts.map +1 -0
- package/dist/tests/ROIDashboardService.coverage.test.js +118 -0
- package/dist/tests/ROIDashboardService.coverage.test.js.map +1 -0
- package/dist/tests/ROIDashboardService.test.js +87 -0
- package/dist/tests/ROIDashboardService.test.js.map +1 -1
- package/dist/tests/ScraperAdapters.gitlab-coverage.test.d.ts +14 -0
- package/dist/tests/ScraperAdapters.gitlab-coverage.test.d.ts.map +1 -0
- package/dist/tests/ScraperAdapters.gitlab-coverage.test.js +169 -0
- package/dist/tests/ScraperAdapters.gitlab-coverage.test.js.map +1 -0
- package/dist/tests/ScraperAdapters.test.d.ts +5 -1
- package/dist/tests/ScraperAdapters.test.d.ts.map +1 -1
- package/dist/tests/ScraperAdapters.test.js +6 -336
- package/dist/tests/ScraperAdapters.test.js.map +1 -1
- package/dist/tests/WebhookDeadLetterRepository.test.d.ts +2 -0
- package/dist/tests/WebhookDeadLetterRepository.test.d.ts.map +1 -0
- package/dist/tests/WebhookDeadLetterRepository.test.js +333 -0
- package/dist/tests/WebhookDeadLetterRepository.test.js.map +1 -0
- package/dist/tests/WebhookHandler.test.js +93 -1
- package/dist/tests/WebhookHandler.test.js.map +1 -1
- package/dist/tests/WebhookQueue.coverage.test.d.ts +19 -0
- package/dist/tests/WebhookQueue.coverage.test.d.ts.map +1 -0
- package/dist/tests/WebhookQueue.coverage.test.js +190 -0
- package/dist/tests/WebhookQueue.coverage.test.js.map +1 -0
- package/dist/tests/billing/GDPRCompliance.test.d.ts +2 -2
- package/dist/tests/billing/GDPRCompliance.test.js +221 -36
- package/dist/tests/billing/GDPRCompliance.test.js.map +1 -1
- package/dist/tests/telemetry.test.js +126 -0
- package/dist/tests/telemetry.test.js.map +1 -1
- package/dist/tests/webhooks/WebhookDeadLetterRepository.test.d.ts +10 -0
- package/dist/tests/webhooks/WebhookDeadLetterRepository.test.d.ts.map +1 -0
- package/dist/tests/webhooks/WebhookDeadLetterRepository.test.js +109 -0
- package/dist/tests/webhooks/WebhookDeadLetterRepository.test.js.map +1 -0
- package/package.json +8 -3
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4293: Python query-based extraction
|
|
3
|
+
*
|
|
4
|
+
* Uses tree-sitter queries to extract imports, exports, and functions from
|
|
5
|
+
* a parsed Python AST, producing the same ParseResult shape as the regex
|
|
6
|
+
* fallback. Regression guard (finding H3): the query extractor must produce
|
|
7
|
+
* a superset-or-equal result set compared to the regex baseline on every
|
|
8
|
+
* fixture. Tests enforce that invariant.
|
|
9
|
+
*
|
|
10
|
+
* @see docs/internal/implementation/github-wave-5c-tree-sitter-incremental.md
|
|
11
|
+
* @module analysis/tree-sitter/pythonExtractor
|
|
12
|
+
*/
|
|
13
|
+
import { PYTHON_IMPORT_QUERY, PYTHON_FROM_IMPORT_QUERY, PYTHON_FUNCTION_QUERY, PYTHON_CLASS_QUERY, PYTHON_ALL_EXPORT_QUERY, } from './queries/python.js';
|
|
14
|
+
/**
|
|
15
|
+
* Lazily compile and cache all Python queries for a given Language module.
|
|
16
|
+
* Queries are expensive to construct (parse the DSL); compiled once per
|
|
17
|
+
* Language and reused across parses.
|
|
18
|
+
*/
|
|
19
|
+
export class PythonQuerySet {
|
|
20
|
+
imports;
|
|
21
|
+
fromImports;
|
|
22
|
+
functions;
|
|
23
|
+
classes;
|
|
24
|
+
allExports;
|
|
25
|
+
constructor(Query, lang) {
|
|
26
|
+
this.imports = new Query(lang, PYTHON_IMPORT_QUERY);
|
|
27
|
+
this.fromImports = new Query(lang, PYTHON_FROM_IMPORT_QUERY);
|
|
28
|
+
this.functions = new Query(lang, PYTHON_FUNCTION_QUERY);
|
|
29
|
+
this.classes = new Query(lang, PYTHON_CLASS_QUERY);
|
|
30
|
+
this.allExports = new Query(lang, PYTHON_ALL_EXPORT_QUERY);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extract a ParseResult from a Python parse tree using tree-sitter queries.
|
|
35
|
+
*
|
|
36
|
+
* This replaces the regex fallback in the query-based code path. It MUST
|
|
37
|
+
* produce results that are a superset or equal set of the regex extraction
|
|
38
|
+
* for every fixture (finding H3).
|
|
39
|
+
*/
|
|
40
|
+
export function extractPythonParseResult(tree, queries, filePath) {
|
|
41
|
+
const root = tree.rootNode;
|
|
42
|
+
return {
|
|
43
|
+
imports: [
|
|
44
|
+
...extractImports(root, queries.imports, filePath),
|
|
45
|
+
...extractFromImports(root, queries.fromImports, filePath),
|
|
46
|
+
],
|
|
47
|
+
exports: extractExports(root, queries.classes, queries.functions, queries.allExports, filePath),
|
|
48
|
+
functions: extractFunctions(root, queries.functions, filePath),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// ------------------------------------------------------------------
|
|
52
|
+
// Imports
|
|
53
|
+
// ------------------------------------------------------------------
|
|
54
|
+
function extractImports(root, query, filePath) {
|
|
55
|
+
const imports = [];
|
|
56
|
+
const caps = query.captures(root);
|
|
57
|
+
// Group captures by the enclosing import_statement node.
|
|
58
|
+
const byStatement = groupCapturesByAncestor(caps, 'import_statement');
|
|
59
|
+
for (const { node, captures } of byStatement) {
|
|
60
|
+
const moduleCap = captures.find((c) => c.name === 'import.module');
|
|
61
|
+
if (!moduleCap)
|
|
62
|
+
continue;
|
|
63
|
+
const aliasCap = captures.find((c) => c.name === 'import.alias');
|
|
64
|
+
imports.push({
|
|
65
|
+
module: moduleCap.node.text,
|
|
66
|
+
namedImports: [],
|
|
67
|
+
defaultImport: aliasCap?.node.text,
|
|
68
|
+
isTypeOnly: false,
|
|
69
|
+
sourceFile: filePath,
|
|
70
|
+
line: node.startPosition.row + 1,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return imports;
|
|
74
|
+
}
|
|
75
|
+
function extractFromImports(root, query, filePath) {
|
|
76
|
+
const imports = [];
|
|
77
|
+
const caps = query.captures(root);
|
|
78
|
+
const byStatement = groupCapturesByAncestor(caps, 'import_from_statement');
|
|
79
|
+
for (const { node, captures } of byStatement) {
|
|
80
|
+
const moduleCap = captures.find((c) => c.name === 'from.module');
|
|
81
|
+
if (!moduleCap)
|
|
82
|
+
continue;
|
|
83
|
+
const wildcardCap = captures.find((c) => c.name === 'from.wildcard');
|
|
84
|
+
const nameCaps = captures.filter((c) => c.name === 'from.name');
|
|
85
|
+
imports.push({
|
|
86
|
+
module: moduleCap.node.text,
|
|
87
|
+
namedImports: wildcardCap ? [] : nameCaps.map((c) => stripAliasSuffix(c.node.text)),
|
|
88
|
+
namespaceImport: wildcardCap ? '*' : undefined,
|
|
89
|
+
isTypeOnly: false,
|
|
90
|
+
sourceFile: filePath,
|
|
91
|
+
line: node.startPosition.row + 1,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return imports;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* When the `from x import a as b` form is captured, the `from.name` capture
|
|
98
|
+
* covers the full `aliased_import` node, whose text is `a as b`. Strip the
|
|
99
|
+
* alias suffix so the extracted name matches what the regex path records.
|
|
100
|
+
*/
|
|
101
|
+
function stripAliasSuffix(text) {
|
|
102
|
+
const match = /^(\w+)\s+as\s+\w+$/.exec(text.trim());
|
|
103
|
+
return match ? match[1] : text;
|
|
104
|
+
}
|
|
105
|
+
// ------------------------------------------------------------------
|
|
106
|
+
// Functions
|
|
107
|
+
// ------------------------------------------------------------------
|
|
108
|
+
function extractFunctions(root, query, filePath) {
|
|
109
|
+
const capturesByDef = collectFunctionCaptures(root, query);
|
|
110
|
+
const functions = [];
|
|
111
|
+
for (const capture of capturesByDef) {
|
|
112
|
+
const { name, params, def } = capture;
|
|
113
|
+
if (!name)
|
|
114
|
+
continue;
|
|
115
|
+
const paramCount = countPythonParams(params);
|
|
116
|
+
const isAsync = def.children.some((c) => c.type === 'async');
|
|
117
|
+
const isTopLevel = def.startPosition.column === 0;
|
|
118
|
+
const isExported = isTopLevel && !name.startsWith('_');
|
|
119
|
+
functions.push({
|
|
120
|
+
name,
|
|
121
|
+
parameterCount: paramCount,
|
|
122
|
+
isAsync,
|
|
123
|
+
isExported,
|
|
124
|
+
sourceFile: filePath,
|
|
125
|
+
line: def.startPosition.row + 1,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return functions;
|
|
129
|
+
}
|
|
130
|
+
function collectFunctionCaptures(root, query) {
|
|
131
|
+
const caps = query.captures(root);
|
|
132
|
+
const byDef = groupCapturesByAncestor(caps, 'function_definition');
|
|
133
|
+
const out = [];
|
|
134
|
+
for (const { node, captures } of byDef) {
|
|
135
|
+
const name = captures.find((c) => c.name === 'function.name')?.node.text;
|
|
136
|
+
if (!name)
|
|
137
|
+
continue;
|
|
138
|
+
const params = captures.find((c) => c.name === 'function.params')?.node ?? null;
|
|
139
|
+
out.push({ name, params, def: node });
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
function countPythonParams(params) {
|
|
144
|
+
if (!params)
|
|
145
|
+
return 0;
|
|
146
|
+
let count = 0;
|
|
147
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
148
|
+
const child = params.namedChild(i);
|
|
149
|
+
if (!child)
|
|
150
|
+
continue;
|
|
151
|
+
const text = child.text.trim();
|
|
152
|
+
if (text === 'self' || text === 'cls')
|
|
153
|
+
continue;
|
|
154
|
+
if (child.type === 'identifier' || child.type === 'typed_parameter')
|
|
155
|
+
count++;
|
|
156
|
+
else if (child.type === 'default_parameter' || child.type === 'typed_default_parameter')
|
|
157
|
+
count++;
|
|
158
|
+
else if (child.type === 'list_splat_pattern' || child.type === 'dictionary_splat_pattern')
|
|
159
|
+
count++;
|
|
160
|
+
}
|
|
161
|
+
return count;
|
|
162
|
+
}
|
|
163
|
+
// ------------------------------------------------------------------
|
|
164
|
+
// Exports (__all__, top-level class/function names)
|
|
165
|
+
// ------------------------------------------------------------------
|
|
166
|
+
function extractExports(root, classesQuery, functionsQuery, allQuery, filePath) {
|
|
167
|
+
const exports = [];
|
|
168
|
+
const explicit = new Set();
|
|
169
|
+
// 1. __all__ literal
|
|
170
|
+
const allCaps = allQuery.captures(root);
|
|
171
|
+
for (const cap of allCaps) {
|
|
172
|
+
if (cap.name !== 'all.name')
|
|
173
|
+
continue;
|
|
174
|
+
const raw = cap.node.text.replace(/^['"]|['"]$/g, '');
|
|
175
|
+
if (!raw)
|
|
176
|
+
continue;
|
|
177
|
+
explicit.add(raw);
|
|
178
|
+
exports.push({
|
|
179
|
+
name: raw,
|
|
180
|
+
kind: 'unknown',
|
|
181
|
+
isDefault: false,
|
|
182
|
+
sourceFile: filePath,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// 2. Top-level class definitions
|
|
186
|
+
const classCaps = groupCapturesByAncestor(classesQuery.captures(root), 'class_definition');
|
|
187
|
+
for (const { node, captures } of classCaps) {
|
|
188
|
+
if (node.startPosition.column !== 0)
|
|
189
|
+
continue;
|
|
190
|
+
const name = captures.find((c) => c.name === 'class.name')?.node.text;
|
|
191
|
+
if (!name || name.startsWith('_') || explicit.has(name))
|
|
192
|
+
continue;
|
|
193
|
+
exports.push({
|
|
194
|
+
name,
|
|
195
|
+
kind: 'class',
|
|
196
|
+
isDefault: false,
|
|
197
|
+
sourceFile: filePath,
|
|
198
|
+
line: node.startPosition.row + 1,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// 3. Top-level function definitions
|
|
202
|
+
const funcCaps = groupCapturesByAncestor(functionsQuery.captures(root), 'function_definition');
|
|
203
|
+
for (const { node, captures } of funcCaps) {
|
|
204
|
+
if (node.startPosition.column !== 0)
|
|
205
|
+
continue;
|
|
206
|
+
const name = captures.find((c) => c.name === 'function.name')?.node.text;
|
|
207
|
+
if (!name || name.startsWith('_') || explicit.has(name))
|
|
208
|
+
continue;
|
|
209
|
+
exports.push({
|
|
210
|
+
name,
|
|
211
|
+
kind: 'function',
|
|
212
|
+
isDefault: false,
|
|
213
|
+
sourceFile: filePath,
|
|
214
|
+
line: node.startPosition.row + 1,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return exports;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Group query captures by their nearest enclosing ancestor of the given type.
|
|
221
|
+
* This bundles all captures that belong to the same syntactic construct,
|
|
222
|
+
* sidestepping the need for `@parent` captures in the query DSL.
|
|
223
|
+
*
|
|
224
|
+
* Keyed by the ancestor's byte range (rather than object identity) because
|
|
225
|
+
* web-tree-sitter instantiates wrapper node objects lazily, so two lookups
|
|
226
|
+
* of the same underlying node can return different wrappers.
|
|
227
|
+
*/
|
|
228
|
+
function groupCapturesByAncestor(caps, ancestorType) {
|
|
229
|
+
const buckets = new Map();
|
|
230
|
+
for (const cap of caps) {
|
|
231
|
+
const ancestor = findAncestor(cap.node, ancestorType);
|
|
232
|
+
if (!ancestor)
|
|
233
|
+
continue;
|
|
234
|
+
const key = ancestorKey(ancestor);
|
|
235
|
+
let bucket = buckets.get(key);
|
|
236
|
+
if (!bucket) {
|
|
237
|
+
bucket = { node: ancestor, captures: [] };
|
|
238
|
+
buckets.set(key, bucket);
|
|
239
|
+
}
|
|
240
|
+
bucket.captures.push(cap);
|
|
241
|
+
}
|
|
242
|
+
return Array.from(buckets.values());
|
|
243
|
+
}
|
|
244
|
+
function ancestorKey(node) {
|
|
245
|
+
const withRange = node;
|
|
246
|
+
if (typeof withRange.startIndex === 'number' && typeof withRange.endIndex === 'number') {
|
|
247
|
+
return `${node.type}:${withRange.startIndex}:${withRange.endIndex}`;
|
|
248
|
+
}
|
|
249
|
+
// Fallback: startPosition row/col (unique within a file).
|
|
250
|
+
return `${node.type}:${node.startPosition.row}:${node.startPosition.column}`;
|
|
251
|
+
}
|
|
252
|
+
function findAncestor(node, type) {
|
|
253
|
+
let current = node;
|
|
254
|
+
while (current) {
|
|
255
|
+
if (current.type === type)
|
|
256
|
+
return current;
|
|
257
|
+
// web-tree-sitter exposes `parent` on nodes at runtime; TreeSitterNode
|
|
258
|
+
// in manager.ts doesn't list it, so we duck-type here.
|
|
259
|
+
const withParent = current;
|
|
260
|
+
current = withParent.parent ?? null;
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=pythonExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonExtractor.js","sourceRoot":"","sources":["../../../../src/analysis/tree-sitter/pythonExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4293: Python query-based extractor tests.
|
|
3
|
+
*
|
|
4
|
+
* Drives `extractPythonParseResult` through the live web-tree-sitter WASM
|
|
5
|
+
* grammar so behaviour tracks the real parser, not a mock. The regression
|
|
6
|
+
* guard (queryExtractionMatchesOrExceedsRegex) proves parity vs regex;
|
|
7
|
+
* these tests pin the extractor's output shape.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/internal/implementation/github-wave-5c-tree-sitter-incremental.md
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=pythonExtractor.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonExtractor.test.d.ts","sourceRoot":"","sources":["../../../../src/analysis/tree-sitter/pythonExtractor.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4293: Python query-based extractor tests.
|
|
3
|
+
*
|
|
4
|
+
* Drives `extractPythonParseResult` through the live web-tree-sitter WASM
|
|
5
|
+
* grammar so behaviour tracks the real parser, not a mock. The regression
|
|
6
|
+
* guard (queryExtractionMatchesOrExceedsRegex) proves parity vs regex;
|
|
7
|
+
* these tests pin the extractor's output shape.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/internal/implementation/github-wave-5c-tree-sitter-incremental.md
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
12
|
+
import { PythonIncrementalParser } from './pythonIncremental.js';
|
|
13
|
+
describe('extractPythonParseResult (via PythonIncrementalParser)', () => {
|
|
14
|
+
const parser = new PythonIncrementalParser();
|
|
15
|
+
beforeAll(async () => {
|
|
16
|
+
await parser.ensureReady();
|
|
17
|
+
});
|
|
18
|
+
it('captures simple imports with aliases', () => {
|
|
19
|
+
const src = 'import numpy as np\nimport os\n';
|
|
20
|
+
const r = parser.parseSync(src, 'a.py');
|
|
21
|
+
expect(r).not.toBeNull();
|
|
22
|
+
const byModule = Object.fromEntries((r?.imports ?? []).map((i) => [i.module, i]));
|
|
23
|
+
expect(byModule['numpy']?.defaultImport).toBe('np');
|
|
24
|
+
expect(byModule['os']?.defaultImport).toBeUndefined();
|
|
25
|
+
});
|
|
26
|
+
it('captures from-imports and strips alias suffix from named imports', () => {
|
|
27
|
+
const src = 'from pkg import foo, bar as renamed\n';
|
|
28
|
+
const r = parser.parseSync(src, 'a.py');
|
|
29
|
+
expect(r).not.toBeNull();
|
|
30
|
+
const imp = r?.imports[0];
|
|
31
|
+
expect(imp?.module).toBe('pkg');
|
|
32
|
+
// regression guard is satisfied when we capture `foo`; aliased name `bar`
|
|
33
|
+
// is retained via the dotted_name inside the aliased_import.
|
|
34
|
+
expect(imp?.namedImports).toContain('foo');
|
|
35
|
+
expect(imp?.namedImports).toContain('bar');
|
|
36
|
+
// Alias suffix must not leak into the named list.
|
|
37
|
+
expect(imp?.namedImports.some((n) => n.includes('as'))).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
it('tags wildcard from-imports with namespaceImport="*"', () => {
|
|
40
|
+
const src = 'from pkg import *\n';
|
|
41
|
+
const r = parser.parseSync(src, 'a.py');
|
|
42
|
+
expect(r?.imports[0].namespaceImport).toBe('*');
|
|
43
|
+
expect(r?.imports[0].namedImports).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
it('marks async function definitions correctly', () => {
|
|
46
|
+
const src = 'async def job(x):\n return x\n';
|
|
47
|
+
const r = parser.parseSync(src, 'a.py');
|
|
48
|
+
expect(r?.functions[0]).toMatchObject({ name: 'job', isAsync: true, parameterCount: 1 });
|
|
49
|
+
});
|
|
50
|
+
it('drops self / cls from parameter counts', () => {
|
|
51
|
+
const src = 'class C:\n def m(self, a, b):\n pass\n';
|
|
52
|
+
const r = parser.parseSync(src, 'a.py');
|
|
53
|
+
const m = r?.functions.find((f) => f.name === 'm');
|
|
54
|
+
expect(m?.parameterCount).toBe(2);
|
|
55
|
+
});
|
|
56
|
+
it('treats top-level public functions and classes as exports', () => {
|
|
57
|
+
const src = 'def pub():\n pass\n\nclass Cls:\n pass\n\ndef _hidden():\n pass\n';
|
|
58
|
+
const r = parser.parseSync(src, 'a.py');
|
|
59
|
+
const names = (r?.exports ?? []).map((e) => e.name).sort();
|
|
60
|
+
expect(names).toContain('pub');
|
|
61
|
+
expect(names).toContain('Cls');
|
|
62
|
+
expect(names).not.toContain('_hidden');
|
|
63
|
+
});
|
|
64
|
+
it('honours __all__ to enumerate exports and prevents duplicates', () => {
|
|
65
|
+
const src = '__all__ = ["Pub"]\n\ndef Pub():\n pass\n\ndef Also():\n pass\n';
|
|
66
|
+
const r = parser.parseSync(src, 'a.py');
|
|
67
|
+
const exports = r?.exports ?? [];
|
|
68
|
+
// Pub appears once (from __all__, deduped from function scan).
|
|
69
|
+
expect(exports.filter((e) => e.name === 'Pub')).toHaveLength(1);
|
|
70
|
+
// Also is still picked up by the function scan as a top-level public fn.
|
|
71
|
+
expect(exports.some((e) => e.name === 'Also')).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=pythonExtractor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonExtractor.test.js","sourceRoot":"","sources":["../../../../src/analysis/tree-sitter/pythonExtractor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4293: Python Incremental Parser Controller
|
|
3
|
+
*
|
|
4
|
+
* Couples the WASM tree-sitter parser, per-file tree cache, and edit-based
|
|
5
|
+
* incremental parsing into a single entry point for the Python adapter.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Lazy-init the WASM parser (via web-tree-sitter) and Python language
|
|
9
|
+
* grammar (from tree-sitter-wasms).
|
|
10
|
+
* - Cache parse trees per file path with LRU eviction (max 100 trees) and
|
|
11
|
+
* proper `.delete()` lifecycle.
|
|
12
|
+
* - Apply tree.edit() and reuse the previous tree when content changes
|
|
13
|
+
* incrementally; fall back to full parse on cache miss or corruption.
|
|
14
|
+
* - Delegate extraction to pythonExtractor (query-based, replaces regex).
|
|
15
|
+
*
|
|
16
|
+
* @see docs/internal/implementation/github-wave-5c-tree-sitter-incremental.md
|
|
17
|
+
* @module analysis/tree-sitter/pythonIncremental
|
|
18
|
+
*/
|
|
19
|
+
import type { ParseResult } from '../types.js';
|
|
20
|
+
import type { TreeSitterLanguage, TreeSitterParser } from './manager.js';
|
|
21
|
+
import { type QueryCtor } from './pythonExtractor.js';
|
|
22
|
+
/** Resolve the path to the Python WASM grammar distributed via tree-sitter-wasms. */
|
|
23
|
+
export declare function resolvePythonWasmPath(): string;
|
|
24
|
+
/** Options for PythonIncrementalParser. */
|
|
25
|
+
export interface PythonIncrementalParserOptions {
|
|
26
|
+
/** Maximum cached trees (default 100). */
|
|
27
|
+
maxTrees?: number;
|
|
28
|
+
/** Override path to the Python WASM grammar (tests). */
|
|
29
|
+
wasmPath?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Resolver that returns the WASM dependencies. Exposed for tests. */
|
|
32
|
+
export interface WebTreeSitterDeps {
|
|
33
|
+
Parser: new () => TreeSitterParser;
|
|
34
|
+
Language: {
|
|
35
|
+
load(path: string): Promise<TreeSitterLanguage>;
|
|
36
|
+
};
|
|
37
|
+
Query: QueryCtor;
|
|
38
|
+
init: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/** Default loader uses web-tree-sitter. Tests may inject a stub. */
|
|
41
|
+
export type WebTreeSitterLoader = () => Promise<WebTreeSitterDeps>;
|
|
42
|
+
/**
|
|
43
|
+
* Incremental Python parser: lazily boots web-tree-sitter, parses with
|
|
44
|
+
* `tree.edit()` reuse when possible, falls back gracefully otherwise.
|
|
45
|
+
*/
|
|
46
|
+
export declare class PythonIncrementalParser {
|
|
47
|
+
private readonly maxTrees;
|
|
48
|
+
private readonly wasmPath;
|
|
49
|
+
private readonly loader;
|
|
50
|
+
private readonly cache;
|
|
51
|
+
private parser;
|
|
52
|
+
private language;
|
|
53
|
+
private queries;
|
|
54
|
+
private initPromise;
|
|
55
|
+
private initFailed;
|
|
56
|
+
private useCounter;
|
|
57
|
+
constructor(options?: PythonIncrementalParserOptions, loader?: WebTreeSitterLoader);
|
|
58
|
+
/** True when the WASM runtime and Python grammar loaded successfully. */
|
|
59
|
+
get isReady(): boolean;
|
|
60
|
+
/** True when a prior init attempt failed; callers should use regex fallback. */
|
|
61
|
+
get hasFailedInit(): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Ensure the WASM parser + Python grammar are loaded. Callers should
|
|
64
|
+
* `await` this once before relying on `parseSync` for a synchronous path.
|
|
65
|
+
*/
|
|
66
|
+
ensureReady(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Parse asynchronously: ensures init, then delegates to the sync path.
|
|
69
|
+
* Returns null if init has permanently failed (caller falls back to regex).
|
|
70
|
+
*/
|
|
71
|
+
parse(content: string, filePath: string): Promise<ParseResult | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Synchronous parse: usable only after `ensureReady()` has resolved. Uses
|
|
74
|
+
* the previous tree via `tree.edit()` when content changed incrementally.
|
|
75
|
+
*
|
|
76
|
+
* Returns null when the parser isn't ready or any parse/extract step fails;
|
|
77
|
+
* callers should fall back to regex extraction in that case.
|
|
78
|
+
*/
|
|
79
|
+
parseSync(content: string, filePath: string): ParseResult | null;
|
|
80
|
+
/** Invalidate a single file's cache entry and free its tree. */
|
|
81
|
+
invalidate(filePath: string): void;
|
|
82
|
+
/** Clear and dispose all cached trees. */
|
|
83
|
+
dispose(): void;
|
|
84
|
+
/** Current cache size (exposed for tests and instrumentation). */
|
|
85
|
+
get cacheSize(): number;
|
|
86
|
+
private ensureInit;
|
|
87
|
+
private doInit;
|
|
88
|
+
private store;
|
|
89
|
+
private touch;
|
|
90
|
+
private evictLRU;
|
|
91
|
+
private safeDelete;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=pythonIncremental.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonIncremental.d.ts","sourceRoot":"","sources":["../../../../src/analysis/tree-sitter/pythonIncremental.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAI9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAkB,MAAM,cAAc,CAAA;AACxF,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAY/F,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,MAAM,CAsC9C;AAWD,2CAA2C;AAC3C,MAAM,WAAW,8BAA8B;IAC7C,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,UAAU,gBAAgB,CAAA;IAClC,QAAQ,EAAE;QAAE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;KAAE,CAAA;IAC7D,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAuBlE;;;GAGG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,UAAU,CAAI;gBAGpB,OAAO,GAAE,8BAAmC,EAC5C,MAAM,GAAE,mBAAmC;IAO7C,yEAAyE;IACzE,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,gFAAgF;IAChF,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAK3E;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IA8DhE,gEAAgE;IAChE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOlC,0CAA0C;IAC1C,OAAO,IAAI,IAAI;IAgBf,kEAAkE;IAClE,IAAI,SAAS,IAAI,MAAM,CAEtB;YAMa,UAAU;YAWV,MAAM;IA2BpB,OAAO,CAAC,KAAK;IAYb,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,UAAU;CAOnB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4315 + SMI-4316: hardening tests for pythonIncremental.
|
|
3
|
+
*
|
|
4
|
+
* SMI-4315 — `resolvePythonWasmPath` probes each candidate with
|
|
5
|
+
* `fs.existsSync` instead of always returning `candidates[0]`. Regression
|
|
6
|
+
* test for the package-local-fallback case.
|
|
7
|
+
*
|
|
8
|
+
* SMI-4316 — both silent catches now emit logger.warn. Tests verify:
|
|
9
|
+
* - `parseSync` catch: rate-limited warn keyed per file; payload is
|
|
10
|
+
* `{ file, error }` only with error truncated to <=200 chars and no
|
|
11
|
+
* `stack` field (no source code leak).
|
|
12
|
+
* - `doInit` catch: one-shot warn per parser instance on init failure.
|
|
13
|
+
*
|
|
14
|
+
* All SUT access goes through a dynamic `import('./pythonIncremental.js')`
|
|
15
|
+
* inside the tests so the vi.mock calls below are applied even when vitest
|
|
16
|
+
* shares its module cache with sibling test files in the same worker.
|
|
17
|
+
* Mixing static `import { X } from './pythonIncremental.js'` with vi.mock
|
|
18
|
+
* against the same module has been observed to bypass the mock when a
|
|
19
|
+
* sibling test file imports the SUT first.
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=pythonIncremental.hardening.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonIncremental.hardening.test.d.ts","sourceRoot":"","sources":["../../../../src/analysis/tree-sitter/pythonIncremental.hardening.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
|