@bamboocss/vite 1.49.0 → 1.50.1
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/fold-module.cjs +324 -330
- package/dist/fold-module.mjs +234 -240
- package/dist/index.d.mts +1 -1
- package/package.json +11 -10
package/dist/fold-module.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, relative, resolve } from "node:path";
|
|
|
4
4
|
import MagicString from "magic-string";
|
|
5
5
|
import { resolveTsPathPattern } from "@bamboocss/config/ts-path";
|
|
6
6
|
import { box, maybeBoxNode } from "@bamboocss/extractor";
|
|
7
|
-
import { Node, SyntaxKind,
|
|
7
|
+
import { Node, SyntaxKind, childOf, forEachDescendant, getAliasNode, getDefaultImport, getDescendantsOfKind, getExportDeclarations, getFirstAncestor, getFirstAncestorByKind, getImportDeclarations, getModuleSpecifierValue, getName, getNamedExports, getNamedImports, getNamespaceExport, getNamespaceImport, isStarExport, isTypeOnly, literalValueOf, nameNodeOf, pathOf, stringLiteralValue, ts } from "@bamboocss/ts-ast";
|
|
8
8
|
//#region src/fold-analysis.ts
|
|
9
9
|
/**
|
|
10
10
|
* Nodes that *compose* a value out of their children rather than computing one.
|
|
@@ -43,9 +43,9 @@ const isBindingElementDefault = (node) => {
|
|
|
43
43
|
if (node && Node.isCallExpression(node)) return false;
|
|
44
44
|
let current = node;
|
|
45
45
|
while (current) {
|
|
46
|
-
const parent = current.
|
|
46
|
+
const parent = current.parent;
|
|
47
47
|
if (!parent) return false;
|
|
48
|
-
if (Node.isBindingElement(parent)) return parent.
|
|
48
|
+
if (Node.isBindingElement(parent)) return parent.initializer === current;
|
|
49
49
|
if (!composesValue(parent)) return false;
|
|
50
50
|
current = parent;
|
|
51
51
|
}
|
|
@@ -72,7 +72,7 @@ const isFromBindingDefault = (node) => {
|
|
|
72
72
|
const own = node.getNode?.();
|
|
73
73
|
if (isBindingElementDefault(own)) return true;
|
|
74
74
|
for (const entry of node.getStack?.() ?? []) {
|
|
75
|
-
if (!Node.isBindingElement(entry) || !entry.
|
|
75
|
+
if (!Node.isBindingElement(entry) || !entry.initializer) continue;
|
|
76
76
|
if (own && contains(entry, own)) continue;
|
|
77
77
|
return true;
|
|
78
78
|
}
|
|
@@ -115,7 +115,7 @@ const isStaticBox = (node, seen = /* @__PURE__ */ new Set()) => {
|
|
|
115
115
|
* surface. Recognising fewer wrappers than it does is not a cosmetic difference: an
|
|
116
116
|
* unrecognised one leaves an object literal wrapped, and the object checks below skip it.
|
|
117
117
|
*/
|
|
118
|
-
const unwrapExpression = (node) => Node.isAsExpression(node) || Node.isParenthesizedExpression(node) || Node.isNonNullExpression(node) || Node.isTypeAssertion(node) || Node.isSatisfiesExpression(node) ? unwrapExpression(node.
|
|
118
|
+
const unwrapExpression = (node) => Node.isAsExpression(node) || Node.isParenthesizedExpression(node) || Node.isNonNullExpression(node) || Node.isTypeAssertion(node) || Node.isSatisfiesExpression(node) ? unwrapExpression(node.expression) : node;
|
|
119
119
|
/**
|
|
120
120
|
* Mirrors the parser's evaluator environment, so re-boxing an operand here gets the same
|
|
121
121
|
* answer the extraction did. Left to its default, ts-evaluator presets to `NODE` and
|
|
@@ -148,7 +148,7 @@ const resolvesExactly = (node) => {
|
|
|
148
148
|
*/
|
|
149
149
|
const isWrittenHere = (node) => {
|
|
150
150
|
const inner = unwrapExpression(node);
|
|
151
|
-
return Node.isStringLiteral(inner) || Node.isNumericLiteral(inner) || Node.isNoSubstitutionTemplateLiteral(inner) || Node.isObjectLiteralExpression(inner) || Node.isArrayLiteralExpression(inner) || Node.isTrueLiteral(inner) || Node.isFalseLiteral(inner) || inner.
|
|
151
|
+
return Node.isStringLiteral(inner) || Node.isNumericLiteral(inner) || Node.isNoSubstitutionTemplateLiteral(inner) || Node.isObjectLiteralExpression(inner) || Node.isArrayLiteralExpression(inner) || Node.isTrueLiteral(inner) || Node.isFalseLiteral(inner) || inner.kind === SyntaxKind.NullKeyword || Node.isPrefixUnaryExpression(inner) && Node.isNumericLiteral(inner.operand);
|
|
152
152
|
};
|
|
153
153
|
/** An inline value's truthiness, which its box carries directly. */
|
|
154
154
|
const isTruthy = (boxNode) => box.isLiteral(boxNode) ? Boolean(boxNode.value) : box.isMap(boxNode) || box.isArray(boxNode) || box.isObject(boxNode);
|
|
@@ -166,15 +166,15 @@ const isTruthy = (boxNode) => box.isLiteral(boxNode) ? Boolean(boxNode.value) :
|
|
|
166
166
|
* be established is that the left is the side that wins.
|
|
167
167
|
*/
|
|
168
168
|
const decidedAtBuildTime = (node) => {
|
|
169
|
-
if (Node.isConditionalExpression(node)) return resolvesExactly(node.
|
|
170
|
-
const operator = node.
|
|
169
|
+
if (Node.isConditionalExpression(node)) return resolvesExactly(node.whenTrue) && resolvesExactly(node.whenFalse);
|
|
170
|
+
const operator = node.operatorToken.kind;
|
|
171
171
|
if (!SHORT_CIRCUIT.includes(operator)) return false;
|
|
172
|
-
if (!isWrittenHere(node.
|
|
173
|
-
const left = rebox(node.
|
|
172
|
+
if (!isWrittenHere(node.left)) return false;
|
|
173
|
+
const left = rebox(node.left);
|
|
174
174
|
if (!left) return false;
|
|
175
175
|
if (operator === SyntaxKind.BarBarToken) return isTruthy(left);
|
|
176
176
|
if (operator === SyntaxKind.QuestionQuestionToken) return !box.isLiteral(left) || left.value != null;
|
|
177
|
-
return isTruthy(left) ? resolvesExactly(node.
|
|
177
|
+
return isTruthy(left) ? resolvesExactly(node.right) : true;
|
|
178
178
|
};
|
|
179
179
|
const SHORT_CIRCUIT = [
|
|
180
180
|
SyntaxKind.AmpersandAmpersandToken,
|
|
@@ -202,7 +202,7 @@ const COLLAPSED_BINARY = new Set([
|
|
|
202
202
|
SyntaxKind.InKeyword,
|
|
203
203
|
SyntaxKind.InstanceOfKeyword
|
|
204
204
|
]);
|
|
205
|
-
const isCollapsedBinary = (node) => Node.isBinaryExpression(node) && COLLAPSED_BINARY.has(node.
|
|
205
|
+
const isCollapsedBinary = (node) => Node.isBinaryExpression(node) && COLLAPSED_BINARY.has(node.operatorToken.kind);
|
|
206
206
|
/**
|
|
207
207
|
* Does the extracted box account for every property the source declares?
|
|
208
208
|
*
|
|
@@ -229,14 +229,14 @@ const isCollapsedBinary = (node) => Node.isBinaryExpression(node) && COLLAPSED_B
|
|
|
229
229
|
* expression — reading an initializer that is not there reports the property as having no
|
|
230
230
|
* source, and everything hidden behind the name goes unchecked.
|
|
231
231
|
*/
|
|
232
|
-
const valueOf = (property) => Node.isPropertyAssignment(property) ? property.
|
|
232
|
+
const valueOf = (property) => Node.isPropertyAssignment(property) ? property.initializer : Node.isShorthandPropertyAssignment(property) ? property.name : void 0;
|
|
233
233
|
const accountsForSource = (node, boxNode) => {
|
|
234
234
|
if (!node) return true;
|
|
235
235
|
const unwrapped = unwrapExpression(node);
|
|
236
236
|
if ((Node.isConditionalExpression(unwrapped) || isCollapsedBinary(unwrapped)) && !box.isConditional(boxNode) && !decidedAtBuildTime(unwrapped)) return false;
|
|
237
237
|
if (Node.isArrayLiteralExpression(unwrapped)) {
|
|
238
238
|
if (!box.isArray(boxNode)) return false;
|
|
239
|
-
const elements = unwrapped.
|
|
239
|
+
const elements = unwrapped.elements;
|
|
240
240
|
if (elements.length !== boxNode.value.length) return false;
|
|
241
241
|
return elements.every((element, index) => accountsForSource(element, boxNode.value[index]));
|
|
242
242
|
}
|
|
@@ -245,9 +245,9 @@ const accountsForSource = (node, boxNode) => {
|
|
|
245
245
|
return !origin || origin === unwrapped || !Node.isObjectLiteralExpression(origin) ? true : accountsForSource(origin, boxNode);
|
|
246
246
|
}
|
|
247
247
|
if (!box.isMap(boxNode)) return false;
|
|
248
|
-
for (const property of unwrapped.
|
|
248
|
+
for (const property of unwrapped.properties) {
|
|
249
249
|
if (Node.isSpreadAssignment(property)) {
|
|
250
|
-
const expression = unwrapExpression(property.
|
|
250
|
+
const expression = unwrapExpression(property.expression);
|
|
251
251
|
if (Node.isObjectLiteralExpression(expression)) continue;
|
|
252
252
|
const walked = boxNode.resolvedSpreads?.find((entry) => entry.node === expression);
|
|
253
253
|
if (!walked) return false;
|
|
@@ -256,9 +256,9 @@ const accountsForSource = (node, boxNode) => {
|
|
|
256
256
|
}
|
|
257
257
|
if (Node.isMethodDeclaration(property) || Node.isGetAccessorDeclaration(property) || Node.isSetAccessorDeclaration(property)) return false;
|
|
258
258
|
if (!Node.isPropertyAssignment(property) && !Node.isShorthandPropertyAssignment(property)) return false;
|
|
259
|
-
const nameNode = property.
|
|
259
|
+
const nameNode = property.name;
|
|
260
260
|
if (Node.isComputedPropertyName(nameNode)) return false;
|
|
261
|
-
const key = Node.isStringLiteral(nameNode) || Node.isNumericLiteral(nameNode) ? String(nameNode
|
|
261
|
+
const key = Node.isStringLiteral(nameNode) || Node.isNumericLiteral(nameNode) ? String(literalValueOf(nameNode)) : nameNode.getText();
|
|
262
262
|
const value = valueOf(property);
|
|
263
263
|
if (value && Node.isIdentifier(value) && value.getText() === "undefined") continue;
|
|
264
264
|
if (!boxNode.value.has(key)) return false;
|
|
@@ -309,19 +309,19 @@ const collectModuleScopeNames = (sourceFile) => {
|
|
|
309
309
|
const addBinding = (node) => {
|
|
310
310
|
if (!node) return;
|
|
311
311
|
if (Node.isObjectBindingPattern(node) || Node.isArrayBindingPattern(node)) {
|
|
312
|
-
for (const element of node.
|
|
312
|
+
for (const element of node.elements) if (Node.isBindingElement(element)) addBinding(element.name);
|
|
313
313
|
return;
|
|
314
314
|
}
|
|
315
315
|
if (Node.isIdentifier(node)) names.add(node.getText());
|
|
316
316
|
};
|
|
317
317
|
const addDeclarations = (list) => {
|
|
318
318
|
if (Node.isVariableStatement(list)) {
|
|
319
|
-
for (const declaration of list.
|
|
319
|
+
for (const declaration of list.declarationList.declarations) addBinding(declaration.name);
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
322
|
-
if (Node.isVariableDeclarationList(list)) for (const declaration of list.
|
|
322
|
+
if (Node.isVariableDeclarationList(list)) for (const declaration of list.declarations) addBinding(declaration.name);
|
|
323
323
|
};
|
|
324
|
-
const isVar = (node) => (Node.isVariableStatement(node) || Node.isVariableDeclarationList(node)) && node
|
|
324
|
+
const isVar = (node) => (Node.isVariableStatement(node) || Node.isVariableDeclarationList(node)) && (childOf(node, "declarationList")?.flags ?? 0) === 0;
|
|
325
325
|
/**
|
|
326
326
|
* `var` is scoped to the enclosing *function*, not the enclosing block, so one written
|
|
327
327
|
* inside any statement at the top level still binds at module scope. Walking only the
|
|
@@ -336,61 +336,61 @@ const collectModuleScopeNames = (sourceFile) => {
|
|
|
336
336
|
return;
|
|
337
337
|
}
|
|
338
338
|
if (Node.isBlock(node)) {
|
|
339
|
-
for (const statement of node.
|
|
339
|
+
for (const statement of node.statements) addHoistedVars(statement);
|
|
340
340
|
return;
|
|
341
341
|
}
|
|
342
342
|
if (Node.isIfStatement(node)) {
|
|
343
|
-
addHoistedVars(node.
|
|
344
|
-
const otherwise = node.
|
|
343
|
+
addHoistedVars(node.thenStatement);
|
|
344
|
+
const otherwise = node.elseStatement;
|
|
345
345
|
if (otherwise) addHoistedVars(otherwise);
|
|
346
346
|
return;
|
|
347
347
|
}
|
|
348
348
|
if (Node.isForStatement(node)) {
|
|
349
|
-
const initializer = node.
|
|
349
|
+
const initializer = node.initializer;
|
|
350
350
|
if (initializer) addHoistedVars(initializer);
|
|
351
|
-
addHoistedVars(node.
|
|
351
|
+
addHoistedVars(node.statement);
|
|
352
352
|
return;
|
|
353
353
|
}
|
|
354
354
|
if (Node.isForInStatement(node) || Node.isForOfStatement(node)) {
|
|
355
|
-
addHoistedVars(node.
|
|
356
|
-
addHoistedVars(node.
|
|
355
|
+
addHoistedVars(node.initializer);
|
|
356
|
+
addHoistedVars(node.statement);
|
|
357
357
|
return;
|
|
358
358
|
}
|
|
359
359
|
if (Node.isWhileStatement(node) || Node.isDoStatement(node) || Node.isWithStatement(node)) {
|
|
360
|
-
addHoistedVars(node.
|
|
360
|
+
addHoistedVars(node.statement);
|
|
361
361
|
return;
|
|
362
362
|
}
|
|
363
363
|
if (Node.isLabeledStatement(node)) {
|
|
364
|
-
addHoistedVars(node.
|
|
364
|
+
addHoistedVars(node.statement);
|
|
365
365
|
return;
|
|
366
366
|
}
|
|
367
367
|
if (Node.isTryStatement(node)) {
|
|
368
|
-
addHoistedVars(node.
|
|
369
|
-
const caught = node
|
|
370
|
-
if (caught) addHoistedVars(caught
|
|
371
|
-
const finally_ = node
|
|
368
|
+
addHoistedVars(node.tryBlock);
|
|
369
|
+
const caught = childOf(node, "catchClause");
|
|
370
|
+
if (caught) addHoistedVars(childOf(caught, "block"));
|
|
371
|
+
const finally_ = childOf(node, "finallyBlock");
|
|
372
372
|
if (finally_) addHoistedVars(finally_);
|
|
373
373
|
return;
|
|
374
374
|
}
|
|
375
|
-
if (Node.isSwitchStatement(node)) for (const clause of node
|
|
375
|
+
if (Node.isSwitchStatement(node)) for (const clause of childOf(node, "caseBlock")?.clauses ?? []) for (const statement of childOf(clause, "statements") ?? []) addHoistedVars(statement);
|
|
376
376
|
};
|
|
377
|
-
for (const statement of sourceFile.
|
|
377
|
+
for (const statement of sourceFile.statements) {
|
|
378
378
|
if (Node.isVariableStatement(statement)) {
|
|
379
379
|
addDeclarations(statement);
|
|
380
380
|
continue;
|
|
381
381
|
}
|
|
382
382
|
if (Node.isImportDeclaration(statement)) {
|
|
383
|
-
addBinding(
|
|
384
|
-
addBinding(
|
|
385
|
-
for (const named of
|
|
383
|
+
addBinding(getDefaultImport(statement));
|
|
384
|
+
addBinding(getNamespaceImport(statement));
|
|
385
|
+
for (const named of getNamedImports(statement)) addBinding(getAliasNode(named) ?? nameNodeOf(named));
|
|
386
386
|
continue;
|
|
387
387
|
}
|
|
388
388
|
if (Node.isImportEqualsDeclaration(statement)) {
|
|
389
|
-
addBinding(statement.
|
|
389
|
+
addBinding(statement.name);
|
|
390
390
|
continue;
|
|
391
391
|
}
|
|
392
392
|
if (Node.isFunctionDeclaration(statement) || Node.isClassDeclaration(statement) || Node.isEnumDeclaration(statement) || Node.isModuleDeclaration(statement) || Node.isTypeAliasDeclaration(statement) || Node.isInterfaceDeclaration(statement)) {
|
|
393
|
-
addBinding(statement.
|
|
393
|
+
addBinding(statement.name);
|
|
394
394
|
continue;
|
|
395
395
|
}
|
|
396
396
|
addHoistedVars(statement);
|
|
@@ -408,35 +408,34 @@ const collectModuleScopeNames = (sourceFile) => {
|
|
|
408
408
|
*
|
|
409
409
|
* `SyntaxKind.Identifier` sorts *below* `SyntaxKind.FirstNode`, which is what ts-morph tests to
|
|
410
410
|
* decide whether it may search the parse tree. For a kind below that line it falls back to
|
|
411
|
-
* materialising the whole **token** tree — every brace, comma and keyword
|
|
411
|
+
* materialising the whole **token** tree — every brace, comma and keyword became a ts-morph node
|
|
412
412
|
* on the way to collecting the identifiers. On 55 KB of real tsx that measured 22ms against
|
|
413
|
-
* 0.22ms for the same collection over compiler nodes, and the node cache
|
|
413
|
+
* 0.22ms for the same collection over compiler nodes, and the node cache did not help: a second
|
|
414
414
|
* call cost the same 22ms.
|
|
415
415
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
416
|
+
* That cost was ts-morph's wrapper objects, and TypeScript 7 has none — the walk below yields
|
|
417
|
+
* the compiler's own nodes, which is exactly what `getDescendantsOfKind` would return. So the
|
|
418
|
+
* lazy per-bucket wrapping this used to do has nothing left to defer, and the buckets are handed
|
|
419
|
+
* back as collected. `localReferencesTo` still depends on the identity of what comes out, since
|
|
420
|
+
* it compares each reference against the declaration.
|
|
421
421
|
*
|
|
422
422
|
* JSDoc is walked explicitly. `ts.forEachChild` does not descend into it, while the token path
|
|
423
423
|
* this replaces does, so a name mentioned only in a `@type` annotation was previously found and
|
|
424
424
|
* would otherwise stop being — a silent narrowing of what counts as a surviving reference.
|
|
425
|
-
* Keyed on `
|
|
426
|
-
*
|
|
425
|
+
* Keyed on the identifier's `text` because that is the name as the compiler resolves it, so
|
|
426
|
+
* `\u0062adge` and `badge` share a bucket exactly as before.
|
|
427
427
|
*
|
|
428
428
|
* Deliberately *not* memoized across passes, unlike the module-scope names beside it. That
|
|
429
|
-
* cache holds strings, which outlive anything; this one holds nodes, and a node
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
* `Attempted to get information from a node that was removed or forgotten` on the next read.
|
|
429
|
+
* cache holds strings, which outlive anything; this one holds nodes, and a node belongs to the
|
|
430
|
+
* tree it was taken from. Keying on the source text does not help, because identical text
|
|
431
|
+
* re-parsed is a fresh tree: the cache would hit and hand back nodes from a previous snapshot,
|
|
432
|
+
* which no longer match anything the current pass compares them against.
|
|
434
433
|
*/
|
|
435
434
|
const identifierIndex = (sourceFile) => {
|
|
436
435
|
const compilerNodes = /* @__PURE__ */ new Map();
|
|
437
436
|
const collect = (node) => {
|
|
438
437
|
if (node.kind === ts.SyntaxKind.Identifier) {
|
|
439
|
-
const name = String(node.
|
|
438
|
+
const name = String(node.text);
|
|
440
439
|
const known = compilerNodes.get(name);
|
|
441
440
|
if (known) known.push(node);
|
|
442
441
|
else compilerNodes.set(name, [node]);
|
|
@@ -445,32 +444,24 @@ const identifierIndex = (sourceFile) => {
|
|
|
445
444
|
if (jsDoc) for (const doc of jsDoc) collect(doc);
|
|
446
445
|
ts.forEachChild(node, collect);
|
|
447
446
|
};
|
|
448
|
-
ts.forEachChild(sourceFile
|
|
449
|
-
|
|
450
|
-
const wrap = sourceFile;
|
|
451
|
-
return { get: (name) => {
|
|
452
|
-
const known = wrapped.get(name);
|
|
453
|
-
if (known) return known;
|
|
454
|
-
const nodes = (compilerNodes.get(name) ?? []).map((node) => wrap._getNodeFromCompilerNode(node));
|
|
455
|
-
wrapped.set(name, nodes);
|
|
456
|
-
return nodes;
|
|
457
|
-
} };
|
|
447
|
+
ts.forEachChild(sourceFile, collect);
|
|
448
|
+
return { get: (name) => compilerNodes.get(name) ?? [] };
|
|
458
449
|
};
|
|
459
450
|
const localReferencesTo = (index, name, declaration) => {
|
|
460
451
|
const references = [];
|
|
461
452
|
for (const identifier of index.get(name)) {
|
|
462
453
|
if (identifier === declaration) continue;
|
|
463
|
-
const parent = identifier.
|
|
454
|
+
const parent = identifier.parent;
|
|
464
455
|
if (!parent) continue;
|
|
465
|
-
if (Node.isPropertyAccessExpression(parent) && parent.
|
|
466
|
-
if (Node.isPropertyAssignment(parent) && parent.
|
|
467
|
-
if (Node.isBindingElement(parent) && parent.
|
|
468
|
-
if ((Node.isJsxOpeningElement(parent) || Node.isJsxSelfClosingElement(parent) || Node.isJsxClosingElement(parent)) && parent.
|
|
469
|
-
if (Node.isJsxAttribute(parent) && parent.
|
|
470
|
-
if ((Node.isMethodDeclaration(parent) || Node.isPropertyDeclaration(parent) || Node.isGetAccessorDeclaration(parent) || Node.isSetAccessorDeclaration(parent) || Node.
|
|
471
|
-
if ((Node.isVariableDeclaration(parent) || Node.isParameterDeclaration(parent) || Node.isFunctionDeclaration(parent) || Node.isClassDeclaration(parent) || Node.isBindingElement(parent)) && parent.
|
|
456
|
+
if (Node.isPropertyAccessExpression(parent) && parent.name === identifier) continue;
|
|
457
|
+
if (Node.isPropertyAssignment(parent) && parent.name === identifier) continue;
|
|
458
|
+
if (Node.isBindingElement(parent) && parent.propertyName === identifier) continue;
|
|
459
|
+
if ((Node.isJsxOpeningElement(parent) || Node.isJsxSelfClosingElement(parent) || Node.isJsxClosingElement(parent)) && parent.tagName === identifier) continue;
|
|
460
|
+
if (Node.isJsxAttribute(parent) && parent.name === identifier) continue;
|
|
461
|
+
if ((Node.isMethodDeclaration(parent) || Node.isPropertyDeclaration(parent) || Node.isGetAccessorDeclaration(parent) || Node.isSetAccessorDeclaration(parent) || Node.isMethodSignatureDeclaration(parent) || Node.isPropertySignatureDeclaration(parent) || Node.isEnumMember(parent)) && nameNodeOf(parent) === identifier) continue;
|
|
462
|
+
if ((Node.isVariableDeclaration(parent) || Node.isParameterDeclaration(parent) || Node.isFunctionDeclaration(parent) || Node.isClassDeclaration(parent) || Node.isBindingElement(parent)) && parent.name === identifier) continue;
|
|
472
463
|
if (Node.isImportSpecifier(parent) || Node.isExportSpecifier(parent)) {
|
|
473
|
-
if (parent.
|
|
464
|
+
if (parent.name !== identifier) continue;
|
|
474
465
|
if (Node.isExportSpecifier(parent)) {
|
|
475
466
|
references.push(identifier);
|
|
476
467
|
continue;
|
|
@@ -498,7 +489,9 @@ const collectRecipeConfigs = (parserResult) => {
|
|
|
498
489
|
for (const definition of definitions) {
|
|
499
490
|
const node = definition.box?.getNode?.();
|
|
500
491
|
if (!node) continue;
|
|
501
|
-
const
|
|
492
|
+
const call = Node.isCallExpression(node) ? node : getFirstAncestorByKind(node, SyntaxKind.CallExpression);
|
|
493
|
+
const declaration = call && getFirstAncestorByKind(call, SyntaxKind.VariableDeclaration);
|
|
494
|
+
const nameNode = declaration && nameNodeOf(declaration);
|
|
502
495
|
if (!nameNode || !Node.isIdentifier(nameNode)) continue;
|
|
503
496
|
if (definition.data?.length !== 1) {
|
|
504
497
|
configs.set(nameNode.getText(), AMBIGUOUS);
|
|
@@ -547,11 +540,11 @@ const LITERAL_KINDS = new Set([
|
|
|
547
540
|
* string missing the variant — the element renders, wrongly, with no report.
|
|
548
541
|
*/
|
|
549
542
|
const literalValue = (node) => {
|
|
550
|
-
if (!node || !LITERAL_KINDS.has(node.
|
|
551
|
-
if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) return node
|
|
552
|
-
if (Node.isNumericLiteral(node)) return node
|
|
553
|
-
if (node.
|
|
554
|
-
if (node.
|
|
543
|
+
if (!node || !LITERAL_KINDS.has(node.kind)) return void 0;
|
|
544
|
+
if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) return literalValueOf(node);
|
|
545
|
+
if (Node.isNumericLiteral(node)) return literalValueOf(node);
|
|
546
|
+
if (node.kind === SyntaxKind.TrueKeyword) return true;
|
|
547
|
+
if (node.kind === SyntaxKind.FalseKeyword) return false;
|
|
555
548
|
};
|
|
556
549
|
/**
|
|
557
550
|
* The property name a key node denotes.
|
|
@@ -563,8 +556,8 @@ const literalValue = (node) => {
|
|
|
563
556
|
*/
|
|
564
557
|
const propertyKey = (nameNode) => {
|
|
565
558
|
if (Node.isIdentifier(nameNode)) return nameNode.getText();
|
|
566
|
-
if (Node.isStringLiteral(nameNode) || Node.isNoSubstitutionTemplateLiteral(nameNode)) return nameNode
|
|
567
|
-
if (Node.isNumericLiteral(nameNode)) return String(nameNode
|
|
559
|
+
if (Node.isStringLiteral(nameNode) || Node.isNoSubstitutionTemplateLiteral(nameNode)) return stringLiteralValue(nameNode);
|
|
560
|
+
if (Node.isNumericLiteral(nameNode)) return String(literalValueOf(nameNode));
|
|
568
561
|
};
|
|
569
562
|
/**
|
|
570
563
|
* Make a generated compile helper callable at this call site, by whatever name the file gives it.
|
|
@@ -577,26 +570,26 @@ const ensureRecipeHelperImport = (imported, call, isBambooCssModule, isGenerated
|
|
|
577
570
|
const sourceFile = call.getSourceFile();
|
|
578
571
|
let host;
|
|
579
572
|
let subpathModule;
|
|
580
|
-
for (const declaration of
|
|
581
|
-
const mod =
|
|
582
|
-
if (
|
|
583
|
-
for (const named of
|
|
584
|
-
if (
|
|
585
|
-
if (named
|
|
586
|
-
if (!isBambooCssModule(mod)) return void 0;
|
|
587
|
-
const local = (
|
|
573
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
574
|
+
const mod = getModuleSpecifierValue(declaration);
|
|
575
|
+
if (isTypeOnly(declaration)) continue;
|
|
576
|
+
for (const named of getNamedImports(declaration)) {
|
|
577
|
+
if (isTypeOnly(named)) continue;
|
|
578
|
+
if (nameNodeOf(named)?.getText() === imported) {
|
|
579
|
+
if (!isBambooCssModule(mod ?? "")) return void 0;
|
|
580
|
+
const local = (getAliasNode(named) ?? nameNodeOf(named))?.getText() ?? "";
|
|
588
581
|
return isShadowed(call, local) ? void 0 : { name: local };
|
|
589
582
|
}
|
|
590
583
|
}
|
|
591
|
-
if (!host && isGeneratedCssModule(mod) &&
|
|
592
|
-
if (!subpathModule) subpathModule = helperModuleFromSubpath?.(mod);
|
|
584
|
+
if (!host && isGeneratedCssModule(mod ?? "") && getNamedImports(declaration).length > 0) host = declaration;
|
|
585
|
+
if (!subpathModule) subpathModule = helperModuleFromSubpath?.(mod ?? "");
|
|
593
586
|
}
|
|
594
587
|
const fallbackModule = newImportModule ?? subpathModule;
|
|
595
588
|
if (!host && !fallbackModule) return void 0;
|
|
596
589
|
if (declaredAtModuleScope(sourceFile).has(imported)) return void 0;
|
|
597
590
|
if (isShadowed(call, imported)) return void 0;
|
|
598
591
|
if (!host) {
|
|
599
|
-
const anchor =
|
|
592
|
+
const anchor = getImportDeclarations(sourceFile).at(-1);
|
|
600
593
|
if (!anchor) return void 0;
|
|
601
594
|
return {
|
|
602
595
|
name: imported,
|
|
@@ -607,7 +600,7 @@ const ensureRecipeHelperImport = (imported, call, isBambooCssModule, isGenerated
|
|
|
607
600
|
}
|
|
608
601
|
};
|
|
609
602
|
}
|
|
610
|
-
const last =
|
|
603
|
+
const last = getNamedImports(host).at(-1);
|
|
611
604
|
if (!last) return void 0;
|
|
612
605
|
return {
|
|
613
606
|
name: imported,
|
|
@@ -647,7 +640,7 @@ const lowerRecipeCall = (call, entry, styleCompiler, isInert, resolvedSelection,
|
|
|
647
640
|
kind: "decline",
|
|
648
641
|
reason: "unsupported-shape"
|
|
649
642
|
};
|
|
650
|
-
const args = call.
|
|
643
|
+
const args = call.arguments;
|
|
651
644
|
if (args.length > 1) return {
|
|
652
645
|
kind: "decline",
|
|
653
646
|
reason: "unsupported-shape"
|
|
@@ -689,21 +682,21 @@ const lowerRecipeCall = (call, entry, styleCompiler, isInert, resolvedSelection,
|
|
|
689
682
|
kind: "decline",
|
|
690
683
|
reason: "dynamic"
|
|
691
684
|
};
|
|
692
|
-
else for (const property of arg.
|
|
685
|
+
else for (const property of arg.properties) {
|
|
693
686
|
if (Node.isSpreadAssignment(property)) return {
|
|
694
687
|
kind: "decline",
|
|
695
688
|
reason: "dynamic"
|
|
696
689
|
};
|
|
697
690
|
if (Node.isShorthandPropertyAssignment(property)) {
|
|
698
|
-
dynamicAxes.set(
|
|
699
|
-
delete selection[
|
|
691
|
+
dynamicAxes.set(getName(property) ?? "", getName(property) ?? "");
|
|
692
|
+
delete selection[getName(property) ?? ""];
|
|
700
693
|
continue;
|
|
701
694
|
}
|
|
702
695
|
if (!Node.isPropertyAssignment(property)) return {
|
|
703
696
|
kind: "decline",
|
|
704
697
|
reason: "dynamic"
|
|
705
698
|
};
|
|
706
|
-
const nameNode = property.
|
|
699
|
+
const nameNode = property.name;
|
|
707
700
|
if (Node.isComputedPropertyName(nameNode)) return {
|
|
708
701
|
kind: "decline",
|
|
709
702
|
reason: "dynamic"
|
|
@@ -713,7 +706,7 @@ const lowerRecipeCall = (call, entry, styleCompiler, isInert, resolvedSelection,
|
|
|
713
706
|
kind: "decline",
|
|
714
707
|
reason: "dynamic"
|
|
715
708
|
};
|
|
716
|
-
const initializer = property.
|
|
709
|
+
const initializer = property.initializer;
|
|
717
710
|
if (initializer && !isInert(initializer)) {
|
|
718
711
|
if (!Object.hasOwn(config.variants ?? {}, key)) return {
|
|
719
712
|
kind: "decline",
|
|
@@ -1151,24 +1144,24 @@ const RECIPE_CALL_TYPE = "cva-call";
|
|
|
1151
1144
|
* A type position is excluded for a different reason: it is erased, and with it the import.
|
|
1152
1145
|
*/
|
|
1153
1146
|
const isValueReference = (identifier) => {
|
|
1154
|
-
const parent = identifier.
|
|
1147
|
+
const parent = identifier.parent;
|
|
1155
1148
|
if (!parent) return false;
|
|
1156
1149
|
if (Node.isImportSpecifier(parent) || Node.isExportSpecifier(parent)) return false;
|
|
1157
1150
|
if (Node.isImportClause(parent) || Node.isNamespaceImport(parent)) return false;
|
|
1158
|
-
if (Node.isPropertyAccessExpression(parent) && parent.
|
|
1159
|
-
if (Node.isQualifiedName(parent) && parent.
|
|
1160
|
-
if (Node.isPropertyAssignment(parent) && parent.
|
|
1161
|
-
if (Node.isMethodDeclaration(parent) || Node.isPropertyDeclaration(parent) || Node.isGetAccessorDeclaration(parent) || Node.isSetAccessorDeclaration(parent) || Node.
|
|
1162
|
-
if (parent
|
|
1151
|
+
if (Node.isPropertyAccessExpression(parent) && parent.name === identifier) return false;
|
|
1152
|
+
if (Node.isQualifiedName(parent) && parent.right === identifier) return false;
|
|
1153
|
+
if (Node.isPropertyAssignment(parent) && parent.name === identifier) return false;
|
|
1154
|
+
if (Node.isMethodDeclaration(parent) || Node.isPropertyDeclaration(parent) || Node.isGetAccessorDeclaration(parent) || Node.isSetAccessorDeclaration(parent) || Node.isMethodSignatureDeclaration(parent) || Node.isPropertySignatureDeclaration(parent) || Node.isEnumMember(parent)) {
|
|
1155
|
+
if (nameNodeOf(parent) === identifier) return false;
|
|
1163
1156
|
}
|
|
1164
1157
|
if (Node.isLabeledStatement(parent) || Node.isBreakStatement(parent) || Node.isContinueStatement(parent)) return false;
|
|
1165
1158
|
if (Node.isJsxOpeningElement(parent) || Node.isJsxSelfClosingElement(parent) || Node.isJsxClosingElement(parent)) {
|
|
1166
|
-
if (parent.
|
|
1159
|
+
if (parent.tagName === identifier) return identifier.getText()[0] === identifier.getText()[0]?.toUpperCase();
|
|
1167
1160
|
}
|
|
1168
1161
|
if (Node.isJsxAttribute(parent)) return false;
|
|
1169
|
-
if (Node.isBindingElement(parent) && parent.
|
|
1170
|
-
if ((Node.isVariableDeclaration(parent) || Node.isParameterDeclaration(parent) || Node.isBindingElement(parent) || Node.isFunctionDeclaration(parent) || Node.isClassDeclaration(parent)) && parent.
|
|
1171
|
-
return !
|
|
1162
|
+
if (Node.isBindingElement(parent) && parent.propertyName === identifier) return false;
|
|
1163
|
+
if ((Node.isVariableDeclaration(parent) || Node.isParameterDeclaration(parent) || Node.isBindingElement(parent) || Node.isFunctionDeclaration(parent) || Node.isClassDeclaration(parent)) && parent.name === identifier) return false;
|
|
1164
|
+
return !getFirstAncestor(identifier, (ancestor) => Node.isTypeNode(ancestor) || Node.isTypeAliasDeclaration(ancestor) || Node.isInterfaceDeclaration(ancestor));
|
|
1172
1165
|
};
|
|
1173
1166
|
/**
|
|
1174
1167
|
* Imports a surviving reference to is not a failure.
|
|
@@ -1209,7 +1202,7 @@ const TRAILING_INDEX = /\/index$/;
|
|
|
1209
1202
|
* contract is behaviour preservation regardless: a literal is the cheap way to prove it, since
|
|
1210
1203
|
* it means no call, no property read, no getter.
|
|
1211
1204
|
*/
|
|
1212
|
-
const isInertArgument = (node) => Node.isStringLiteral(node) || Node.isNumericLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node) || node.
|
|
1205
|
+
const isInertArgument = (node) => Node.isStringLiteral(node) || Node.isNumericLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node) || node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.NullKeyword || Node.isIdentifier(node) && node.getText() === "undefined";
|
|
1213
1206
|
/**
|
|
1214
1207
|
* An expression whose evaluation cannot do anything observable, so deleting it preserves
|
|
1215
1208
|
* behaviour.
|
|
@@ -1222,25 +1215,25 @@ const isInertArgument = (node) => Node.isStringLiteral(node) || Node.isNumericLi
|
|
|
1222
1215
|
const isInertExpression = (node) => {
|
|
1223
1216
|
if (isInertArgument(node)) return true;
|
|
1224
1217
|
if (Node.isIdentifier(node)) return true;
|
|
1225
|
-
if (Node.isAsExpression(node) || Node.isSatisfiesExpression(node) || Node.isNonNullExpression(node) || Node.isTypeAssertion(node) || Node.isParenthesizedExpression(node)) return isInertExpression(node.
|
|
1218
|
+
if (Node.isAsExpression(node) || Node.isSatisfiesExpression(node) || Node.isNonNullExpression(node) || Node.isTypeAssertion(node) || Node.isParenthesizedExpression(node)) return isInertExpression(node.expression);
|
|
1226
1219
|
if (Node.isArrowFunction(node) || Node.isFunctionExpression(node)) return true;
|
|
1227
1220
|
if (Node.isRegularExpressionLiteral(node) || Node.isBigIntLiteral(node)) return true;
|
|
1228
1221
|
if (Node.isPrefixUnaryExpression(node)) {
|
|
1229
|
-
const operator = node.
|
|
1230
|
-
return (operator === SyntaxKind.MinusToken || operator === SyntaxKind.PlusToken || operator === SyntaxKind.ExclamationToken || operator === SyntaxKind.TildeToken) && isInertExpression(node.
|
|
1222
|
+
const operator = node.operator;
|
|
1223
|
+
return (operator === SyntaxKind.MinusToken || operator === SyntaxKind.PlusToken || operator === SyntaxKind.ExclamationToken || operator === SyntaxKind.TildeToken) && isInertExpression(node.operand);
|
|
1231
1224
|
}
|
|
1232
1225
|
if (Node.isBinaryExpression(node)) {
|
|
1233
|
-
const operator = node.
|
|
1234
|
-
return (operator === SyntaxKind.QuestionQuestionToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.AmpersandAmpersandToken) && isInertExpression(node.
|
|
1226
|
+
const operator = node.operatorToken.kind;
|
|
1227
|
+
return (operator === SyntaxKind.QuestionQuestionToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.AmpersandAmpersandToken) && isInertExpression(node.left) && isInertExpression(node.right);
|
|
1235
1228
|
}
|
|
1236
|
-
if (Node.isObjectLiteralExpression(node)) return node.
|
|
1229
|
+
if (Node.isObjectLiteralExpression(node)) return node.properties.every((property) => {
|
|
1237
1230
|
if (Node.isShorthandPropertyAssignment(property)) return true;
|
|
1238
1231
|
if (!Node.isPropertyAssignment(property)) return false;
|
|
1239
|
-
if (Node.isComputedPropertyName(property.
|
|
1240
|
-
const initializer = property.
|
|
1232
|
+
if (Node.isComputedPropertyName(property.name)) return false;
|
|
1233
|
+
const initializer = property.initializer;
|
|
1241
1234
|
return initializer !== void 0 && isInertExpression(initializer);
|
|
1242
1235
|
});
|
|
1243
|
-
if (Node.isArrayLiteralExpression(node)) return node.
|
|
1236
|
+
if (Node.isArrayLiteralExpression(node)) return node.elements.every(isInertExpression);
|
|
1244
1237
|
return false;
|
|
1245
1238
|
};
|
|
1246
1239
|
/**
|
|
@@ -1272,7 +1265,7 @@ const createDependencyScan = (ownFile) => {
|
|
|
1272
1265
|
if (sourceFile === ownFile) return;
|
|
1273
1266
|
let path = paths.get(sourceFile);
|
|
1274
1267
|
if (path === void 0) {
|
|
1275
|
-
path = sourceFile
|
|
1268
|
+
path = pathOf(sourceFile);
|
|
1276
1269
|
paths.set(sourceFile, path);
|
|
1277
1270
|
}
|
|
1278
1271
|
if (path) results.add(path);
|
|
@@ -1295,7 +1288,7 @@ const findCallExpression = (node) => {
|
|
|
1295
1288
|
let current = own;
|
|
1296
1289
|
for (let depth = 0; current && depth < 3; depth++) {
|
|
1297
1290
|
if (Node.isCallExpression(current)) return current;
|
|
1298
|
-
current = current.
|
|
1291
|
+
current = current.parent;
|
|
1299
1292
|
}
|
|
1300
1293
|
};
|
|
1301
1294
|
/**
|
|
@@ -1305,14 +1298,14 @@ const findCallExpression = (node) => {
|
|
|
1305
1298
|
*/
|
|
1306
1299
|
const isRawCall = (call) => {
|
|
1307
1300
|
if (!Node.isCallExpression(call)) return false;
|
|
1308
|
-
const callee = call.
|
|
1301
|
+
const callee = call.expression.getText();
|
|
1309
1302
|
return callee === "raw" || callee.endsWith(".raw");
|
|
1310
1303
|
};
|
|
1311
1304
|
/** The identifier a callee is rooted at: `css` for `css(…)`, `panda` for `panda.css(…)`. */
|
|
1312
1305
|
const calleeRootName = (call) => {
|
|
1313
1306
|
if (!Node.isCallExpression(call)) return void 0;
|
|
1314
|
-
let current = call.
|
|
1315
|
-
while (Node.isPropertyAccessExpression(current)) current = current.
|
|
1307
|
+
let current = call.expression;
|
|
1308
|
+
while (Node.isPropertyAccessExpression(current)) current = current.expression;
|
|
1316
1309
|
return Node.isIdentifier(current) ? current.getText() : void 0;
|
|
1317
1310
|
};
|
|
1318
1311
|
/**
|
|
@@ -1332,26 +1325,26 @@ const calleeRootName = (call) => {
|
|
|
1332
1325
|
*/
|
|
1333
1326
|
const bambooImportedNames = (sourceFile, ctx) => {
|
|
1334
1327
|
const names = /* @__PURE__ */ new Set();
|
|
1335
|
-
for (const declaration of
|
|
1336
|
-
const mod =
|
|
1337
|
-
for (const named of
|
|
1338
|
-
const name = named
|
|
1339
|
-
const alias =
|
|
1328
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
1329
|
+
const mod = getModuleSpecifierValue(declaration);
|
|
1330
|
+
for (const named of getNamedImports(declaration)) {
|
|
1331
|
+
const name = nameNodeOf(named)?.getText();
|
|
1332
|
+
const alias = getAliasNode(named)?.getText() ?? name;
|
|
1340
1333
|
if (ctx.imports.match({
|
|
1341
|
-
mod,
|
|
1342
|
-
name,
|
|
1343
|
-
alias
|
|
1344
|
-
})) names.add(alias);
|
|
1334
|
+
mod: mod ?? "",
|
|
1335
|
+
name: name ?? "",
|
|
1336
|
+
alias: alias ?? ""
|
|
1337
|
+
})) names.add(alias ?? "");
|
|
1345
1338
|
}
|
|
1346
|
-
const namespace =
|
|
1339
|
+
const namespace = getNamespaceImport(declaration);
|
|
1347
1340
|
if (namespace) {
|
|
1348
1341
|
const alias = namespace.getText();
|
|
1349
1342
|
if (ctx.imports.match({
|
|
1350
|
-
mod,
|
|
1351
|
-
name: alias,
|
|
1352
|
-
alias,
|
|
1343
|
+
mod: mod ?? "",
|
|
1344
|
+
name: alias ?? "",
|
|
1345
|
+
alias: alias ?? "",
|
|
1353
1346
|
kind: "namespace"
|
|
1354
|
-
})) names.add(alias);
|
|
1347
|
+
})) names.add(alias ?? "");
|
|
1355
1348
|
}
|
|
1356
1349
|
}
|
|
1357
1350
|
return names;
|
|
@@ -1366,7 +1359,7 @@ const bambooImportedNames = (sourceFile, ctx) => {
|
|
|
1366
1359
|
* attributes, which match neither and cost nothing.
|
|
1367
1360
|
*/
|
|
1368
1361
|
const isShadowed = (call, name) => {
|
|
1369
|
-
for (let node = call.
|
|
1362
|
+
for (let node = call.parent; node; node = node.parent) {
|
|
1370
1363
|
if (Node.isSourceFile(node)) return false;
|
|
1371
1364
|
if (bindsName(node, name)) return true;
|
|
1372
1365
|
}
|
|
@@ -1383,20 +1376,20 @@ const isShadowed = (call, name) => {
|
|
|
1383
1376
|
const bindingIntroduces = (nameNode, name) => {
|
|
1384
1377
|
if (!nameNode) return false;
|
|
1385
1378
|
if (Node.isIdentifier(nameNode)) return nameNode.getText() === name;
|
|
1386
|
-
if (Node.isObjectBindingPattern(nameNode) || Node.isArrayBindingPattern(nameNode)) return nameNode.
|
|
1379
|
+
if (Node.isObjectBindingPattern(nameNode) || Node.isArrayBindingPattern(nameNode)) return nameNode.elements.some((element) => Node.isBindingElement(element) && bindingIntroduces(element.name, name));
|
|
1387
1380
|
return false;
|
|
1388
1381
|
};
|
|
1389
|
-
const declarationsBind = (list, name) => Node.isVariableDeclarationList(list) && list.
|
|
1382
|
+
const declarationsBind = (list, name) => list !== void 0 && Node.isVariableDeclarationList(list) && list.declarations.some((declaration) => bindingIntroduces(declaration.name, name));
|
|
1390
1383
|
const bindsName = (scope, name) => {
|
|
1391
|
-
if (Node.isBlock(scope)) return scope.
|
|
1392
|
-
if (Node.isFunctionDeclaration(scope) || Node.isArrowFunction(scope) || Node.isFunctionExpression(scope) || Node.isMethodDeclaration(scope)) return scope.
|
|
1393
|
-
if (Node.isCatchClause(scope)) return bindingIntroduces(scope.
|
|
1394
|
-
if (Node.isForStatement(scope) || Node.isForOfStatement(scope) || Node.isForInStatement(scope)) return declarationsBind(scope.
|
|
1384
|
+
if (Node.isBlock(scope)) return scope.statements.some((statement) => statementBinds(statement, name));
|
|
1385
|
+
if (Node.isFunctionDeclaration(scope) || Node.isArrowFunction(scope) || Node.isFunctionExpression(scope) || Node.isMethodDeclaration(scope)) return scope.parameters.some((parameter) => bindingIntroduces(parameter.name, name));
|
|
1386
|
+
if (Node.isCatchClause(scope)) return bindingIntroduces(scope.variableDeclaration?.name, name);
|
|
1387
|
+
if (Node.isForStatement(scope) || Node.isForOfStatement(scope) || Node.isForInStatement(scope)) return declarationsBind(scope.initializer, name);
|
|
1395
1388
|
return false;
|
|
1396
1389
|
};
|
|
1397
1390
|
const statementBinds = (statement, name) => {
|
|
1398
|
-
if (Node.isVariableStatement(statement)) return statement.
|
|
1399
|
-
if (Node.isFunctionDeclaration(statement) || Node.isClassDeclaration(statement)) return statement.
|
|
1391
|
+
if (Node.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingIntroduces(declaration.name, name));
|
|
1392
|
+
if (Node.isFunctionDeclaration(statement) || Node.isClassDeclaration(statement)) return statement.name?.getText() === name;
|
|
1400
1393
|
return false;
|
|
1401
1394
|
};
|
|
1402
1395
|
const hasStyles = (data) => data.length > 0 && data.every((entry) => entry != null && typeof entry === "object");
|
|
@@ -1407,7 +1400,7 @@ const hasStyles = (data) => data.length > 0 && data.every((entry) => entry != nu
|
|
|
1407
1400
|
*/
|
|
1408
1401
|
const argumentsAccountedFor = (call, boxNode) => {
|
|
1409
1402
|
if (!Node.isCallExpression(call)) return false;
|
|
1410
|
-
const args = call.
|
|
1403
|
+
const args = call.arguments;
|
|
1411
1404
|
if (args.length === 0) return true;
|
|
1412
1405
|
if (box.isArray(boxNode) && boxNode.getNode() === call) {
|
|
1413
1406
|
if (boxNode.value.length !== args.length) return false;
|
|
@@ -1513,13 +1506,13 @@ const foldSource = (options) => {
|
|
|
1513
1506
|
* its `/recipes` suffix; falling back to the configured generated entry covers bare imports.
|
|
1514
1507
|
*/
|
|
1515
1508
|
const configRecipeCssSpecifier = (call, binding) => {
|
|
1516
|
-
for (const declaration of call.getSourceFile()
|
|
1517
|
-
if (
|
|
1518
|
-
if (!
|
|
1519
|
-
if (
|
|
1520
|
-
return (
|
|
1509
|
+
for (const declaration of getImportDeclarations(call.getSourceFile())) {
|
|
1510
|
+
if (isTypeOnly(declaration)) continue;
|
|
1511
|
+
if (!getNamedImports(declaration).some((named) => {
|
|
1512
|
+
if (isTypeOnly(named)) return false;
|
|
1513
|
+
return (getAliasNode(named) ?? nameNodeOf(named))?.getText() === binding;
|
|
1521
1514
|
})) continue;
|
|
1522
|
-
const mod =
|
|
1515
|
+
const mod = (getModuleSpecifierValue(declaration) ?? "").replaceAll("\\", "/");
|
|
1523
1516
|
const at = mod.lastIndexOf("/recipes");
|
|
1524
1517
|
if (at >= 0) return `${mod.slice(0, at)}/css`;
|
|
1525
1518
|
}
|
|
@@ -1537,10 +1530,10 @@ const foldSource = (options) => {
|
|
|
1537
1530
|
* expressed from the module being folded.
|
|
1538
1531
|
*/
|
|
1539
1532
|
const cssModuleSpecifierFrom = (declaring) => {
|
|
1540
|
-
for (const declaration of
|
|
1541
|
-
if (
|
|
1542
|
-
const mod =
|
|
1543
|
-
if (isGeneratedCssModule(mod)) return mod;
|
|
1533
|
+
for (const declaration of getImportDeclarations(declaring)) {
|
|
1534
|
+
if (isTypeOnly(declaration)) continue;
|
|
1535
|
+
const mod = getModuleSpecifierValue(declaration);
|
|
1536
|
+
if (isGeneratedCssModule(mod ?? "")) return mod;
|
|
1544
1537
|
}
|
|
1545
1538
|
};
|
|
1546
1539
|
/**
|
|
@@ -1591,7 +1584,7 @@ const foldSource = (options) => {
|
|
|
1591
1584
|
const resolve = () => {
|
|
1592
1585
|
if (!parseModule) return void 0;
|
|
1593
1586
|
const consuming = call.getSourceFile();
|
|
1594
|
-
if (origin.filePath === consuming
|
|
1587
|
+
if (origin.filePath === pathOf(consuming)) return void 0;
|
|
1595
1588
|
let foreign = configsByModule.get(origin.filePath);
|
|
1596
1589
|
if (!foreign) {
|
|
1597
1590
|
const result = parseModule(origin.filePath);
|
|
@@ -1618,7 +1611,7 @@ const foldSource = (options) => {
|
|
|
1618
1611
|
name: origin.name,
|
|
1619
1612
|
digest: digestRecipeConfig(entry)
|
|
1620
1613
|
});
|
|
1621
|
-
helperModules.set(name, foreign.cssSpecifier ? rebaseSpecifier(foreign.cssSpecifier, origin.filePath, consuming
|
|
1614
|
+
helperModules.set(name, foreign.cssSpecifier ? rebaseSpecifier(foreign.cssSpecifier, origin.filePath, pathOf(consuming)) : void 0);
|
|
1622
1615
|
return entry;
|
|
1623
1616
|
};
|
|
1624
1617
|
const resolved = resolve();
|
|
@@ -1635,7 +1628,7 @@ const foldSource = (options) => {
|
|
|
1635
1628
|
if (entry === AMBIGUOUS) continue;
|
|
1636
1629
|
const definition = entry.box?.getNode?.();
|
|
1637
1630
|
if (!definition) continue;
|
|
1638
|
-
const call = Node.isCallExpression(definition) ? definition :
|
|
1631
|
+
const call = Node.isCallExpression(definition) ? definition : getFirstAncestorByKind(definition, SyntaxKind.CallExpression);
|
|
1639
1632
|
if (!call || code.slice(call.getStart(), call.getEnd()) !== call.getText()) continue;
|
|
1640
1633
|
recipeDefinitions.push({
|
|
1641
1634
|
name,
|
|
@@ -1692,8 +1685,8 @@ const foldSource = (options) => {
|
|
|
1692
1685
|
});
|
|
1693
1686
|
continue;
|
|
1694
1687
|
}
|
|
1695
|
-
const callee = Node.isCallExpression(call) ? call.
|
|
1696
|
-
const propertyName = Node.isPropertyAccessExpression(callee) ? callee
|
|
1688
|
+
const callee = Node.isCallExpression(call) ? call.expression : void 0;
|
|
1689
|
+
const propertyName = callee !== void 0 && Node.isPropertyAccessExpression(callee) ? nameNodeOf(callee)?.getText() ?? "" : void 0;
|
|
1697
1690
|
const wantsValue = type === "tokenValue";
|
|
1698
1691
|
if (wantsValue !== (propertyName === "value")) {
|
|
1699
1692
|
skipped.push({
|
|
@@ -1732,7 +1725,7 @@ const foldSource = (options) => {
|
|
|
1732
1725
|
});
|
|
1733
1726
|
continue;
|
|
1734
1727
|
}
|
|
1735
|
-
if (!(Node.isCallExpression(call) ? call.
|
|
1728
|
+
if (!(Node.isCallExpression(call) ? call.arguments.slice(1) : []).every(isInertArgument)) {
|
|
1736
1729
|
skipped.push({
|
|
1737
1730
|
name,
|
|
1738
1731
|
reason: "dynamic",
|
|
@@ -1806,16 +1799,16 @@ const foldSource = (options) => {
|
|
|
1806
1799
|
let inlineSlot;
|
|
1807
1800
|
let inlineEnd = end;
|
|
1808
1801
|
if (Array.isArray(entry?.config.slots)) {
|
|
1809
|
-
const parent = call.
|
|
1810
|
-
if (Node.isPropertyAccessExpression(parent) && parent.
|
|
1811
|
-
const accessed =
|
|
1802
|
+
const parent = call.parent;
|
|
1803
|
+
if (Node.isPropertyAccessExpression(parent) && parent.expression === call) {
|
|
1804
|
+
const accessed = getName(parent);
|
|
1812
1805
|
if (entry.config.slots.includes(accessed)) {
|
|
1813
1806
|
inlineSlot = accessed;
|
|
1814
1807
|
inlineEnd = parent.getEnd();
|
|
1815
1808
|
}
|
|
1816
|
-
} else if (Node.isElementAccessExpression(parent) && parent.
|
|
1817
|
-
const argument = parent.
|
|
1818
|
-
const accessed = argument && (Node.isStringLiteral(argument) || Node.isNoSubstitutionTemplateLiteral(argument)) ? argument
|
|
1809
|
+
} else if (Node.isElementAccessExpression(parent) && parent.expression === call) {
|
|
1810
|
+
const argument = parent.argumentExpression;
|
|
1811
|
+
const accessed = argument && (Node.isStringLiteral(argument) || Node.isNoSubstitutionTemplateLiteral(argument)) ? literalValueOf(argument) : void 0;
|
|
1819
1812
|
if (typeof accessed === "string" && entry.config.slots.includes(accessed)) {
|
|
1820
1813
|
inlineSlot = accessed;
|
|
1821
1814
|
inlineEnd = parent.getEnd();
|
|
@@ -1913,9 +1906,9 @@ const foldSource = (options) => {
|
|
|
1913
1906
|
}
|
|
1914
1907
|
const start = call.getStart();
|
|
1915
1908
|
const end = call.getEnd();
|
|
1916
|
-
const memberParent = call.
|
|
1917
|
-
const accessed = type === "recipe" && Node.isPropertyAccessExpression(memberParent) && memberParent.
|
|
1918
|
-
const accessedName = accessed?.
|
|
1909
|
+
const memberParent = call.parent;
|
|
1910
|
+
const accessed = type === "recipe" && Node.isPropertyAccessExpression(memberParent) && memberParent.expression === call ? memberParent : void 0;
|
|
1911
|
+
const accessedName = accessed?.name.getText();
|
|
1919
1912
|
const declaredSlots = accessed ? ctx.recipes.getConfig(name)?.slots ?? [] : [];
|
|
1920
1913
|
const memberAccess = accessedName && declaredSlots.includes(accessedName) ? accessed : void 0;
|
|
1921
1914
|
const slot = memberAccess ? accessedName : void 0;
|
|
@@ -1951,7 +1944,7 @@ const foldSource = (options) => {
|
|
|
1951
1944
|
});
|
|
1952
1945
|
continue;
|
|
1953
1946
|
}
|
|
1954
|
-
if (!(Node.isCallExpression(call) && call.
|
|
1947
|
+
if (!(Node.isCallExpression(call) && call.arguments.length === 0 && item.data.length === 1) && !isStaticBox(item.box) || !hasStyles(item.data) || !argumentsAccountedFor(call, item.box)) {
|
|
1955
1948
|
skipped.push({
|
|
1956
1949
|
name,
|
|
1957
1950
|
reason: "dynamic",
|
|
@@ -1999,17 +1992,17 @@ const foldSource = (options) => {
|
|
|
1999
1992
|
const sourceFile = ownSourceFile ?? candidates[0]?.node.getSourceFile();
|
|
2000
1993
|
if (sourceFile) {
|
|
2001
1994
|
const cxBindings = /* @__PURE__ */ new Set();
|
|
2002
|
-
for (const declaration of
|
|
2003
|
-
if (
|
|
2004
|
-
for (const named of
|
|
2005
|
-
if (
|
|
2006
|
-
cxBindings.add((
|
|
1995
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
1996
|
+
if (isTypeOnly(declaration) || !isBambooCssModule(getModuleSpecifierValue(declaration) ?? "")) continue;
|
|
1997
|
+
for (const named of getNamedImports(declaration)) {
|
|
1998
|
+
if (isTypeOnly(named) || nameNodeOf(named)?.getText() !== "cx") continue;
|
|
1999
|
+
cxBindings.add((getAliasNode(named) ?? nameNodeOf(named))?.getText() ?? "");
|
|
2007
2000
|
}
|
|
2008
2001
|
}
|
|
2009
2002
|
const byRange = new Map(candidates.map((candidate) => [`${candidate.start}:${candidate.end}`, candidate]));
|
|
2010
|
-
for (const call of cxBindings.size ?
|
|
2011
|
-
const callee = call
|
|
2012
|
-
if (!Node.isIdentifier(callee) || !cxBindings.has(callee.getText()) || isShadowed(call, callee.getText())) continue;
|
|
2003
|
+
for (const call of cxBindings.size ? getDescendantsOfKind(sourceFile, SyntaxKind.CallExpression) : []) {
|
|
2004
|
+
const callee = childOf(call, "expression");
|
|
2005
|
+
if (callee === void 0 || !Node.isIdentifier(callee) || !cxBindings.has(callee.getText()) || isShadowed(call, callee.getText())) continue;
|
|
2013
2006
|
const matched = [];
|
|
2014
2007
|
const parts = [];
|
|
2015
2008
|
const dynamic = [];
|
|
@@ -2045,18 +2038,18 @@ const foldSource = (options) => {
|
|
|
2045
2038
|
if (Node.isStringLiteral(arg) || Node.isNoSubstitutionTemplateLiteral(arg)) {
|
|
2046
2039
|
parts.push({
|
|
2047
2040
|
kind: "class",
|
|
2048
|
-
value: arg
|
|
2041
|
+
value: stringLiteralValue(arg)
|
|
2049
2042
|
});
|
|
2050
2043
|
return true;
|
|
2051
2044
|
}
|
|
2052
2045
|
if (Node.isArrayLiteralExpression(arg)) {
|
|
2053
|
-
for (const element of arg.
|
|
2046
|
+
for (const element of arg.elements) if (Node.isSpreadElement(element) || !take(element)) return false;
|
|
2054
2047
|
return true;
|
|
2055
2048
|
}
|
|
2056
|
-
if (arg.
|
|
2049
|
+
if (arg.kind === SyntaxKind.FalseKeyword || arg.kind === SyntaxKind.TrueKeyword || Node.isNumericLiteral(arg) || arg.kind === SyntaxKind.NullKeyword || Node.isIdentifier(arg) && arg.getText() === "undefined") return true;
|
|
2057
2050
|
return false;
|
|
2058
2051
|
};
|
|
2059
|
-
for (const arg of call
|
|
2052
|
+
for (const arg of childOf(call, "arguments") ?? []) {
|
|
2060
2053
|
if (take(arg)) continue;
|
|
2061
2054
|
supported = false;
|
|
2062
2055
|
break;
|
|
@@ -2286,10 +2279,10 @@ const foldSource = (options) => {
|
|
|
2286
2279
|
collectSourceFiles(item.box, dependencyScan);
|
|
2287
2280
|
}
|
|
2288
2281
|
const recipeSourceFile = candidates[0]?.node.getSourceFile();
|
|
2289
|
-
if (recipeSourceFile && mayNameSplitVariantProps(recipeSourceFile.getFullText())) for (const access of
|
|
2290
|
-
if (
|
|
2291
|
-
const target = access
|
|
2292
|
-
if (!Node.isIdentifier(target)) continue;
|
|
2282
|
+
if (recipeSourceFile && mayNameSplitVariantProps(recipeSourceFile.getFullText())) for (const access of getDescendantsOfKind(recipeSourceFile, SyntaxKind.PropertyAccessExpression)) {
|
|
2283
|
+
if (getName(access) !== "splitVariantProps") continue;
|
|
2284
|
+
const target = childOf(access, "expression");
|
|
2285
|
+
if (target === void 0 || !Node.isIdentifier(target)) continue;
|
|
2293
2286
|
if (isShadowed(access, target.getText())) continue;
|
|
2294
2287
|
const local = recipeConfigs?.get(target.getText());
|
|
2295
2288
|
const importedConfig = !local && importsFor(recipeSourceFile).has(target.getText()) ? ctx.recipes.getConfig(target.getText()) : void 0;
|
|
@@ -2298,9 +2291,9 @@ const foldSource = (options) => {
|
|
|
2298
2291
|
box: void 0
|
|
2299
2292
|
} : void 0;
|
|
2300
2293
|
if (!entry) continue;
|
|
2301
|
-
const call = access.
|
|
2302
|
-
if (!Node.isCallExpression(call) || call.
|
|
2303
|
-
const args = call.
|
|
2294
|
+
const call = access.parent;
|
|
2295
|
+
if (!Node.isCallExpression(call) || call.expression !== access) continue;
|
|
2296
|
+
const args = call.arguments;
|
|
2304
2297
|
if (args.length !== 1) continue;
|
|
2305
2298
|
const start = call.getStart();
|
|
2306
2299
|
const end = call.getEnd();
|
|
@@ -2342,11 +2335,11 @@ const foldSource = (options) => {
|
|
|
2342
2335
|
*/
|
|
2343
2336
|
/** The specifier this module imported `binding` through, if it did. */
|
|
2344
2337
|
function importSpecifierFor(sourceFile, binding) {
|
|
2345
|
-
for (const declaration of
|
|
2346
|
-
if (
|
|
2347
|
-
for (const named of
|
|
2348
|
-
if (
|
|
2349
|
-
if ((
|
|
2338
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
2339
|
+
if (isTypeOnly(declaration)) continue;
|
|
2340
|
+
for (const named of getNamedImports(declaration)) {
|
|
2341
|
+
if (isTypeOnly(named)) continue;
|
|
2342
|
+
if ((getAliasNode(named) ?? nameNodeOf(named))?.getText() === binding) return getAliasNode(named) ?? nameNodeOf(named);
|
|
2350
2343
|
}
|
|
2351
2344
|
}
|
|
2352
2345
|
}
|
|
@@ -2374,9 +2367,9 @@ const foldSource = (options) => {
|
|
|
2374
2367
|
if (entry === AMBIGUOUS) continue;
|
|
2375
2368
|
if (!entry && !importedRecipeBindings.has(binding)) continue;
|
|
2376
2369
|
const definition = entry?.box?.getNode?.();
|
|
2377
|
-
const nameNode = definition?.getSourceFile() === sourceFile ?
|
|
2370
|
+
const nameNode = definition?.getSourceFile() === sourceFile ? nameNodeOf(getFirstAncestorByKind(definition, SyntaxKind.VariableDeclaration)) : importSpecifierFor(sourceFile, binding);
|
|
2378
2371
|
if (!nameNode || !Node.isIdentifier(nameNode)) continue;
|
|
2379
|
-
const references = localReferencesTo(identifiersByName(), binding, nameNode).filter((reference) => !
|
|
2372
|
+
const references = localReferencesTo(identifiersByName(), binding, nameNode).filter((reference) => !getFirstAncestorByKind(reference, SyntaxKind.TypeQuery));
|
|
2380
2373
|
if (skipped.filter((item) => SURVIVES_TO_RUNTIME.has(item.reason) && item.end > item.start).some((item) => references.some((ref) => ref.getStart() >= item.start && ref.getStart() < item.end))) continue;
|
|
2381
2374
|
const survivor = references.find((ref) => !applied.some(([from, to]) => ref.getStart() >= from && ref.getStart() < to));
|
|
2382
2375
|
if (!survivor) continue;
|
|
@@ -2395,16 +2388,16 @@ const foldSource = (options) => {
|
|
|
2395
2388
|
];
|
|
2396
2389
|
const runtimeCalls = [];
|
|
2397
2390
|
const importEquals = [];
|
|
2398
|
-
|
|
2391
|
+
forEachDescendant(sourceFile, (node) => {
|
|
2399
2392
|
if (Node.isCallExpression(node)) runtimeCalls.push(node);
|
|
2400
2393
|
else if (Node.isImportEqualsDeclaration(node)) importEquals.push(node);
|
|
2401
2394
|
});
|
|
2402
2395
|
for (const call of runtimeCalls) {
|
|
2403
|
-
const callee = call.
|
|
2404
|
-
const argument = call.
|
|
2396
|
+
const callee = call.expression;
|
|
2397
|
+
const argument = call.arguments[0];
|
|
2405
2398
|
if (!argument || !Node.isStringLiteral(argument) && !Node.isNoSubstitutionTemplateLiteral(argument)) continue;
|
|
2406
|
-
if (!matchesModule(argument
|
|
2407
|
-
const isDynamicImport = callee.
|
|
2399
|
+
if (!matchesModule(stringLiteralValue(argument), bambooModules)) continue;
|
|
2400
|
+
const isDynamicImport = callee.kind === SyntaxKind.ImportKeyword;
|
|
2408
2401
|
const isRequire = Node.isIdentifier(callee) && callee.getText() === "require" && !isShadowed(call, "require");
|
|
2409
2402
|
if (!isDynamicImport && !isRequire) continue;
|
|
2410
2403
|
skipped.push({
|
|
@@ -2415,13 +2408,13 @@ const foldSource = (options) => {
|
|
|
2415
2408
|
});
|
|
2416
2409
|
}
|
|
2417
2410
|
for (const declaration of importEquals) {
|
|
2418
|
-
if (
|
|
2419
|
-
const reference = declaration.
|
|
2411
|
+
if (isTypeOnly(declaration)) continue;
|
|
2412
|
+
const reference = declaration.moduleReference;
|
|
2420
2413
|
if (!Node.isExternalModuleReference(reference)) continue;
|
|
2421
|
-
const expression = reference.
|
|
2422
|
-
if (!expression || !Node.isStringLiteral(expression) || !matchesModule(expression
|
|
2414
|
+
const expression = reference.expression;
|
|
2415
|
+
if (!expression || !Node.isStringLiteral(expression) || !matchesModule(stringLiteralValue(expression), bambooModules)) continue;
|
|
2423
2416
|
skipped.push({
|
|
2424
|
-
name:
|
|
2417
|
+
name: getName(declaration) ?? "",
|
|
2425
2418
|
reason: "runtime-binding",
|
|
2426
2419
|
start: declaration.getStart(),
|
|
2427
2420
|
end: declaration.getEnd()
|
|
@@ -2429,52 +2422,53 @@ const foldSource = (options) => {
|
|
|
2429
2422
|
}
|
|
2430
2423
|
/** Local name -> what to call it in the report. */
|
|
2431
2424
|
const watched = /* @__PURE__ */ new Map();
|
|
2432
|
-
for (const declaration of
|
|
2433
|
-
if (
|
|
2434
|
-
if (!matchesModule(
|
|
2435
|
-
for (const named of
|
|
2436
|
-
if (
|
|
2437
|
-
const imported = named
|
|
2438
|
-
if (PERMITTED_BINDINGS.has(imported)) continue;
|
|
2439
|
-
watched.set((
|
|
2425
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
2426
|
+
if (isTypeOnly(declaration)) continue;
|
|
2427
|
+
if (!matchesModule(getModuleSpecifierValue(declaration) ?? "", bambooModules)) continue;
|
|
2428
|
+
for (const named of getNamedImports(declaration)) {
|
|
2429
|
+
if (isTypeOnly(named)) continue;
|
|
2430
|
+
const imported = nameNodeOf(named)?.getText();
|
|
2431
|
+
if (PERMITTED_BINDINGS.has(imported ?? "")) continue;
|
|
2432
|
+
watched.set((getAliasNode(named) ?? nameNodeOf(named))?.getText() ?? "", imported ?? "");
|
|
2440
2433
|
}
|
|
2441
|
-
const namespace =
|
|
2434
|
+
const namespace = getNamespaceImport(declaration);
|
|
2442
2435
|
if (namespace) watched.set(namespace.getText(), `${namespace.getText()}.*`);
|
|
2443
|
-
const defaultImport =
|
|
2436
|
+
const defaultImport = getDefaultImport(declaration);
|
|
2444
2437
|
if (defaultImport) watched.set(defaultImport.getText(), defaultImport.getText());
|
|
2445
2438
|
}
|
|
2446
|
-
for (const declaration of
|
|
2447
|
-
if (
|
|
2448
|
-
if (!matchesModule(
|
|
2449
|
-
if (declaration
|
|
2439
|
+
for (const declaration of getExportDeclarations(sourceFile)) {
|
|
2440
|
+
if (isTypeOnly(declaration)) continue;
|
|
2441
|
+
if (!matchesModule(getModuleSpecifierValue(declaration) ?? "", bambooModules)) continue;
|
|
2442
|
+
if (isStarExport(declaration)) {
|
|
2443
|
+
const namespace = getNamespaceExport(declaration);
|
|
2450
2444
|
skipped.push({
|
|
2451
|
-
name:
|
|
2445
|
+
name: (namespace && getName(namespace)) ?? "*",
|
|
2452
2446
|
reason: "runtime-binding",
|
|
2453
2447
|
start: declaration.getStart(),
|
|
2454
2448
|
end: declaration.getEnd()
|
|
2455
2449
|
});
|
|
2456
2450
|
continue;
|
|
2457
2451
|
}
|
|
2458
|
-
for (const named of
|
|
2459
|
-
if (
|
|
2460
|
-
const imported = named
|
|
2461
|
-
if (PERMITTED_BINDINGS.has(imported)) continue;
|
|
2452
|
+
for (const named of getNamedExports(declaration)) {
|
|
2453
|
+
if (isTypeOnly(named)) continue;
|
|
2454
|
+
const imported = nameNodeOf(named)?.getText();
|
|
2455
|
+
if (PERMITTED_BINDINGS.has(imported ?? "")) continue;
|
|
2462
2456
|
skipped.push({
|
|
2463
|
-
name: imported,
|
|
2457
|
+
name: imported ?? "",
|
|
2464
2458
|
reason: "runtime-binding",
|
|
2465
2459
|
start: named.getStart(),
|
|
2466
2460
|
end: named.getEnd()
|
|
2467
2461
|
});
|
|
2468
2462
|
}
|
|
2469
2463
|
}
|
|
2470
|
-
for (const declaration of
|
|
2471
|
-
if (
|
|
2472
|
-
for (const named of
|
|
2473
|
-
if (
|
|
2474
|
-
const imported = watched.get(named
|
|
2464
|
+
for (const declaration of getExportDeclarations(sourceFile)) {
|
|
2465
|
+
if (isTypeOnly(declaration) || childOf(declaration, "moduleSpecifier")) continue;
|
|
2466
|
+
for (const named of getNamedExports(declaration)) {
|
|
2467
|
+
if (isTypeOnly(named)) continue;
|
|
2468
|
+
const imported = watched.get(nameNodeOf(named)?.getText() ?? "");
|
|
2475
2469
|
if (imported === void 0) continue;
|
|
2476
2470
|
skipped.push({
|
|
2477
|
-
name: imported,
|
|
2471
|
+
name: imported ?? "",
|
|
2478
2472
|
reason: "runtime-binding",
|
|
2479
2473
|
start: named.getStart(),
|
|
2480
2474
|
end: named.getEnd()
|
|
@@ -2486,7 +2480,7 @@ const foldSource = (options) => {
|
|
|
2486
2480
|
const survivors = [];
|
|
2487
2481
|
for (const [local, imported] of watched) for (const identifier of identifiersByName().get(local)) {
|
|
2488
2482
|
const start = identifier.getStart();
|
|
2489
|
-
if (
|
|
2483
|
+
if (getFirstAncestorByKind(identifier, SyntaxKind.ImportDeclaration)) continue;
|
|
2490
2484
|
if (applied.some(([from, to]) => start >= from && start < to)) continue;
|
|
2491
2485
|
if (declined.some(([from, to]) => start >= from && start < to)) continue;
|
|
2492
2486
|
if (!isValueReference(identifier)) continue;
|