@bamboocss/vite 1.37.9 → 1.37.10

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
@@ -751,10 +751,28 @@ const collectModuleScopeNames = (sourceFile) => {
751
751
  * while under-reporting ships an element whose class has no rule behind it and says nothing.
752
752
  * Shadowing a recipe binding is rare; silently shipping unstyled markup is not recoverable.
753
753
  */
754
+ const identifiersByName = /* @__PURE__ */ new WeakMap();
755
+ /**
756
+ * Every identifier in the module, grouped by the name it spells.
757
+ *
758
+ * Walking the whole tree per binding made this O(bindings x identifiers): a module declaring
759
+ * ten recipes walked its identifiers ten times. One walk answers for all of them, and the
760
+ * result is cached against the source text like the module-scope names beside it, so a
761
+ * re-transform of unchanged text reuses it.
762
+ */
763
+ const identifierIndex = (sourceFile) => byText(identifiersByName, sourceFile, () => {
764
+ const index = /* @__PURE__ */ new Map();
765
+ for (const identifier of sourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.Identifier)) {
766
+ const text = identifier.getText();
767
+ const known = index.get(text);
768
+ if (known) known.push(identifier);
769
+ else index.set(text, [identifier]);
770
+ }
771
+ return index;
772
+ });
754
773
  const localReferencesTo = (sourceFile, name, declaration) => {
755
774
  const references = [];
756
- for (const identifier of sourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.Identifier)) {
757
- if (identifier.getText() !== name) continue;
775
+ for (const identifier of identifierIndex(sourceFile).get(name) ?? []) {
758
776
  if (identifier === declaration) continue;
759
777
  const parent = identifier.getParent();
760
778
  if (!parent) continue;
@@ -2839,18 +2857,24 @@ const bamboocss = (options = {}) => {
2839
2857
  skipped: /* @__PURE__ */ new Map()
2840
2858
  };
2841
2859
  const staticSession = createStaticCompilationSession();
2842
- const survivors = [];
2843
- const survivorKeys = /* @__PURE__ */ new Set();
2860
+ /**
2861
+ * Indexed by file, because the only bulk operation on it is "forget this one's".
2862
+ *
2863
+ * A flat array meant every transform scanned every survivor and then rebuilt the dedupe key
2864
+ * set from scratch — O(modules x survivors) across a build, and worst exactly when a build is
2865
+ * already failing and the user is iterating on it. One project had 736 of them across 9,461
2866
+ * modules, which is seven million string builds to discard.
2867
+ */
2868
+ const survivorsByFile = /* @__PURE__ */ new Map();
2869
+ const allSurvivors = () => [...survivorsByFile.values()].flat();
2844
2870
  const addSurvivor = (entry) => {
2845
- const key = `${entry.file}:${entry.line}:${entry.name}:${entry.reason}`;
2846
- if (survivorKeys.has(key)) return;
2847
- survivorKeys.add(key);
2848
- survivors.push(entry);
2871
+ const forFile = survivorsByFile.get(entry.file) ?? [];
2872
+ if (forFile.some((seen) => seen.line === entry.line && seen.name === entry.name && seen.reason === entry.reason)) return;
2873
+ forFile.push(entry);
2874
+ survivorsByFile.set(entry.file, forFile);
2849
2875
  };
2850
2876
  const clearSurvivorsFor = (file) => {
2851
- for (let index = survivors.length - 1; index >= 0; index--) if (survivors[index]?.file === file) survivors.splice(index, 1);
2852
- survivorKeys.clear();
2853
- for (const entry of survivors) survivorKeys.add(`${entry.file}:${entry.line}:${entry.name}:${entry.reason}`);
2877
+ survivorsByFile.delete(file);
2854
2878
  };
2855
2879
  const createSurvivorError = (entries) => {
2856
2880
  const byFile = /* @__PURE__ */ new Map();
@@ -2909,8 +2933,7 @@ const bamboocss = (options = {}) => {
2909
2933
  totals.files = 0;
2910
2934
  totals.filesWithFolds = 0;
2911
2935
  totals.skipped.clear();
2912
- survivors.length = 0;
2913
- survivorKeys.clear();
2936
+ survivorsByFile.clear();
2914
2937
  recipeConfigCache.clear();
2915
2938
  resetStaticCompilationSession(staticSession);
2916
2939
  }
@@ -3013,7 +3036,8 @@ const bamboocss = (options = {}) => {
3013
3036
  }
3014
3037
  if (reportSkipped && result.skipped.length) _bamboocss_logger.logger.info("vite:transform", formatSkipped(filePath, result.skipped));
3015
3038
  for (const dependency of result.dependencies) this.addWatchFile?.(dependency);
3016
- if (command === "serve" && survivors.some((entry) => entry.file === filePath)) throw createSurvivorError(survivors.filter((entry) => entry.file === filePath));
3039
+ const forFile = survivorsByFile.get(filePath);
3040
+ if (command === "serve" && forFile?.length) throw createSurvivorError(forFile);
3017
3041
  if (!result.folded.length) return null;
3018
3042
  _bamboocss_logger.logger.debug("vite:transform", `Compiled ${result.folded.length} call(s) in ${filePath}`);
3019
3043
  return {
@@ -3022,6 +3046,7 @@ const bamboocss = (options = {}) => {
3022
3046
  };
3023
3047
  },
3024
3048
  buildEnd() {
3049
+ const survivors = allSurvivors();
3025
3050
  if (survivors.length) throw createSurvivorError(survivors);
3026
3051
  if (typeof this.getModuleInfo === "function") {
3027
3052
  if (!staticSession.cssLoaded) throw new Error(`bamboocss: compiled class values were produced, but ${JSON.stringify(VIRTUAL_CSS_ID)} was not imported. Add \`import ${JSON.stringify(VIRTUAL_CSS_ID)}\` once, from a JavaScript or TypeScript module in the application entry graph.\n\nIt has to be a JS import. \`@import\` from a stylesheet does not reach it: the id names a virtual module resolved by this plugin, and Vite resolves CSS \`@import\` before plugin resolution, so it fails as an unresolvable path. A project that ships one preloaded stylesheet imports this from its entry module instead, and lets Vite emit the CSS asset.`);
package/dist/index.mjs CHANGED
@@ -721,10 +721,28 @@ const collectModuleScopeNames = (sourceFile) => {
721
721
  * while under-reporting ships an element whose class has no rule behind it and says nothing.
722
722
  * Shadowing a recipe binding is rare; silently shipping unstyled markup is not recoverable.
723
723
  */
724
+ const identifiersByName = /* @__PURE__ */ new WeakMap();
725
+ /**
726
+ * Every identifier in the module, grouped by the name it spells.
727
+ *
728
+ * Walking the whole tree per binding made this O(bindings x identifiers): a module declaring
729
+ * ten recipes walked its identifiers ten times. One walk answers for all of them, and the
730
+ * result is cached against the source text like the module-scope names beside it, so a
731
+ * re-transform of unchanged text reuses it.
732
+ */
733
+ const identifierIndex = (sourceFile) => byText(identifiersByName, sourceFile, () => {
734
+ const index = /* @__PURE__ */ new Map();
735
+ for (const identifier of sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)) {
736
+ const text = identifier.getText();
737
+ const known = index.get(text);
738
+ if (known) known.push(identifier);
739
+ else index.set(text, [identifier]);
740
+ }
741
+ return index;
742
+ });
724
743
  const localReferencesTo = (sourceFile, name, declaration) => {
725
744
  const references = [];
726
- for (const identifier of sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)) {
727
- if (identifier.getText() !== name) continue;
745
+ for (const identifier of identifierIndex(sourceFile).get(name) ?? []) {
728
746
  if (identifier === declaration) continue;
729
747
  const parent = identifier.getParent();
730
748
  if (!parent) continue;
@@ -2809,18 +2827,24 @@ const bamboocss = (options = {}) => {
2809
2827
  skipped: /* @__PURE__ */ new Map()
2810
2828
  };
2811
2829
  const staticSession = createStaticCompilationSession();
2812
- const survivors = [];
2813
- const survivorKeys = /* @__PURE__ */ new Set();
2830
+ /**
2831
+ * Indexed by file, because the only bulk operation on it is "forget this one's".
2832
+ *
2833
+ * A flat array meant every transform scanned every survivor and then rebuilt the dedupe key
2834
+ * set from scratch — O(modules x survivors) across a build, and worst exactly when a build is
2835
+ * already failing and the user is iterating on it. One project had 736 of them across 9,461
2836
+ * modules, which is seven million string builds to discard.
2837
+ */
2838
+ const survivorsByFile = /* @__PURE__ */ new Map();
2839
+ const allSurvivors = () => [...survivorsByFile.values()].flat();
2814
2840
  const addSurvivor = (entry) => {
2815
- const key = `${entry.file}:${entry.line}:${entry.name}:${entry.reason}`;
2816
- if (survivorKeys.has(key)) return;
2817
- survivorKeys.add(key);
2818
- survivors.push(entry);
2841
+ const forFile = survivorsByFile.get(entry.file) ?? [];
2842
+ if (forFile.some((seen) => seen.line === entry.line && seen.name === entry.name && seen.reason === entry.reason)) return;
2843
+ forFile.push(entry);
2844
+ survivorsByFile.set(entry.file, forFile);
2819
2845
  };
2820
2846
  const clearSurvivorsFor = (file) => {
2821
- for (let index = survivors.length - 1; index >= 0; index--) if (survivors[index]?.file === file) survivors.splice(index, 1);
2822
- survivorKeys.clear();
2823
- for (const entry of survivors) survivorKeys.add(`${entry.file}:${entry.line}:${entry.name}:${entry.reason}`);
2847
+ survivorsByFile.delete(file);
2824
2848
  };
2825
2849
  const createSurvivorError = (entries) => {
2826
2850
  const byFile = /* @__PURE__ */ new Map();
@@ -2879,8 +2903,7 @@ const bamboocss = (options = {}) => {
2879
2903
  totals.files = 0;
2880
2904
  totals.filesWithFolds = 0;
2881
2905
  totals.skipped.clear();
2882
- survivors.length = 0;
2883
- survivorKeys.clear();
2906
+ survivorsByFile.clear();
2884
2907
  recipeConfigCache.clear();
2885
2908
  resetStaticCompilationSession(staticSession);
2886
2909
  }
@@ -2983,7 +3006,8 @@ const bamboocss = (options = {}) => {
2983
3006
  }
2984
3007
  if (reportSkipped && result.skipped.length) logger.info("vite:transform", formatSkipped(filePath, result.skipped));
2985
3008
  for (const dependency of result.dependencies) this.addWatchFile?.(dependency);
2986
- if (command === "serve" && survivors.some((entry) => entry.file === filePath)) throw createSurvivorError(survivors.filter((entry) => entry.file === filePath));
3009
+ const forFile = survivorsByFile.get(filePath);
3010
+ if (command === "serve" && forFile?.length) throw createSurvivorError(forFile);
2987
3011
  if (!result.folded.length) return null;
2988
3012
  logger.debug("vite:transform", `Compiled ${result.folded.length} call(s) in ${filePath}`);
2989
3013
  return {
@@ -2992,6 +3016,7 @@ const bamboocss = (options = {}) => {
2992
3016
  };
2993
3017
  },
2994
3018
  buildEnd() {
3019
+ const survivors = allSurvivors();
2995
3020
  if (survivors.length) throw createSurvivorError(survivors);
2996
3021
  if (typeof this.getModuleInfo === "function") {
2997
3022
  if (!staticSession.cssLoaded) throw new Error(`bamboocss: compiled class values were produced, but ${JSON.stringify(VIRTUAL_CSS_ID)} was not imported. Add \`import ${JSON.stringify(VIRTUAL_CSS_ID)}\` once, from a JavaScript or TypeScript module in the application entry graph.\n\nIt has to be a JS import. \`@import\` from a stylesheet does not reach it: the id names a virtual module resolved by this plugin, and Vite resolves CSS \`@import\` before plugin resolution, so it fails as an unresolvable path. A project that ships one preloaded stylesheet imports this from its entry module instead, and lets Vite emit the CSS asset.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/vite",
3
- "version": "1.37.9",
3
+ "version": "1.37.10",
4
4
  "description": "Vite integration for Bamboo CSS",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -40,18 +40,18 @@
40
40
  "postcss": "8.5.26",
41
41
  "postcss-selector-parser": "7.1.5",
42
42
  "ts-morph": "28.0.0",
43
- "@bamboocss/config": "1.37.9",
44
- "@bamboocss/core": "1.37.9",
45
- "@bamboocss/extractor": "1.37.9",
46
- "@bamboocss/logger": "1.37.9",
47
- "@bamboocss/node": "1.37.9",
48
- "@bamboocss/types": "1.37.9",
49
- "@bamboocss/shared": "1.37.9"
43
+ "@bamboocss/config": "1.37.10",
44
+ "@bamboocss/core": "1.37.10",
45
+ "@bamboocss/extractor": "1.37.10",
46
+ "@bamboocss/node": "1.37.10",
47
+ "@bamboocss/logger": "1.37.10",
48
+ "@bamboocss/types": "1.37.10",
49
+ "@bamboocss/shared": "1.37.10"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jridgewell/trace-mapping": "^0.3.31",
53
53
  "vite": "7.2.6",
54
- "@bamboocss/fixture": "1.37.9"
54
+ "@bamboocss/fixture": "1.37.10"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "vite": ">=5"