@danielblomma/cortex-mcp 0.4.5 → 1.0.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/README.md +125 -42
- package/bin/cortex.mjs +36 -63
- package/bin/wsl.mjs +30 -0
- package/package.json +15 -3
- package/scaffold/.context/ontology.cypher +47 -0
- package/scaffold/.githooks/post-commit +14 -0
- package/scaffold/.githooks/post-rewrite +23 -0
- package/scaffold/mcp/package-lock.json +16 -16
- package/scaffold/mcp/package.json +4 -1
- package/scaffold/mcp/src/contextEntities.ts +311 -0
- package/scaffold/mcp/src/defaults.ts +6 -0
- package/scaffold/mcp/src/embed.ts +163 -37
- package/scaffold/mcp/src/frontmatter.ts +39 -0
- package/scaffold/mcp/src/graph.ts +253 -130
- package/scaffold/mcp/src/graphMetrics.ts +12 -0
- package/scaffold/mcp/src/impactPresentation.ts +202 -0
- package/scaffold/mcp/src/impactRanking.ts +237 -0
- package/scaffold/mcp/src/impactResponse.ts +47 -0
- package/scaffold/mcp/src/impactResults.ts +173 -0
- package/scaffold/mcp/src/impactSeed.ts +33 -0
- package/scaffold/mcp/src/impactTraversal.ts +83 -0
- package/scaffold/mcp/src/jsonl.ts +34 -0
- package/scaffold/mcp/src/loadGraph.ts +345 -86
- package/scaffold/mcp/src/paths.ts +33 -2
- package/scaffold/mcp/src/presets.ts +137 -0
- package/scaffold/mcp/src/relatedResponse.ts +30 -0
- package/scaffold/mcp/src/relatedTraversal.ts +101 -0
- package/scaffold/mcp/src/rules.ts +27 -0
- package/scaffold/mcp/src/search.ts +186 -455
- package/scaffold/mcp/src/searchCore.ts +274 -0
- package/scaffold/mcp/src/searchResults.ts +133 -0
- package/scaffold/mcp/src/server.ts +95 -3
- package/scaffold/mcp/src/types.ts +82 -3
- package/scaffold/scripts/context.sh +12 -46
- package/scaffold/scripts/dashboard.mjs +797 -0
- package/scaffold/scripts/dashboard.sh +13 -0
- package/scaffold/scripts/ingest.mjs +2227 -59
- package/scaffold/scripts/install-git-hooks.sh +3 -1
- package/scaffold/scripts/memory-compile.mjs +241 -0
- package/scaffold/scripts/memory-compile.sh +20 -0
- package/scaffold/scripts/memory-lint.mjs +384 -0
- package/scaffold/scripts/memory-lint.sh +20 -0
- package/scaffold/scripts/parsers/config.mjs +178 -0
- package/scaffold/scripts/parsers/cpp.mjs +316 -0
- package/scaffold/scripts/parsers/dotnet/VbNetParser/Program.cs +374 -0
- package/scaffold/scripts/parsers/dotnet/VbNetParser/VbNetParser.csproj +13 -0
- package/scaffold/scripts/parsers/javascript/ast.mjs +61 -0
- package/scaffold/scripts/parsers/javascript/calls.mjs +53 -0
- package/scaffold/scripts/parsers/javascript/chunks.mjs +388 -0
- package/scaffold/scripts/parsers/javascript/imports.mjs +162 -0
- package/scaffold/scripts/parsers/javascript/patterns.mjs +82 -0
- package/scaffold/scripts/parsers/javascript/scope-analysis.mjs +3 -0
- package/scaffold/scripts/parsers/javascript/scope-builder.mjs +305 -0
- package/scaffold/scripts/parsers/javascript/scope-resolver.mjs +82 -0
- package/scaffold/scripts/parsers/javascript.mjs +27 -350
- package/scaffold/scripts/parsers/resources.mjs +166 -0
- package/scaffold/scripts/parsers/rust.mjs +515 -0
- package/scaffold/scripts/parsers/sql.mjs +137 -0
- package/scaffold/scripts/parsers/vbnet.mjs +143 -0
- package/scaffold/scripts/status.sh +0 -7
- package/scaffold/scripts/watch.sh +9 -1
- package/scaffold/scripts/capture-note.sh +0 -55
- package/scaffold/scripts/plan-state-engine.cjs +0 -310
- package/scaffold/scripts/plan-state.sh +0 -71
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { ancestor as walkAncestor, simple as walkSimple } from "acorn-walk";
|
|
2
|
+
|
|
3
|
+
import { WALK_BASE } from "./ast.mjs";
|
|
4
|
+
|
|
5
|
+
export function discoverChunks(ast, code, language = "javascript") {
|
|
6
|
+
const chunks = [];
|
|
7
|
+
const exportedNames = collectExportedNames(ast);
|
|
8
|
+
|
|
9
|
+
function pushChunk(chunk) {
|
|
10
|
+
if (!chunk) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
chunk.language = language;
|
|
15
|
+
if (exportedNames.has(chunk.name)) {
|
|
16
|
+
chunk.exported = true;
|
|
17
|
+
}
|
|
18
|
+
chunks.push(chunk);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
walkSimple(
|
|
22
|
+
ast,
|
|
23
|
+
{
|
|
24
|
+
FunctionDeclaration(node) {
|
|
25
|
+
if (!node.id) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pushChunk(extractFunctionChunk(node, "function", code));
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
ClassDeclaration(node) {
|
|
33
|
+
if (!node.id) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const chunk = extractClassChunk(node, code);
|
|
38
|
+
if (chunk) {
|
|
39
|
+
pushChunk(chunk);
|
|
40
|
+
|
|
41
|
+
for (const method of extractClassMethods(node, code, language)) {
|
|
42
|
+
method.parentChunk = chunk.name;
|
|
43
|
+
chunks.push(method);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
VariableDeclaration(node) {
|
|
49
|
+
for (const declarator of node.declarations || []) {
|
|
50
|
+
if (!declarator.id || declarator.id.type !== "Identifier" || !declarator.init) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isFunctionExpr =
|
|
55
|
+
declarator.init.type === "FunctionExpression" ||
|
|
56
|
+
declarator.init.type === "ArrowFunctionExpression";
|
|
57
|
+
|
|
58
|
+
if (!isFunctionExpr) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const chunk = extractFunctionChunk(declarator.init, "const", code, declarator.id.name);
|
|
63
|
+
pushChunk(chunk);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
WALK_BASE
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return dedupeChunks(chunks);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function dedupeChunks(chunks) {
|
|
74
|
+
const seenChunks = new Map();
|
|
75
|
+
|
|
76
|
+
for (const chunk of chunks) {
|
|
77
|
+
const key = `${chunk.name}:${chunk.startLine}`;
|
|
78
|
+
const existing = seenChunks.get(key);
|
|
79
|
+
if (!existing || chunk.exported) {
|
|
80
|
+
seenChunks.set(key, chunk);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return [...seenChunks.values()];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function collectExportedNames(ast) {
|
|
88
|
+
const exportedNames = new Set();
|
|
89
|
+
|
|
90
|
+
walkSimple(
|
|
91
|
+
ast,
|
|
92
|
+
{
|
|
93
|
+
ExportNamedDeclaration(node) {
|
|
94
|
+
if (node.declaration) {
|
|
95
|
+
if (
|
|
96
|
+
(node.declaration.type === "FunctionDeclaration" ||
|
|
97
|
+
node.declaration.type === "ClassDeclaration") &&
|
|
98
|
+
node.declaration.id?.name
|
|
99
|
+
) {
|
|
100
|
+
exportedNames.add(node.declaration.id.name);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (node.declaration.type === "VariableDeclaration") {
|
|
104
|
+
for (const declarator of node.declaration.declarations || []) {
|
|
105
|
+
if (declarator.id?.type === "Identifier") {
|
|
106
|
+
exportedNames.add(declarator.id.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!node.source) {
|
|
113
|
+
for (const specifier of node.specifiers || []) {
|
|
114
|
+
if (specifier.local?.type === "Identifier") {
|
|
115
|
+
exportedNames.add(specifier.local.name);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
ExportDefaultDeclaration(node) {
|
|
122
|
+
const declaration = node.declaration;
|
|
123
|
+
if (
|
|
124
|
+
(declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") &&
|
|
125
|
+
declaration.id?.name
|
|
126
|
+
) {
|
|
127
|
+
exportedNames.add(declaration.id.name);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (declaration.type === "Identifier") {
|
|
132
|
+
exportedNames.add(declaration.name);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
WALK_BASE
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
walkAncestor(
|
|
140
|
+
ast,
|
|
141
|
+
{
|
|
142
|
+
AssignmentExpression(node, ancestors) {
|
|
143
|
+
if (isNestedInFunctionScope(ancestors)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
addCommonJsExportedNames(exportedNames, node);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
WALK_BASE
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
return exportedNames;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function isNestedInFunctionScope(ancestors) {
|
|
157
|
+
return ancestors.slice(0, -1).some((node) =>
|
|
158
|
+
node.type === "FunctionDeclaration" ||
|
|
159
|
+
node.type === "FunctionExpression" ||
|
|
160
|
+
node.type === "ArrowFunctionExpression"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function addCommonJsExportedNames(exportedNames, assignment) {
|
|
165
|
+
const exportPath = getCommonJsExportPath(assignment.left);
|
|
166
|
+
if (!exportPath) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
addExportedNamesFromValue(exportedNames, assignment.right);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getCommonJsExportPath(node) {
|
|
174
|
+
if (!node || node.type !== "MemberExpression") {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const propertyName = getStaticPropertyName(node);
|
|
179
|
+
if (!propertyName) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (node.object.type === "Identifier") {
|
|
184
|
+
if (node.object.name === "exports") {
|
|
185
|
+
return ["exports", propertyName];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (node.object.name === "module" && propertyName === "exports") {
|
|
189
|
+
return ["module", "exports"];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const objectPath = getCommonJsExportPath(node.object);
|
|
194
|
+
if (!objectPath) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (objectPath.length >= 2 && objectPath[0] === "module" && objectPath[1] === "exports") {
|
|
199
|
+
return [...objectPath, propertyName];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function getStaticPropertyName(node) {
|
|
206
|
+
if (!node.computed && node.property.type === "Identifier") {
|
|
207
|
+
return node.property.name;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (node.computed && node.property.type === "Literal" && typeof node.property.value === "string") {
|
|
211
|
+
return node.property.value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function addExportedNamesFromValue(exportedNames, value) {
|
|
218
|
+
if (!value) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (value.type === "Identifier") {
|
|
223
|
+
exportedNames.add(value.name);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (value.type === "AssignmentExpression") {
|
|
228
|
+
addExportedNamesFromValue(exportedNames, value.right);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (value.type !== "ObjectExpression") {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
for (const property of value.properties || []) {
|
|
237
|
+
if (property.type !== "Property" || property.kind !== "init") {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
addExportedNamesFromValue(exportedNames, property.value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function extractFunctionChunk(node, kind, code, nameOverride = null) {
|
|
246
|
+
const name = nameOverride || node.id?.name;
|
|
247
|
+
if (!name) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const params = (node.params || []).map(formatParameterName);
|
|
252
|
+
const bodyStart = findLeadingCommentStart(code, node);
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
name,
|
|
256
|
+
kind,
|
|
257
|
+
signature: `${name}(${params.join(", ")})`,
|
|
258
|
+
body: code.slice(bodyStart, node.end),
|
|
259
|
+
startLine: node.loc.start.line,
|
|
260
|
+
endLine: node.loc.end.line,
|
|
261
|
+
callNode: node.body || node,
|
|
262
|
+
importNode: node,
|
|
263
|
+
async: node.async === true,
|
|
264
|
+
generator: node.generator === true
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function extractClassChunk(node, code) {
|
|
269
|
+
const name = node.id?.name;
|
|
270
|
+
if (!name) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const superClass = node.superClass?.name || null;
|
|
275
|
+
const bodyStart = findLeadingCommentStart(code, node);
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
name,
|
|
279
|
+
kind: "class",
|
|
280
|
+
signature: superClass ? `class ${name} extends ${superClass}` : `class ${name}`,
|
|
281
|
+
body: code.slice(bodyStart, node.end),
|
|
282
|
+
startLine: node.loc.start.line,
|
|
283
|
+
endLine: node.loc.end.line,
|
|
284
|
+
callNode: node.body,
|
|
285
|
+
importNode: node,
|
|
286
|
+
superClass
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function extractClassMethods(classNode, code, language) {
|
|
291
|
+
const methods = [];
|
|
292
|
+
const className = classNode.id?.name || "UnknownClass";
|
|
293
|
+
|
|
294
|
+
for (const member of classNode.body.body || []) {
|
|
295
|
+
if (member.type !== "MethodDefinition" || member.key.type !== "Identifier") {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const params = (member.value.params || []).map(formatParameterName);
|
|
300
|
+
const isStatic = member.static === true;
|
|
301
|
+
const prefix = isStatic ? "static " : "";
|
|
302
|
+
const bodyStart = findLeadingCommentStart(code, member);
|
|
303
|
+
|
|
304
|
+
methods.push({
|
|
305
|
+
name: `${className}.${member.key.name}`,
|
|
306
|
+
kind: "method",
|
|
307
|
+
signature: `${prefix}${member.key.name}(${params.join(", ")})`,
|
|
308
|
+
body: code.slice(bodyStart, member.end),
|
|
309
|
+
startLine: member.loc.start.line,
|
|
310
|
+
endLine: member.loc.end.line,
|
|
311
|
+
callNode: member.value.body,
|
|
312
|
+
importNode: member,
|
|
313
|
+
static: isStatic,
|
|
314
|
+
async: member.value.async === true,
|
|
315
|
+
generator: member.value.generator === true,
|
|
316
|
+
language
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return methods;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function findLeadingCommentStart(code, node) {
|
|
324
|
+
let bodyStart = node.start;
|
|
325
|
+
let lineStart = code.lastIndexOf("\n", node.start - 1) + 1;
|
|
326
|
+
|
|
327
|
+
while (lineStart > 0) {
|
|
328
|
+
const previousLineEnd = lineStart - 1;
|
|
329
|
+
const previousLineStart = code.lastIndexOf("\n", previousLineEnd - 1) + 1;
|
|
330
|
+
const previousLine = code.slice(previousLineStart, previousLineEnd).replace(/\r$/, "");
|
|
331
|
+
const trimmed = previousLine.trim();
|
|
332
|
+
|
|
333
|
+
if (!trimmed) {
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (trimmed.startsWith("//")) {
|
|
338
|
+
bodyStart = previousLineStart;
|
|
339
|
+
lineStart = previousLineStart;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (trimmed.endsWith("*/")) {
|
|
344
|
+
let blockStart = previousLineStart;
|
|
345
|
+
let searchStart = previousLineStart;
|
|
346
|
+
let foundBlockStart = trimmed.startsWith("/*");
|
|
347
|
+
|
|
348
|
+
while (!foundBlockStart && searchStart > 0) {
|
|
349
|
+
const blockLineEnd = searchStart - 1;
|
|
350
|
+
const blockLineStart = code.lastIndexOf("\n", blockLineEnd - 1) + 1;
|
|
351
|
+
const blockLine = code.slice(blockLineStart, blockLineEnd).replace(/\r$/, "");
|
|
352
|
+
const blockTrimmed = blockLine.trim();
|
|
353
|
+
|
|
354
|
+
if (!blockTrimmed) {
|
|
355
|
+
return bodyStart;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
blockStart = blockLineStart;
|
|
359
|
+
searchStart = blockLineStart;
|
|
360
|
+
foundBlockStart = blockTrimmed.startsWith("/*");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (!foundBlockStart) {
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
bodyStart = blockStart;
|
|
368
|
+
lineStart = blockStart;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return bodyStart;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function formatParameterName(param) {
|
|
379
|
+
if (param.type === "Identifier") {
|
|
380
|
+
return param.name;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (param.type === "RestElement" && param.argument.type === "Identifier") {
|
|
384
|
+
return `...${param.argument.name}`;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return "_";
|
|
388
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { fullAncestor, simple as walkSimple } from "acorn-walk";
|
|
2
|
+
|
|
3
|
+
import { WALK_BASE } from "./ast.mjs";
|
|
4
|
+
import { collectPatternIdentifiers } from "./patterns.mjs";
|
|
5
|
+
import { buildScopeGraph } from "./scope-builder.mjs";
|
|
6
|
+
import { isReferenceIdentifier, resolveIdentifier } from "./scope-resolver.mjs";
|
|
7
|
+
|
|
8
|
+
export function collectStaticImports(ast) {
|
|
9
|
+
const bindings = [];
|
|
10
|
+
const sideEffectImports = new Set();
|
|
11
|
+
|
|
12
|
+
for (const node of ast.body || []) {
|
|
13
|
+
if (node.type === "ImportDeclaration") {
|
|
14
|
+
if (node.source?.type === "Literal" && typeof node.source.value === "string") {
|
|
15
|
+
if ((node.specifiers || []).length === 0) {
|
|
16
|
+
sideEffectImports.add(node.source.value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const specifier of node.specifiers || []) {
|
|
20
|
+
if (specifier.local?.type === "Identifier") {
|
|
21
|
+
bindings.push({
|
|
22
|
+
localName: specifier.local.name,
|
|
23
|
+
source: node.source.value
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (node.type === "VariableDeclaration") {
|
|
32
|
+
for (const declarator of node.declarations || []) {
|
|
33
|
+
const source = getStaticRequireImportSource(declarator.init);
|
|
34
|
+
if (!source) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
collectPatternIdentifiers(declarator.id, (localName) => {
|
|
39
|
+
bindings.push({ localName, source });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (node.type === "ExpressionStatement") {
|
|
46
|
+
const source = getStaticRequireImportSource(node.expression);
|
|
47
|
+
if (source) {
|
|
48
|
+
sideEffectImports.add(source);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
bindings,
|
|
55
|
+
sideEffectImports: [...sideEffectImports].sort()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function extractImportsForChunk(bodyNode, staticImports) {
|
|
60
|
+
const imports = new Set(extractDynamicImports(bodyNode));
|
|
61
|
+
|
|
62
|
+
for (const source of staticImports.sideEffectImports || []) {
|
|
63
|
+
imports.add(source);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const source of extractReferencedStaticImportSources(bodyNode, staticImports.bindings || [])) {
|
|
67
|
+
imports.add(source);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return [...imports].sort();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getStaticRequireImportSource(node) {
|
|
74
|
+
if (
|
|
75
|
+
node?.type === "CallExpression" &&
|
|
76
|
+
node.callee.type === "Identifier" &&
|
|
77
|
+
node.callee.name === "require" &&
|
|
78
|
+
node.arguments[0]?.type === "Literal" &&
|
|
79
|
+
typeof node.arguments[0].value === "string"
|
|
80
|
+
) {
|
|
81
|
+
return node.arguments[0].value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function extractReferencedStaticImportSources(bodyNode, bindings) {
|
|
88
|
+
if (!bodyNode || bindings.length === 0) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const importsByLocalName = new Map();
|
|
93
|
+
for (const binding of bindings) {
|
|
94
|
+
if (!importsByLocalName.has(binding.localName)) {
|
|
95
|
+
importsByLocalName.set(binding.localName, binding.source);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const scopeGraph = buildScopeGraph(bodyNode);
|
|
100
|
+
const sources = new Set();
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
fullAncestor(
|
|
104
|
+
bodyNode,
|
|
105
|
+
(node, state, ancestors) => {
|
|
106
|
+
if (node.type !== "Identifier") {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const source = importsByLocalName.get(node.name);
|
|
111
|
+
if (!source || !isReferenceIdentifier(node, ancestors)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (resolveIdentifier(node.name, ancestors, scopeGraph)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
sources.add(source);
|
|
120
|
+
},
|
|
121
|
+
WALK_BASE
|
|
122
|
+
);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
// Ignore walk errors for incomplete ASTs.
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [...sources].sort();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function extractDynamicImports(bodyNode) {
|
|
131
|
+
if (!bodyNode) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const imports = new Set();
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
walkSimple(
|
|
139
|
+
bodyNode,
|
|
140
|
+
{
|
|
141
|
+
CallExpression(node) {
|
|
142
|
+
if (node.callee.type === "Import" && node.arguments[0]?.type === "Literal") {
|
|
143
|
+
imports.add(node.arguments[0].value);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (
|
|
147
|
+
node.callee.type === "Identifier" &&
|
|
148
|
+
node.callee.name === "require" &&
|
|
149
|
+
node.arguments[0]?.type === "Literal"
|
|
150
|
+
) {
|
|
151
|
+
imports.add(node.arguments[0].value);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
WALK_BASE
|
|
156
|
+
);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// Ignore walk errors for incomplete ASTs.
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return [...imports].sort();
|
|
162
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export function collectPatternIdentifiers(pattern, visit) {
|
|
2
|
+
if (!pattern) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
switch (pattern.type) {
|
|
7
|
+
case "Identifier":
|
|
8
|
+
visit(pattern.name);
|
|
9
|
+
break;
|
|
10
|
+
case "AssignmentPattern":
|
|
11
|
+
collectPatternIdentifiers(pattern.left, visit);
|
|
12
|
+
break;
|
|
13
|
+
case "ArrayPattern":
|
|
14
|
+
for (const element of pattern.elements || []) {
|
|
15
|
+
if (element) {
|
|
16
|
+
collectPatternIdentifiers(element, visit);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
break;
|
|
20
|
+
case "ObjectPattern":
|
|
21
|
+
for (const property of pattern.properties || []) {
|
|
22
|
+
if (!property) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (property.type === "Property") {
|
|
27
|
+
collectPatternIdentifiers(property.value, visit);
|
|
28
|
+
} else if (property.type === "RestElement") {
|
|
29
|
+
collectPatternIdentifiers(property.argument, visit);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case "RestElement":
|
|
34
|
+
collectPatternIdentifiers(pattern.argument, visit);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function walkPatternExpressions(pattern, visit) {
|
|
42
|
+
if (!pattern) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
switch (pattern.type) {
|
|
47
|
+
case "AssignmentPattern":
|
|
48
|
+
walkPatternExpressions(pattern.left, visit);
|
|
49
|
+
if (pattern.right) {
|
|
50
|
+
visit(pattern.right);
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
case "ArrayPattern":
|
|
54
|
+
for (const element of pattern.elements || []) {
|
|
55
|
+
if (element) {
|
|
56
|
+
walkPatternExpressions(element, visit);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case "ObjectPattern":
|
|
61
|
+
for (const property of pattern.properties || []) {
|
|
62
|
+
if (!property) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (property.type === "Property") {
|
|
67
|
+
if (property.computed) {
|
|
68
|
+
visit(property.key);
|
|
69
|
+
}
|
|
70
|
+
walkPatternExpressions(property.value, visit);
|
|
71
|
+
} else if (property.type === "RestElement") {
|
|
72
|
+
walkPatternExpressions(property.argument, visit);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case "RestElement":
|
|
77
|
+
walkPatternExpressions(pattern.argument, visit);
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|