@bamboocss/parser 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/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- let ts_morph = require("ts-morph");
2
+ let _bamboocss_ts_ast = require("@bamboocss/ts-ast");
3
3
  let _bamboocss_extractor = require("@bamboocss/extractor");
4
4
  let _bamboocss_shared = require("@bamboocss/shared");
5
5
  let node_crypto = require("node:crypto");
@@ -411,20 +411,6 @@ function createReportMaps() {
411
411
  };
412
412
  }
413
413
  //#endregion
414
- //#region src/get-module-specifier-value.ts
415
- /**
416
- * Both declaration kinds carry a specifier, and `export { x } from './m'` is how a barrel
417
- * forwards a recipe — so this reads either. An `export { x }` with no `from` returns
418
- * undefined, which is the same answer the throwing case gives.
419
- */
420
- const getModuleSpecifierValue = (node) => {
421
- try {
422
- return node.getModuleSpecifierValue();
423
- } catch {
424
- return;
425
- }
426
- };
427
- //#endregion
428
414
  //#region src/imported-recipes.ts
429
415
  /**
430
416
  * A module's exported recipes, memoized.
@@ -440,15 +426,15 @@ const clearImportedRecipeCache = () => {
440
426
  /** The names a file bound `cva`/`sva` to, or empty when it imports neither. */
441
427
  const recipeFactoryAliases = (sourceFile, imports) => {
442
428
  const aliases = /* @__PURE__ */ new Set();
443
- for (const declaration of sourceFile.getImportDeclarations()) {
444
- if (declaration.isTypeOnly()) continue;
445
- const mod = getModuleSpecifierValue(declaration);
429
+ for (const declaration of (0, _bamboocss_ts_ast.getImportDeclarations)(sourceFile)) {
430
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(declaration)) continue;
431
+ const mod = (0, _bamboocss_ts_ast.getModuleSpecifierValue)(declaration);
446
432
  if (!mod) continue;
447
- for (const specifier of declaration.getNamedImports()) {
448
- if (specifier.isTypeOnly()) continue;
449
- const name = specifier.getNameNode().getText();
433
+ for (const specifier of (0, _bamboocss_ts_ast.getNamedImports)(declaration)) {
434
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(specifier)) continue;
435
+ const name = (0, _bamboocss_ts_ast.nameNodeOf)(specifier)?.getText();
450
436
  if (name !== "cva" && name !== "sva") continue;
451
- const alias = specifier.getAliasNode()?.getText() || name;
437
+ const alias = (0, _bamboocss_ts_ast.getAliasNode)(specifier)?.getText() || name;
452
438
  if (!imports.match({
453
439
  name,
454
440
  alias,
@@ -469,21 +455,21 @@ const declaredRecipes = (sourceFile, imports) => {
469
455
  declared,
470
456
  exported
471
457
  };
472
- const filePath = sourceFile.getFilePath();
473
- for (const statement of sourceFile.compilerNode.statements) {
474
- if (!ts_morph.ts.isVariableStatement(statement)) continue;
475
- if (!(statement.declarationList.flags & ts_morph.ts.NodeFlags.Const)) continue;
458
+ const filePath = (0, _bamboocss_ts_ast.pathOf)(sourceFile);
459
+ for (const statement of sourceFile.statements) {
460
+ if (!_bamboocss_ts_ast.ts.isVariableStatement(statement)) continue;
461
+ if (!(statement.declarationList.flags & _bamboocss_ts_ast.ts.NodeFlags.Const)) continue;
476
462
  for (const declaration of statement.declarationList.declarations) {
477
463
  const initializer = declaration.initializer;
478
- if (!initializer || !ts_morph.ts.isCallExpression(initializer)) continue;
464
+ if (!initializer || !_bamboocss_ts_ast.ts.isCallExpression(initializer)) continue;
479
465
  const callee = initializer.expression;
480
- if (!ts_morph.ts.isIdentifier(callee) || !ts_morph.ts.isIdentifier(declaration.name)) continue;
466
+ if (!_bamboocss_ts_ast.ts.isIdentifier(callee) || !_bamboocss_ts_ast.ts.isIdentifier(declaration.name)) continue;
481
467
  if (!factories.has(callee.text)) continue;
482
468
  declared.set(declaration.name.text, {
483
469
  filePath,
484
470
  name: declaration.name.text
485
471
  });
486
- if (statement.modifiers?.some((modifier) => modifier.kind === ts_morph.ts.SyntaxKind.ExportKeyword)) exported.add(declaration.name.text);
472
+ if (statement.modifiers?.some((modifier) => modifier.kind === _bamboocss_ts_ast.ts.SyntaxKind.ExportKeyword)) exported.add(declaration.name.text);
487
473
  }
488
474
  }
489
475
  return {
@@ -530,13 +516,13 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
530
516
  const imported = walkImports(sourceFile, imports, resolveModule, seen);
531
517
  complete &&= imported.complete;
532
518
  for (const [alias, origin] of imported.bindings) if (!local.has(alias)) local.set(alias, origin);
533
- for (const declaration of sourceFile.getExportDeclarations()) {
534
- if (declaration.isTypeOnly()) continue;
535
- const specifier = getModuleSpecifierValue(declaration);
519
+ for (const declaration of (0, _bamboocss_ts_ast.getExportDeclarations)(sourceFile)) {
520
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(declaration)) continue;
521
+ const specifier = (0, _bamboocss_ts_ast.getModuleSpecifierValue)(declaration);
536
522
  const target = specifier ? resolveModule(specifier, sourceFile) : void 0;
537
523
  if (specifier && !target) continue;
538
- if (declaration.getNamespaceExport()) continue;
539
- if (declaration.isNamespaceExport()) {
524
+ if ((0, _bamboocss_ts_ast.getNamespaceExport)(declaration)) continue;
525
+ if ((0, _bamboocss_ts_ast.isStarExport)(declaration)) {
540
526
  if (!target) continue;
541
527
  const walk = walkExports(target, imports, resolveModule, seen);
542
528
  complete &&= walk.complete;
@@ -556,11 +542,11 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
556
542
  complete &&= walk.complete;
557
543
  source = walk.names;
558
544
  }
559
- for (const exportSpecifier of declaration.getNamedExports()) {
560
- if (exportSpecifier.isTypeOnly()) continue;
561
- const name = exportSpecifier.getNameNode().getText();
562
- const origin = source.get(name);
563
- if (origin) names.set(exportSpecifier.getAliasNode()?.getText() || name, origin);
545
+ for (const exportSpecifier of (0, _bamboocss_ts_ast.getNamedExports)(declaration)) {
546
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(exportSpecifier)) continue;
547
+ const name = (0, _bamboocss_ts_ast.nameNodeOf)(exportSpecifier)?.getText();
548
+ const origin = source.get(name ?? "");
549
+ if (origin) names.set((0, _bamboocss_ts_ast.getAliasNode)(exportSpecifier)?.getText() || (name ?? ""), origin);
564
550
  }
565
551
  }
566
552
  for (const [name, origin] of starred) if (!names.has(name) && !ambiguous.has(name)) names.set(name, origin);
@@ -580,11 +566,11 @@ const walkExports = (sourceFile, imports, resolveModule, seen) => {
580
566
  const walkImports = (sourceFile, imports, resolveModule, seen) => {
581
567
  const bindings = /* @__PURE__ */ new Map();
582
568
  let complete = true;
583
- for (const declaration of sourceFile.getImportDeclarations()) {
584
- if (declaration.isTypeOnly()) continue;
585
- const named = declaration.getNamedImports();
569
+ for (const declaration of (0, _bamboocss_ts_ast.getImportDeclarations)(sourceFile)) {
570
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(declaration)) continue;
571
+ const named = (0, _bamboocss_ts_ast.getNamedImports)(declaration);
586
572
  if (named.length === 0) continue;
587
- const specifier = getModuleSpecifierValue(declaration);
573
+ const specifier = (0, _bamboocss_ts_ast.getModuleSpecifierValue)(declaration);
588
574
  if (!specifier) continue;
589
575
  const target = resolveModule(specifier, sourceFile);
590
576
  if (!target || target === sourceFile) continue;
@@ -593,10 +579,10 @@ const walkImports = (sourceFile, imports, resolveModule, seen) => {
593
579
  const { names } = walk;
594
580
  if (names.size === 0) continue;
595
581
  for (const importSpecifier of named) {
596
- if (importSpecifier.isTypeOnly()) continue;
597
- const origin = names.get(importSpecifier.getNameNode().getText());
582
+ if ((0, _bamboocss_ts_ast.isTypeOnly)(importSpecifier)) continue;
583
+ const origin = names.get((0, _bamboocss_ts_ast.nameNodeOf)(importSpecifier)?.getText() ?? "");
598
584
  if (!origin) continue;
599
- bindings.set(importSpecifier.getAliasNode()?.getText() || importSpecifier.getNameNode().getText(), origin);
585
+ bindings.set((0, _bamboocss_ts_ast.getAliasNode)(importSpecifier)?.getText() || ((0, _bamboocss_ts_ast.nameNodeOf)(importSpecifier)?.getText() ?? ""), origin);
600
586
  }
601
587
  }
602
588
  return {
@@ -645,7 +631,7 @@ const digestExportValue = (sourceFile, exportedName, resolveModule, onCrossing)
645
631
  try {
646
632
  const declaration = (0, _bamboocss_extractor.getExportedVarDeclarationWithName)(exportedName, sourceFile, [], boxCtx);
647
633
  if (!declaration) return "bamboo:export-missing";
648
- const initializer = declaration.getInitializer?.();
634
+ const initializer = (0, _bamboocss_ts_ast.childOf)(declaration, "initializer");
649
635
  if (!initializer) return void 0;
650
636
  const box = (0, _bamboocss_extractor.maybeBoxNode)(initializer, [], boxCtx);
651
637
  if (!box || Array.isArray(box)) return void 0;
@@ -660,17 +646,18 @@ const digestExportValue = (sourceFile, exportedName, resolveModule, onCrossing)
660
646
  };
661
647
  //#endregion
662
648
  //#region src/get-import-declarations.ts
663
- function getImportDeclarations(context, sourceFile) {
649
+ function getImportDeclarations$1(context, sourceFile) {
664
650
  const { imports, tsOptions } = context;
665
651
  const importDeclarations = [];
666
- sourceFile.getImportDeclarations().forEach((node) => {
667
- const mod = getModuleSpecifierValue(node);
652
+ (0, _bamboocss_ts_ast.getImportDeclarations)(sourceFile).forEach((node) => {
653
+ const mod = (0, _bamboocss_ts_ast.getModuleSpecifierValue)(node);
668
654
  if (!mod) return;
669
- node.getNamedImports().forEach((specifier) => {
670
- const name = specifier.getNameNode().getText();
655
+ (0, _bamboocss_ts_ast.getNamedImports)(node).forEach((specifier) => {
656
+ const name = (0, _bamboocss_ts_ast.nameNodeOf)(specifier)?.getText();
657
+ const alias = (0, _bamboocss_ts_ast.getAliasNode)(specifier)?.getText() || name;
671
658
  const result = {
672
- name,
673
- alias: specifier.getAliasNode()?.getText() || name,
659
+ name: name ?? "",
660
+ alias: alias ?? "",
674
661
  mod,
675
662
  kind: "named"
676
663
  };
@@ -680,7 +667,7 @@ function getImportDeclarations(context, sourceFile) {
680
667
  })) return;
681
668
  importDeclarations.push(result);
682
669
  });
683
- const namespace = node.getNamespaceImport();
670
+ const namespace = (0, _bamboocss_ts_ast.getNamespaceImport)(node);
684
671
  if (namespace) {
685
672
  const name = namespace.getText();
686
673
  const result = {
@@ -717,7 +704,7 @@ const findUnresolvable = (node, path, out, seen = /* @__PURE__ */ new Set()) =>
717
704
  }
718
705
  if (_bamboocss_extractor.box.isConditional(node)) return;
719
706
  if (_bamboocss_extractor.box.isLiteral(node) && node.value === void 0) {
720
- if (ts_morph.Node.isTemplateExpression(node.getNode())) out.push(path.join("."));
707
+ if (_bamboocss_ts_ast.Node.isTemplateExpression(node.getNode())) out.push(path.join("."));
721
708
  return;
722
709
  }
723
710
  if (_bamboocss_extractor.box.isMap(node)) {
@@ -740,17 +727,17 @@ const findUnresolvable = (node, path, out, seen = /* @__PURE__ */ new Set()) =>
740
727
  */
741
728
  const writtenProps = (node) => {
742
729
  let literal = node;
743
- if (literal && ts_morph.Node.isCallExpression(literal)) {
744
- const args = literal.getArguments();
730
+ if (literal && _bamboocss_ts_ast.Node.isCallExpression(literal)) {
731
+ const args = literal.arguments;
745
732
  if (args.length !== 1) return void 0;
746
733
  literal = args[0];
747
734
  }
748
- if (!literal || !ts_morph.Node.isObjectLiteralExpression(literal)) return void 0;
735
+ if (!literal || !_bamboocss_ts_ast.Node.isObjectLiteralExpression(literal)) return void 0;
749
736
  const names = [];
750
737
  let uncertain = false;
751
- for (const property of literal.getProperties()) {
752
- if (ts_morph.Node.isPropertyAssignment(property) || ts_morph.Node.isShorthandPropertyAssignment(property)) {
753
- const name = property.getName();
738
+ for (const property of literal.properties) {
739
+ if (_bamboocss_ts_ast.Node.isPropertyAssignment(property) || _bamboocss_ts_ast.Node.isShorthandPropertyAssignment(property)) {
740
+ const name = (0, _bamboocss_ts_ast.getName)(property) ?? "";
754
741
  if (name.startsWith("[")) {
755
742
  uncertain = true;
756
743
  continue;
@@ -786,11 +773,11 @@ const writtenProps = (node) => {
786
773
  const findUnresolvedInValue = (node, resolved, path, out) => {
787
774
  const value = node ? (0, _bamboocss_extractor.unwrapExpression)(node) : void 0;
788
775
  if (!value) return;
789
- if (ts_morph.Node.isArrayLiteralExpression(value)) {
790
- value.getElements().forEach((element, index) => {
776
+ if (_bamboocss_ts_ast.Node.isArrayLiteralExpression(value)) {
777
+ value.elements.forEach((element, index) => {
791
778
  const at = path ? `${path}.${index}` : String(index);
792
779
  const element_ = resolved?.[index];
793
- if (ts_morph.Node.isSpreadElement(element) && element_ == null) {
780
+ if (_bamboocss_ts_ast.Node.isSpreadElement(element) && element_ == null) {
794
781
  out.push({
795
782
  prop: at || void 0,
796
783
  reason: "unenumerable-keys"
@@ -801,17 +788,17 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
801
788
  });
802
789
  return;
803
790
  }
804
- if (!ts_morph.Node.isObjectLiteralExpression(value)) return;
805
- const properties = value.getProperties();
791
+ if (!_bamboocss_ts_ast.Node.isObjectLiteralExpression(value)) return;
792
+ const properties = value.properties;
806
793
  const written = [];
807
794
  let uncertain = false;
808
795
  for (const property of properties) {
809
- if (ts_morph.Node.isSpreadAssignment(property)) {
810
- const spread = (0, _bamboocss_extractor.unwrapExpression)(property.getExpression());
811
- if (ts_morph.Node.isObjectLiteralExpression(spread)) {
812
- for (const inner of spread.getProperties()) {
813
- if (!ts_morph.Node.isPropertyAssignment(inner) && !ts_morph.Node.isShorthandPropertyAssignment(inner)) continue;
814
- const innerName = inner.getName();
796
+ if (_bamboocss_ts_ast.Node.isSpreadAssignment(property)) {
797
+ const spread = (0, _bamboocss_extractor.unwrapExpression)(property.expression);
798
+ if (_bamboocss_ts_ast.Node.isObjectLiteralExpression(spread)) {
799
+ for (const inner of spread.properties) {
800
+ if (!_bamboocss_ts_ast.Node.isPropertyAssignment(inner) && !_bamboocss_ts_ast.Node.isShorthandPropertyAssignment(inner)) continue;
801
+ const innerName = (0, _bamboocss_ts_ast.getName)(inner) ?? "";
815
802
  if (!innerName.startsWith("[")) written.push(innerName.replace(/^['"]|['"]$/g, ""));
816
803
  }
817
804
  continue;
@@ -819,8 +806,8 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
819
806
  uncertain = true;
820
807
  continue;
821
808
  }
822
- if (!ts_morph.Node.isPropertyAssignment(property) && !ts_morph.Node.isShorthandPropertyAssignment(property)) continue;
823
- const name = property.getName();
809
+ if (!_bamboocss_ts_ast.Node.isPropertyAssignment(property) && !_bamboocss_ts_ast.Node.isShorthandPropertyAssignment(property)) continue;
810
+ const name = (0, _bamboocss_ts_ast.getName)(property) ?? "";
824
811
  if (name.startsWith("[")) {
825
812
  uncertain = true;
826
813
  continue;
@@ -837,10 +824,10 @@ const findUnresolvedInValue = (node, resolved, path, out) => {
837
824
  reason: "unenumerable-keys"
838
825
  });
839
826
  for (const property of properties) {
840
- if (!ts_morph.Node.isPropertyAssignment(property)) continue;
841
- const name = property.getName().replace(/^['"]|['"]$/g, "");
827
+ if (!_bamboocss_ts_ast.Node.isPropertyAssignment(property)) continue;
828
+ const name = ((0, _bamboocss_ts_ast.getName)(property) ?? "").replace(/^['"]|['"]$/g, "");
842
829
  if (name.startsWith("[")) continue;
843
- findUnresolvedInValue(property.getInitializer(), resolved?.[name], path ? `${path}.${name}` : name, out);
830
+ findUnresolvedInValue(property.initializer, resolved?.[name], path ? `${path}.${name}` : name, out);
844
831
  }
845
832
  };
846
833
  /** A recipe config the build could not fully read — see `findUnresolvedInValue`. */
@@ -849,20 +836,20 @@ const findUnresolvedRecipeStyles = (item) => {
849
836
  const sourceFile = node?.getSourceFile();
850
837
  if (!node || !sourceFile) return [];
851
838
  let argument = node;
852
- if (ts_morph.Node.isCallExpression(argument)) {
853
- const args = argument.getArguments();
839
+ if (_bamboocss_ts_ast.Node.isCallExpression(argument)) {
840
+ const args = argument.arguments;
854
841
  if (args.length !== 1) return [];
855
842
  argument = args[0];
856
843
  }
857
844
  const losses = [];
858
845
  const config = argument ? (0, _bamboocss_extractor.unwrapExpression)(argument) : void 0;
859
- if (!config || !ts_morph.Node.isObjectLiteralExpression(config)) losses.push({ reason: "unresolvable-value" });
846
+ if (!config || !_bamboocss_ts_ast.Node.isObjectLiteralExpression(config)) losses.push({ reason: "unresolvable-value" });
860
847
  else findUnresolvedInValue(config, item.data[0], "", losses);
861
848
  if (!losses.length) return [];
862
- const { line, column } = sourceFile.getLineAndColumnAtPos(node.getStart());
849
+ const { line, column } = (0, _bamboocss_ts_ast.getLineAndColumnAtPos)(sourceFile, node.getStart());
863
850
  return losses.map((loss) => ({
864
851
  column,
865
- filePath: sourceFile.getFilePath(),
852
+ filePath: (0, _bamboocss_ts_ast.pathOf)(sourceFile),
866
853
  kind: "recipe",
867
854
  line,
868
855
  ...loss
@@ -892,9 +879,9 @@ const findUnresolvedStyles = (item, kind) => {
892
879
  if (written.uncertain && !hasKeyOutside(resolved, written.names)) losses.push({ reason: "unenumerable-keys" });
893
880
  }
894
881
  if (!losses.length) return [];
895
- const { line, column } = sourceFile.getLineAndColumnAtPos(node.getStart());
882
+ const { line, column } = (0, _bamboocss_ts_ast.getLineAndColumnAtPos)(sourceFile, node.getStart());
896
883
  const at = {
897
- filePath: sourceFile.getFilePath(),
884
+ filePath: (0, _bamboocss_ts_ast.pathOf)(sourceFile),
898
885
  line,
899
886
  column
900
887
  };
@@ -1120,7 +1107,7 @@ var ParserResult = class {
1120
1107
  const visit = (node) => {
1121
1108
  if (!node || seen.has(node)) return;
1122
1109
  seen.add(node);
1123
- const path = node.getNode?.()?.getSourceFile().getFilePath().replaceAll("\\", "/");
1110
+ const path = (0, _bamboocss_ts_ast.pathOf)(node.getNode?.()?.getSourceFile())?.replaceAll("\\", "/");
1124
1111
  if (path && path !== own) paths.add(path);
1125
1112
  if (_bamboocss_extractor.box.isMap(node)) for (const child of node.value.values()) visit(child);
1126
1113
  else if (_bamboocss_extractor.box.isArray(node)) for (const child of node.value) visit(child);
@@ -1174,10 +1161,10 @@ const combineResult = (unboxed) => {
1174
1161
  };
1175
1162
  /** The exact binding token accounting visits for a token call. */
1176
1163
  const tokenCalleeRange = (call) => {
1177
- if (!ts_morph.Node.isCallExpression(call)) return void 0;
1178
- let current = call.getExpression();
1179
- while (ts_morph.Node.isPropertyAccessExpression(current)) current = current.getExpression();
1180
- if (!ts_morph.Node.isIdentifier(current)) return void 0;
1164
+ if (!_bamboocss_ts_ast.Node.isCallExpression(call)) return void 0;
1165
+ let current = call.expression;
1166
+ while (_bamboocss_ts_ast.Node.isPropertyAccessExpression(current)) current = current.expression;
1167
+ if (!_bamboocss_ts_ast.Node.isIdentifier(current)) return void 0;
1181
1168
  return {
1182
1169
  start: current.getStart(),
1183
1170
  end: current.getEnd()
@@ -1196,23 +1183,23 @@ function createParser(context) {
1196
1183
  const { jsx, imports, recipes } = context;
1197
1184
  return function parse(sourceFile, encoder, options, resolveModule) {
1198
1185
  if (!sourceFile) return;
1199
- const importDeclarations = getImportDeclarations(context, sourceFile);
1186
+ const importDeclarations = getImportDeclarations$1(context, sourceFile);
1200
1187
  const file = imports.file(importDeclarations);
1201
- const filePath = sourceFile.getFilePath();
1188
+ const filePath = (0, _bamboocss_ts_ast.pathOf)(sourceFile);
1202
1189
  _bamboocss_logger.logger.debug("ast:import", !file.isEmpty() ? `Found import { ${file.toString()} } in ${filePath}` : `No import found in ${filePath}`);
1203
1190
  const parserResult = new ParserResult(context, encoder);
1204
1191
  const importedRecipes = resolveModule ? importedRecipeBindings(sourceFile, imports, resolveModule) : /* @__PURE__ */ new Map();
1205
1192
  if (file.isEmpty() && !jsx.isEnabled && importedRecipes.size === 0) return parserResult;
1206
1193
  parserResult.importedRecipes = importedRecipes;
1207
1194
  for (const binding of importedRecipes.keys()) file.addLocalRecipe(binding);
1208
- if (file.importsRecipeFactory()) for (const statement of sourceFile.compilerNode.statements) {
1209
- if (!ts_morph.ts.isVariableStatement(statement)) continue;
1210
- if (!(statement.declarationList.flags & ts_morph.ts.NodeFlags.Const)) continue;
1195
+ if (file.importsRecipeFactory()) for (const statement of sourceFile.statements) {
1196
+ if (!_bamboocss_ts_ast.ts.isVariableStatement(statement)) continue;
1197
+ if (!(statement.declarationList.flags & _bamboocss_ts_ast.ts.NodeFlags.Const)) continue;
1211
1198
  for (const declaration of statement.declarationList.declarations) {
1212
1199
  const initializer = declaration.initializer;
1213
- if (!initializer || !ts_morph.ts.isCallExpression(initializer)) continue;
1200
+ if (!initializer || !_bamboocss_ts_ast.ts.isCallExpression(initializer)) continue;
1214
1201
  const callee = initializer.expression;
1215
- if (!ts_morph.ts.isIdentifier(callee) || !ts_morph.ts.isIdentifier(declaration.name)) continue;
1202
+ if (!_bamboocss_ts_ast.ts.isIdentifier(callee) || !_bamboocss_ts_ast.ts.isIdentifier(declaration.name)) continue;
1216
1203
  const imported = file.getName(callee.text);
1217
1204
  if (imported !== "cva" && imported !== "sva") continue;
1218
1205
  if (!file.matchFn(callee.text)) continue;
@@ -1230,7 +1217,7 @@ function createParser(context) {
1230
1217
  * Defined out here rather than inside `getEvaluateOptions`, which runs per call node.
1231
1218
  */
1232
1219
  const reportUnresolvedRaw = (base, at) => {
1233
- const { line, column } = sourceFile.getLineAndColumnAtPos(at.getStart());
1220
+ const { line, column } = (0, _bamboocss_ts_ast.getLineAndColumnAtPos)(sourceFile, at.getStart());
1234
1221
  parserResult.unresolved.push({
1235
1222
  kind: "atomic",
1236
1223
  prop: base,
@@ -1272,14 +1259,14 @@ function createParser(context) {
1272
1259
  matchArg: () => true
1273
1260
  },
1274
1261
  getEvaluateOptions: (node) => {
1275
- if (!ts_morph.Node.isCallExpression(node)) return evaluateOptions;
1276
- const propAccessExpr = node.getExpression();
1277
- if (ts_morph.Node.isIdentifier(propAccessExpr)) {
1262
+ if (!_bamboocss_ts_ast.Node.isCallExpression(node)) return evaluateOptions;
1263
+ const propAccessExpr = node.expression;
1264
+ if (_bamboocss_ts_ast.Node.isIdentifier(propAccessExpr)) {
1278
1265
  const local = propAccessExpr.getText();
1279
1266
  if (!file.match(local) || file.getName(local) !== "fallback") return evaluateOptions;
1280
1267
  return { environment: Object.assign({}, defaultEnv, { extra: { [local]: fallbackImpl } }) };
1281
1268
  }
1282
- if (!ts_morph.Node.isPropertyAccessExpression(propAccessExpr)) return evaluateOptions;
1269
+ if (!_bamboocss_ts_ast.Node.isPropertyAccessExpression(propAccessExpr)) return evaluateOptions;
1283
1270
  let name = propAccessExpr.getText();
1284
1271
  const rawBase = name.endsWith(".raw") ? name.slice(0, -4) : void 0;
1285
1272
  if (rawBase && file.isLocalRecipe(rawBase)) {
@@ -1348,7 +1335,7 @@ function createParser(context) {
1348
1335
  });
1349
1336
  }).when(file.isValidPattern, (name) => {
1350
1337
  result.queryList.forEach((query) => {
1351
- if (query.kind === "call-expression") parserResult.setPattern(name, {
1338
+ if (query.kind === "call-expression") parserResult.setPattern(name ?? "", {
1352
1339
  name,
1353
1340
  box: query.box.value[0] ?? _bamboocss_extractor.box.fallback(query.box),
1354
1341
  data: combineResult((0, _bamboocss_extractor.unbox)(query.box.value[0]))
@@ -1356,7 +1343,7 @@ function createParser(context) {
1356
1343
  });
1357
1344
  }).when(file.isValidRecipe, (name) => {
1358
1345
  result.queryList.forEach((query) => {
1359
- if (query.kind === "call-expression") parserResult.setRecipe(name, {
1346
+ if (query.kind === "call-expression") parserResult.setRecipe(name ?? "", {
1360
1347
  name,
1361
1348
  box: query.box.value[0] ?? _bamboocss_extractor.box.fallback(query.box),
1362
1349
  data: combineResult((0, _bamboocss_extractor.unbox)(query.box.value[0]))
@@ -1374,8 +1361,8 @@ function createParser(context) {
1374
1361
  } else if (jsx.isEnabled && result.kind === "component") result.queryList.forEach((query) => {
1375
1362
  const data = combineResult((0, _bamboocss_extractor.unbox)(query.box));
1376
1363
  for (const tag of [name, alias]) {
1377
- if (!jsx.isJsxTagRecipe(tag)) continue;
1378
- recipes.filter(tag).forEach((recipe) => {
1364
+ if (!jsx.isJsxTagRecipe(tag ?? "")) continue;
1365
+ recipes.filter(tag ?? "").forEach((recipe) => {
1379
1366
  parserResult.setRecipe(recipe.baseName, {
1380
1367
  type: "jsx-recipe",
1381
1368
  name: tag,
@@ -1388,19 +1375,16 @@ function createParser(context) {
1388
1375
  });
1389
1376
  });
1390
1377
  parserResult.deadCalls = file.getDeadCalls();
1391
- if (exportReadPairs.size) {
1392
- const project = sourceFile.getProject();
1393
- parserResult.setExportReads([...exportReadPairs].map((pair) => {
1394
- const at = pair.indexOf("\0");
1395
- const file = pair.slice(0, at);
1396
- const name = pair.slice(at + 1);
1397
- return {
1398
- file,
1399
- name,
1400
- digest: digestExportValue(project.getSourceFile(file), name, resolveModule)
1401
- };
1402
- }));
1403
- }
1378
+ if (exportReadPairs.size) parserResult.setExportReads([...exportReadPairs].map((pair) => {
1379
+ const at = pair.indexOf("\0");
1380
+ const file = pair.slice(0, at);
1381
+ const name = pair.slice(at + 1);
1382
+ return {
1383
+ file,
1384
+ name,
1385
+ digest: digestExportValue(resolveModule?.(file, sourceFile), name, resolveModule)
1386
+ };
1387
+ }));
1404
1388
  return parserResult;
1405
1389
  };
1406
1390
  }
@@ -1417,11 +1401,16 @@ const invalidateResolutions = () => {
1417
1401
  (0, _bamboocss_extractor.clearBoxNodeCache)();
1418
1402
  clearImportedRecipeCache();
1419
1403
  };
1420
- const normalizeCompilerOptions = (raw, basePath = process.cwd()) => {
1421
- if (!raw) return {};
1422
- const { options } = ts_morph.ts.convertCompilerOptionsFromJson(raw, basePath);
1423
- return options;
1424
- };
1404
+ /**
1405
+ * Compiler options as given.
1406
+ *
1407
+ * TypeScript 6 needed `convertCompilerOptionsFromJson` to turn a tsconfig's JSON spellings —
1408
+ * `"target": "esnext"`, relative `paths` — into the enum values and absolute paths a program
1409
+ * consumed. TypeScript 7 parses the tsconfig in the Go process and hands back options already
1410
+ * in that form, so there is nothing left to convert; the argument survives because callers pass
1411
+ * overrides that are already normalized.
1412
+ */
1413
+ const normalizeCompilerOptions = (raw, _basePath = process.cwd()) => raw ?? {};
1425
1414
  /** Snapshot the JSON-shaped ts-morph options while retaining opaque hosts and callbacks. */
1426
1415
  const snapshotProjectOption = (value) => {
1427
1416
  if (Array.isArray(value)) return value.map(snapshotProjectOption);
@@ -1451,7 +1440,7 @@ const prepareTsProjectOptions = (options, snapshotNested = false, compilerOption
1451
1440
  }
1452
1441
  };
1453
1442
  };
1454
- const createTsProject = (options) => new ts_morph.Project(options);
1443
+ const createTsProject = (options) => new _bamboocss_ts_ast.Project(options);
1455
1444
  /** Filesystem errors proving a lexical candidate cannot name a resolvable file. */
1456
1445
  const isMissingPathShapeError = (error) => {
1457
1446
  const code = error?.code;
@@ -1495,7 +1484,7 @@ const setProjectOnReceiver = (receiver, project) => {
1495
1484
  */
1496
1485
  const scriptKindFor = (filePath) => {
1497
1486
  const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
1498
- return extension === ".ts" || extension === ".mts" || extension === ".cts" ? ts_morph.ScriptKind.TS : ts_morph.ScriptKind.TSX;
1487
+ return extension === ".ts" || extension === ".mts" || extension === ".cts" ? _bamboocss_ts_ast.ScriptKind.TS : _bamboocss_ts_ast.ScriptKind.TSX;
1499
1488
  };
1500
1489
  var Project = class {
1501
1490
  /**
@@ -1632,32 +1621,33 @@ var Project = class {
1632
1621
  this.#assertSourceFilesAccessor();
1633
1622
  const revision = this.#sourceFiles.revision;
1634
1623
  this.#sourceFiles.phase = "loading";
1624
+ let candidate;
1635
1625
  try {
1636
- const candidate = createTsProject(this.#sourceFiles.projectOptions);
1626
+ candidate = createTsProject(this.#sourceFiles.projectOptions);
1637
1627
  this.#assertSourceFilesTransaction(revision);
1638
1628
  let loaded = 0;
1629
+ const entries = [];
1639
1630
  for (const [index, file] of this.#sourceFiles.initialFiles.entries()) try {
1640
1631
  const content = read(file, index);
1641
1632
  this.#assertSourceFilesTransaction(revision);
1642
- candidate.createSourceFile(file, content, {
1643
- overwrite: true,
1644
- scriptKind: scriptKindFor(file)
1645
- });
1633
+ entries.push([file, content]);
1646
1634
  this.#assertSourceFilesTransaction(revision);
1647
1635
  loaded++;
1648
1636
  } catch (error) {
1649
1637
  this.#assertSourceFilesTransaction(revision);
1650
1638
  if (!skipMissing || error?.code !== "ENOENT") throw error;
1651
1639
  }
1640
+ candidate.addSourceFiles(entries);
1652
1641
  this.#assertSourceFilesTransaction(revision);
1653
1642
  if (loaded > 0) invalidateResolutions();
1654
- this.#moduleResolutionCache = void 0;
1643
+ this.#resolver = void 0;
1655
1644
  this.#fileTreeRevision++;
1656
1645
  this.#assertSourceFilesTransaction(revision);
1657
1646
  this.#sourceFiles.project = candidate;
1658
1647
  this.#sourceFiles.phase = "ready";
1659
1648
  return;
1660
1649
  } catch (error) {
1650
+ candidate?.dispose();
1661
1651
  this.#sourceFiles.project = void 0;
1662
1652
  this.#sourceFiles.phase = "pending";
1663
1653
  throw error;
@@ -1730,7 +1720,7 @@ var Project = class {
1730
1720
  sourceFilesRead: 0
1731
1721
  };
1732
1722
  resetResolutionState = () => {
1733
- this.#moduleResolutionCache = void 0;
1723
+ this.#resolver = void 0;
1734
1724
  this.#fileTreeRevision++;
1735
1725
  this.dependents = /* @__PURE__ */ new Map();
1736
1726
  this.dependencies = /* @__PURE__ */ new Map();
@@ -1771,12 +1761,24 @@ var Project = class {
1771
1761
  };
1772
1762
  getSourceFile = (filePath) => {
1773
1763
  this.#assertNotLoading();
1764
+ if (!this.project.has(filePath)) return void 0;
1774
1765
  return this.project.getSourceFile(filePath);
1775
1766
  };
1767
+ /**
1768
+ * How many syntax errors this file's parse produced.
1769
+ *
1770
+ * Asked by the token accounting, which may only speak for a file whose tree it can trust: a
1771
+ * construct the parser could not read leaves an ast that stops early, and every call below
1772
+ * the offending line silently ceases to exist. Zero means the file parsed as written.
1773
+ */
1774
+ getSyntacticDiagnosticCount = (filePath) => {
1775
+ this.#assertNotLoading();
1776
+ return this.project.getSyntacticDiagnosticCount(filePath);
1777
+ };
1776
1778
  /** ts-morph reports forward slashes; normalize callers' paths to match on Windows. */
1777
1779
  normalizePath = (filePath) => filePath.replaceAll("\\", "/");
1778
1780
  /** Shared filesystem-only resolution cache; no type checker is constructed. */
1779
- #moduleResolutionCache;
1781
+ #resolver;
1780
1782
  /**
1781
1783
  * Everything memoized against the shape of the file tree, including the negative half.
1782
1784
  *
@@ -1809,7 +1811,7 @@ var Project = class {
1809
1811
  }
1810
1812
  invalidateResolutions();
1811
1813
  if (fileTreeChanged) {
1812
- this.#moduleResolutionCache = void 0;
1814
+ this.#resolver = void 0;
1813
1815
  this.#fileTreeRevision++;
1814
1816
  }
1815
1817
  };
@@ -1832,17 +1834,10 @@ var Project = class {
1832
1834
  ...this.#sourceFiles.projectOptions,
1833
1835
  compilerOptions: snapshotProjectOption(next)
1834
1836
  };
1835
- if (this.#sourceFiles.phase === "ready") {
1836
- const current = this.project.getCompilerOptions();
1837
- const cleared = Object.fromEntries(Object.keys(current).map((key) => [key, void 0]));
1838
- this.project.compilerOptions.set({
1839
- ...cleared,
1840
- ...next
1841
- });
1842
- }
1837
+ this.#sourceFiles.project?.setCompilerOptions(next);
1843
1838
  }
1844
1839
  invalidateResolutions();
1845
- this.#moduleResolutionCache = void 0;
1840
+ this.#resolver = void 0;
1846
1841
  this.#fileTreeRevision++;
1847
1842
  this.sourcePreparations.clear();
1848
1843
  };
@@ -1888,33 +1883,33 @@ var Project = class {
1888
1883
  this.#assertNotLoading();
1889
1884
  const project = this.project;
1890
1885
  const compilerOptions = project.getCompilerOptions();
1891
- this.#moduleResolutionCache ??= ts_morph.ts.createModuleResolutionCache(project.getFileSystem().getCurrentDirectory(), (f) => f, compilerOptions);
1892
1886
  const configurationFiles = /* @__PURE__ */ new Set();
1893
- const resolutionHost = project.getModuleResolutionHost();
1894
1887
  const recordConfigurationFile = (filePath) => {
1895
1888
  const normalized = this.normalizePath(filePath);
1896
1889
  if (!normalized.endsWith("/package.json") || normalized.includes("/node_modules/")) return;
1897
1890
  if (!this.isInCheckout(normalized)) return;
1898
1891
  configurationFiles.add(normalized);
1899
1892
  };
1900
- const host = {
1901
- ...resolutionHost,
1902
- fileExists: (filePath) => {
1903
- recordConfigurationFile(filePath);
1904
- return resolutionHost.fileExists(filePath);
1905
- },
1906
- readFile: (filePath) => {
1907
- recordConfigurationFile(filePath);
1908
- return resolutionHost.readFile?.(filePath);
1893
+ this.#resolver ??= (0, _bamboocss_ts_ast.createResolver)({
1894
+ cwd: project.getCurrentDirectory(),
1895
+ fs: {
1896
+ fileExists: (filePath) => project.fileExists(filePath),
1897
+ readFile: (filePath) => project.readFile(filePath)
1909
1898
  }
1910
- };
1899
+ });
1900
+ const configured = this.#sourceFiles.projectOptions.compilerOptions ?? compilerOptions;
1911
1901
  this.resolutionWork.moduleResolutionsAttempted++;
1912
- const resolved = ts_morph.ts.resolveModuleName(moduleName, from.getFilePath(), compilerOptions, host, this.#moduleResolutionCache);
1913
- const failedLookupLocations = resolved.failedLookupLocations;
1914
- const affectingLocations = resolved.affectingLocations;
1915
- for (const filePath of affectingLocations ?? []) recordConfigurationFile(filePath);
1916
- const pendingCandidates = this.getLocalFailedLookupCandidates(failedLookupLocations);
1917
- const module = resolved.resolvedModule;
1902
+ const resolved = this.#resolver(moduleName, {
1903
+ importer: (0, _bamboocss_ts_ast.pathOf)(from),
1904
+ baseUrl: configured?.baseUrl,
1905
+ paths: configured?.paths
1906
+ });
1907
+ for (const filePath of resolved.affectingFiles) recordConfigurationFile(filePath);
1908
+ const pendingCandidates = this.getLocalFailedLookupCandidates(resolved.failedLookups);
1909
+ const module = resolved.path ? {
1910
+ resolvedFileName: resolved.path,
1911
+ isExternalLibraryImport: resolved.path.includes("/node_modules/")
1912
+ } : void 0;
1918
1913
  if (!module) return {
1919
1914
  configurationFiles: [...configurationFiles].sort(),
1920
1915
  local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates) || moduleName.startsWith("#"),
@@ -1931,7 +1926,7 @@ var Project = class {
1931
1926
  local: this.isUnresolvedLocalSpecifier(moduleName, pendingCandidates),
1932
1927
  pendingCandidates
1933
1928
  };
1934
- const existing = project.getSourceFile(name);
1929
+ const existing = this.project.has(name) ? project.getSourceFile(name) : void 0;
1935
1930
  if (existing) {
1936
1931
  this.removedSourcePaths.delete(name);
1937
1932
  return {
@@ -1950,12 +1945,10 @@ var Project = class {
1950
1945
  try {
1951
1946
  this.resolutionWork.sourceFilesRead++;
1952
1947
  const content = project.getFileSystem().readFileSync(name);
1953
- const sourceFile = project.createSourceFile(name, content, {
1954
- overwrite: true,
1955
- scriptKind: scriptKindFor(name)
1956
- });
1948
+ const sourceFile = project.createSourceFile(name, content, { scriptKind: scriptKindFor(name) });
1949
+ if (!sourceFile) throw new Error(`bamboo: resolved ${name} but the project produced no source file`);
1957
1950
  this.resolutionWork.sourceFilesAdded++;
1958
- this.canonicalPaths.set(name, this.normalizePath(sourceFile.getFilePath()));
1951
+ this.canonicalPaths.set(name, this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile)));
1959
1952
  return {
1960
1953
  configurationFiles: [...configurationFiles].sort(),
1961
1954
  local: true,
@@ -2009,28 +2002,28 @@ var Project = class {
2009
2002
  };
2010
2003
  ensureResolutionFacts = (sourceFile) => {
2011
2004
  this.#assertNotLoading();
2012
- const importer = this.normalizePath(sourceFile.getFilePath());
2005
+ const importer = this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile));
2013
2006
  const text = sourceFile.getFullText();
2014
2007
  const cached = this.resolutionsByImporter.get(importer);
2015
2008
  if (cached?.sourceFile === sourceFile && cached.text === text && cached.treeRevision === this.#fileTreeRevision) return cached;
2016
- const declarations = [...sourceFile.getImportDeclarations().map((declaration) => ({
2009
+ const declarations = [...(0, _bamboocss_ts_ast.getImportDeclarations)(sourceFile).map((declaration) => ({
2017
2010
  declaration,
2018
2011
  kind: "import"
2019
- })), ...sourceFile.getExportDeclarations().map((declaration) => ({
2012
+ })), ...(0, _bamboocss_ts_ast.getExportDeclarations)(sourceFile).map((declaration) => ({
2020
2013
  declaration,
2021
2014
  kind: "export"
2022
- }))].filter(({ declaration }) => declaration.getModuleSpecifierValue() !== void 0).sort((left, right) => left.declaration.getStart() - right.declaration.getStart());
2015
+ }))].filter(({ declaration }) => (0, _bamboocss_ts_ast.getModuleSpecifierValue)(declaration) !== void 0).sort((left, right) => left.declaration.getStart() - right.declaration.getStart());
2023
2016
  const facts = [];
2024
2017
  const pendingCandidates = [];
2025
2018
  const configurationFiles = [];
2026
2019
  for (const [ordinal, { declaration, kind }] of declarations.entries()) {
2027
- const specifier = declaration.getModuleSpecifierValue();
2020
+ const specifier = (0, _bamboocss_ts_ast.getModuleSpecifierValue)(declaration);
2028
2021
  if (!specifier) continue;
2029
2022
  const resolved = this.resolveSpecifier(specifier, sourceFile);
2030
2023
  if (!resolved.local) continue;
2031
2024
  facts.push(Object.freeze({
2032
2025
  importer,
2033
- target: resolved.sourceFile ? this.normalizePath(resolved.sourceFile.getFilePath()) : null,
2026
+ target: resolved.sourceFile ? this.normalizePath((0, _bamboocss_ts_ast.pathOf)(resolved.sourceFile)) : null,
2034
2027
  specifier,
2035
2028
  kind,
2036
2029
  ordinal
@@ -2055,22 +2048,22 @@ var Project = class {
2055
2048
  };
2056
2049
  /** The sole cross-file source resolver supplied to parser and extractor. */
2057
2050
  resolveModule = (specifier, from) => {
2058
- const target = this.ensureResolutionFacts(from).facts.find((fact) => fact.specifier === specifier)?.target;
2051
+ const target = this.ensureResolutionFacts(from).facts.find((fact) => fact.specifier === specifier)?.target ?? (specifier.startsWith("/") ? specifier : void 0);
2059
2052
  if (!target) return;
2060
2053
  const sourceFile = this.project.getSourceFile(target);
2061
2054
  if (!sourceFile) return;
2062
- this.prepareEffectiveSource(sourceFile.getFilePath(), sourceFile);
2055
+ this.prepareEffectiveSource((0, _bamboocss_ts_ast.pathOf)(sourceFile), sourceFile);
2063
2056
  return sourceFile;
2064
2057
  };
2065
2058
  trackDependencies = (filePath, sourceFile) => {
2066
2059
  this.#assertNotLoading();
2067
- const importer = this.normalizePath(sourceFile.getFilePath());
2060
+ const importer = this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile));
2068
2061
  this.canonicalPaths.set(this.normalizePath(filePath), importer);
2069
2062
  this.canonicalPaths.set(importer, importer);
2070
2063
  this.ensureResolutionFacts(sourceFile);
2071
2064
  };
2072
2065
  invalidateSourcePreparation = (filePath, sourceFile) => {
2073
- const sourcePath = this.normalizePath(sourceFile?.getFilePath() ?? filePath);
2066
+ const sourcePath = this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile) ?? filePath);
2074
2067
  const preparation = this.sourcePreparations.get(sourcePath);
2075
2068
  if (preparation?.state === "preparing") preparation.invalidated = true;
2076
2069
  this.sourcePreparations.delete(sourcePath);
@@ -2086,7 +2079,7 @@ var Project = class {
2086
2079
  */
2087
2080
  prepareEffectiveSource = (filePath, sourceFile, hookFilePath = filePath) => {
2088
2081
  this.#assertNotLoading();
2089
- const sourcePath = this.normalizePath(sourceFile.getFilePath());
2082
+ const sourcePath = this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile));
2090
2083
  const currentText = sourceFile.getFullText();
2091
2084
  const current = this.sourcePreparations.get(sourcePath);
2092
2085
  if (current?.state === "ready" && current.sourceFile === sourceFile && current.effectiveText === currentText) {
@@ -2131,7 +2124,7 @@ var Project = class {
2131
2124
  assertTransaction(currentText);
2132
2125
  const transformed = custom ?? this.transformFile(hookFilePath, currentText);
2133
2126
  assertTransaction(currentText);
2134
- if (currentText !== transformed) sourceFile.replaceWithText(transformed);
2127
+ if (currentText !== transformed) sourceFile = this.project.addSourceFile(filePath, transformed) ?? sourceFile;
2135
2128
  assertTransaction(transformed);
2136
2129
  this.trackDependencies(filePath, sourceFile);
2137
2130
  assertTransaction(transformed);
@@ -2148,7 +2141,7 @@ var Project = class {
2148
2141
  if (this.sourcePreparations.get(sourcePath) === transaction) this.sourcePreparations.delete(sourcePath);
2149
2142
  this.retractImporter(sourcePath);
2150
2143
  try {
2151
- if (sourceFile.getFullText() !== currentText) sourceFile.replaceWithText(currentText);
2144
+ if (sourceFile.getFullText() !== currentText) this.project.addSourceFile(filePath, currentText);
2152
2145
  } catch {}
2153
2146
  throw error;
2154
2147
  }
@@ -2175,7 +2168,7 @@ var Project = class {
2175
2168
  this.retractImporter(target);
2176
2169
  this.removedSourcePaths.add(target);
2177
2170
  this.canonicalPaths.set(target, target);
2178
- this.canonicalPaths.set(this.normalizePath(sourceFile.getFilePath()), target);
2171
+ this.canonicalPaths.set(this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile)), target);
2179
2172
  };
2180
2173
  /**
2181
2174
  * Every file that transitively imports `filePath`, so a watcher can re-parse the
@@ -2184,7 +2177,7 @@ var Project = class {
2184
2177
  getDependents = (filePath) => {
2185
2178
  this.#assertNotLoading();
2186
2179
  const given = this.normalizePath(filePath);
2187
- const resolved = this.project.getSourceFile(filePath)?.getFilePath();
2180
+ const resolved = (0, _bamboocss_ts_ast.pathOf)(this.project.getSourceFile(filePath));
2188
2181
  const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
2189
2182
  const seen = /* @__PURE__ */ new Set();
2190
2183
  const queue = [start];
@@ -2212,7 +2205,7 @@ var Project = class {
2212
2205
  getDependencies = (filePath, targets) => {
2213
2206
  this.#assertNotLoading();
2214
2207
  const given = this.normalizePath(filePath);
2215
- const resolved = this.project.getSourceFile(filePath)?.getFilePath();
2208
+ const resolved = (0, _bamboocss_ts_ast.pathOf)(this.project.getSourceFile(filePath));
2216
2209
  const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
2217
2210
  const seen = /* @__PURE__ */ new Set();
2218
2211
  const importersByDependency = /* @__PURE__ */ new Map();
@@ -2233,7 +2226,7 @@ var Project = class {
2233
2226
  const selected = /* @__PURE__ */ new Set();
2234
2227
  const reverse = Array.from(targets, (target) => {
2235
2228
  const normalized = this.normalizePath(target);
2236
- const source = this.project.getSourceFile(target)?.getFilePath();
2229
+ const source = (0, _bamboocss_ts_ast.pathOf)(this.project.getSourceFile(target));
2237
2230
  return source ? this.normalizePath(source) : this.canonicalPaths.get(normalized) ?? normalized;
2238
2231
  }).filter((target) => seen.has(target));
2239
2232
  let reverseCursor = 0;
@@ -2259,7 +2252,7 @@ var Project = class {
2259
2252
  const selected = new Set(dependencies);
2260
2253
  const retained = new Set([...previous?.dependencies ?? [], ...previous?.pendingCandidates ?? []]);
2261
2254
  const given = this.normalizePath(filePath);
2262
- const resolved = this.project.getSourceFile(filePath)?.getFilePath();
2255
+ const resolved = (0, _bamboocss_ts_ast.pathOf)(this.project.getSourceFile(filePath));
2263
2256
  const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
2264
2257
  const pendingCandidates = /* @__PURE__ */ new Set();
2265
2258
  for (const importer of [start, ...dependencies]) {
@@ -2292,7 +2285,7 @@ var Project = class {
2292
2285
  const selected = new Set(dependencies);
2293
2286
  const retained = new Set(Array.from(previous, (file) => this.normalizePath(file)));
2294
2287
  const given = this.normalizePath(filePath);
2295
- const resolved = this.project.getSourceFile(filePath)?.getFilePath();
2288
+ const resolved = (0, _bamboocss_ts_ast.pathOf)(this.project.getSourceFile(filePath));
2296
2289
  const start = resolved ? this.normalizePath(resolved) : this.canonicalPaths.get(given) ?? given;
2297
2290
  const files = /* @__PURE__ */ new Set();
2298
2291
  let hasSemanticFact = false;
@@ -2319,10 +2312,9 @@ var Project = class {
2319
2312
  this.invalidateSourcePreparation(filePath, existing);
2320
2313
  this.removedSourcePaths.delete(this.normalizePath(filePath));
2321
2314
  this.invalidate();
2322
- return this.project.createSourceFile(filePath, content, {
2323
- overwrite: true,
2324
- scriptKind: scriptKindFor(filePath)
2325
- });
2315
+ const created = this.project.createSourceFile(filePath, content, { scriptKind: scriptKindFor(filePath) });
2316
+ if (!created) throw new Error(`bamboo: could not add ${filePath} to the project`);
2317
+ return created;
2326
2318
  };
2327
2319
  createSourceFiles = () => {
2328
2320
  this.#assertNotLoading();
@@ -2361,17 +2353,15 @@ var Project = class {
2361
2353
  * matches its own source, falls through, and is overwritten exactly as before.
2362
2354
  */
2363
2355
  if (existing && existing.getFullText() === content) {
2364
- this.markAuxiliary(existing.getFilePath(), options.auxiliary);
2356
+ this.markAuxiliary((0, _bamboocss_ts_ast.pathOf)(existing), options.auxiliary);
2365
2357
  return existing;
2366
2358
  }
2367
2359
  this.invalidateSourcePreparation(filePath, existing);
2368
2360
  this.removedSourcePaths.delete(this.normalizePath(filePath));
2369
- this.invalidate(!existing, existing?.getFilePath());
2370
- const sourceFile = this.project.createSourceFile(filePath, content, {
2371
- overwrite: true,
2372
- scriptKind: scriptKindFor(filePath)
2373
- });
2374
- this.markAuxiliary(sourceFile.getFilePath(), options.auxiliary);
2361
+ this.invalidate(!existing, (0, _bamboocss_ts_ast.pathOf)(existing));
2362
+ const sourceFile = this.project.createSourceFile(filePath, content, { scriptKind: scriptKindFor(filePath) });
2363
+ if (!sourceFile) throw new Error(`bamboo: could not add ${filePath} to the project`);
2364
+ this.markAuxiliary((0, _bamboocss_ts_ast.pathOf)(sourceFile), options.auxiliary);
2375
2365
  return sourceFile;
2376
2366
  };
2377
2367
  /** Claim or release compiler ownership of one source, in the ledger's own spelling. */
@@ -2387,10 +2377,10 @@ var Project = class {
2387
2377
  if (sourceFile) {
2388
2378
  this.invalidate();
2389
2379
  this.invalidateSourcePreparation(filePath, sourceFile);
2390
- this.markTargetRemoved(this.normalizePath(sourceFile.getFilePath()), sourceFile);
2391
- this.options.parserOptions.encoder.releaseFile(sourceFile.getFilePath());
2392
- this.auxiliarySources.delete(this.normalizePath(sourceFile.getFilePath()));
2393
- return this.project.removeSourceFile(sourceFile);
2380
+ this.markTargetRemoved(this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile)), sourceFile);
2381
+ this.options.parserOptions.encoder.releaseFile((0, _bamboocss_ts_ast.pathOf)(sourceFile));
2382
+ this.auxiliarySources.delete(this.normalizePath((0, _bamboocss_ts_ast.pathOf)(sourceFile)));
2383
+ return this.project.removeSourceFile((0, _bamboocss_ts_ast.pathOf)(sourceFile));
2394
2384
  }
2395
2385
  return false;
2396
2386
  };
@@ -2409,10 +2399,10 @@ var Project = class {
2409
2399
  this.#assertNotLoading();
2410
2400
  this.#ensureSourceFiles();
2411
2401
  const sourceFile = this.getSourceFile(filePath);
2412
- this.invalidate(false, sourceFile?.getFilePath());
2402
+ this.invalidate(false, (0, _bamboocss_ts_ast.pathOf)(sourceFile));
2413
2403
  if (!sourceFile) return;
2414
2404
  this.invalidateSourcePreparation(filePath, sourceFile);
2415
- return sourceFile.refreshFromFileSystemSync();
2405
+ return this.project.reloadSourceFile(filePath);
2416
2406
  };
2417
2407
  reloadSourceFiles = () => {
2418
2408
  this.#assertNotLoading();
@@ -2423,7 +2413,7 @@ var Project = class {
2423
2413
  const source = this.getSourceFile(file);
2424
2414
  if (source) {
2425
2415
  this.invalidateSourcePreparation(file, source);
2426
- source.refreshFromFileSystemSync();
2416
+ this.project.reloadSourceFile(file);
2427
2417
  } else {
2428
2418
  this.invalidateSourcePreparation(file);
2429
2419
  this.removedSourcePaths.delete(this.normalizePath(file));
@@ -2465,10 +2455,12 @@ var Project = class {
2465
2455
  const { hooks } = this.options;
2466
2456
  const hookFilePath = options.hookFilePath ?? filePath;
2467
2457
  if (filePath.endsWith(".json")) return this.parseJson(filePath, encoder);
2468
- const sourceFile = this.project.getSourceFile(filePath);
2458
+ let sourceFile = this.project.getSourceFile(filePath);
2469
2459
  if (!sourceFile) return;
2470
- const { options: parserOptions } = this.prepareEffectiveSource(filePath, sourceFile, hookFilePath);
2471
- const result = (encoder ?? this.options.parserOptions.encoder).withOwner("parse", sourceFile.getFilePath(), () => this.parser(sourceFile, encoder, parserOptions, this.resolveModule))?.setFilePath(filePath);
2460
+ const prepared = this.prepareEffectiveSource(filePath, sourceFile, hookFilePath);
2461
+ const parserOptions = prepared.options;
2462
+ sourceFile = prepared.sourceFile ?? sourceFile;
2463
+ const result = (encoder ?? this.options.parserOptions.encoder).withOwner("parse", (0, _bamboocss_ts_ast.pathOf)(sourceFile), () => this.parser(sourceFile, encoder, parserOptions, this.resolveModule))?.setFilePath(filePath);
2472
2464
  hooks["parser:after"]?.({
2473
2465
  filePath: hookFilePath,
2474
2466
  result