@bamboocss/parser 1.49.0 → 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 +200 -208
- package/dist/index.d.cts +11 -3
- package/dist/index.d.mts +11 -3
- package/dist/index.mjs +166 -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);
|
|
@@ -1174,8 +1161,8 @@ const combineResult = (unboxed) => {
|
|
|
1174
1161
|
/** The exact binding token accounting visits for a token call. */
|
|
1175
1162
|
const tokenCalleeRange = (call) => {
|
|
1176
1163
|
if (!Node.isCallExpression(call)) return void 0;
|
|
1177
|
-
let current = call.
|
|
1178
|
-
while (Node.isPropertyAccessExpression(current)) current = current.
|
|
1164
|
+
let current = call.expression;
|
|
1165
|
+
while (Node.isPropertyAccessExpression(current)) current = current.expression;
|
|
1179
1166
|
if (!Node.isIdentifier(current)) return void 0;
|
|
1180
1167
|
return {
|
|
1181
1168
|
start: current.getStart(),
|
|
@@ -1195,16 +1182,16 @@ function createParser(context) {
|
|
|
1195
1182
|
const { jsx, imports, recipes } = context;
|
|
1196
1183
|
return function parse(sourceFile, encoder, options, resolveModule) {
|
|
1197
1184
|
if (!sourceFile) return;
|
|
1198
|
-
const importDeclarations = getImportDeclarations(context, sourceFile);
|
|
1185
|
+
const importDeclarations = getImportDeclarations$1(context, sourceFile);
|
|
1199
1186
|
const file = imports.file(importDeclarations);
|
|
1200
|
-
const filePath = sourceFile
|
|
1187
|
+
const filePath = pathOf(sourceFile);
|
|
1201
1188
|
logger.debug("ast:import", !file.isEmpty() ? `Found import { ${file.toString()} } in ${filePath}` : `No import found in ${filePath}`);
|
|
1202
1189
|
const parserResult = new ParserResult(context, encoder);
|
|
1203
1190
|
const importedRecipes = resolveModule ? importedRecipeBindings(sourceFile, imports, resolveModule) : /* @__PURE__ */ new Map();
|
|
1204
1191
|
if (file.isEmpty() && !jsx.isEnabled && importedRecipes.size === 0) return parserResult;
|
|
1205
1192
|
parserResult.importedRecipes = importedRecipes;
|
|
1206
1193
|
for (const binding of importedRecipes.keys()) file.addLocalRecipe(binding);
|
|
1207
|
-
if (file.importsRecipeFactory()) for (const statement of sourceFile.
|
|
1194
|
+
if (file.importsRecipeFactory()) for (const statement of sourceFile.statements) {
|
|
1208
1195
|
if (!ts.isVariableStatement(statement)) continue;
|
|
1209
1196
|
if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
|
|
1210
1197
|
for (const declaration of statement.declarationList.declarations) {
|
|
@@ -1229,7 +1216,7 @@ function createParser(context) {
|
|
|
1229
1216
|
* Defined out here rather than inside `getEvaluateOptions`, which runs per call node.
|
|
1230
1217
|
*/
|
|
1231
1218
|
const reportUnresolvedRaw = (base, at) => {
|
|
1232
|
-
const { line, column } =
|
|
1219
|
+
const { line, column } = getLineAndColumnAtPos(sourceFile, at.getStart());
|
|
1233
1220
|
parserResult.unresolved.push({
|
|
1234
1221
|
kind: "atomic",
|
|
1235
1222
|
prop: base,
|
|
@@ -1272,7 +1259,7 @@ function createParser(context) {
|
|
|
1272
1259
|
},
|
|
1273
1260
|
getEvaluateOptions: (node) => {
|
|
1274
1261
|
if (!Node.isCallExpression(node)) return evaluateOptions;
|
|
1275
|
-
const propAccessExpr = node.
|
|
1262
|
+
const propAccessExpr = node.expression;
|
|
1276
1263
|
if (Node.isIdentifier(propAccessExpr)) {
|
|
1277
1264
|
const local = propAccessExpr.getText();
|
|
1278
1265
|
if (!file.match(local) || file.getName(local) !== "fallback") return evaluateOptions;
|
|
@@ -1347,7 +1334,7 @@ function createParser(context) {
|
|
|
1347
1334
|
});
|
|
1348
1335
|
}).when(file.isValidPattern, (name) => {
|
|
1349
1336
|
result.queryList.forEach((query) => {
|
|
1350
|
-
if (query.kind === "call-expression") parserResult.setPattern(name, {
|
|
1337
|
+
if (query.kind === "call-expression") parserResult.setPattern(name ?? "", {
|
|
1351
1338
|
name,
|
|
1352
1339
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1353
1340
|
data: combineResult(unbox(query.box.value[0]))
|
|
@@ -1355,7 +1342,7 @@ function createParser(context) {
|
|
|
1355
1342
|
});
|
|
1356
1343
|
}).when(file.isValidRecipe, (name) => {
|
|
1357
1344
|
result.queryList.forEach((query) => {
|
|
1358
|
-
if (query.kind === "call-expression") parserResult.setRecipe(name, {
|
|
1345
|
+
if (query.kind === "call-expression") parserResult.setRecipe(name ?? "", {
|
|
1359
1346
|
name,
|
|
1360
1347
|
box: query.box.value[0] ?? box.fallback(query.box),
|
|
1361
1348
|
data: combineResult(unbox(query.box.value[0]))
|
|
@@ -1373,8 +1360,8 @@ function createParser(context) {
|
|
|
1373
1360
|
} else if (jsx.isEnabled && result.kind === "component") result.queryList.forEach((query) => {
|
|
1374
1361
|
const data = combineResult(unbox(query.box));
|
|
1375
1362
|
for (const tag of [name, alias]) {
|
|
1376
|
-
if (!jsx.isJsxTagRecipe(tag)) continue;
|
|
1377
|
-
recipes.filter(tag).forEach((recipe) => {
|
|
1363
|
+
if (!jsx.isJsxTagRecipe(tag ?? "")) continue;
|
|
1364
|
+
recipes.filter(tag ?? "").forEach((recipe) => {
|
|
1378
1365
|
parserResult.setRecipe(recipe.baseName, {
|
|
1379
1366
|
type: "jsx-recipe",
|
|
1380
1367
|
name: tag,
|
|
@@ -1387,19 +1374,16 @@ function createParser(context) {
|
|
|
1387
1374
|
});
|
|
1388
1375
|
});
|
|
1389
1376
|
parserResult.deadCalls = file.getDeadCalls();
|
|
1390
|
-
if (exportReadPairs.size) {
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
};
|
|
1401
|
-
}));
|
|
1402
|
-
}
|
|
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
|
+
}));
|
|
1403
1387
|
return parserResult;
|
|
1404
1388
|
};
|
|
1405
1389
|
}
|
|
@@ -1416,11 +1400,16 @@ const invalidateResolutions = () => {
|
|
|
1416
1400
|
clearBoxNodeCache();
|
|
1417
1401
|
clearImportedRecipeCache();
|
|
1418
1402
|
};
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
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 ?? {};
|
|
1424
1413
|
/** Snapshot the JSON-shaped ts-morph options while retaining opaque hosts and callbacks. */
|
|
1425
1414
|
const snapshotProjectOption = (value) => {
|
|
1426
1415
|
if (Array.isArray(value)) return value.map(snapshotProjectOption);
|
|
@@ -1631,32 +1620,33 @@ var Project = class {
|
|
|
1631
1620
|
this.#assertSourceFilesAccessor();
|
|
1632
1621
|
const revision = this.#sourceFiles.revision;
|
|
1633
1622
|
this.#sourceFiles.phase = "loading";
|
|
1623
|
+
let candidate;
|
|
1634
1624
|
try {
|
|
1635
|
-
|
|
1625
|
+
candidate = createTsProject(this.#sourceFiles.projectOptions);
|
|
1636
1626
|
this.#assertSourceFilesTransaction(revision);
|
|
1637
1627
|
let loaded = 0;
|
|
1628
|
+
const entries = [];
|
|
1638
1629
|
for (const [index, file] of this.#sourceFiles.initialFiles.entries()) try {
|
|
1639
1630
|
const content = read(file, index);
|
|
1640
1631
|
this.#assertSourceFilesTransaction(revision);
|
|
1641
|
-
|
|
1642
|
-
overwrite: true,
|
|
1643
|
-
scriptKind: scriptKindFor(file)
|
|
1644
|
-
});
|
|
1632
|
+
entries.push([file, content]);
|
|
1645
1633
|
this.#assertSourceFilesTransaction(revision);
|
|
1646
1634
|
loaded++;
|
|
1647
1635
|
} catch (error) {
|
|
1648
1636
|
this.#assertSourceFilesTransaction(revision);
|
|
1649
1637
|
if (!skipMissing || error?.code !== "ENOENT") throw error;
|
|
1650
1638
|
}
|
|
1639
|
+
candidate.addSourceFiles(entries);
|
|
1651
1640
|
this.#assertSourceFilesTransaction(revision);
|
|
1652
1641
|
if (loaded > 0) invalidateResolutions();
|
|
1653
|
-
this.#
|
|
1642
|
+
this.#resolver = void 0;
|
|
1654
1643
|
this.#fileTreeRevision++;
|
|
1655
1644
|
this.#assertSourceFilesTransaction(revision);
|
|
1656
1645
|
this.#sourceFiles.project = candidate;
|
|
1657
1646
|
this.#sourceFiles.phase = "ready";
|
|
1658
1647
|
return;
|
|
1659
1648
|
} catch (error) {
|
|
1649
|
+
candidate?.dispose();
|
|
1660
1650
|
this.#sourceFiles.project = void 0;
|
|
1661
1651
|
this.#sourceFiles.phase = "pending";
|
|
1662
1652
|
throw error;
|
|
@@ -1729,7 +1719,7 @@ var Project = class {
|
|
|
1729
1719
|
sourceFilesRead: 0
|
|
1730
1720
|
};
|
|
1731
1721
|
resetResolutionState = () => {
|
|
1732
|
-
this.#
|
|
1722
|
+
this.#resolver = void 0;
|
|
1733
1723
|
this.#fileTreeRevision++;
|
|
1734
1724
|
this.dependents = /* @__PURE__ */ new Map();
|
|
1735
1725
|
this.dependencies = /* @__PURE__ */ new Map();
|
|
@@ -1770,12 +1760,24 @@ var Project = class {
|
|
|
1770
1760
|
};
|
|
1771
1761
|
getSourceFile = (filePath) => {
|
|
1772
1762
|
this.#assertNotLoading();
|
|
1763
|
+
if (!this.project.has(filePath)) return void 0;
|
|
1773
1764
|
return this.project.getSourceFile(filePath);
|
|
1774
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
|
+
};
|
|
1775
1777
|
/** ts-morph reports forward slashes; normalize callers' paths to match on Windows. */
|
|
1776
1778
|
normalizePath = (filePath) => filePath.replaceAll("\\", "/");
|
|
1777
1779
|
/** Shared filesystem-only resolution cache; no type checker is constructed. */
|
|
1778
|
-
#
|
|
1780
|
+
#resolver;
|
|
1779
1781
|
/**
|
|
1780
1782
|
* Everything memoized against the shape of the file tree, including the negative half.
|
|
1781
1783
|
*
|
|
@@ -1808,7 +1810,7 @@ var Project = class {
|
|
|
1808
1810
|
}
|
|
1809
1811
|
invalidateResolutions();
|
|
1810
1812
|
if (fileTreeChanged) {
|
|
1811
|
-
this.#
|
|
1813
|
+
this.#resolver = void 0;
|
|
1812
1814
|
this.#fileTreeRevision++;
|
|
1813
1815
|
}
|
|
1814
1816
|
};
|
|
@@ -1831,17 +1833,10 @@ var Project = class {
|
|
|
1831
1833
|
...this.#sourceFiles.projectOptions,
|
|
1832
1834
|
compilerOptions: snapshotProjectOption(next)
|
|
1833
1835
|
};
|
|
1834
|
-
|
|
1835
|
-
const current = this.project.getCompilerOptions();
|
|
1836
|
-
const cleared = Object.fromEntries(Object.keys(current).map((key) => [key, void 0]));
|
|
1837
|
-
this.project.compilerOptions.set({
|
|
1838
|
-
...cleared,
|
|
1839
|
-
...next
|
|
1840
|
-
});
|
|
1841
|
-
}
|
|
1836
|
+
this.#sourceFiles.project?.setCompilerOptions(next);
|
|
1842
1837
|
}
|
|
1843
1838
|
invalidateResolutions();
|
|
1844
|
-
this.#
|
|
1839
|
+
this.#resolver = void 0;
|
|
1845
1840
|
this.#fileTreeRevision++;
|
|
1846
1841
|
this.sourcePreparations.clear();
|
|
1847
1842
|
};
|
|
@@ -1887,33 +1882,33 @@ var Project = class {
|
|
|
1887
1882
|
this.#assertNotLoading();
|
|
1888
1883
|
const project = this.project;
|
|
1889
1884
|
const compilerOptions = project.getCompilerOptions();
|
|
1890
|
-
this.#moduleResolutionCache ??= ts.createModuleResolutionCache(project.getFileSystem().getCurrentDirectory(), (f) => f, compilerOptions);
|
|
1891
1885
|
const configurationFiles = /* @__PURE__ */ new Set();
|
|
1892
|
-
const resolutionHost = project.getModuleResolutionHost();
|
|
1893
1886
|
const recordConfigurationFile = (filePath) => {
|
|
1894
1887
|
const normalized = this.normalizePath(filePath);
|
|
1895
1888
|
if (!normalized.endsWith("/package.json") || normalized.includes("/node_modules/")) return;
|
|
1896
1889
|
if (!this.isInCheckout(normalized)) return;
|
|
1897
1890
|
configurationFiles.add(normalized);
|
|
1898
1891
|
};
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
},
|
|
1905
|
-
readFile: (filePath) => {
|
|
1906
|
-
recordConfigurationFile(filePath);
|
|
1907
|
-
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)
|
|
1908
1897
|
}
|
|
1909
|
-
};
|
|
1898
|
+
});
|
|
1899
|
+
const configured = this.#sourceFiles.projectOptions.compilerOptions ?? compilerOptions;
|
|
1910
1900
|
this.resolutionWork.moduleResolutionsAttempted++;
|
|
1911
|
-
const resolved =
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
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;
|
|
1917
1912
|
if (!module) return {
|
|
1918
1913
|
configurationFiles: [...configurationFiles].sort(),
|
|
1919
1914
|
local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates) || moduleName.startsWith("#"),
|
|
@@ -1930,7 +1925,7 @@ var Project = class {
|
|
|
1930
1925
|
local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates),
|
|
1931
1926
|
pendingCandidates
|
|
1932
1927
|
};
|
|
1933
|
-
const existing = project.getSourceFile(name);
|
|
1928
|
+
const existing = this.project.has(name) ? project.getSourceFile(name) : void 0;
|
|
1934
1929
|
if (existing) {
|
|
1935
1930
|
this.removedSourcePaths.delete(name);
|
|
1936
1931
|
return {
|
|
@@ -1949,12 +1944,10 @@ var Project = class {
|
|
|
1949
1944
|
try {
|
|
1950
1945
|
this.resolutionWork.sourceFilesRead++;
|
|
1951
1946
|
const content = project.getFileSystem().readFileSync(name);
|
|
1952
|
-
const sourceFile = project.createSourceFile(name, content, {
|
|
1953
|
-
|
|
1954
|
-
scriptKind: scriptKindFor(name)
|
|
1955
|
-
});
|
|
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`);
|
|
1956
1949
|
this.resolutionWork.sourceFilesAdded++;
|
|
1957
|
-
this.canonicalPaths.set(name, this.normalizePath(sourceFile
|
|
1950
|
+
this.canonicalPaths.set(name, this.normalizePath(pathOf(sourceFile)));
|
|
1958
1951
|
return {
|
|
1959
1952
|
configurationFiles: [...configurationFiles].sort(),
|
|
1960
1953
|
local: true,
|
|
@@ -2008,28 +2001,28 @@ var Project = class {
|
|
|
2008
2001
|
};
|
|
2009
2002
|
ensureResolutionFacts = (sourceFile) => {
|
|
2010
2003
|
this.#assertNotLoading();
|
|
2011
|
-
const importer = this.normalizePath(sourceFile
|
|
2004
|
+
const importer = this.normalizePath(pathOf(sourceFile));
|
|
2012
2005
|
const text = sourceFile.getFullText();
|
|
2013
2006
|
const cached = this.resolutionsByImporter.get(importer);
|
|
2014
2007
|
if (cached?.sourceFile === sourceFile && cached.text === text && cached.treeRevision === this.#fileTreeRevision) return cached;
|
|
2015
|
-
const declarations = [...
|
|
2008
|
+
const declarations = [...getImportDeclarations(sourceFile).map((declaration) => ({
|
|
2016
2009
|
declaration,
|
|
2017
2010
|
kind: "import"
|
|
2018
|
-
})), ...
|
|
2011
|
+
})), ...getExportDeclarations(sourceFile).map((declaration) => ({
|
|
2019
2012
|
declaration,
|
|
2020
2013
|
kind: "export"
|
|
2021
|
-
}))].filter(({ declaration }) =>
|
|
2014
|
+
}))].filter(({ declaration }) => getModuleSpecifierValue(declaration) !== void 0).sort((left, right) => left.declaration.getStart() - right.declaration.getStart());
|
|
2022
2015
|
const facts = [];
|
|
2023
2016
|
const pendingCandidates = [];
|
|
2024
2017
|
const configurationFiles = [];
|
|
2025
2018
|
for (const [ordinal, { declaration, kind }] of declarations.entries()) {
|
|
2026
|
-
const specifier =
|
|
2019
|
+
const specifier = getModuleSpecifierValue(declaration);
|
|
2027
2020
|
if (!specifier) continue;
|
|
2028
2021
|
const resolved = this.resolveSpecifier(specifier, sourceFile);
|
|
2029
2022
|
if (!resolved.local) continue;
|
|
2030
2023
|
facts.push(Object.freeze({
|
|
2031
2024
|
importer,
|
|
2032
|
-
target: resolved.sourceFile ? this.normalizePath(resolved.sourceFile
|
|
2025
|
+
target: resolved.sourceFile ? this.normalizePath(pathOf(resolved.sourceFile)) : null,
|
|
2033
2026
|
specifier,
|
|
2034
2027
|
kind,
|
|
2035
2028
|
ordinal
|
|
@@ -2054,22 +2047,22 @@ var Project = class {
|
|
|
2054
2047
|
};
|
|
2055
2048
|
/** The sole cross-file source resolver supplied to parser and extractor. */
|
|
2056
2049
|
resolveModule = (specifier, from) => {
|
|
2057
|
-
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);
|
|
2058
2051
|
if (!target) return;
|
|
2059
2052
|
const sourceFile = this.project.getSourceFile(target);
|
|
2060
2053
|
if (!sourceFile) return;
|
|
2061
|
-
this.prepareEffectiveSource(sourceFile
|
|
2054
|
+
this.prepareEffectiveSource(pathOf(sourceFile), sourceFile);
|
|
2062
2055
|
return sourceFile;
|
|
2063
2056
|
};
|
|
2064
2057
|
trackDependencies = (filePath, sourceFile) => {
|
|
2065
2058
|
this.#assertNotLoading();
|
|
2066
|
-
const importer = this.normalizePath(sourceFile
|
|
2059
|
+
const importer = this.normalizePath(pathOf(sourceFile));
|
|
2067
2060
|
this.canonicalPaths.set(this.normalizePath(filePath), importer);
|
|
2068
2061
|
this.canonicalPaths.set(importer, importer);
|
|
2069
2062
|
this.ensureResolutionFacts(sourceFile);
|
|
2070
2063
|
};
|
|
2071
2064
|
invalidateSourcePreparation = (filePath, sourceFile) => {
|
|
2072
|
-
const sourcePath = this.normalizePath(sourceFile
|
|
2065
|
+
const sourcePath = this.normalizePath(pathOf(sourceFile) ?? filePath);
|
|
2073
2066
|
const preparation = this.sourcePreparations.get(sourcePath);
|
|
2074
2067
|
if (preparation?.state === "preparing") preparation.invalidated = true;
|
|
2075
2068
|
this.sourcePreparations.delete(sourcePath);
|
|
@@ -2085,7 +2078,7 @@ var Project = class {
|
|
|
2085
2078
|
*/
|
|
2086
2079
|
prepareEffectiveSource = (filePath, sourceFile, hookFilePath = filePath) => {
|
|
2087
2080
|
this.#assertNotLoading();
|
|
2088
|
-
const sourcePath = this.normalizePath(sourceFile
|
|
2081
|
+
const sourcePath = this.normalizePath(pathOf(sourceFile));
|
|
2089
2082
|
const currentText = sourceFile.getFullText();
|
|
2090
2083
|
const current = this.sourcePreparations.get(sourcePath);
|
|
2091
2084
|
if (current?.state === "ready" && current.sourceFile === sourceFile && current.effectiveText === currentText) {
|
|
@@ -2130,7 +2123,7 @@ var Project = class {
|
|
|
2130
2123
|
assertTransaction(currentText);
|
|
2131
2124
|
const transformed = custom ?? this.transformFile(hookFilePath, currentText);
|
|
2132
2125
|
assertTransaction(currentText);
|
|
2133
|
-
if (currentText !== transformed) sourceFile.
|
|
2126
|
+
if (currentText !== transformed) sourceFile = this.project.addSourceFile(filePath, transformed) ?? sourceFile;
|
|
2134
2127
|
assertTransaction(transformed);
|
|
2135
2128
|
this.trackDependencies(filePath, sourceFile);
|
|
2136
2129
|
assertTransaction(transformed);
|
|
@@ -2147,7 +2140,7 @@ var Project = class {
|
|
|
2147
2140
|
if (this.sourcePreparations.get(sourcePath) === transaction) this.sourcePreparations.delete(sourcePath);
|
|
2148
2141
|
this.retractImporter(sourcePath);
|
|
2149
2142
|
try {
|
|
2150
|
-
if (sourceFile.getFullText() !== currentText)
|
|
2143
|
+
if (sourceFile.getFullText() !== currentText) this.project.addSourceFile(filePath, currentText);
|
|
2151
2144
|
} catch {}
|
|
2152
2145
|
throw error;
|
|
2153
2146
|
}
|
|
@@ -2174,7 +2167,7 @@ var Project = class {
|
|
|
2174
2167
|
this.retractImporter(target);
|
|
2175
2168
|
this.removedSourcePaths.add(target);
|
|
2176
2169
|
this.canonicalPaths.set(target, target);
|
|
2177
|
-
this.canonicalPaths.set(this.normalizePath(sourceFile
|
|
2170
|
+
this.canonicalPaths.set(this.normalizePath(pathOf(sourceFile)), target);
|
|
2178
2171
|
};
|
|
2179
2172
|
/**
|
|
2180
2173
|
* Every file that transitively imports `filePath`, so a watcher can re-parse the
|
|
@@ -2183,7 +2176,7 @@ var Project = class {
|
|
|
2183
2176
|
getDependents = (filePath) => {
|
|
2184
2177
|
this.#assertNotLoading();
|
|
2185
2178
|
const given = this.normalizePath(filePath);
|
|
2186
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2179
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2187
2180
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2188
2181
|
const seen = /* @__PURE__ */ new Set();
|
|
2189
2182
|
const queue = [start];
|
|
@@ -2211,7 +2204,7 @@ var Project = class {
|
|
|
2211
2204
|
getDependencies = (filePath, targets) => {
|
|
2212
2205
|
this.#assertNotLoading();
|
|
2213
2206
|
const given = this.normalizePath(filePath);
|
|
2214
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2207
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2215
2208
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2216
2209
|
const seen = /* @__PURE__ */ new Set();
|
|
2217
2210
|
const importersByDependency = /* @__PURE__ */ new Map();
|
|
@@ -2232,7 +2225,7 @@ var Project = class {
|
|
|
2232
2225
|
const selected = /* @__PURE__ */ new Set();
|
|
2233
2226
|
const reverse = Array.from(targets, (target) => {
|
|
2234
2227
|
const normalized = this.normalizePath(target);
|
|
2235
|
-
const source = this.project.getSourceFile(target)
|
|
2228
|
+
const source = pathOf(this.project.getSourceFile(target));
|
|
2236
2229
|
return source ? this.normalizePath(source) : this.canonicalPaths.get(normalized) ?? normalized;
|
|
2237
2230
|
}).filter((target) => seen.has(target));
|
|
2238
2231
|
let reverseCursor = 0;
|
|
@@ -2258,7 +2251,7 @@ var Project = class {
|
|
|
2258
2251
|
const selected = new Set(dependencies);
|
|
2259
2252
|
const retained = new Set([...previous?.dependencies ?? [], ...previous?.pendingCandidates ?? []]);
|
|
2260
2253
|
const given = this.normalizePath(filePath);
|
|
2261
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2254
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2262
2255
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2263
2256
|
const pendingCandidates = /* @__PURE__ */ new Set();
|
|
2264
2257
|
for (const importer of [start, ...dependencies]) {
|
|
@@ -2291,7 +2284,7 @@ var Project = class {
|
|
|
2291
2284
|
const selected = new Set(dependencies);
|
|
2292
2285
|
const retained = new Set(Array.from(previous, (file) => this.normalizePath(file)));
|
|
2293
2286
|
const given = this.normalizePath(filePath);
|
|
2294
|
-
const resolved = this.project.getSourceFile(filePath)
|
|
2287
|
+
const resolved = pathOf(this.project.getSourceFile(filePath));
|
|
2295
2288
|
const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
|
|
2296
2289
|
const files = /* @__PURE__ */ new Set();
|
|
2297
2290
|
let hasSemanticFact = false;
|
|
@@ -2318,10 +2311,9 @@ var Project = class {
|
|
|
2318
2311
|
this.invalidateSourcePreparation(filePath, existing);
|
|
2319
2312
|
this.removedSourcePaths.delete(this.normalizePath(filePath));
|
|
2320
2313
|
this.invalidate();
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
});
|
|
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;
|
|
2325
2317
|
};
|
|
2326
2318
|
createSourceFiles = () => {
|
|
2327
2319
|
this.#assertNotLoading();
|
|
@@ -2360,17 +2352,15 @@ var Project = class {
|
|
|
2360
2352
|
* matches its own source, falls through, and is overwritten exactly as before.
|
|
2361
2353
|
*/
|
|
2362
2354
|
if (existing && existing.getFullText() === content) {
|
|
2363
|
-
this.markAuxiliary(existing
|
|
2355
|
+
this.markAuxiliary(pathOf(existing), options.auxiliary);
|
|
2364
2356
|
return existing;
|
|
2365
2357
|
}
|
|
2366
2358
|
this.invalidateSourcePreparation(filePath, existing);
|
|
2367
2359
|
this.removedSourcePaths.delete(this.normalizePath(filePath));
|
|
2368
|
-
this.invalidate(!existing, existing
|
|
2369
|
-
const sourceFile = this.project.createSourceFile(filePath, content, {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
});
|
|
2373
|
-
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);
|
|
2374
2364
|
return sourceFile;
|
|
2375
2365
|
};
|
|
2376
2366
|
/** Claim or release compiler ownership of one source, in the ledger's own spelling. */
|
|
@@ -2386,10 +2376,10 @@ var Project = class {
|
|
|
2386
2376
|
if (sourceFile) {
|
|
2387
2377
|
this.invalidate();
|
|
2388
2378
|
this.invalidateSourcePreparation(filePath, sourceFile);
|
|
2389
|
-
this.markTargetRemoved(this.normalizePath(sourceFile
|
|
2390
|
-
this.options.parserOptions.encoder.releaseFile(sourceFile
|
|
2391
|
-
this.auxiliarySources.delete(this.normalizePath(sourceFile
|
|
2392
|
-
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));
|
|
2393
2383
|
}
|
|
2394
2384
|
return false;
|
|
2395
2385
|
};
|
|
@@ -2408,10 +2398,10 @@ var Project = class {
|
|
|
2408
2398
|
this.#assertNotLoading();
|
|
2409
2399
|
this.#ensureSourceFiles();
|
|
2410
2400
|
const sourceFile = this.getSourceFile(filePath);
|
|
2411
|
-
this.invalidate(false, sourceFile
|
|
2401
|
+
this.invalidate(false, pathOf(sourceFile));
|
|
2412
2402
|
if (!sourceFile) return;
|
|
2413
2403
|
this.invalidateSourcePreparation(filePath, sourceFile);
|
|
2414
|
-
return
|
|
2404
|
+
return this.project.reloadSourceFile(filePath);
|
|
2415
2405
|
};
|
|
2416
2406
|
reloadSourceFiles = () => {
|
|
2417
2407
|
this.#assertNotLoading();
|
|
@@ -2422,7 +2412,7 @@ var Project = class {
|
|
|
2422
2412
|
const source = this.getSourceFile(file);
|
|
2423
2413
|
if (source) {
|
|
2424
2414
|
this.invalidateSourcePreparation(file, source);
|
|
2425
|
-
|
|
2415
|
+
this.project.reloadSourceFile(file);
|
|
2426
2416
|
} else {
|
|
2427
2417
|
this.invalidateSourcePreparation(file);
|
|
2428
2418
|
this.removedSourcePaths.delete(this.normalizePath(file));
|
|
@@ -2464,10 +2454,12 @@ var Project = class {
|
|
|
2464
2454
|
const { hooks } = this.options;
|
|
2465
2455
|
const hookFilePath = options.hookFilePath ?? filePath;
|
|
2466
2456
|
if (filePath.endsWith(".json")) return this.parseJson(filePath, encoder);
|
|
2467
|
-
|
|
2457
|
+
let sourceFile = this.project.getSourceFile(filePath);
|
|
2468
2458
|
if (!sourceFile) return;
|
|
2469
|
-
const
|
|
2470
|
-
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);
|
|
2471
2463
|
hooks["parser:after"]?.({
|
|
2472
2464
|
filePath: hookFilePath,
|
|
2473
2465
|
result
|