@bamboocss/vite 1.48.2 → 1.48.4

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
@@ -200,6 +200,8 @@ const createCompilationHost = (options = {}) => {
200
200
  };
201
201
  //#endregion
202
202
  //#region src/static-session.ts
203
+ /** Store one semantic class token in the selector spelling used by reachability sets. */
204
+ const selectorClassName = (token) => token.includes("\\") ? token : (0, _bamboocss_shared.esc)(token);
203
205
  const createStaticCompilationSession = () => {
204
206
  const session = {
205
207
  utilityLayer: "utilities",
@@ -227,7 +229,7 @@ const createStaticCompilationSession = () => {
227
229
  markClassUsed(className) {
228
230
  for (const token of className.split(" ")) {
229
231
  if (!token) continue;
230
- session.usedClasses.add(token.includes("\\") ? token : (0, _bamboocss_shared.esc)(token));
232
+ session.usedClasses.add(selectorClassName(token));
231
233
  }
232
234
  }
233
235
  };
@@ -875,10 +877,20 @@ const bamboocss = (options = {}) => {
875
877
  ] : null
876
878
  ]);
877
879
  const transformArtifactIntegrity = (environment, artifact) => (0, node_crypto.createHmac)("sha256", transformArtifactIntegrityKey).update(serializeTransformArtifact(environment, artifact)).digest("base64url");
878
- const sealTransformArtifact = (environment, artifact) => ({
879
- ...artifact,
880
- integrity: transformArtifactIntegrity(environment, artifact)
881
- });
880
+ const sealTransformArtifact = (environment, artifact) => {
881
+ const detached = {
882
+ ...artifact,
883
+ skipped: artifact.skipped.map(([reason, count]) => [reason, count]),
884
+ survivors: artifact.survivors.map((survivor) => ({ ...survivor })),
885
+ classNames: [...artifact.classNames],
886
+ dependencies: [...artifact.dependencies],
887
+ ...artifact.signature ? { signature: { ...artifact.signature } } : {}
888
+ };
889
+ return {
890
+ ...detached,
891
+ integrity: transformArtifactIntegrity(environment, detached)
892
+ };
893
+ };
882
894
  const skipReasons = new Set([
883
895
  "dynamic",
884
896
  "raw-call",
@@ -922,6 +934,11 @@ const bamboocss = (options = {}) => {
922
934
  return /* @__PURE__ */ new Error(`bamboocss: cached transform metadata for ${JSON.stringify(id)} in the ${JSON.stringify(environment)} environment ${problem}.\n\nBamboo cannot safely rebuild from this entry because cached JavaScript may still name CSS classes whose rules would be dropped. Restart Vite to invalidate its in-memory transform cache. If this persists, clear Vite's cache directory and rebuild.`);
923
935
  };
924
936
  const transformStateByEnvironment = /* @__PURE__ */ new Map();
937
+ /** States currently materialized in the shared CSS session's reachability projection. */
938
+ const projectedTransformStates = /* @__PURE__ */ new Set();
939
+ const projectedUsedClassCounts = /* @__PURE__ */ new Map();
940
+ const projectedTransformedFileCounts = /* @__PURE__ */ new Map();
941
+ let projectedCssLoadedCount = 0;
925
942
  /**
926
943
  * One fold per file content per change event, shared across environments and hooks.
927
944
  *
@@ -987,6 +1004,8 @@ const bamboocss = (options = {}) => {
987
1004
  const environmentName = (context) => environmentOf(context)?.name ?? "default";
988
1005
  const newEnvironmentState = () => ({
989
1006
  transformArtifactsByModule: /* @__PURE__ */ new Map(),
1007
+ usedClassCounts: /* @__PURE__ */ new Map(),
1008
+ transformedFileCounts: /* @__PURE__ */ new Map(),
990
1009
  dependentsByDependency: /* @__PURE__ */ new Map(),
991
1010
  dependenciesByModule: /* @__PURE__ */ new Map(),
992
1011
  filesByModule: /* @__PURE__ */ new Map(),
@@ -1001,6 +1020,8 @@ const bamboocss = (options = {}) => {
1001
1020
  });
1002
1021
  const cloneEnvironmentState = (state) => ({
1003
1022
  transformArtifactsByModule: new Map(state.transformArtifactsByModule),
1023
+ usedClassCounts: new Map(state.usedClassCounts),
1024
+ transformedFileCounts: new Map(state.transformedFileCounts),
1004
1025
  dependentsByDependency: new Map([...state.dependentsByDependency].map(([dependency, dependents]) => [dependency, new Set(dependents)])),
1005
1026
  dependenciesByModule: new Map([...state.dependenciesByModule].map(([moduleId, dependencies]) => [moduleId, new Set(dependencies)])),
1006
1027
  filesByModule: new Map(state.filesByModule),
@@ -1127,10 +1148,43 @@ const bamboocss = (options = {}) => {
1127
1148
  if (!assets.length) return void 0;
1128
1149
  return digest(JSON.stringify(assets.sort()));
1129
1150
  };
1130
- /** Add one detached transform contribution to the global reachability projection. */
1131
- const applyStaticTransformContribution = (artifact) => {
1132
- if (artifact.transformedFile) staticSession.transformedFiles.add((0, node_path.resolve)(artifact.file));
1133
- for (const className of artifact.classNames) staticSession.markClassUsed(className);
1151
+ const adjustContributionCount = (counts, value, delta) => {
1152
+ const next = (counts.get(value) ?? 0) + delta;
1153
+ if (next < 0) throw new Error(`bamboocss: internal contribution count underflow for ${JSON.stringify(value)}`);
1154
+ if (next > 0) counts.set(value, next);
1155
+ else counts.delete(value);
1156
+ return next;
1157
+ };
1158
+ /** Update the projection index for one module contribution without scanning its siblings. */
1159
+ const adjustTransformContribution = (state, artifact, delta) => {
1160
+ if (artifact.transformedFile) adjustContributionCount(state.transformedFileCounts, (0, node_path.resolve)(artifact.file), delta);
1161
+ for (const classNames of artifact.classNames) for (const token of classNames.split(" ")) if (token) adjustContributionCount(state.usedClassCounts, selectorClassName(token), delta);
1162
+ };
1163
+ const replaceTransformArtifact = (state, artifact) => {
1164
+ const previous = state.transformArtifactsByModule.get(artifact.moduleId);
1165
+ if (previous) adjustTransformContribution(state, previous, -1);
1166
+ state.transformArtifactsByModule.set(artifact.moduleId, artifact);
1167
+ adjustTransformContribution(state, artifact, 1);
1168
+ };
1169
+ const deleteTransformArtifact = (state, moduleId) => {
1170
+ const previous = state.transformArtifactsByModule.get(moduleId);
1171
+ if (!previous) return false;
1172
+ adjustTransformContribution(state, previous, -1);
1173
+ return state.transformArtifactsByModule.delete(moduleId);
1174
+ };
1175
+ const adjustProjectedTransformState = (state, delta) => {
1176
+ for (const className of state.usedClassCounts.keys()) {
1177
+ const next = adjustContributionCount(projectedUsedClassCounts, className, delta);
1178
+ if (next === 1 && delta === 1) staticSession.usedClasses.add(className);
1179
+ else if (next === 0) staticSession.usedClasses.delete(className);
1180
+ }
1181
+ for (const file of state.transformedFileCounts.keys()) {
1182
+ const next = adjustContributionCount(projectedTransformedFileCounts, file, delta);
1183
+ if (next === 1 && delta === 1) staticSession.transformedFiles.add(file);
1184
+ else if (next === 0) staticSession.transformedFiles.delete(file);
1185
+ }
1186
+ if (state.cssLoaded) projectedCssLoadedCount += delta;
1187
+ if (projectedCssLoadedCount < 0) throw new Error("bamboocss: internal stylesheet contribution count underflow");
1134
1188
  };
1135
1189
  /**
1136
1190
  * Re-derive the two global sets CSS pruning consumes from environment-owned artifacts.
@@ -1157,13 +1211,12 @@ const bamboocss = (options = {}) => {
1157
1211
  return states;
1158
1212
  };
1159
1213
  const rebuildStaticTransformContributions = (candidateEnvironment, candidateState) => {
1160
- staticSession.transformedFiles.clear();
1161
- staticSession.usedClasses.clear();
1162
- staticSession.cssLoaded = false;
1163
- for (const state of contributionStates(candidateEnvironment, candidateState)) {
1164
- if (state.cssLoaded) staticSession.cssLoaded = true;
1165
- for (const artifact of state.transformArtifactsByModule.values()) applyStaticTransformContribution(artifact);
1166
- }
1214
+ const nextStates = new Set(contributionStates(candidateEnvironment, candidateState));
1215
+ for (const state of projectedTransformStates) if (!nextStates.has(state)) adjustProjectedTransformState(state, -1);
1216
+ for (const state of nextStates) if (!projectedTransformStates.has(state)) adjustProjectedTransformState(state, 1);
1217
+ projectedTransformStates.clear();
1218
+ for (const state of nextStates) projectedTransformStates.add(state);
1219
+ staticSession.cssLoaded = projectedCssLoadedCount > 0;
1167
1220
  };
1168
1221
  /**
1169
1222
  * Snapshot which reported classes Bamboo actually extracted for this JavaScript generation.
@@ -1175,9 +1228,8 @@ const bamboocss = (options = {}) => {
1175
1228
  const ownedClassesForState = (state) => {
1176
1229
  const extracted = new Map([...staticSession.prunableClasses].map((className) => [require_class_name.bare(className), className]));
1177
1230
  const owned = /* @__PURE__ */ new Set();
1178
- for (const artifact of state.transformArtifactsByModule.values()) for (const reported of artifact.classNames) for (const token of reported.split(" ")) {
1179
- if (!token) continue;
1180
- const extractedClass = extracted.get(require_class_name.bare(token));
1231
+ for (const className of state.usedClassCounts.keys()) {
1232
+ const extractedClass = extracted.get(require_class_name.bare(className));
1181
1233
  if (extractedClass !== void 0) owned.add(extractedClass);
1182
1234
  }
1183
1235
  return owned;
@@ -1408,18 +1460,10 @@ const bamboocss = (options = {}) => {
1408
1460
  const reasons = Array.from(skipped.entries()).sort((a, b) => b[1] - a[1]).map(([reason, count]) => `${reason}=${count}`).join(" ");
1409
1461
  _bamboocss_logger.logger.info("vite:transform", `Compiled ${folded}/${total} (${share}%) across ${filesWithFolds}/${perFile.size} files` + (reasons ? ` — declined: ${reasons}` : ""));
1410
1462
  };
1411
- /** Restore every per-build fact established by one successful transform. */
1412
- const applyTransformArtifact = (state, value, expectedModuleId, environment) => {
1413
- let snapshot;
1414
- try {
1415
- snapshot = structuredClone(value);
1416
- } catch {
1417
- throw cachedArtifactError(expectedModuleId, environment, void 0, `could not be snapshotted as serializable schema version ${TRANSFORM_ARTIFACT_VERSION} data`);
1418
- }
1419
- if (!isTransformArtifact(snapshot) || snapshot.moduleId !== expectedModuleId || snapshot.file !== expectedModuleId.split("?")[0] || !hasValidTransformArtifactIntegrity(environment, snapshot)) throw cachedArtifactError(expectedModuleId, environment, snapshot);
1420
- const artifact = snapshot;
1463
+ /** Apply every per-build fact established by one trusted or validated transform artifact. */
1464
+ const commitTransformArtifact = (state, artifact) => {
1421
1465
  const { file, moduleId } = artifact;
1422
- state.transformArtifactsByModule.set(moduleId, artifact);
1466
+ replaceTransformArtifact(state, artifact);
1423
1467
  recordFoldDependencies(state, moduleId, file, artifact.dependencies);
1424
1468
  if (artifact.signature) state.foldSignatures.set(moduleId, artifact.signature);
1425
1469
  else {
@@ -1427,6 +1471,17 @@ const bamboocss = (options = {}) => {
1427
1471
  state.foldInputsByModule.delete(moduleId);
1428
1472
  }
1429
1473
  };
1474
+ /** Snapshot and authenticate transform metadata owned by Rollup's external cache. */
1475
+ const applyCachedTransformArtifact = (state, value, expectedModuleId, environment) => {
1476
+ let snapshot;
1477
+ try {
1478
+ snapshot = structuredClone(value);
1479
+ } catch {
1480
+ throw cachedArtifactError(expectedModuleId, environment, void 0, `could not be snapshotted as serializable schema version ${TRANSFORM_ARTIFACT_VERSION} data`);
1481
+ }
1482
+ if (!isTransformArtifact(snapshot) || snapshot.moduleId !== expectedModuleId || snapshot.file !== expectedModuleId.split("?")[0] || !hasValidTransformArtifactIntegrity(environment, snapshot)) throw cachedArtifactError(expectedModuleId, environment, snapshot);
1483
+ commitTransformArtifact(state, snapshot);
1484
+ };
1430
1485
  /**
1431
1486
  * Replay transform metadata for modules Rollup reused from its cache.
1432
1487
  *
@@ -1449,7 +1504,7 @@ const bamboocss = (options = {}) => {
1449
1504
  const meta = pluginContext.getModuleInfo(id)?.meta;
1450
1505
  if (!meta || !Object.prototype.hasOwnProperty.call(meta, TRANSFORM_META_KEY)) continue;
1451
1506
  const artifact = meta[TRANSFORM_META_KEY];
1452
- applyTransformArtifact(state, artifact, id, environmentName(pluginContext));
1507
+ applyCachedTransformArtifact(state, artifact, id, environmentName(pluginContext));
1453
1508
  }
1454
1509
  };
1455
1510
  /**
@@ -2006,7 +2061,7 @@ const bamboocss = (options = {}) => {
2006
2061
  recordFoldDependencies(state, moduleId, moduleFile, []);
2007
2062
  state.foldSignatures.delete(moduleId);
2008
2063
  state.foldInputsByModule.delete(moduleId);
2009
- state.transformArtifactsByModule.delete(moduleId);
2064
+ deleteTransformArtifact(state, moduleId);
2010
2065
  state.filesByModule.delete(moduleId);
2011
2066
  }
2012
2067
  return;
@@ -2233,7 +2288,7 @@ const bamboocss = (options = {}) => {
2233
2288
  });
2234
2289
  if (!compiled) return null;
2235
2290
  if ("unparsed" in compiled) {
2236
- state.transformArtifactsByModule.delete(id);
2291
+ deleteTransformArtifact(state, id);
2237
2292
  recordFoldDependencies(state, id, filePath, []);
2238
2293
  state.foldSignatures.delete(id);
2239
2294
  state.foldInputsByModule.delete(id);
@@ -2246,8 +2301,7 @@ const bamboocss = (options = {}) => {
2246
2301
  })), ...result.exportReads]);
2247
2302
  } catch (error) {
2248
2303
  _bamboocss_logger.logger.caughtError("vite:transform", `Failed to compile ${filePath}`, error);
2249
- const previousDependencies = [...state.dependenciesByModule.get(id) ?? []];
2250
- applyTransformArtifact(state, sealTransformArtifact(environmentName(this), {
2304
+ commitTransformArtifact(state, {
2251
2305
  version: TRANSFORM_ARTIFACT_VERSION,
2252
2306
  moduleId: id,
2253
2307
  file: filePath,
@@ -2260,8 +2314,8 @@ const bamboocss = (options = {}) => {
2260
2314
  }],
2261
2315
  transformedFile: false,
2262
2316
  classNames: [],
2263
- dependencies: previousDependencies
2264
- }), id, environmentName(this));
2317
+ dependencies: [...state.dependenciesByModule.get(id) ?? []]
2318
+ });
2265
2319
  state.foldSignatures.delete(id);
2266
2320
  state.foldInputsByModule.delete(id);
2267
2321
  if (command === "serve") throw asError(error, `failed to compile ${filePath}`);
@@ -2279,7 +2333,7 @@ const bamboocss = (options = {}) => {
2279
2333
  reason: entry.reason
2280
2334
  });
2281
2335
  }
2282
- const artifact = sealTransformArtifact(environmentName(this), {
2336
+ const artifact = {
2283
2337
  version: TRANSFORM_ARTIFACT_VERSION,
2284
2338
  moduleId: id,
2285
2339
  file: filePath,
@@ -2294,8 +2348,8 @@ const bamboocss = (options = {}) => {
2294
2348
  output: digest(result.code),
2295
2349
  path: filePath
2296
2350
  } } : {}
2297
- });
2298
- applyTransformArtifact(state, artifact, id, environmentName(this));
2351
+ };
2352
+ commitTransformArtifact(state, artifact);
2299
2353
  if (artifact.signature && (command === "serve" || requestedParsePath !== filePath)) state.foldInputsByModule.set(id, {
2300
2354
  code,
2301
2355
  input: artifact.signature.input,
@@ -2312,7 +2366,7 @@ const bamboocss = (options = {}) => {
2312
2366
  ...survivor
2313
2367
  })));
2314
2368
  }
2315
- const meta = { [TRANSFORM_META_KEY]: artifact };
2369
+ const meta = { [TRANSFORM_META_KEY]: sealTransformArtifact(environmentName(this), artifact) };
2316
2370
  if (!result.folded.length) return typeof this.getModuleInfo === "function" ? {
2317
2371
  code,
2318
2372
  map: null,
package/dist/index.mjs CHANGED
@@ -195,6 +195,8 @@ const createCompilationHost = (options = {}) => {
195
195
  };
196
196
  //#endregion
197
197
  //#region src/static-session.ts
198
+ /** Store one semantic class token in the selector spelling used by reachability sets. */
199
+ const selectorClassName = (token) => token.includes("\\") ? token : esc(token);
198
200
  const createStaticCompilationSession = () => {
199
201
  const session = {
200
202
  utilityLayer: "utilities",
@@ -222,7 +224,7 @@ const createStaticCompilationSession = () => {
222
224
  markClassUsed(className) {
223
225
  for (const token of className.split(" ")) {
224
226
  if (!token) continue;
225
- session.usedClasses.add(token.includes("\\") ? token : esc(token));
227
+ session.usedClasses.add(selectorClassName(token));
226
228
  }
227
229
  }
228
230
  };
@@ -870,10 +872,20 @@ const bamboocss = (options = {}) => {
870
872
  ] : null
871
873
  ]);
872
874
  const transformArtifactIntegrity = (environment, artifact) => createHmac("sha256", transformArtifactIntegrityKey).update(serializeTransformArtifact(environment, artifact)).digest("base64url");
873
- const sealTransformArtifact = (environment, artifact) => ({
874
- ...artifact,
875
- integrity: transformArtifactIntegrity(environment, artifact)
876
- });
875
+ const sealTransformArtifact = (environment, artifact) => {
876
+ const detached = {
877
+ ...artifact,
878
+ skipped: artifact.skipped.map(([reason, count]) => [reason, count]),
879
+ survivors: artifact.survivors.map((survivor) => ({ ...survivor })),
880
+ classNames: [...artifact.classNames],
881
+ dependencies: [...artifact.dependencies],
882
+ ...artifact.signature ? { signature: { ...artifact.signature } } : {}
883
+ };
884
+ return {
885
+ ...detached,
886
+ integrity: transformArtifactIntegrity(environment, detached)
887
+ };
888
+ };
877
889
  const skipReasons = new Set([
878
890
  "dynamic",
879
891
  "raw-call",
@@ -917,6 +929,11 @@ const bamboocss = (options = {}) => {
917
929
  return /* @__PURE__ */ new Error(`bamboocss: cached transform metadata for ${JSON.stringify(id)} in the ${JSON.stringify(environment)} environment ${problem}.\n\nBamboo cannot safely rebuild from this entry because cached JavaScript may still name CSS classes whose rules would be dropped. Restart Vite to invalidate its in-memory transform cache. If this persists, clear Vite's cache directory and rebuild.`);
918
930
  };
919
931
  const transformStateByEnvironment = /* @__PURE__ */ new Map();
932
+ /** States currently materialized in the shared CSS session's reachability projection. */
933
+ const projectedTransformStates = /* @__PURE__ */ new Set();
934
+ const projectedUsedClassCounts = /* @__PURE__ */ new Map();
935
+ const projectedTransformedFileCounts = /* @__PURE__ */ new Map();
936
+ let projectedCssLoadedCount = 0;
920
937
  /**
921
938
  * One fold per file content per change event, shared across environments and hooks.
922
939
  *
@@ -982,6 +999,8 @@ const bamboocss = (options = {}) => {
982
999
  const environmentName = (context) => environmentOf(context)?.name ?? "default";
983
1000
  const newEnvironmentState = () => ({
984
1001
  transformArtifactsByModule: /* @__PURE__ */ new Map(),
1002
+ usedClassCounts: /* @__PURE__ */ new Map(),
1003
+ transformedFileCounts: /* @__PURE__ */ new Map(),
985
1004
  dependentsByDependency: /* @__PURE__ */ new Map(),
986
1005
  dependenciesByModule: /* @__PURE__ */ new Map(),
987
1006
  filesByModule: /* @__PURE__ */ new Map(),
@@ -996,6 +1015,8 @@ const bamboocss = (options = {}) => {
996
1015
  });
997
1016
  const cloneEnvironmentState = (state) => ({
998
1017
  transformArtifactsByModule: new Map(state.transformArtifactsByModule),
1018
+ usedClassCounts: new Map(state.usedClassCounts),
1019
+ transformedFileCounts: new Map(state.transformedFileCounts),
999
1020
  dependentsByDependency: new Map([...state.dependentsByDependency].map(([dependency, dependents]) => [dependency, new Set(dependents)])),
1000
1021
  dependenciesByModule: new Map([...state.dependenciesByModule].map(([moduleId, dependencies]) => [moduleId, new Set(dependencies)])),
1001
1022
  filesByModule: new Map(state.filesByModule),
@@ -1122,10 +1143,43 @@ const bamboocss = (options = {}) => {
1122
1143
  if (!assets.length) return void 0;
1123
1144
  return digest(JSON.stringify(assets.sort()));
1124
1145
  };
1125
- /** Add one detached transform contribution to the global reachability projection. */
1126
- const applyStaticTransformContribution = (artifact) => {
1127
- if (artifact.transformedFile) staticSession.transformedFiles.add(resolve(artifact.file));
1128
- for (const className of artifact.classNames) staticSession.markClassUsed(className);
1146
+ const adjustContributionCount = (counts, value, delta) => {
1147
+ const next = (counts.get(value) ?? 0) + delta;
1148
+ if (next < 0) throw new Error(`bamboocss: internal contribution count underflow for ${JSON.stringify(value)}`);
1149
+ if (next > 0) counts.set(value, next);
1150
+ else counts.delete(value);
1151
+ return next;
1152
+ };
1153
+ /** Update the projection index for one module contribution without scanning its siblings. */
1154
+ const adjustTransformContribution = (state, artifact, delta) => {
1155
+ if (artifact.transformedFile) adjustContributionCount(state.transformedFileCounts, resolve(artifact.file), delta);
1156
+ for (const classNames of artifact.classNames) for (const token of classNames.split(" ")) if (token) adjustContributionCount(state.usedClassCounts, selectorClassName(token), delta);
1157
+ };
1158
+ const replaceTransformArtifact = (state, artifact) => {
1159
+ const previous = state.transformArtifactsByModule.get(artifact.moduleId);
1160
+ if (previous) adjustTransformContribution(state, previous, -1);
1161
+ state.transformArtifactsByModule.set(artifact.moduleId, artifact);
1162
+ adjustTransformContribution(state, artifact, 1);
1163
+ };
1164
+ const deleteTransformArtifact = (state, moduleId) => {
1165
+ const previous = state.transformArtifactsByModule.get(moduleId);
1166
+ if (!previous) return false;
1167
+ adjustTransformContribution(state, previous, -1);
1168
+ return state.transformArtifactsByModule.delete(moduleId);
1169
+ };
1170
+ const adjustProjectedTransformState = (state, delta) => {
1171
+ for (const className of state.usedClassCounts.keys()) {
1172
+ const next = adjustContributionCount(projectedUsedClassCounts, className, delta);
1173
+ if (next === 1 && delta === 1) staticSession.usedClasses.add(className);
1174
+ else if (next === 0) staticSession.usedClasses.delete(className);
1175
+ }
1176
+ for (const file of state.transformedFileCounts.keys()) {
1177
+ const next = adjustContributionCount(projectedTransformedFileCounts, file, delta);
1178
+ if (next === 1 && delta === 1) staticSession.transformedFiles.add(file);
1179
+ else if (next === 0) staticSession.transformedFiles.delete(file);
1180
+ }
1181
+ if (state.cssLoaded) projectedCssLoadedCount += delta;
1182
+ if (projectedCssLoadedCount < 0) throw new Error("bamboocss: internal stylesheet contribution count underflow");
1129
1183
  };
1130
1184
  /**
1131
1185
  * Re-derive the two global sets CSS pruning consumes from environment-owned artifacts.
@@ -1152,13 +1206,12 @@ const bamboocss = (options = {}) => {
1152
1206
  return states;
1153
1207
  };
1154
1208
  const rebuildStaticTransformContributions = (candidateEnvironment, candidateState) => {
1155
- staticSession.transformedFiles.clear();
1156
- staticSession.usedClasses.clear();
1157
- staticSession.cssLoaded = false;
1158
- for (const state of contributionStates(candidateEnvironment, candidateState)) {
1159
- if (state.cssLoaded) staticSession.cssLoaded = true;
1160
- for (const artifact of state.transformArtifactsByModule.values()) applyStaticTransformContribution(artifact);
1161
- }
1209
+ const nextStates = new Set(contributionStates(candidateEnvironment, candidateState));
1210
+ for (const state of projectedTransformStates) if (!nextStates.has(state)) adjustProjectedTransformState(state, -1);
1211
+ for (const state of nextStates) if (!projectedTransformStates.has(state)) adjustProjectedTransformState(state, 1);
1212
+ projectedTransformStates.clear();
1213
+ for (const state of nextStates) projectedTransformStates.add(state);
1214
+ staticSession.cssLoaded = projectedCssLoadedCount > 0;
1162
1215
  };
1163
1216
  /**
1164
1217
  * Snapshot which reported classes Bamboo actually extracted for this JavaScript generation.
@@ -1170,9 +1223,8 @@ const bamboocss = (options = {}) => {
1170
1223
  const ownedClassesForState = (state) => {
1171
1224
  const extracted = new Map([...staticSession.prunableClasses].map((className) => [bare(className), className]));
1172
1225
  const owned = /* @__PURE__ */ new Set();
1173
- for (const artifact of state.transformArtifactsByModule.values()) for (const reported of artifact.classNames) for (const token of reported.split(" ")) {
1174
- if (!token) continue;
1175
- const extractedClass = extracted.get(bare(token));
1226
+ for (const className of state.usedClassCounts.keys()) {
1227
+ const extractedClass = extracted.get(bare(className));
1176
1228
  if (extractedClass !== void 0) owned.add(extractedClass);
1177
1229
  }
1178
1230
  return owned;
@@ -1403,18 +1455,10 @@ const bamboocss = (options = {}) => {
1403
1455
  const reasons = Array.from(skipped.entries()).sort((a, b) => b[1] - a[1]).map(([reason, count]) => `${reason}=${count}`).join(" ");
1404
1456
  logger.info("vite:transform", `Compiled ${folded}/${total} (${share}%) across ${filesWithFolds}/${perFile.size} files` + (reasons ? ` — declined: ${reasons}` : ""));
1405
1457
  };
1406
- /** Restore every per-build fact established by one successful transform. */
1407
- const applyTransformArtifact = (state, value, expectedModuleId, environment) => {
1408
- let snapshot;
1409
- try {
1410
- snapshot = structuredClone(value);
1411
- } catch {
1412
- throw cachedArtifactError(expectedModuleId, environment, void 0, `could not be snapshotted as serializable schema version ${TRANSFORM_ARTIFACT_VERSION} data`);
1413
- }
1414
- if (!isTransformArtifact(snapshot) || snapshot.moduleId !== expectedModuleId || snapshot.file !== expectedModuleId.split("?")[0] || !hasValidTransformArtifactIntegrity(environment, snapshot)) throw cachedArtifactError(expectedModuleId, environment, snapshot);
1415
- const artifact = snapshot;
1458
+ /** Apply every per-build fact established by one trusted or validated transform artifact. */
1459
+ const commitTransformArtifact = (state, artifact) => {
1416
1460
  const { file, moduleId } = artifact;
1417
- state.transformArtifactsByModule.set(moduleId, artifact);
1461
+ replaceTransformArtifact(state, artifact);
1418
1462
  recordFoldDependencies(state, moduleId, file, artifact.dependencies);
1419
1463
  if (artifact.signature) state.foldSignatures.set(moduleId, artifact.signature);
1420
1464
  else {
@@ -1422,6 +1466,17 @@ const bamboocss = (options = {}) => {
1422
1466
  state.foldInputsByModule.delete(moduleId);
1423
1467
  }
1424
1468
  };
1469
+ /** Snapshot and authenticate transform metadata owned by Rollup's external cache. */
1470
+ const applyCachedTransformArtifact = (state, value, expectedModuleId, environment) => {
1471
+ let snapshot;
1472
+ try {
1473
+ snapshot = structuredClone(value);
1474
+ } catch {
1475
+ throw cachedArtifactError(expectedModuleId, environment, void 0, `could not be snapshotted as serializable schema version ${TRANSFORM_ARTIFACT_VERSION} data`);
1476
+ }
1477
+ if (!isTransformArtifact(snapshot) || snapshot.moduleId !== expectedModuleId || snapshot.file !== expectedModuleId.split("?")[0] || !hasValidTransformArtifactIntegrity(environment, snapshot)) throw cachedArtifactError(expectedModuleId, environment, snapshot);
1478
+ commitTransformArtifact(state, snapshot);
1479
+ };
1425
1480
  /**
1426
1481
  * Replay transform metadata for modules Rollup reused from its cache.
1427
1482
  *
@@ -1444,7 +1499,7 @@ const bamboocss = (options = {}) => {
1444
1499
  const meta = pluginContext.getModuleInfo(id)?.meta;
1445
1500
  if (!meta || !Object.prototype.hasOwnProperty.call(meta, TRANSFORM_META_KEY)) continue;
1446
1501
  const artifact = meta[TRANSFORM_META_KEY];
1447
- applyTransformArtifact(state, artifact, id, environmentName(pluginContext));
1502
+ applyCachedTransformArtifact(state, artifact, id, environmentName(pluginContext));
1448
1503
  }
1449
1504
  };
1450
1505
  /**
@@ -2001,7 +2056,7 @@ const bamboocss = (options = {}) => {
2001
2056
  recordFoldDependencies(state, moduleId, moduleFile, []);
2002
2057
  state.foldSignatures.delete(moduleId);
2003
2058
  state.foldInputsByModule.delete(moduleId);
2004
- state.transformArtifactsByModule.delete(moduleId);
2059
+ deleteTransformArtifact(state, moduleId);
2005
2060
  state.filesByModule.delete(moduleId);
2006
2061
  }
2007
2062
  return;
@@ -2228,7 +2283,7 @@ const bamboocss = (options = {}) => {
2228
2283
  });
2229
2284
  if (!compiled) return null;
2230
2285
  if ("unparsed" in compiled) {
2231
- state.transformArtifactsByModule.delete(id);
2286
+ deleteTransformArtifact(state, id);
2232
2287
  recordFoldDependencies(state, id, filePath, []);
2233
2288
  state.foldSignatures.delete(id);
2234
2289
  state.foldInputsByModule.delete(id);
@@ -2241,8 +2296,7 @@ const bamboocss = (options = {}) => {
2241
2296
  })), ...result.exportReads]);
2242
2297
  } catch (error) {
2243
2298
  logger.caughtError("vite:transform", `Failed to compile ${filePath}`, error);
2244
- const previousDependencies = [...state.dependenciesByModule.get(id) ?? []];
2245
- applyTransformArtifact(state, sealTransformArtifact(environmentName(this), {
2299
+ commitTransformArtifact(state, {
2246
2300
  version: TRANSFORM_ARTIFACT_VERSION,
2247
2301
  moduleId: id,
2248
2302
  file: filePath,
@@ -2255,8 +2309,8 @@ const bamboocss = (options = {}) => {
2255
2309
  }],
2256
2310
  transformedFile: false,
2257
2311
  classNames: [],
2258
- dependencies: previousDependencies
2259
- }), id, environmentName(this));
2312
+ dependencies: [...state.dependenciesByModule.get(id) ?? []]
2313
+ });
2260
2314
  state.foldSignatures.delete(id);
2261
2315
  state.foldInputsByModule.delete(id);
2262
2316
  if (command === "serve") throw asError(error, `failed to compile ${filePath}`);
@@ -2274,7 +2328,7 @@ const bamboocss = (options = {}) => {
2274
2328
  reason: entry.reason
2275
2329
  });
2276
2330
  }
2277
- const artifact = sealTransformArtifact(environmentName(this), {
2331
+ const artifact = {
2278
2332
  version: TRANSFORM_ARTIFACT_VERSION,
2279
2333
  moduleId: id,
2280
2334
  file: filePath,
@@ -2289,8 +2343,8 @@ const bamboocss = (options = {}) => {
2289
2343
  output: digest(result.code),
2290
2344
  path: filePath
2291
2345
  } } : {}
2292
- });
2293
- applyTransformArtifact(state, artifact, id, environmentName(this));
2346
+ };
2347
+ commitTransformArtifact(state, artifact);
2294
2348
  if (artifact.signature && (command === "serve" || requestedParsePath !== filePath)) state.foldInputsByModule.set(id, {
2295
2349
  code,
2296
2350
  input: artifact.signature.input,
@@ -2307,7 +2361,7 @@ const bamboocss = (options = {}) => {
2307
2361
  ...survivor
2308
2362
  })));
2309
2363
  }
2310
- const meta = { [TRANSFORM_META_KEY]: artifact };
2364
+ const meta = { [TRANSFORM_META_KEY]: sealTransformArtifact(environmentName(this), artifact) };
2311
2365
  if (!result.folded.length) return typeof this.getModuleInfo === "function" ? {
2312
2366
  code,
2313
2367
  map: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/vite",
3
- "version": "1.48.2",
3
+ "version": "1.48.4",
4
4
  "description": "Vite integration for Bamboo CSS",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -42,18 +42,18 @@
42
42
  "postcss": "8.5.26",
43
43
  "postcss-selector-parser": "7.1.5",
44
44
  "ts-morph": "28.0.0",
45
- "@bamboocss/config": "1.48.2",
46
- "@bamboocss/core": "1.48.2",
47
- "@bamboocss/logger": "1.48.2",
48
- "@bamboocss/extractor": "1.48.2",
49
- "@bamboocss/node": "1.48.2",
50
- "@bamboocss/types": "1.48.2",
51
- "@bamboocss/shared": "1.48.2"
45
+ "@bamboocss/config": "1.48.4",
46
+ "@bamboocss/core": "1.48.4",
47
+ "@bamboocss/node": "1.48.4",
48
+ "@bamboocss/extractor": "1.48.4",
49
+ "@bamboocss/logger": "1.48.4",
50
+ "@bamboocss/types": "1.48.4",
51
+ "@bamboocss/shared": "1.48.4"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@jridgewell/trace-mapping": "^0.3.31",
55
55
  "vite": "7.2.6",
56
- "@bamboocss/fixture": "1.48.2"
56
+ "@bamboocss/fixture": "1.48.4"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "vite": ">=5"