@bamboocss/parser 1.48.5 → 1.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +211 -206
- package/dist/index.d.cts +11 -3
- package/dist/index.d.mts +11 -3
- package/dist/index.mjs +179 -174
- package/package.json +13 -12
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Node, Project as Project$1, ScriptKind, ts } from "ts-
|
|
1
|
+
import { Node, Project as Project$1, ScriptKind, childOf, createResolver, getAliasNode, getExportDeclarations, getImportDeclarations, getLineAndColumnAtPos, getModuleSpecifierValue, getName, getNamedExports, getNamedImports, getNamespaceExport, getNamespaceImport, isStarExport, isTypeOnly, nameNodeOf, pathOf, ts } from "@bamboocss/ts-ast";
|
|
2
2
|
import { box, clearBoxNodeCache, extract, getExportedVarDeclarationWithName, invalidateDependencyPath, maybeBoxNode, unbox, unwrapExpression } from "@bamboocss/extractor";
|
|
3
3
|
import { BambooError, compact, createPatternFns, getOrCreateSet } from "@bamboocss/shared";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -410,20 +410,6 @@ function createReportMaps() {
|
|
|
410
410
|
};
|
|
411
411
|
}
|
|
412
412
|
//#endregion
|
|
413
|
-
//#region src/get-module-specifier-value.ts
|
|
414
|
-
/**
|
|
415
|
-
* Both declaration kinds carry a specifier, and `export { x } from './m'` is how a barrel
|
|
416
|
-
* forwards a recipe — so this reads either. An `export { x }` with no `from` returns
|
|
417
|
-
* undefined, which is the same answer the throwing case gives.
|
|
418
|
-
*/
|
|
419
|
-
const getModuleSpecifierValue = (node) => {
|
|
420
|
-
try {
|
|
421
|
-
return node.getModuleSpecifierValue();
|
|
422
|
-
} catch {
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
//#endregion
|
|
427
413
|
//#region src/imported-recipes.ts
|
|
428
414
|
/**
|
|
429
415
|
* A module's exported recipes, memoized.
|
|
@@ -439,15 +425,15 @@ const clearImportedRecipeCache = () => {
|
|
|
439
425
|
/** The names a file bound `cva`/`sva` to, or empty when it imports neither. */
|
|
440
426
|
const recipeFactoryAliases = (sourceFile, imports) => {
|
|
441
427
|
const aliases = /* @__PURE__ */ new Set();
|
|
442
|
-
for (const declaration of
|
|
443
|
-
if (
|
|
428
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
429
|
+
if (isTypeOnly(declaration)) continue;
|
|
444
430
|
const mod = getModuleSpecifierValue(declaration);
|
|
445
431
|
if (!mod) continue;
|
|
446
|
-
for (const specifier of
|
|
447
|
-
if (
|
|
448
|
-
const name = specifier
|
|
432
|
+
for (const specifier of getNamedImports(declaration)) {
|
|
433
|
+
if (isTypeOnly(specifier)) continue;
|
|
434
|
+
const name = nameNodeOf(specifier)?.getText();
|
|
449
435
|
if (name !== "cva" && name !== "sva") continue;
|
|
450
|
-
const alias =
|
|
436
|
+
const alias = getAliasNode(specifier)?.getText() || name;
|
|
451
437
|
if (!imports.match({
|
|
452
438
|
name,
|
|
453
439
|
alias,
|
|
@@ -468,8 +454,8 @@ const declaredRecipes = (sourceFile, imports) => {
|
|
|
468
454
|
declared,
|
|
469
455
|
exported
|
|
470
456
|
};
|
|
471
|
-
const filePath = sourceFile
|
|
472
|
-
for (const statement of sourceFile.
|
|
457
|
+
const filePath = pathOf(sourceFile);
|
|
458
|
+
for (const statement of sourceFile.statements) {
|
|
473
459
|
if (!ts.isVariableStatement(statement)) continue;
|
|
474
460
|
if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
|
|
475
461
|
for (const declaration of statement.declarationList.declarations) {
|
|
@@ -529,13 +515,13 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
|
|
|
529
515
|
const imported = walkImports(sourceFile, imports, resolveModule, seen);
|
|
530
516
|
complete &&= imported.complete;
|
|
531
517
|
for (const [alias, origin] of imported.bindings) if (!local.has(alias)) local.set(alias, origin);
|
|
532
|
-
for (const declaration of
|
|
533
|
-
if (
|
|
518
|
+
for (const declaration of getExportDeclarations(sourceFile)) {
|
|
519
|
+
if (isTypeOnly(declaration)) continue;
|
|
534
520
|
const specifier = getModuleSpecifierValue(declaration);
|
|
535
521
|
const target = specifier ? resolveModule(specifier, sourceFile) : void 0;
|
|
536
522
|
if (specifier && !target) continue;
|
|
537
|
-
if (
|
|
538
|
-
if (declaration
|
|
523
|
+
if (getNamespaceExport(declaration)) continue;
|
|
524
|
+
if (isStarExport(declaration)) {
|
|
539
525
|
if (!target) continue;
|
|
540
526
|
const walk = walkExports(target, imports, resolveModule, seen);
|
|
541
527
|
complete &&= walk.complete;
|
|
@@ -555,11 +541,11 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
|
|
|
555
541
|
complete &&= walk.complete;
|
|
556
542
|
source = walk.names;
|
|
557
543
|
}
|
|
558
|
-
for (const exportSpecifier of
|
|
559
|
-
if (
|
|
560
|
-
const name = exportSpecifier
|
|
561
|
-
const origin = source.get(name);
|
|
562
|
-
if (origin) names.set(
|
|
544
|
+
for (const exportSpecifier of getNamedExports(declaration)) {
|
|
545
|
+
if (isTypeOnly(exportSpecifier)) continue;
|
|
546
|
+
const name = nameNodeOf(exportSpecifier)?.getText();
|
|
547
|
+
const origin = source.get(name ?? "");
|
|
548
|
+
if (origin) names.set(getAliasNode(exportSpecifier)?.getText() || (name ?? ""), origin);
|
|
563
549
|
}
|
|
564
550
|
}
|
|
565
551
|
for (const [name, origin] of starred) if (!names.has(name) && !ambiguous.has(name)) names.set(name, origin);
|
|
@@ -579,9 +565,9 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
|
|
|
579
565
|
const walkImports = (sourceFile, imports, resolveModule, seen) => {
|
|
580
566
|
const bindings = /* @__PURE__ */ new Map();
|
|
581
567
|
let complete = true;
|
|
582
|
-
for (const declaration of
|
|
583
|
-
if (
|
|
584
|
-
const named =
|
|
568
|
+
for (const declaration of getImportDeclarations(sourceFile)) {
|
|
569
|
+
if (isTypeOnly(declaration)) continue;
|
|
570
|
+
const named = getNamedImports(declaration);
|
|
585
571
|
if (named.length === 0) continue;
|
|
586
572
|
const specifier = getModuleSpecifierValue(declaration);
|
|
587
573
|
if (!specifier) continue;
|
|
@@ -592,10 +578,10 @@ const walkImports = (sourceFile, imports, resolveModule, seen) => {
|
|
|
592
578
|
const { names } = walk;
|
|
593
579
|
if (names.size === 0) continue;
|
|
594
580
|
for (const importSpecifier of named) {
|
|
595
|
-
if (
|
|
596
|
-
const origin = names.get(importSpecifier
|
|
581
|
+
if (isTypeOnly(importSpecifier)) continue;
|
|
582
|
+
const origin = names.get(nameNodeOf(importSpecifier)?.getText() ?? "");
|
|
597
583
|
if (!origin) continue;
|
|
598
|
-
bindings.set(
|
|
584
|
+
bindings.set(getAliasNode(importSpecifier)?.getText() || (nameNodeOf(importSpecifier)?.getText() ?? ""), origin);
|
|
599
585
|
}
|
|
600
586
|
}
|
|
601
587
|
return {
|
|
@@ -644,7 +630,7 @@ const digestExportValue = (sourceFile, exportedName, resolveModule, onCrossing)
|
|
|
644
630
|
try {
|
|
645
631
|
const declaration = getExportedVarDeclarationWithName(exportedName, sourceFile, [], boxCtx);
|
|
646
632
|
if (!declaration) return "bamboo:export-missing";
|
|
647
|
-
const initializer = declaration
|
|
633
|
+
const initializer = childOf(declaration, "initializer");
|
|
648
634
|
if (!initializer) return void 0;
|
|
649
635
|
const box = maybeBoxNode(initializer, [], boxCtx);
|
|
650
636
|
if (!box || Array.isArray(box)) return void 0;
|
|
@@ -659,17 +645,18 @@ const digestExportValue = (sourceFile, exportedName, resolveModule, onCrossing)
|
|
|
659
645
|
};
|
|
660
646
|
//#endregion
|
|
661
647
|
//#region src/get-import-declarations.ts
|
|
662
|
-
function getImportDeclarations(context, sourceFile) {
|
|
648
|
+
function getImportDeclarations$1(context, sourceFile) {
|
|
663
649
|
const { imports, tsOptions } = context;
|
|
664
650
|
const importDeclarations = [];
|
|
665
|
-
|
|
651
|
+
getImportDeclarations(sourceFile).forEach((node) => {
|
|
666
652
|
const mod = getModuleSpecifierValue(node);
|
|
667
653
|
if (!mod) return;
|
|
668
|
-
|
|
669
|
-
const name = specifier
|
|
654
|
+
getNamedImports(node).forEach((specifier) => {
|
|
655
|
+
const name = nameNodeOf(specifier)?.getText();
|
|
656
|
+
const alias = getAliasNode(specifier)?.getText() || name;
|
|
670
657
|
const result = {
|
|
671
|
-
name,
|
|
672
|
-
alias:
|
|
658
|
+
name: name ?? "",
|
|
659
|
+
alias: alias ?? "",
|
|
673
660
|
mod,
|
|
674
661
|
kind: "named"
|
|
675
662
|
};
|
|
@@ -679,7 +666,7 @@ function getImportDeclarations(context, sourceFile) {
|
|
|
679
666
|
})) return;
|
|
680
667
|
importDeclarations.push(result);
|
|
681
668
|
});
|
|
682
|
-
const namespace =
|
|
669
|
+
const namespace = getNamespaceImport(node);
|
|
683
670
|
if (namespace) {
|
|
684
671
|
const name = namespace.getText();
|
|
685
672
|
const result = {
|
|
@@ -740,16 +727,16 @@ const findUnresolvable = (node, path, out, seen = /* @__PURE__ */ new Set()) =>
|
|
|
740
727
|
const writtenProps = (node) => {
|
|
741
728
|
let literal = node;
|
|
742
729
|
if (literal && Node.isCallExpression(literal)) {
|
|
743
|
-
const args = literal.
|
|
730
|
+
const args = literal.arguments;
|
|
744
731
|
if (args.length !== 1) return void 0;
|
|
745
732
|
literal = args[0];
|
|
746
733
|
}
|
|
747
734
|
if (!literal || !Node.isObjectLiteralExpression(literal)) return void 0;
|
|
748
735
|
const names = [];
|
|
749
736
|
let uncertain = false;
|
|
750
|
-
for (const property of literal.
|
|
737
|
+
for (const property of literal.properties) {
|
|
751
738
|
if (Node.isPropertyAssignment(property) || Node.isShorthandPropertyAssignment(property)) {
|
|
752
|
-
const name =
|
|
739
|
+
const name = getName(property) ?? "";
|
|
753
740
|
if (name.startsWith("[")) {
|
|
754
741
|
uncertain = true;
|
|
755
742
|
continue;
|
|
@@ -786,7 +773,7 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
|
|
|
786
773
|
const value = node ? unwrapExpression(node) : void 0;
|
|
787
774
|
if (!value) return;
|
|
788
775
|
if (Node.isArrayLiteralExpression(value)) {
|
|
789
|
-
value.
|
|
776
|
+
value.elements.forEach((element, index) => {
|
|
790
777
|
const at = path ? `${path}.${index}` : String(index);
|
|
791
778
|
const element_ = resolved?.[index];
|
|
792
779
|
if (Node.isSpreadElement(element) && element_ == null) {
|
|
@@ -801,16 +788,16 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
|
|
|
801
788
|
return;
|
|
802
789
|
}
|
|
803
790
|
if (!Node.isObjectLiteralExpression(value)) return;
|
|
804
|
-
const properties = value.
|
|
791
|
+
const properties = value.properties;
|
|
805
792
|
const written = [];
|
|
806
793
|
let uncertain = false;
|
|
807
794
|
for (const property of properties) {
|
|
808
795
|
if (Node.isSpreadAssignment(property)) {
|
|
809
|
-
const spread = unwrapExpression(property.
|
|
796
|
+
const spread = unwrapExpression(property.expression);
|
|
810
797
|
if (Node.isObjectLiteralExpression(spread)) {
|
|
811
|
-
for (const inner of spread.
|
|
798
|
+
for (const inner of spread.properties) {
|
|
812
799
|
if (!Node.isPropertyAssignment(inner) && !Node.isShorthandPropertyAssignment(inner)) continue;
|
|
813
|
-
const innerName =
|
|
800
|
+
const innerName = getName(inner) ?? "";
|
|
814
801
|
if (!innerName.startsWith("[")) written.push(innerName.replace(/^['"]|['"]$/g, ""));
|
|
815
802
|
}
|
|
816
803
|
continue;
|
|
@@ -819,7 +806,7 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
|
|
|
819
806
|
continue;
|
|
820
807
|
}
|
|
821
808
|
if (!Node.isPropertyAssignment(property) && !Node.isShorthandPropertyAssignment(property)) continue;
|
|
822
|
-
const name =
|
|
809
|
+
const name = getName(property) ?? "";
|
|
823
810
|
if (name.startsWith("[")) {
|
|
824
811
|
uncertain = true;
|
|
825
812
|
continue;
|
|
@@ -837,9 +824,9 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
|
|
|
837
824
|
});
|
|
838
825
|
for (const property of properties) {
|
|
839
826
|
if (!Node.isPropertyAssignment(property)) continue;
|
|
840
|
-
const name =
|
|
827
|
+
const name = (getName(property) ?? "").replace(/^['"]|['"]$/g, "");
|
|
841
828
|
if (name.startsWith("[")) continue;
|
|
842
|
-
findUnresolvedInValue(property.
|
|
829
|
+
findUnresolvedInValue(property.initializer, resolved?.[name], path ? `${path}.${name}` : name, out);
|
|
843
830
|
}
|
|
844
831
|
};
|
|
845
832
|
/** A recipe config the build could not fully read — see `findUnresolvedInValue`. */
|
|
@@ -849,7 +836,7 @@ const findUnresolvedRecipeStyles = (item) => {
|
|
|
849
836
|
if (!node || !sourceFile) return [];
|
|
850
837
|
let argument = node;
|
|
851
838
|
if (Node.isCallExpression(argument)) {
|
|
852
|
-
const args = argument.
|
|
839
|
+
const args = argument.arguments;
|
|
853
840
|
if (args.length !== 1) return [];
|
|
854
841
|
argument = args[0];
|
|
855
842
|
}
|
|
@@ -858,10 +845,10 @@ const findUnresolvedRecipeStyles = (item) => {
|
|
|
858
845
|
if (!config || !Node.isObjectLiteralExpression(config)) losses.push({ reason: "unresolvable-value" });
|
|
859
846
|
else findUnresolvedInValue(config, item.data[0], "", losses);
|
|
860
847
|
if (!losses.length) return [];
|
|
861
|
-
const { line, column } =
|
|
848
|
+
const { line, column } = getLineAndColumnAtPos(sourceFile, node.getStart());
|
|
862
849
|
return losses.map((loss) => ({
|
|
863
850
|
column,
|
|
864
|
-
filePath: sourceFile
|
|
851
|
+
filePath: pathOf(sourceFile),
|
|
865
852
|
kind: "recipe",
|
|
866
853
|
line,
|
|
867
854
|
...loss
|
|
@@ -891,9 +878,9 @@ const findUnresolvedStyles = (item, kind) => {
|
|
|
891
878
|
if (written.uncertain && !hasKeyOutside(resolved, written.names)) losses.push({ reason: "unenumerable-keys" });
|
|
892
879
|
}
|
|
893
880
|
if (!losses.length) return [];
|
|
894
|
-
const { line, column } =
|
|
881
|
+
const { line, column } = getLineAndColumnAtPos(sourceFile, node.getStart());
|
|
895
882
|
const at = {
|
|
896
|
-
filePath: sourceFile
|
|
883
|
+
filePath: pathOf(sourceFile),
|
|
897
884
|
line,
|
|
898
885
|
column
|
|
899
886
|
};
|
|
@@ -1119,7 +1106,7 @@ var ParserResult = class {
|
|
|
1119
1106
|
const visit = (node) => {
|
|
1120
1107
|
if (!node || seen.has(node)) return;
|
|
1121
1108
|
seen.add(node);
|
|
1122
|
-
const path = node.getNode?.()?.getSourceFile()
|
|
1109
|
+
const path = pathOf(node.getNode?.()?.getSourceFile())?.replaceAll("\\", "/");
|
|
1123
1110
|
if (path && path !== own) paths.add(path);
|
|
1124
1111
|
if (box.isMap(node)) for (const child of node.value.values()) visit(child);
|
|
1125
1112
|
else if (box.isArray(node)) for (const child of node.value) visit(child);
|
|
@@ -1171,6 +1158,17 @@ const combineResult = (unboxed) => {
|
|
|
1171
1158
|
...unboxed.spreadConditions
|
|
1172
1159
|
];
|
|
1173
1160
|
};
|
|
1161
|
+
/** The exact binding token accounting visits for a token call. */
|
|
1162
|
+
const tokenCalleeRange = (call) => {
|
|
1163
|
+
if (!Node.isCallExpression(call)) return void 0;
|
|
1164
|
+
let current = call.expression;
|
|
1165
|
+
while (Node.isPropertyAccessExpression(current)) current = current.expression;
|
|
1166
|
+
if (!Node.isIdentifier(current)) return void 0;
|
|
1167
|
+
return {
|
|
1168
|
+
start: current.getStart(),
|
|
1169
|
+
end: current.getEnd()
|
|
1170
|
+
};
|
|
1171
|
+
};
|
|
1174
1172
|
const defaultEnv = { preset: "ECMA" };
|
|
1175
1173
|
/**
|
|
1176
1174
|
* `fallback()` is generated into `styled-system/css`, so evaluating a call to it would mean
|
|
@@ -1184,16 +1182,16 @@ function createParser(context) {
|
|
|
1184
1182
|
const { jsx, imports, recipes } = context;
|
|
1185
1183
|
return function parse(sourceFile, encoder, options, resolveModule) {
|
|
1186
1184
|
if (!sourceFile) return;
|
|
1187
|
-
const importDeclarations = getImportDeclarations(context, sourceFile);
|
|
1185
|
+
const importDeclarations = getImportDeclarations$1(context, sourceFile);
|
|
1188
1186
|
const file = imports.file(importDeclarations);
|
|
1189
|
-
const filePath = sourceFile
|
|
1187
|
+
const filePath = pathOf(sourceFile);
|
|
1190
1188
|
logger.debug("ast:import", !file.isEmpty() ? `Found import { ${file.toString()} } in ${filePath}` : `No import found in ${filePath}`);
|
|
1191
1189
|
const parserResult = new ParserResult(context, encoder);
|
|
1192
1190
|
const importedRecipes = resolveModule ? importedRecipeBindings(sourceFile, imports, resolveModule) : /* @__PURE__ */ new Map();
|
|
1193
1191
|
if (file.isEmpty() && !jsx.isEnabled && importedRecipes.size === 0) return parserResult;
|
|
1194
1192
|
parserResult.importedRecipes = importedRecipes;
|
|
1195
1193
|
for (const binding of importedRecipes.keys()) file.addLocalRecipe(binding);
|
|
1196
|
-
if (file.importsRecipeFactory()) for (const statement of sourceFile.
|
|
1194
|
+
if (file.importsRecipeFactory()) for (const statement of sourceFile.statements) {
|
|
1197
1195
|
if (!ts.isVariableStatement(statement)) continue;
|
|
1198
1196
|
if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
|
|
1199
1197
|
for (const declaration of statement.declarationList.declarations) {
|
|
@@ -1218,7 +1216,7 @@ function createParser(context) {
|
|
|
1218
1216
|
* Defined out here rather than inside `getEvaluateOptions`, which runs per call node.
|
|
1219
1217
|
*/
|
|
1220
1218
|
const reportUnresolvedRaw = (base, at) => {
|
|
1221
|
-
const { line, column } =
|
|
1219
|
+
const { line, column } = getLineAndColumnAtPos(sourceFile, at.getStart());
|
|
1222
1220
|
parserResult.unresolved.push({
|
|
1223
1221
|
kind: "atomic",
|
|
1224
1222
|
prop: base,
|
|
@@ -1261,7 +1259,7 @@ function createParser(context) {
|
|
|
1261
1259
|
},
|
|
1262
1260
|
getEvaluateOptions: (node) => {
|
|
1263
1261
|
if (!Node.isCallExpression(node)) return evaluateOptions;
|
|
1264
|
-
const propAccessExpr = node.
|
|
1262
|
+
const propAccessExpr = node.expression;
|
|
1265
1263
|
if (Node.isIdentifier(propAccessExpr)) {
|
|
1266
1264
|
const local = propAccessExpr.getText();
|
|
1267
1265
|
if (!file.match(local) || file.getName(local) !== "fallback") return evaluateOptions;
|
|
@@ -1306,7 +1304,8 @@ function createParser(context) {
|
|
|
1306
1304
|
if (query.kind === "call-expression") parserResult.setToken({
|
|
1307
1305
|
name: "token.value",
|
|
1308
1306
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1309
|
-
data: combineResult(unbox(query.box.value[0]))
|
|
1307
|
+
data: combineResult(unbox(query.box.value[0])),
|
|
1308
|
+
tokenCalleeRange: tokenCalleeRange(query.box.getNode())
|
|
1310
1309
|
}, "tokenValue");
|
|
1311
1310
|
});
|
|
1312
1311
|
return;
|
|
@@ -1329,12 +1328,13 @@ function createParser(context) {
|
|
|
1329
1328
|
if (query.kind === "call-expression") parserResult.setToken({
|
|
1330
1329
|
name,
|
|
1331
1330
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1332
|
-
data: combineResult(unbox(query.box.value[0]))
|
|
1331
|
+
data: combineResult(unbox(query.box.value[0])),
|
|
1332
|
+
tokenCalleeRange: tokenCalleeRange(query.box.getNode())
|
|
1333
1333
|
});
|
|
1334
1334
|
});
|
|
1335
1335
|
}).when(file.isValidPattern, (name) => {
|
|
1336
1336
|
result.queryList.forEach((query) => {
|
|
1337
|
-
if (query.kind === "call-expression") parserResult.setPattern(name, {
|
|
1337
|
+
if (query.kind === "call-expression") parserResult.setPattern(name ?? "", {
|
|
1338
1338
|
name,
|
|
1339
1339
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1340
1340
|
data: combineResult(unbox(query.box.value[0]))
|
|
@@ -1342,7 +1342,7 @@ function createParser(context) {
|
|
|
1342
1342
|
});
|
|
1343
1343
|
}).when(file.isValidRecipe, (name) => {
|
|
1344
1344
|
result.queryList.forEach((query) => {
|
|
1345
|
-
if (query.kind === "call-expression") parserResult.setRecipe(name, {
|
|
1345
|
+
if (query.kind === "call-expression") parserResult.setRecipe(name ?? "", {
|
|
1346
1346
|
name,
|
|
1347
1347
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1348
1348
|
data: combineResult(unbox(query.box.value[0]))
|
|
@@ -1360,8 +1360,8 @@ function createParser(context) {
|
|
|
1360
1360
|
} else if (jsx.isEnabled && result.kind === "component") result.queryList.forEach((query) => {
|
|
1361
1361
|
const data = combineResult(unbox(query.box));
|
|
1362
1362
|
for (const tag of [name, alias]) {
|
|
1363
|
-
if (!jsx.isJsxTagRecipe(tag)) continue;
|
|
1364
|
-
recipes.filter(tag).forEach((recipe) => {
|
|
1363
|
+
if (!jsx.isJsxTagRecipe(tag ?? "")) continue;
|
|
1364
|
+
recipes.filter(tag ?? "").forEach((recipe) => {
|
|
1365
1365
|
parserResult.setRecipe(recipe.baseName, {
|
|
1366
1366
|
type: "jsx-recipe",
|
|
1367
1367
|
name: tag,
|
|
@@ -1374,19 +1374,16 @@ function createParser(context) {
|
|
|
1374
1374
|
});
|
|
1375
1375
|
});
|
|
1376
1376
|
parserResult.deadCalls = file.getDeadCalls();
|
|
1377
|
-
if (exportReadPairs.size) {
|
|
1378
|
-
const
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
};
|
|
1388
|
-
}));
|
|
1389
|
-
}
|
|
1377
|
+
if (exportReadPairs.size) parserResult.setExportReads([...exportReadPairs].map((pair) => {
|
|
1378
|
+
const at = pair.indexOf("\0");
|
|
1379
|
+
const file = pair.slice(0, at);
|
|
1380
|
+
const name = pair.slice(at + 1);
|
|
1381
|
+
return {
|
|
1382
|
+
file,
|
|
1383
|
+
name,
|
|
1384
|
+
digest: digestExportValue(resolveModule?.(file, sourceFile), name, resolveModule)
|
|
1385
|
+
};
|
|
1386
|
+
}));
|
|
1390
1387
|
return parserResult;
|
|
1391
1388
|
};
|
|
1392
1389
|
}
|
|
@@ -1403,11 +1400,16 @@ const invalidateResolutions = () => {
|
|
|
1403
1400
|
clearBoxNodeCache();
|
|
1404
1401
|
clearImportedRecipeCache();
|
|
1405
1402
|
};
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1403
|
+
/**
|
|
1404
|
+
* Compiler options as given.
|
|
1405
|
+
*
|
|
1406
|
+
* TypeScript 6 needed `convertCompilerOptionsFromJson` to turn a tsconfig's JSON spellings —
|
|
1407
|
+
* `"target": "esnext"`, relative `paths` — into the enum values and absolute paths a program
|
|
1408
|
+
* consumed. TypeScript 7 parses the tsconfig in the Go process and hands back options already
|
|
1409
|
+
* in that form, so there is nothing left to convert; the argument survives because callers pass
|
|
1410
|
+
* overrides that are already normalized.
|
|
1411
|
+
*/
|
|
1412
|
+
const normalizeCompilerOptions = (raw, _basePath = process.cwd()) => raw ?? {};
|
|
1411
1413
|
/** Snapshot the JSON-shaped ts-morph options while retaining opaque hosts and callbacks. */
|
|
1412
1414
|
const snapshotProjectOption = (value) => {
|
|
1413
1415
|
if (Array.isArray(value)) return value.map(snapshotProjectOption);
|
|
@@ -1618,32 +1620,33 @@ var Project = class {
|
|
|
1618
1620
|
this.#assertSourceFilesAccessor();
|
|
1619
1621
|
const revision = this.#sourceFiles.revision;
|
|
1620
1622
|
this.#sourceFiles.phase = "loading";
|
|
1623
|
+
let candidate;
|
|
1621
1624
|
try {
|
|
1622
|
-
|
|
1625
|
+
candidate = createTsProject(this.#sourceFiles.projectOptions);
|
|
1623
1626
|
this.#assertSourceFilesTransaction(revision);
|
|
1624
1627
|
let loaded = 0;
|
|
1628
|
+
const entries = [];
|
|
1625
1629
|
for (const [index, file] of this.#sourceFiles.initialFiles.entries()) try {
|
|
1626
1630
|
const content = read(file, index);
|
|
1627
1631
|
this.#assertSourceFilesTransaction(revision);
|
|
1628
|
-
|
|
1629
|
-
overwrite: true,
|
|
1630
|
-
scriptKind: scriptKindFor(file)
|
|
1631
|
-
});
|
|
1632
|
+
entries.push([file, content]);
|
|
1632
1633
|
this.#assertSourceFilesTransaction(revision);
|
|
1633
1634
|
loaded++;
|
|
1634
1635
|
} catch (error) {
|
|
1635
1636
|
this.#assertSourceFilesTransaction(revision);
|
|
1636
1637
|
if (!skipMissing || error?.code !== "ENOENT") throw error;
|
|
1637
1638
|
}
|
|
1639
|
+
candidate.addSourceFiles(entries);
|
|
1638
1640
|
this.#assertSourceFilesTransaction(revision);
|
|
1639
1641
|
if (loaded > 0) invalidateResolutions();
|
|
1640
|
-
this.#
|
|
1642
|
+
this.#resolver = void 0;
|
|
1641
1643
|
this.#fileTreeRevision++;
|
|
1642
1644
|
this.#assertSourceFilesTransaction(revision);
|
|
1643
1645
|
this.#sourceFiles.project = candidate;
|
|
1644
1646
|
this.#sourceFiles.phase = "ready";
|
|
1645
1647
|
return;
|
|
1646
1648
|
} catch (error) {
|
|
1649
|
+
candidate?.dispose();
|
|
1647
1650
|
this.#sourceFiles.project = void 0;
|
|
1648
1651
|
this.#sourceFiles.phase = "pending";
|
|
1649
1652
|
throw error;
|
|
@@ -1716,7 +1719,7 @@ var Project = class {
|
|
|
1716
1719
|
sourceFilesRead: 0
|
|
1717
1720
|
};
|
|
1718
1721
|
resetResolutionState = () => {
|
|
1719
|
-
this.#
|
|
1722
|
+
this.#resolver = void 0;
|
|
1720
1723
|
this.#fileTreeRevision++;
|
|
1721
1724
|
this.dependents = /* @__PURE__ */ new Map();
|
|
1722
1725
|
this.dependencies = /* @__PURE__ */ new Map();
|
|
@@ -1757,12 +1760,24 @@ var Project = class {
|
|
|
1757
1760
|
};
|
|
1758
1761
|
getSourceFile = (filePath) => {
|
|
1759
1762
|
this.#assertNotLoading();
|
|
1763
|
+
if (!this.project.has(filePath)) return void 0;
|
|
1760
1764
|
return this.project.getSourceFile(filePath);
|
|
1761
1765
|
};
|
|
1766
|
+
/**
|
|
1767
|
+
* How many syntax errors this file's parse produced.
|
|
1768
|
+
*
|
|
1769
|
+
* Asked by the token accounting, which may only speak for a file whose tree it can trust: a
|
|
1770
|
+
* construct the parser could not read leaves an ast that stops early, and every call below
|
|
1771
|
+
* the offending line silently ceases to exist. Zero means the file parsed as written.
|
|
1772
|
+
*/
|
|
1773
|
+
getSyntacticDiagnosticCount = (filePath) => {
|
|
1774
|
+
this.#assertNotLoading();
|
|
1775
|
+
return this.project.getSyntacticDiagnosticCount(filePath);
|
|
1776
|
+
};
|
|
1762
1777
|
/** ts-morph reports forward slashes; normalize callers' paths to match on Windows. */
|
|
1763
1778
|
normalizePath = (filePath) => filePath.replaceAll("\\", "/");
|
|
1764
1779
|
/** Shared filesystem-only resolution cache; no type checker is constructed. */
|
|
1765
|
-
#
|
|
1780
|
+
#resolver;
|
|
1766
1781
|
/**
|
|
1767
1782
|
* Everything memoized against the shape of the file tree, including the negative half.
|
|
1768
1783
|
*
|
|
@@ -1795,7 +1810,7 @@ var Project = class {
|
|
|
1795
1810
|
}
|
|
1796
1811
|
invalidateResolutions();
|
|
1797
1812
|
if (fileTreeChanged) {
|
|
1798
|
-
this.#
|
|
1813
|
+
this.#resolver = void 0;
|
|
1799
1814
|
this.#fileTreeRevision++;
|
|
1800
1815
|
}
|
|
1801
1816
|
};
|
|
@@ -1818,17 +1833,10 @@ var Project = class {
|
|
|
1818
1833
|
...this.#sourceFiles.projectOptions,
|
|
1819
1834
|
compilerOptions: snapshotProjectOption(next)
|
|
1820
1835
|
};
|
|
1821
|
-
|
|
1822
|
-
const current = this.project.getCompilerOptions();
|
|
1823
|
-
const cleared = Object.fromEntries(Object.keys(current).map((key) => [key, void 0]));
|
|
1824
|
-
this.project.compilerOptions.set({
|
|
1825
|
-
...cleared,
|
|
1826
|
-
...next
|
|
1827
|
-
});
|
|
1828
|
-
}
|
|
1836
|
+
this.#sourceFiles.project?.setCompilerOptions(next);
|
|
1829
1837
|
}
|
|
1830
1838
|
invalidateResolutions();
|
|
1831
|
-
this.#
|
|
1839
|
+
this.#resolver = void 0;
|
|
1832
1840
|
this.#fileTreeRevision++;
|
|
1833
1841
|
this.sourcePreparations.clear();
|
|
1834
1842
|
};
|
|
@@ -1874,33 +1882,33 @@ var Project = class {
|
|
|
1874
1882
|
this.#assertNotLoading();
|
|
1875
1883
|
const project = this.project;
|
|
1876
1884
|
const compilerOptions = project.getCompilerOptions();
|
|
1877
|
-
this.#moduleResolutionCache ??= ts.createModuleResolutionCache(project.getFileSystem().getCurrentDirectory(), (f) => f, compilerOptions);
|
|
1878
1885
|
const configurationFiles = /* @__PURE__ */ new Set();
|
|
1879
|
-
const resolutionHost = project.getModuleResolutionHost();
|
|
1880
1886
|
const recordConfigurationFile = (filePath) => {
|
|
1881
1887
|
const normalized = this.normalizePath(filePath);
|
|
1882
1888
|
if (!normalized.endsWith("/package.json") || normalized.includes("/node_modules/")) return;
|
|
1883
1889
|
if (!this.isInCheckout(normalized)) return;
|
|
1884
1890
|
configurationFiles.add(normalized);
|
|
1885
1891
|
};
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
},
|
|
1892
|
-
readFile: (filePath) => {
|
|
1893
|
-
recordConfigurationFile(filePath);
|
|
1894
|
-
return resolutionHost.readFile?.(filePath);
|
|
1892
|
+
this.#resolver ??= createResolver({
|
|
1893
|
+
cwd: project.getCurrentDirectory(),
|
|
1894
|
+
fs: {
|
|
1895
|
+
fileExists: (filePath) => project.fileExists(filePath),
|
|
1896
|
+
readFile: (filePath) => project.readFile(filePath)
|
|
1895
1897
|
}
|
|
1896
|
-
};
|
|
1898
|
+
});
|
|
1899
|
+
const configured = this.#sourceFiles.projectOptions.compilerOptions ?? compilerOptions;
|
|
1897
1900
|
this.resolutionWork.moduleResolutionsAttempted++;
|
|
1898
|
-
const resolved =
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
const
|
|
1901
|
+
const resolved = this.#resolver(moduleName, {
|
|
1902
|
+
importer: pathOf(from),
|
|
1903
|
+
baseUrl: configured?.baseUrl,
|
|
1904
|
+
paths: configured?.paths
|
|
1905
|
+
});
|
|
1906
|
+
for (const filePath of resolved.affectingFiles) recordConfigurationFile(filePath);
|
|
1907
|
+
const pendingCandidates = this.getLocalFailedLookupCandidates(resolved.failedLookups);
|
|
1908
|
+
const module = resolved.path ? {
|
|
1909
|
+
resolvedFileName: resolved.path,
|
|
1910
|
+
isExternalLibraryImport: resolved.path.includes("/node_modules/")
|
|
1911
|
+
} : void 0;
|
|
1904
1912
|
if (!module) return {
|
|
1905
1913
|
configurationFiles: [...configurationFiles].sort(),
|
|
1906
1914
|
local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates) || moduleName.startsWith("#"),
|
|
@@ -1917,7 +1925,7 @@ var Project = class {
|
|
|
1917
1925
|
local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates),
|
|
1918
1926
|
pendingCandidates
|
|
1919
1927
|
};
|
|
1920
|
-
const existing = project.getSourceFile(name);
|
|
1928
|
+
const existing = this.project.has(name) ? project.getSourceFile(name) : void 0;
|
|
1921
1929
|
if (existing) {
|
|
1922
1930
|
this.removedSourcePaths.delete(name);
|
|
1923
1931
|
return {
|
|
@@ -1936,12 +1944,10 @@ var Project = class {
|
|
|
1936
1944
|
try {
|
|
1937
1945
|
this.resolutionWork.sourceFilesRead++;
|
|
1938
1946
|
const content = project.getFileSystem().readFileSync(name);
|
|
1939
|
-
const sourceFile = project.createSourceFile(name, content, {
|
|
1940
|
-
|
|
1941
|
-
scriptKind: scriptKindFor(name)
|
|
1942
|
-
});
|
|
1947
|
+
const sourceFile = project.createSourceFile(name, content, { scriptKind: scriptKindFor(name) });
|
|
1948
|
+
if (!sourceFile) throw new Error(`bamboo: resolved ${name} but the project produced no source file`);
|
|
1943
1949
|
this.resolutionWork.sourceFilesAdded++;
|
|
1944
|
-
this.canonicalPaths.set(name, this.normalizePath(sourceFile
|
|
1950
|
+
this.canonicalPaths.set(name, this.normalizePath(pathOf(sourceFile)));
|
|
1945
1951
|
return {
|
|
1946
1952
|
configurationFiles: [...configurationFiles].sort(),
|
|
1947
1953
|
local: true,
|
|
@@ -1995,28 +2001,28 @@ var Project = class {
|
|
|
1995
2001
|
};
|
|
1996
2002
|
ensureResolutionFacts = (sourceFile) => {
|
|
1997
2003
|
this.#assertNotLoading();
|
|
1998
|
-
const importer = this.normalizePath(sourceFile
|
|
2004
|
+
const importer = this.normalizePath(pathOf(sourceFile));
|
|
1999
2005
|
const text = sourceFile.getFullText();
|
|
2000
2006
|
const cached = this.resolutionsByImporter.get(importer);
|
|
2001
2007
|
if (cached?.sourceFile === sourceFile && cached.text === text && cached.treeRevision === this.#fileTreeRevision) return cached;
|
|
2002
|
-
const declarations = [...
|
|
2008
|
+
const declarations = [...getImportDeclarations(sourceFile).map((declaration) => ({
|
|
2003
2009
|
declaration,
|
|
2004
2010
|
kind: "import"
|
|
2005
|
-
})), ...
|
|
2011
|
+
})), ...getExportDeclarations(sourceFile).map((declaration) => ({
|
|
2006
2012
|
declaration,
|
|
2007
2013
|
kind: "export"
|
|
2008
|
-
}))].filter(({ declaration }) =>
|
|
2014
|
+
}))].filter(({ declaration }) => getModuleSpecifierValue(declaration) !== void 0).sort((left, right) => left.declaration.getStart() - right.declaration.getStart());
|
|
2009
2015
|
const facts = [];
|
|
2010
2016
|
const pendingCandidates = [];
|
|
2011
2017
|
const configurationFiles = [];
|
|
2012
2018
|
for (const [ordinal, { declaration, kind }] of declarations.entries()) {
|
|
2013
|
-
const specifier =
|
|
2019
|
+
const specifier = getModuleSpecifierValue(declaration);
|
|
2014
2020
|
if (!specifier) continue;
|
|
2015
2021
|
const resolved = this.resolveSpecifier(specifier, sourceFile);
|
|
2016
2022
|
if (!resolved.local) continue;
|
|
2017
2023
|
facts.push(Object.freeze({
|
|
2018
2024
|
importer,
|
|
2019
|
-
target: resolved.sourceFile ? this.normalizePath(resolved.sourceFile
|
|
2025
|
+
target: resolved.sourceFile ? this.normalizePath(pathOf(resolved.sourceFile)) : null,
|
|
2020
2026
|
specifier,
|
|
2021
2027
|
kind,
|
|
2022
2028
|
ordinal
|
|
@@ -2041,22 +2047,22 @@ var Project = class {
|
|
|
2041
2047
|
};
|
|
2042
2048
|
/** The sole cross-file source resolver supplied to parser and extractor. */
|
|
2043
2049
|
resolveModule = (specifier, from) => {
|
|
2044
|
-
const target = this.ensureResolutionFacts(from).facts.find((fact) => fact.specifier === specifier)?.target;
|
|
2050
|
+
const target = this.ensureResolutionFacts(from).facts.find((fact) => fact.specifier === specifier)?.target ?? (specifier.startsWith("/") ? specifier : void 0);
|
|
2045
2051
|
if (!target) return;
|
|
2046
2052
|
const sourceFile = this.project.getSourceFile(target);
|
|
2047
2053
|
if (!sourceFile) return;
|
|
2048
|
-
this.prepareEffectiveSource(sourceFile
|
|
2054
|
+
this.prepareEffectiveSource(pathOf(sourceFile), sourceFile);
|
|
2049
2055
|
return sourceFile;
|
|
2050
2056
|
};
|
|
2051
2057
|
trackDependencies = (filePath, sourceFile) => {
|
|
2052
2058
|
this.#assertNotLoading();
|
|
2053
|
-
const importer = this.normalizePath(sourceFile
|
|
2059
|
+
const importer = this.normalizePath(pathOf(sourceFile));
|
|
2054
2060
|
this.canonicalPaths.set(this.normalizePath(filePath), importer);
|
|
2055
2061
|
this.canonicalPaths.set(importer, importer);
|
|
2056
2062
|
this.ensureResolutionFacts(sourceFile);
|
|
2057
2063
|
};
|
|
2058
2064
|
invalidateSourcePreparation = (filePath, sourceFile) => {
|
|
2059
|
-
const sourcePath = this.normalizePath(sourceFile
|
|
2065
|
+
const sourcePath = this.normalizePath(pathOf(sourceFile) ?? filePath);
|
|
2060
2066
|
const preparation = this.sourcePreparations.get(sourcePath);
|
|
2061
2067
|
if (preparation?.state === "preparing") preparation.invalidated = true;
|
|
2062
2068
|
this.sourcePreparations.delete(sourcePath);
|
|
@@ -2072,7 +2078,7 @@ var Project = class {
|
|
|
2072
2078
|
*/
|
|
2073
2079
|
prepareEffectiveSource = (filePath, sourceFile, hookFilePath = filePath) => {
|
|
2074
2080
|
this.#assertNotLoading();
|
|
2075
|
-
const sourcePath = this.normalizePath(sourceFile
|
|
2081
|
+
const sourcePath = this.normalizePath(pathOf(sourceFile));
|
|
2076
2082
|
const currentText = sourceFile.getFullText();
|
|
2077
2083
|
const current = this.sourcePreparations.get(sourcePath);
|
|
2078
2084
|
if (current?.state === "ready" && current.sourceFile === sourceFile && current.effectiveText === currentText) {
|
|
@@ -2117,7 +2123,7 @@ var Project = class {
|
|
|
2117
2123
|
assertTransaction(currentText);
|
|
2118
2124
|
const transformed = custom ?? this.transformFile(hookFilePath, currentText);
|
|
2119
2125
|
assertTransaction(currentText);
|
|
2120
|
-
if (currentText !== transformed) sourceFile.
|
|
2126
|
+
if (currentText !== transformed) sourceFile = this.project.addSourceFile(filePath, transformed) ?? sourceFile;
|
|
2121
2127
|
assertTransaction(transformed);
|
|
2122
2128
|
this.trackDependencies(filePath, sourceFile);
|
|
2123
2129
|
assertTransaction(transformed);
|
|
@@ -2134,7 +2140,7 @@ var Project = class {
|
|
|
2134
2140
|
if (this.sourcePreparations.get(sourcePath) === transaction) this.sourcePreparations.delete(sourcePath);
|
|
2135
2141
|
this.retractImporter(sourcePath);
|
|
2136
2142
|
try {
|
|
2137
|
-
if (sourceFile.getFullText() !== currentText)
|
|
2143
|
+
if (sourceFile.getFullText() !== currentText) this.project.addSourceFile(filePath, currentText);
|
|
2138
2144
|
} catch {}
|
|
2139
2145
|
throw error;
|
|
2140
2146
|
}
|
|
@@ -2161,7 +2167,7 @@ var Project = class {
|
|
|
2161
2167
|
this.retractImporter(target);
|
|
2162
2168
|
this.removedSourcePaths.add(target);
|
|
2163
2169
|
this.canonicalPaths.set(target, target);
|
|
2164
|
-
this.canonicalPaths.set(this.normalizePath(sourceFile
|
|
2170
|
+
this.canonicalPaths.set(this.normalizePath(pathOf(sourceFile)), target);
|
|
2165
2171
|
};
|
|
2166
2172
|
/**
|
|
2167
2173
|
* Every file that transitively imports `filePath`, so a watcher can re-parse the
|
|
@@ -2170,7 +2176,7 @@ var Project = class {
|
|
|
2170
2176
|
getDependents = (filePath) => {
|
|
2171
2177
|
this.#assertNotLoading();
|
|
2172
2178
|
const given = this.normalizePath(filePath);
|
|
2173
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2179
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2174
2180
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2175
2181
|
const seen = /* @__PURE__ */ new Set();
|
|
2176
2182
|
const queue = [start];
|
|
@@ -2198,7 +2204,7 @@ var Project = class {
|
|
|
2198
2204
|
getDependencies = (filePath, targets) => {
|
|
2199
2205
|
this.#assertNotLoading();
|
|
2200
2206
|
const given = this.normalizePath(filePath);
|
|
2201
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2207
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2202
2208
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2203
2209
|
const seen = /* @__PURE__ */ new Set();
|
|
2204
2210
|
const importersByDependency = /* @__PURE__ */ new Map();
|
|
@@ -2219,7 +2225,7 @@ var Project = class {
|
|
|
2219
2225
|
const selected = /* @__PURE__ */ new Set();
|
|
2220
2226
|
const reverse = Array.from(targets, (target) => {
|
|
2221
2227
|
const normalized = this.normalizePath(target);
|
|
2222
|
-
const source = this.project.getSourceFile(target)
|
|
2228
|
+
const source = pathOf(this.project.getSourceFile(target));
|
|
2223
2229
|
return source ? this.normalizePath(source) : this.canonicalPaths.get(normalized) ?? normalized;
|
|
2224
2230
|
}).filter((target) => seen.has(target));
|
|
2225
2231
|
let reverseCursor = 0;
|
|
@@ -2245,7 +2251,7 @@ var Project = class {
|
|
|
2245
2251
|
const selected = new Set(dependencies);
|
|
2246
2252
|
const retained = new Set([...previous?.dependencies ?? [], ...previous?.pendingCandidates ?? []]);
|
|
2247
2253
|
const given = this.normalizePath(filePath);
|
|
2248
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2254
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2249
2255
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2250
2256
|
const pendingCandidates = /* @__PURE__ */ new Set();
|
|
2251
2257
|
for (const importer of [start, ...dependencies]) {
|
|
@@ -2278,7 +2284,7 @@ var Project = class {
|
|
|
2278
2284
|
const selected = new Set(dependencies);
|
|
2279
2285
|
const retained = new Set(Array.from(previous, (file) => this.normalizePath(file)));
|
|
2280
2286
|
const given = this.normalizePath(filePath);
|
|
2281
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2287
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2282
2288
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2283
2289
|
const files = /* @__PURE__ */ new Set();
|
|
2284
2290
|
let hasSemanticFact = false;
|
|
@@ -2305,10 +2311,9 @@ var Project = class {
|
|
|
2305
2311
|
this.invalidateSourcePreparation(filePath, existing);
|
|
2306
2312
|
this.removedSourcePaths.delete(this.normalizePath(filePath));
|
|
2307
2313
|
this.invalidate();
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
});
|
|
2314
|
+
const created = this.project.createSourceFile(filePath, content, { scriptKind: scriptKindFor(filePath) });
|
|
2315
|
+
if (!created) throw new Error(`bamboo: could not add ${filePath} to the project`);
|
|
2316
|
+
return created;
|
|
2312
2317
|
};
|
|
2313
2318
|
createSourceFiles = () => {
|
|
2314
2319
|
this.#assertNotLoading();
|
|
@@ -2347,17 +2352,15 @@ var Project = class {
|
|
|
2347
2352
|
* matches its own source, falls through, and is overwritten exactly as before.
|
|
2348
2353
|
*/
|
|
2349
2354
|
if (existing && existing.getFullText() === content) {
|
|
2350
|
-
this.markAuxiliary(existing
|
|
2355
|
+
this.markAuxiliary(pathOf(existing), options.auxiliary);
|
|
2351
2356
|
return existing;
|
|
2352
2357
|
}
|
|
2353
2358
|
this.invalidateSourcePreparation(filePath, existing);
|
|
2354
2359
|
this.removedSourcePaths.delete(this.normalizePath(filePath));
|
|
2355
|
-
this.invalidate(!existing, existing
|
|
2356
|
-
const sourceFile = this.project.createSourceFile(filePath, content, {
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
});
|
|
2360
|
-
this.markAuxiliary(sourceFile.getFilePath(), options.auxiliary);
|
|
2360
|
+
this.invalidate(!existing, pathOf(existing));
|
|
2361
|
+
const sourceFile = this.project.createSourceFile(filePath, content, { scriptKind: scriptKindFor(filePath) });
|
|
2362
|
+
if (!sourceFile) throw new Error(`bamboo: could not add ${filePath} to the project`);
|
|
2363
|
+
this.markAuxiliary(pathOf(sourceFile), options.auxiliary);
|
|
2361
2364
|
return sourceFile;
|
|
2362
2365
|
};
|
|
2363
2366
|
/** Claim or release compiler ownership of one source, in the ledger's own spelling. */
|
|
@@ -2373,10 +2376,10 @@ var Project = class {
|
|
|
2373
2376
|
if (sourceFile) {
|
|
2374
2377
|
this.invalidate();
|
|
2375
2378
|
this.invalidateSourcePreparation(filePath, sourceFile);
|
|
2376
|
-
this.markTargetRemoved(this.normalizePath(sourceFile
|
|
2377
|
-
this.options.parserOptions.encoder.releaseFile(sourceFile
|
|
2378
|
-
this.auxiliarySources.delete(this.normalizePath(sourceFile
|
|
2379
|
-
return this.project.removeSourceFile(sourceFile);
|
|
2379
|
+
this.markTargetRemoved(this.normalizePath(pathOf(sourceFile)), sourceFile);
|
|
2380
|
+
this.options.parserOptions.encoder.releaseFile(pathOf(sourceFile));
|
|
2381
|
+
this.auxiliarySources.delete(this.normalizePath(pathOf(sourceFile)));
|
|
2382
|
+
return this.project.removeSourceFile(pathOf(sourceFile));
|
|
2380
2383
|
}
|
|
2381
2384
|
return false;
|
|
2382
2385
|
};
|
|
@@ -2395,10 +2398,10 @@ var Project = class {
|
|
|
2395
2398
|
this.#assertNotLoading();
|
|
2396
2399
|
this.#ensureSourceFiles();
|
|
2397
2400
|
const sourceFile = this.getSourceFile(filePath);
|
|
2398
|
-
this.invalidate(false, sourceFile
|
|
2401
|
+
this.invalidate(false, pathOf(sourceFile));
|
|
2399
2402
|
if (!sourceFile) return;
|
|
2400
2403
|
this.invalidateSourcePreparation(filePath, sourceFile);
|
|
2401
|
-
return
|
|
2404
|
+
return this.project.reloadSourceFile(filePath);
|
|
2402
2405
|
};
|
|
2403
2406
|
reloadSourceFiles = () => {
|
|
2404
2407
|
this.#assertNotLoading();
|
|
@@ -2409,7 +2412,7 @@ var Project = class {
|
|
|
2409
2412
|
const source = this.getSourceFile(file);
|
|
2410
2413
|
if (source) {
|
|
2411
2414
|
this.invalidateSourcePreparation(file, source);
|
|
2412
|
-
|
|
2415
|
+
this.project.reloadSourceFile(file);
|
|
2413
2416
|
} else {
|
|
2414
2417
|
this.invalidateSourcePreparation(file);
|
|
2415
2418
|
this.removedSourcePaths.delete(this.normalizePath(file));
|
|
@@ -2451,10 +2454,12 @@ var Project = class {
|
|
|
2451
2454
|
const { hooks } = this.options;
|
|
2452
2455
|
const hookFilePath = options.hookFilePath ?? filePath;
|
|
2453
2456
|
if (filePath.endsWith(".json")) return this.parseJson(filePath, encoder);
|
|
2454
|
-
|
|
2457
|
+
let sourceFile = this.project.getSourceFile(filePath);
|
|
2455
2458
|
if (!sourceFile) return;
|
|
2456
|
-
const
|
|
2457
|
-
const
|
|
2459
|
+
const prepared = this.prepareEffectiveSource(filePath, sourceFile, hookFilePath);
|
|
2460
|
+
const parserOptions = prepared.options;
|
|
2461
|
+
sourceFile = prepared.sourceFile ?? sourceFile;
|
|
2462
|
+
const result = (encoder ?? this.options.parserOptions.encoder).withOwner("parse", pathOf(sourceFile), () => this.parser(sourceFile, encoder, parserOptions, this.resolveModule))?.setFilePath(filePath);
|
|
2458
2463
|
hooks["parser:after"]?.({
|
|
2459
2464
|
filePath: hookFilePath,
|
|
2460
2465
|
result
|