@csszyx/unplugin 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +8 -10
  2. package/dist/index.cjs +14 -7
  3. package/dist/index.d.cts +4 -4
  4. package/dist/index.d.mts +4 -4
  5. package/dist/index.mjs +3 -3
  6. package/dist/next-config.cjs +3 -0
  7. package/dist/next-config.d.cts +13 -2
  8. package/dist/next-config.d.mts +13 -2
  9. package/dist/next-config.mjs +3 -0
  10. package/dist/next-prebuild.cjs +13 -7
  11. package/dist/next-prebuild.d.cts +8 -2
  12. package/dist/next-prebuild.d.mts +8 -2
  13. package/dist/next-prebuild.mjs +13 -7
  14. package/dist/next-turbo-loader.cjs +31 -15
  15. package/dist/next-turbo-loader.d.cts +11 -2
  16. package/dist/next-turbo-loader.d.mts +11 -2
  17. package/dist/next-turbo-loader.mjs +30 -14
  18. package/dist/next-watcher.cjs +1 -1
  19. package/dist/next-watcher.mjs +1 -1
  20. package/dist/shared/{unplugin.CXV7fOa2.d.cts → unplugin.B32Exn-K.d.cts} +2 -2
  21. package/dist/shared/{unplugin.CXV7fOa2.d.mts → unplugin.B32Exn-K.d.mts} +2 -2
  22. package/dist/shared/{unplugin.Bb5TeU9B.cjs → unplugin.BJiWWF6w.cjs} +93 -23
  23. package/dist/shared/unplugin.BKGCkMgM.cjs +523 -0
  24. package/dist/shared/{unplugin.DMcbmP01.mjs → unplugin.BU0O4IkX.mjs} +4 -1
  25. package/dist/shared/unplugin.BcsvXjIV.mjs +579 -0
  26. package/dist/shared/{unplugin.CtnKJhAi.d.cts → unplugin.BsjD3mtb.d.cts} +165 -33
  27. package/dist/shared/{unplugin.CtnKJhAi.d.mts → unplugin.BsjD3mtb.d.mts} +165 -33
  28. package/dist/shared/{unplugin.DblMogcN.cjs → unplugin.Cji6O5jv.cjs} +4 -1
  29. package/dist/shared/unplugin.CkNQjA4G.cjs +613 -0
  30. package/dist/shared/unplugin.DKcwO8O4.mjs +490 -0
  31. package/dist/shared/{unplugin.DXgxFHzO.mjs → unplugin.DjRylBC_.mjs} +77 -25
  32. package/dist/shared/{unplugin.BK3XVHe8.cjs → unplugin.ZMa9YE1H.cjs} +621 -615
  33. package/dist/shared/{unplugin.B9vpjOhD.mjs → unplugin.gR_h2DVG.mjs} +585 -582
  34. package/dist/vite.cjs +3 -3
  35. package/dist/vite.d.cts +2 -2
  36. package/dist/vite.d.mts +1 -1
  37. package/dist/vite.mjs +3 -3
  38. package/dist/webpack.cjs +3 -3
  39. package/dist/webpack.d.cts +2 -2
  40. package/dist/webpack.d.mts +1 -1
  41. package/dist/webpack.mjs +3 -3
  42. package/package.json +9 -9
  43. package/dist/shared/unplugin.C2lHQFii.cjs +0 -114
  44. package/dist/shared/unplugin.CBMJufQ8.mjs +0 -108
  45. package/dist/shared/unplugin.CDqY7kmk.mjs +0 -224
  46. package/dist/shared/unplugin.DbZ7tCfN.cjs +0 -248
@@ -13,9 +13,9 @@ const svelteAdapter = require('@csszyx/svelte-adapter');
13
13
  const types = require('@csszyx/types');
14
14
  const vueAdapter = require('@csszyx/vue-adapter');
15
15
  const unplugin$1 = require('unplugin');
16
- const transformCache = require('./unplugin.DbZ7tCfN.cjs');
16
+ const transformCache = require('./unplugin.BKGCkMgM.cjs');
17
17
  const cssMangler = require('../css-mangler.cjs');
18
- const nextRuntimeInjection = require('./unplugin.C2lHQFii.cjs');
18
+ const themeGroupsFile = require('./unplugin.CkNQjA4G.cjs');
19
19
  const htmlEscape = require('./unplugin.BkRah5Ot.cjs');
20
20
  const node_zlib = require('node:zlib');
21
21
  const postcss = require('postcss');
@@ -312,7 +312,7 @@ function validateCandidates(candidates, definitions, reserved, aliasPrefix) {
312
312
  code: "registered-property",
313
313
  severity: "error",
314
314
  name,
315
- message: `Registered custom property ${name} is not aliasable in Phase H v1.`,
315
+ message: `Registered custom property ${name} cannot be aliased: @property gives it a type and inheritance behaviour that an alias would not carry.`,
316
316
  location: registeredDefinition
317
317
  });
318
318
  }
@@ -1132,237 +1132,6 @@ function maskBlockComment(code, start) {
1132
1132
  return { end, value };
1133
1133
  }
1134
1134
 
1135
- const EMPTY_THEME = {
1136
- colors: [],
1137
- spacings: [],
1138
- fonts: [],
1139
- textSizes: [],
1140
- fontWeights: [],
1141
- radii: [],
1142
- shadows: [],
1143
- breakpoints: []
1144
- };
1145
- function findMatchingBrace(source, openBrace) {
1146
- let depth = 0;
1147
- for (let index = openBrace; index < source.length; index++) {
1148
- if (source[index] === "{") {
1149
- depth++;
1150
- } else if (source[index] === "}") {
1151
- depth--;
1152
- if (depth === 0) {
1153
- return index;
1154
- }
1155
- }
1156
- }
1157
- return -1;
1158
- }
1159
- function stripLayerWrappers(css) {
1160
- let result = "";
1161
- let i = 0;
1162
- while (i < css.length) {
1163
- const layerIdx = css.indexOf("@layer", i);
1164
- if (layerIdx === -1) {
1165
- result += css.slice(i);
1166
- break;
1167
- }
1168
- result += css.slice(i, layerIdx);
1169
- const openBrace = css.indexOf("{", layerIdx);
1170
- if (openBrace === -1) {
1171
- result += css.slice(layerIdx);
1172
- break;
1173
- }
1174
- const closeBrace = findMatchingBrace(css, openBrace);
1175
- if (closeBrace === -1) {
1176
- result += css.slice(openBrace);
1177
- break;
1178
- }
1179
- result += css.slice(openBrace + 1, closeBrace);
1180
- i = closeBrace + 1;
1181
- }
1182
- return result;
1183
- }
1184
- function themePreludeStart(css, at) {
1185
- const cursor = at + "@theme".length;
1186
- const next = css[cursor];
1187
- const validBoundary = next === "{" || next === " " || next === " " || next === "\n" || next === "\r";
1188
- return validBoundary ? cursor : null;
1189
- }
1190
- function readThemeBlock(css, start) {
1191
- for (let cursor = start; cursor < css.length; cursor++) {
1192
- const character = css[cursor];
1193
- if (character === "{") {
1194
- const close = findMatchingBrace(css, cursor);
1195
- return {
1196
- body: close === -1 ? null : css.slice(cursor + 1, close),
1197
- end: close === -1 ? cursor : close
1198
- };
1199
- }
1200
- if (character === ";" || character === "}" || character === "@") {
1201
- return { body: null, end: cursor };
1202
- }
1203
- }
1204
- return { body: null, end: css.length };
1205
- }
1206
- function extractThemeBlocks(css) {
1207
- const blocks = [];
1208
- let searchFrom = 0;
1209
- for (; ; ) {
1210
- const at = css.indexOf("@theme", searchFrom);
1211
- if (at === -1) {
1212
- break;
1213
- }
1214
- const preludeStart = themePreludeStart(css, at);
1215
- if (preludeStart === null) {
1216
- searchFrom = at + "@theme".length;
1217
- continue;
1218
- }
1219
- const match = readThemeBlock(css, preludeStart);
1220
- if (match.body !== null) blocks.push(match.body);
1221
- searchFrom = Math.max(match.end, at + "@theme".length);
1222
- }
1223
- return blocks;
1224
- }
1225
- function categorizeProperty(prop) {
1226
- const categoryMap = [
1227
- ["color-", "colors"],
1228
- ["spacing-", "spacings"],
1229
- // `font-weight-` MUST precede `font-`: startsWith would otherwise route
1230
- // `font-weight-chunky` into font FAMILIES as token "weight-chunky".
1231
- ["font-weight-", "fontWeights"],
1232
- ["font-", "fonts"],
1233
- // `--text-*` defines font-size utilities (text-huge) in Tailwind v4.
1234
- ["text-", "textSizes"],
1235
- ["radius-", "radii"],
1236
- ["shadow-", "shadows"],
1237
- ["breakpoint-", "breakpoints"]
1238
- ];
1239
- for (const [prefix, category] of categoryMap) {
1240
- if (prop.startsWith(prefix)) {
1241
- let token = prop.slice(prefix.length);
1242
- if (category !== "breakpoints") {
1243
- token = token.replace(/-\d+$/, "");
1244
- }
1245
- if (token) {
1246
- return { category, token };
1247
- }
1248
- }
1249
- }
1250
- return null;
1251
- }
1252
- function parseThemeBlocks(cssContent) {
1253
- const result = {
1254
- colors: /* @__PURE__ */ new Set(),
1255
- spacings: /* @__PURE__ */ new Set(),
1256
- fonts: /* @__PURE__ */ new Set(),
1257
- textSizes: /* @__PURE__ */ new Set(),
1258
- fontWeights: /* @__PURE__ */ new Set(),
1259
- radii: /* @__PURE__ */ new Set(),
1260
- shadows: /* @__PURE__ */ new Set(),
1261
- breakpoints: /* @__PURE__ */ new Set()
1262
- };
1263
- const stripped = stripLayerWrappers(cssContent);
1264
- const blocks = extractThemeBlocks(stripped);
1265
- for (const block of blocks) {
1266
- for (const name of scanCustomPropertyNames(block)) {
1267
- const categorized = categorizeProperty(name);
1268
- if (categorized) {
1269
- result[categorized.category].add(categorized.token);
1270
- }
1271
- }
1272
- }
1273
- return {
1274
- colors: htmlEscape.sortStrings(result.colors),
1275
- spacings: htmlEscape.sortStrings(result.spacings),
1276
- fonts: htmlEscape.sortStrings(result.fonts),
1277
- textSizes: htmlEscape.sortStrings(result.textSizes),
1278
- fontWeights: htmlEscape.sortStrings(result.fontWeights),
1279
- radii: htmlEscape.sortStrings(result.radii),
1280
- shadows: htmlEscape.sortStrings(result.shadows),
1281
- breakpoints: htmlEscape.sortStrings(result.breakpoints)
1282
- };
1283
- }
1284
- function mergeThemes(themes) {
1285
- if (themes.length === 0) {
1286
- return { ...EMPTY_THEME };
1287
- }
1288
- const merged = {
1289
- colors: /* @__PURE__ */ new Set(),
1290
- spacings: /* @__PURE__ */ new Set(),
1291
- fonts: /* @__PURE__ */ new Set(),
1292
- textSizes: /* @__PURE__ */ new Set(),
1293
- fontWeights: /* @__PURE__ */ new Set(),
1294
- radii: /* @__PURE__ */ new Set(),
1295
- shadows: /* @__PURE__ */ new Set(),
1296
- breakpoints: /* @__PURE__ */ new Set()
1297
- };
1298
- for (const theme of themes) {
1299
- for (const cat of Object.keys(merged)) {
1300
- for (const token of theme[cat]) {
1301
- merged[cat].add(token);
1302
- }
1303
- }
1304
- }
1305
- return {
1306
- colors: htmlEscape.sortStrings(merged.colors),
1307
- spacings: htmlEscape.sortStrings(merged.spacings),
1308
- fonts: htmlEscape.sortStrings(merged.fonts),
1309
- textSizes: htmlEscape.sortStrings(merged.textSizes),
1310
- fontWeights: htmlEscape.sortStrings(merged.fontWeights),
1311
- radii: htmlEscape.sortStrings(merged.radii),
1312
- shadows: htmlEscape.sortStrings(merged.shadows),
1313
- breakpoints: htmlEscape.sortStrings(merged.breakpoints)
1314
- };
1315
- }
1316
- function hasTokens(theme) {
1317
- return Object.values(theme).some((arr) => arr.length > 0);
1318
- }
1319
- function readCustomPropertyName(block, dashes) {
1320
- let end = dashes + 2;
1321
- if (end >= block.length || !/[a-z]/.test(block[end])) {
1322
- return null;
1323
- }
1324
- end++;
1325
- while (end < block.length && /[a-z0-9-]/.test(block[end])) {
1326
- end++;
1327
- }
1328
- return { name: block.slice(dashes + 2, end), end };
1329
- }
1330
- function findCustomPropertyDeclarationEnd(block, nameEnd) {
1331
- let cursor = nameEnd;
1332
- while (cursor < block.length && /\s/.test(block[cursor])) {
1333
- cursor++;
1334
- }
1335
- if (block[cursor] === ":") {
1336
- const valueStart = cursor + 1;
1337
- const semicolon = block.indexOf(";", valueStart);
1338
- return semicolon > valueStart ? semicolon + 1 : -1;
1339
- }
1340
- return block[nameEnd] === ";" ? nameEnd + 1 : -1;
1341
- }
1342
- function scanCustomPropertyNames(block) {
1343
- const names = [];
1344
- let i = 0;
1345
- while (i < block.length) {
1346
- const dashes = block.indexOf("--", i);
1347
- if (dashes === -1) {
1348
- break;
1349
- }
1350
- const property = readCustomPropertyName(block, dashes);
1351
- if (!property) {
1352
- i = dashes + 1;
1353
- continue;
1354
- }
1355
- const matchEnd = findCustomPropertyDeclarationEnd(block, property.end);
1356
- if (matchEnd === -1) {
1357
- i = dashes + 1;
1358
- continue;
1359
- }
1360
- names.push(property.name);
1361
- i = matchEnd;
1362
- }
1363
- return names;
1364
- }
1365
-
1366
1135
  const REGEX_PREFIXES = new Set("([{:,;=!?&|+-*%^~<>/");
1367
1136
  const REGEX_PREFIX_KEYWORDS = /* @__PURE__ */ new Set([
1368
1137
  "await",
@@ -1732,6 +1501,78 @@ function collectAuthoredClassNames(source) {
1732
1501
  return classes;
1733
1502
  }
1734
1503
 
1504
+ const KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
1505
+ "include",
1506
+ "exclude",
1507
+ "compileSources",
1508
+ "contentScopeCheck",
1509
+ "quiet",
1510
+ "mode",
1511
+ "development",
1512
+ "production",
1513
+ "build",
1514
+ "hydration"
1515
+ ]);
1516
+ const RENAMED_KEYS = {
1517
+ // Replaced by the path-based form: package NAMES could not express a
1518
+ // sibling directory outside the project root, and resolving them meant
1519
+ // guessing at workspace layout.
1520
+ compilePackages: "compileSources"
1521
+ };
1522
+ function nearestKnownConfigKey(key) {
1523
+ const lower = key.toLowerCase();
1524
+ let best = null;
1525
+ let bestDistance = Number.POSITIVE_INFINITY;
1526
+ for (const candidate of KNOWN_TOP_LEVEL_KEYS) {
1527
+ const distance = editDistance(lower, candidate.toLowerCase());
1528
+ if (distance < bestDistance) {
1529
+ bestDistance = distance;
1530
+ best = candidate;
1531
+ }
1532
+ }
1533
+ return best !== null && bestDistance <= Math.max(1, Math.floor(key.length / 4)) ? best : null;
1534
+ }
1535
+ function editDistance(a, b) {
1536
+ let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
1537
+ for (let i = 1; i <= a.length; i += 1) {
1538
+ const current = [i];
1539
+ for (let j = 1; j <= b.length; j += 1) {
1540
+ const substitution = previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1);
1541
+ current.push(Math.min(substitution, previous[j] + 1, current[j - 1] + 1));
1542
+ }
1543
+ previous = current;
1544
+ }
1545
+ return previous[b.length];
1546
+ }
1547
+ function findUnknownConfigKeys(options) {
1548
+ if (options === null || typeof options !== "object" || Array.isArray(options)) {
1549
+ return [];
1550
+ }
1551
+ const unknown = [];
1552
+ for (const key of Object.keys(options)) {
1553
+ if (KNOWN_TOP_LEVEL_KEYS.has(key)) continue;
1554
+ const renamedTo = RENAMED_KEYS[key];
1555
+ if (renamedTo !== void 0) {
1556
+ unknown.push({ key, renamedTo });
1557
+ continue;
1558
+ }
1559
+ const suggestion = nearestKnownConfigKey(key);
1560
+ unknown.push(suggestion === null ? { key } : { key, suggestion });
1561
+ }
1562
+ return unknown;
1563
+ }
1564
+ function unknownConfigKeysMessage(unknown) {
1565
+ const lines = unknown.map((entry) => {
1566
+ if (entry.renamedTo !== void 0) {
1567
+ return ` - \`${entry.key}\` was replaced by \`${entry.renamedTo}\``;
1568
+ }
1569
+ return entry.suggestion === void 0 ? ` - \`${entry.key}\`` : ` - \`${entry.key}\` \u2014 did you mean \`${entry.suggestion}\`?`;
1570
+ });
1571
+ return `[csszyx] ${unknown.length} plugin option(s) are not recognized and have no effect:
1572
+ ${lines.join("\n")}
1573
+ An unread option is silent, so whatever you configured it for is not happening.`;
1574
+ }
1575
+
1735
1576
  const GLOB_MAGIC_RE = /[*?[\]{}]/;
1736
1577
  const DEFAULT_IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", ".turbo", "dist", "build"]);
1737
1578
  function normalizeFileId(id) {
@@ -2002,11 +1843,13 @@ function escapeForDoubleQuotedString(value) {
2002
1843
  }
2003
1844
 
2004
1845
  function createMangleSizeAccount() {
2005
- return { cssGzBefore: 0, cssGzAfter: 0, channels: /* @__PURE__ */ new Set() };
1846
+ return { cssGzBefore: 0, cssGzAfter: 0, codeGzBefore: 0, codeGzAfter: 0, channels: /* @__PURE__ */ new Set() };
2006
1847
  }
2007
1848
  function resetMangleSizeAccount(account) {
2008
1849
  account.cssGzBefore = 0;
2009
1850
  account.cssGzAfter = 0;
1851
+ account.codeGzBefore = 0;
1852
+ account.codeGzAfter = 0;
2010
1853
  account.channels.clear();
2011
1854
  }
2012
1855
  function gzipBytes(text) {
@@ -2023,30 +1866,53 @@ function recordCssPair(account, before, after) {
2023
1866
  account.cssGzBefore += gzipBytes(before);
2024
1867
  account.cssGzAfter += gzipBytes(after);
2025
1868
  }
1869
+ function recordCodePair(account, before, after) {
1870
+ if (before === after) {
1871
+ const bytes = gzipBytes(before);
1872
+ account.codeGzBefore += bytes;
1873
+ account.codeGzAfter += bytes;
1874
+ return;
1875
+ }
1876
+ account.codeGzBefore += gzipBytes(before);
1877
+ account.codeGzAfter += gzipBytes(after);
1878
+ }
2026
1879
  function computeMangleSizeVerdict(account, mapPayload) {
2027
1880
  const channels = htmlEscape.sortStrings(account.channels);
2028
1881
  const mapCost = gzipBytes(mapPayload) * channels.length;
2029
1882
  const cssSaving = account.cssGzBefore - account.cssGzAfter;
2030
- return { mapCost, cssSaving, net: mapCost - cssSaving, channels };
1883
+ const codeSaving = account.codeGzBefore - account.codeGzAfter;
1884
+ return { mapCost, cssSaving, codeSaving, net: mapCost - cssSaving - codeSaving, channels };
2031
1885
  }
2032
1886
  function mangleSizeMessage(verdict) {
2033
1887
  if (verdict.channels.length === 0) return null;
2034
1888
  if (verdict.net <= 0) return null;
2035
1889
  const cssPart = verdict.cssSaving >= 0 ? `the mangled CSS saves ${verdict.cssSaving} B` : `the mangled CSS COSTS ${-verdict.cssSaving} B (short tokens compress worse than the names they replaced)`;
1890
+ const codePart = verdict.codeSaving >= 0 ? `the shortened classes in code save ${verdict.codeSaving} B` : `the shortened classes in code COST ${-verdict.codeSaving} B`;
2036
1891
  const channelPart = verdict.channels.length > 1 ? `${verdict.channels.join(" + ")} (${verdict.channels.length} copies)` : verdict.channels[0];
2037
- return `[csszyx] production.mangle is making this build BIGGER: +${verdict.net} B gzipped. The runtime mangle map costs ${verdict.mapCost} B via ${channelPart}, while ${cssPart}. Mangling is a name-obfuscation feature; over a compressed response it does not reduce payload, because utility class names compress far better than the map they need. If you enabled it for size, set \`production.mangle: false\`. If you enabled it to hide class names, this is the expected price and you can ignore this. Narrowing \`production.mangleMapDelivery\` removes a map copy when only one channel is needed. (Measured on CSS and the map; class shortening inside JS chunks is not counted, so the real net is slightly better than this figure.)`;
1892
+ return `[csszyx] production.mangle is making this build BIGGER: +${verdict.net} B gzipped. The runtime mangle map costs ${verdict.mapCost} B via ${channelPart}, while ${cssPart} and ${codePart}. Mangling is a name-obfuscation feature; over a compressed response it does not reduce payload, because utility class names compress far better than the map they need. If you enabled it for size, set \`production.mangle: false\`. If you enabled it to hide class names, this is the expected price and you can ignore this. Narrowing \`production.mangleMapDelivery\` removes a map copy when only one channel is needed.`;
2038
1893
  }
2039
1894
 
2040
1895
  function isParserMode(value) {
2041
- return value === "rust" || value === "oxc" || value === "babel";
1896
+ return value === "rust" || value === "wasm";
2042
1897
  }
2043
1898
  function resolveParserMode(input) {
2044
1899
  const { configParser, envParser, defaultParser, isRustAvailable } = input;
2045
1900
  const envValid = isParserMode(envParser);
2046
- const explicit = envValid || configParser != null;
2047
- const parser = envValid ? envParser : configParser ?? defaultParser;
1901
+ const configValid = isParserMode(configParser);
1902
+ const explicit = envValid || configValid;
1903
+ let parser;
1904
+ if (envValid) {
1905
+ parser = envParser;
1906
+ } else if (configValid) {
1907
+ parser = configParser;
1908
+ } else {
1909
+ parser = defaultParser;
1910
+ }
2048
1911
  if (parser === "rust" && !explicit && !isRustAvailable()) {
2049
- return { parser: "oxc", degraded: true, explicit: false };
1912
+ if (input.isWasmAvailable()) {
1913
+ return { parser: "wasm", degraded: true, explicit: false };
1914
+ }
1915
+ return { parser: "rust", degraded: false, explicit: false };
2050
1916
  }
2051
1917
  return { parser, degraded: false, explicit };
2052
1918
  }
@@ -2081,41 +1947,6 @@ function isSameFileVersion(before, after) {
2081
1947
  return before.dev === after.dev && before.ino === after.ino && before.size === after.size && before.mtimeNs === after.mtimeNs && before.ctimeNs === after.ctimeNs;
2082
1948
  }
2083
1949
 
2084
- function recordSzvRegistryFile(registry, filePath, content) {
2085
- const key = transformCache.normalizePathSeparators(filePath);
2086
- const qualifies = content.includes("szv(") && content.includes("export");
2087
- const entries = qualifies ? compiler.extractSzvRegistryEntries(content, filePath) : [];
2088
- if (entries.length === 0) {
2089
- registry.delete(key);
2090
- return;
2091
- }
2092
- const byName = {};
2093
- for (const entry of entries) {
2094
- byName[entry.exportName] = entry.config;
2095
- }
2096
- registry.set(key, byName);
2097
- }
2098
- const SPECIFIER_PROBES = ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx"];
2099
- function resolveCrossModuleStaticsFor(registry, filename, source) {
2100
- if (registry.size === 0 || !source.includes("from")) return void 0;
2101
- const directory = path__namespace.dirname(filename);
2102
- let resolved;
2103
- for (const match of source.matchAll(/from\s*['"](\.[^'"]*)['"]/g)) {
2104
- const specifier = match[1];
2105
- if (resolved?.[specifier] !== void 0) continue;
2106
- const base = transformCache.normalizePathSeparators(path__namespace.resolve(directory, specifier));
2107
- for (const probe of SPECIFIER_PROBES) {
2108
- const entries = registry.get(`${base}${probe}`);
2109
- if (entries !== void 0) {
2110
- resolved ??= {};
2111
- resolved[specifier] = entries;
2112
- break;
2113
- }
2114
- }
2115
- }
2116
- return resolved;
2117
- }
2118
-
2119
1950
  function generateThemeDts(opts) {
2120
1951
  const { theme, sourceFiles } = opts;
2121
1952
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -2187,127 +2018,6 @@ function writeThemeDts(opts) {
2187
2018
  fs.writeFileSync(opts.outputPath, content, "utf-8");
2188
2019
  }
2189
2020
 
2190
- const VIRTUAL_MODULE_ID = "virtual:csszyx/mangle-map";
2191
- const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
2192
- const THEME_GROUPS_VIRTUAL_ID = "virtual:csszyx/theme-groups";
2193
- const RESOLVED_THEME_GROUPS_VIRTUAL_ID = `\0${THEME_GROUPS_VIRTUAL_ID}`;
2194
- const VIRTUAL_CHECKSUM_ID = "virtual:csszyx/checksum";
2195
- const RESOLVED_VIRTUAL_CHECKSUM_ID = `\0${VIRTUAL_CHECKSUM_ID}`;
2196
- function createMangleMapModule(mangleMap, checksum, varMangleMap = {}, cssVarMetrics = null) {
2197
- return `/**
2198
- * Auto-generated mangle map for csszyx.
2199
- * This module is generated at build time and contains the mapping
2200
- * from original class names and CSS variable names to mangled names.
2201
- *
2202
- * @generated
2203
- */
2204
-
2205
- export const mangleMap = ${JSON.stringify(mangleMap, null, 2)};
2206
-
2207
- export const varMangleMap = ${JSON.stringify(varMangleMap, null, 2)};
2208
-
2209
- export const cssVarMetrics = ${JSON.stringify(cssVarMetrics, null, 2)};
2210
-
2211
- export const checksum = ${JSON.stringify(checksum)};
2212
-
2213
- export default {
2214
- mangleMap,
2215
- varMangleMap,
2216
- cssVarMetrics,
2217
- checksum,
2218
- };
2219
- `;
2220
- }
2221
- function createChecksumModule(checksum) {
2222
- return `/**
2223
- * Auto-generated checksum for csszyx mangle map.
2224
- *
2225
- * @generated
2226
- */
2227
-
2228
- export const checksum = ${JSON.stringify(checksum)};
2229
-
2230
- export default checksum;
2231
- `;
2232
- }
2233
- function isVirtualModule(id) {
2234
- return id === VIRTUAL_MODULE_ID || id === VIRTUAL_CHECKSUM_ID || id === THEME_GROUPS_VIRTUAL_ID || id === MANGLE_RUNTIME_VIRTUAL_ID;
2235
- }
2236
- function resolveVirtualModule(id) {
2237
- if (id === VIRTUAL_MODULE_ID) {
2238
- return RESOLVED_VIRTUAL_MODULE_ID;
2239
- }
2240
- if (id === VIRTUAL_CHECKSUM_ID) {
2241
- return RESOLVED_VIRTUAL_CHECKSUM_ID;
2242
- }
2243
- if (id === THEME_GROUPS_VIRTUAL_ID) {
2244
- return RESOLVED_THEME_GROUPS_VIRTUAL_ID;
2245
- }
2246
- if (id === MANGLE_RUNTIME_VIRTUAL_ID) {
2247
- return RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID;
2248
- }
2249
- return void 0;
2250
- }
2251
- const MANGLE_RUNTIME_VIRTUAL_ID = "virtual:csszyx/mangle-runtime";
2252
- const RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID = `\0${MANGLE_RUNTIME_VIRTUAL_ID}`;
2253
- const MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
2254
- const VAR_MANGLE_MAP_PLACEHOLDER = "___CSSZYX_VAR_MANGLE_MAP___";
2255
- const CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
2256
- function createMangleRuntimeModule(globalVarAliasPrefix) {
2257
- return `/**
2258
- * Auto-generated by csszyx: installs the runtime mangle map from the bundle.
2259
- *
2260
- * @generated
2261
- */
2262
-
2263
- const m = ${MANGLE_MAP_PLACEHOLDER};
2264
- const vm = ${VAR_MANGLE_MAP_PLACEHOLDER};
2265
- const gp = ${JSON.stringify(globalVarAliasPrefix)};
2266
- const checksum = "${CHECKSUM_PLACEHOLDER}";
2267
-
2268
- if (typeof window !== 'undefined' && !window.__csszyx) {
2269
- const r = {};
2270
- const vr = {};
2271
- for (const k in m) r[m[k]] = k;
2272
- for (const vk in vm) {
2273
- const vv = vm[vk];
2274
- const vs = Array.isArray(vv) ? vv : [vv];
2275
- for (const v of vs) (vr[v] || (vr[v] = [])).push(vk);
2276
- }
2277
- window.__csszyx = {
2278
- mangleMap: m,
2279
- varMangleMap: vm,
2280
- checksum,
2281
- decode: (c) => r[c],
2282
- encode: (c) => m[c],
2283
- decodeVar: (v) => vr[v] || [],
2284
- encodeVar: (v) => vm[v],
2285
- decodeGlobalVar: (v) => {
2286
- const a = vr[v] || [];
2287
- return v.indexOf(gp) === 0 ? a[0] : undefined;
2288
- },
2289
- decodeAll: (el) => (el.className || '').split(' ').map((c) => r[c] || c),
2290
- };
2291
- }
2292
-
2293
- export {};
2294
- `;
2295
- }
2296
- function createThemeGroupsModule(tokens) {
2297
- const payload = JSON.stringify({
2298
- colors: tokens.colors,
2299
- textSizes: tokens.textSizes,
2300
- fontFamilies: tokens.fontFamilies,
2301
- fontWeights: tokens.fontWeights
2302
- });
2303
- return [
2304
- "// Auto-generated by csszyx from the @theme blocks in scanned CSS.",
2305
- "import { registerSzcnGroups } from '@csszyx/runtime';",
2306
- `registerSzcnGroups(${payload});`,
2307
- "export {};"
2308
- ].join("\n");
2309
- }
2310
-
2311
2021
  function registerWebpackAssetProcessor(compiler, processAssets) {
2312
2022
  compiler.hooks.compilation.tap("csszyx:post", (compilation) => {
2313
2023
  const stage = compiler.webpack?.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE || compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE;
@@ -2349,10 +2059,9 @@ let _hasWarnedTsConfig = false;
2349
2059
  let _hasWarnedTransformCacheVersion = false;
2350
2060
  let _hasWarnedNativeFallback = false;
2351
2061
  const _loggedActiveParsers = /* @__PURE__ */ new Set();
2352
- const _babelFallbackFiles = /* @__PURE__ */ new Set();
2353
- const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.BK3XVHe8.cjs', document.baseURI).href)));
2062
+ const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.ZMa9YE1H.cjs', document.baseURI).href)));
2354
2063
  const PLUGIN_VERSION = findPackageVersionFromFile(
2355
- node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.BK3XVHe8.cjs', document.baseURI).href))),
2064
+ node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.ZMa9YE1H.cjs', document.baseURI).href))),
2356
2065
  UNKNOWN_PACKAGE_VERSION
2357
2066
  );
2358
2067
  const COMPILER_VERSION = findPackageVersionFromModule("@csszyx/compiler", UNKNOWN_PACKAGE_VERSION);
@@ -2466,9 +2175,20 @@ function mangleHybridHazardMessage(hazards) {
2466
2175
  }
2467
2176
  return parts.join("");
2468
2177
  }
2178
+ const TAILWIND_IMPORT_SPECIFIER = /@import\s+["']tailwindcss(?:\/[^"']*)?["']/g;
2179
+ const SOURCE_MODIFIER = /\bsource\(/;
2180
+ function tailwindImportScopesContent(css) {
2181
+ for (const match of css.matchAll(TAILWIND_IMPORT_SPECIFIER)) {
2182
+ const modifiersStart = match.index + match[0].length;
2183
+ const terminator = css.indexOf(";", modifiersStart);
2184
+ const modifiers = terminator === -1 ? css.slice(modifiersStart) : css.slice(modifiersStart, terminator);
2185
+ if (SOURCE_MODIFIER.test(modifiers)) return true;
2186
+ }
2187
+ return false;
2188
+ }
2469
2189
  function cssHasContentScope(code) {
2470
2190
  const s = stripCssBlockComments(code);
2471
- return /@import\s+["']tailwindcss(?:\/[^"']*)?["']\s+source\(/.test(s) || /@source\s+not\b/.test(s);
2191
+ return tailwindImportScopesContent(s) || /@source\s+not\b/.test(s);
2472
2192
  }
2473
2193
  function isMonorepoPackage(root) {
2474
2194
  let dir = path__namespace.dirname(path__namespace.resolve(root));
@@ -2494,19 +2214,33 @@ function shouldWarnUnscopedMonorepo(sawTailwindEntry, tailwindEntryScoped, inMon
2494
2214
  return sawTailwindEntry && !tailwindEntryScoped && inMonorepo;
2495
2215
  }
2496
2216
  function unscopedMonorepoMessage() {
2497
- return '[csszyx] Tailwind content detection is UNSCOPED in a monorepo. Tailwind v4 climbs to the workspace root and scans sibling packages + docs (.md/.mdx/.txt are not ignored), which can generate phantom or broken url() classes and fail the build. Scope it in your Tailwind CSS entry:\n @import "tailwindcss" source(none);\n @source "."; /* this package, relative to the CSS file */\ncsszyx auto-injects @source for its generated classes, so only your own templates need listing. Guide: https://csszyx.com/docs/monorepo-content-scope/\nSilence (if a broad scan is intentional): csszyx({ contentScopeCheck: false }).';
2217
+ return '[csszyx] Tailwind content detection is UNSCOPED in a monorepo. Tailwind v4 scans every file under its detection base \u2014 .md/.mdx/.txt included \u2014 so a doc or fixture holding class-shaped strings becomes CSS, which can generate phantom or broken url() classes and fail the build. That base is as wide as the build makes it: a Vite build roots it at the Vite root, other setups at the workspace root. Scope it in your Tailwind CSS entry:\n @import "tailwindcss" source(none);\n @source ".";\nThat @source is your package, relative to the CSS file; csszyx auto-injects one for the classes it generates, so only your own templates need listing. Guide: https://csszyx.com/docs/monorepo-content-scope/\nSilence (if a broad scan is intentional): csszyx({ contentScopeCheck: false }).';
2218
+ }
2219
+ function isAdvisoryDiagnostic(message) {
2220
+ return !(message.includes("unresolvable sz spread") || message.includes("AST budget exceeded") || compiler.szFallbackConsequenceOf(message) === "missing-css");
2221
+ }
2222
+ function suppressedAdvisoryMessage(count) {
2223
+ if (count <= 0) return null;
2224
+ const held = count === 1 ? "1 advisory sz fallback" : `${count} advisory sz fallbacks`;
2225
+ return `[csszyx] ${held} not listed above. At an sz prop a fallback is advisory \u2014 the runtime path works and the classes are collected \u2014 so a production build keeps the list short. A development build prints each one with its file and position.`;
2226
+ }
2227
+ function resolveQuietMode(quiet) {
2228
+ if (quiet === true || quiet === "all") return "all";
2229
+ if (quiet === "nudges") return "nudges";
2230
+ return "off";
2498
2231
  }
2499
2232
  function shouldEmitWarning(quiet, devOnly, isProduction) {
2500
- if (quiet) {
2233
+ const mode = resolveQuietMode(quiet);
2234
+ if (mode === "all") {
2501
2235
  return false;
2502
2236
  }
2503
- if (devOnly && isProduction) {
2237
+ if (devOnly && (isProduction || mode === "nudges")) {
2504
2238
  return false;
2505
2239
  }
2506
2240
  return true;
2507
2241
  }
2508
2242
  function shouldEmitMissingCssFallback(quiet, message) {
2509
- return !quiet && compiler.szFallbackConsequenceOf(message) === "missing-css";
2243
+ return resolveQuietMode(quiet) !== "all" && compiler.szFallbackConsequenceOf(message) === "missing-css";
2510
2244
  }
2511
2245
  function emitMissingCssFallback(quiet, message, id, emit) {
2512
2246
  if (shouldEmitMissingCssFallback(quiet, message)) emit(`[csszyx] ${id}
@@ -2616,11 +2350,29 @@ function isPackagesSkippedSource(id, sourceDirs = []) {
2616
2350
  }
2617
2351
  return !isCompileSourceOptedIn(p, sourceDirs);
2618
2352
  }
2619
- function skippedSzFilesMessage(files) {
2353
+ function skippedSzFilesMessage(files, szvExportFiles = []) {
2620
2354
  const list = files.map((file) => ` - ${file}`).join("\n");
2621
- return `[csszyx] ${files.length} file(s) under packages/ contain \`sz\` but were skipped by ignore rules:
2355
+ const registryClause = szvExportFiles.length === 0 ? "" : `
2356
+ ${szvExportFiles.length} of them may export \`szv\` factories, so they stay out of the cross-module registry and every importer falls back to the runtime path.`;
2357
+ return `[csszyx] ${files.length} file(s) under packages/ use csszyx but were skipped by ignore rules:
2622
2358
  ${list}
2623
- Add the package directory to \`compileSources\` (or move the file out of packages/) \u2014 otherwise their \`sz\` produces no CSS.`;
2359
+ Add the package directory to \`compileSources\` (or move the file out of packages/) \u2014 otherwise their classes never reach the safelist.` + registryClause;
2360
+ }
2361
+ function lateMangleCensusMessage(lateOwned, lateAuthored) {
2362
+ const sections = [
2363
+ lateOwned.length > 0 ? `csszyx-owned classes: ${lateOwned.join(", ")}` : "",
2364
+ lateAuthored.length > 0 ? `author classes: ${lateAuthored.join(", ")}` : ""
2365
+ ].filter(Boolean);
2366
+ const found = sections.length > 0 ? sections.join("\n") : "the class census changed";
2367
+ return `[csszyx] production.mangle: classes appeared after the mangle map was frozen, so the emitted CSS was hashed against a different map:
2368
+ ${found}
2369
+ The prescan walks the project root and every \`compileSources\` directory. Move the file that owns these classes under one of them, or turn off \`production.mangle\` for this build.`;
2370
+ }
2371
+ function watchModeMangleMessage() {
2372
+ return "[csszyx] production.mangle is disabled for this watch build. Mangling needs the whole-project prescan that only runs once per process, and a watch rebuild cannot repeat it \u2014 the map would go stale against the files you edit. Run a one-shot build to get mangled output.";
2373
+ }
2374
+ function realContentHashDisabledMessage() {
2375
+ return "[csszyx] optimization.realContentHash is off while production.mangle is on. csszyx mangles assets after webpack computes their content hashes, and realContentHash is what recomputes those hashes from the final bytes. Without it, two builds that differ only by mangling emit the same filenames with different contents and caches keep serving the old file.";
2624
2376
  }
2625
2377
  function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
2626
2378
  const safelistPath = transformCache.normalizePathSeparators(path__namespace.join(rootDir, safelistFilename));
@@ -2697,6 +2449,20 @@ function collectConfiguredGlobalVarCssSources(rootDir, scanCss) {
2697
2449
  }
2698
2450
  });
2699
2451
  }
2452
+ const MANGLEABLE_CSS_ID_RE = /\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
2453
+ const NON_STYLESHEET_CSS_QUERY_RE = /[?&](?:worker|sharedworker|raw|url)(?:&|=|$)/;
2454
+ const COMMONJS_PROXY_RE = /\?commonjs-proxy/;
2455
+ function isMangleableCssId(id) {
2456
+ return MANGLEABLE_CSS_ID_RE.test(id) && !NON_STYLESHEET_CSS_QUERY_RE.test(id) && !COMMONJS_PROXY_RE.test(id);
2457
+ }
2458
+ function dedupeCssAssetsByName(assets) {
2459
+ const seen = /* @__PURE__ */ new Set();
2460
+ return assets.filter((asset) => {
2461
+ if (seen.has(asset.fileName)) return false;
2462
+ seen.add(asset.fileName);
2463
+ return true;
2464
+ });
2465
+ }
2700
2466
  function collectWebpackGlobalVarCssAssets(assets) {
2701
2467
  return Object.entries(assets).flatMap(([fileName, asset]) => {
2702
2468
  if (!/\.css(?:$|\?)/.test(fileName)) {
@@ -2944,12 +2710,12 @@ function runThemeScan(rootDir, scanCss) {
2944
2710
  }
2945
2711
  const themes = sourceFiles.map((f) => {
2946
2712
  try {
2947
- return parseThemeBlocks(readStableTextFileSnapshotSync(f).source);
2713
+ return themeGroupsFile.parseThemeBlocks(readStableTextFileSnapshotSync(f).source);
2948
2714
  } catch {
2949
2715
  return null;
2950
2716
  }
2951
2717
  }).filter((t) => t !== null);
2952
- const merged = mergeThemes(themes);
2718
+ const merged = themeGroupsFile.mergeThemes(themes);
2953
2719
  const outputPath = path__namespace.join(rootDir, ".csszyx", "theme.d.ts");
2954
2720
  writeThemeDts({ outputPath, theme: merged, sourceFiles });
2955
2721
  if (!_hasWarnedTsConfig) {
@@ -3017,7 +2783,7 @@ function matchesScriptExtension(id, extensions) {
3017
2783
  return extensions.some((ext) => id.endsWith(ext) || id.includes(`${ext}?`));
3018
2784
  }
3019
2785
  function insertRuntimeImport(code, importStmt) {
3020
- return nextRuntimeInjection.insertAfterUseDirective(code, importStmt);
2786
+ return themeGroupsFile.insertAfterUseDirective(code, importStmt);
3021
2787
  }
3022
2788
  function scanClassExpression(source, from) {
3023
2789
  let depth = 0;
@@ -3261,12 +3027,12 @@ ${errors.join("\n")}`
3261
3027
  if (config?.enabled === true) {
3262
3028
  if (!config.tokens || config.tokens.length === 0) {
3263
3029
  throw new Error(
3264
- "[csszyx] production.mangleGlobalVars.enabled requires explicit tokens in Phase H v1."
3030
+ "[csszyx] production.mangleGlobalVars.enabled requires explicit tokens. Aliasing a property csszyx was not told about would rename references it cannot see."
3265
3031
  );
3266
3032
  }
3267
3033
  if (config.autoPrefix !== void 0 && config.autoPrefix !== "") {
3268
3034
  throw new Error(
3269
- "[csszyx] production.mangleGlobalVars.autoPrefix requires CSS pre-scan support and is not enabled in Phase H v1."
3035
+ "[csszyx] production.mangleGlobalVars.autoPrefix is not available: choosing tokens by prefix needs a CSS pre-scan that does not exist yet. List the tokens instead."
3270
3036
  );
3271
3037
  }
3272
3038
  }
@@ -3274,9 +3040,18 @@ ${errors.join("\n")}`
3274
3040
  function createCsszyxPlugins(options = {}) {
3275
3041
  assertGlobalVarMangleConfig(options);
3276
3042
  let manglingEnabled = options.production?.mangle === true;
3277
- let crossModuleRegistryEnabled = process.env.NODE_ENV !== "development";
3043
+ const importedStaticSzEnabled = options.build?.importedStaticSz ?? types.DEFAULT_IMPORTED_STATIC_SZ;
3278
3044
  const szvCrossModuleRegistry = /* @__PURE__ */ new Map();
3045
+ const szObjectProvidersExamined = /* @__PURE__ */ new Set();
3046
+ let specifierAliases = [];
3279
3047
  const mangleReserved = new Set(options.production?.mangleExclude ?? []);
3048
+ let mangleMapFrozen = false;
3049
+ let frozenOwnedClasses = /* @__PURE__ */ new Set();
3050
+ let frozenAuthoredClasses = /* @__PURE__ */ new Set();
3051
+ let cssRewrittenInTransform = false;
3052
+ let projectCssFiles = [];
3053
+ const transformMangledSources = /* @__PURE__ */ new Set();
3054
+ const transformExternalClasses = /* @__PURE__ */ new Set();
3280
3055
  const mangleMapDelivery = options.production?.mangleMapDelivery ?? "both";
3281
3056
  if (!["both", "html", "bundle"].includes(mangleMapDelivery)) {
3282
3057
  throw new Error(
@@ -3307,7 +3082,11 @@ function createCsszyxPlugins(options = {}) {
3307
3082
  );
3308
3083
  }
3309
3084
  const compileSources = options.compileSources ?? [];
3310
- const quiet = options.quiet === true;
3085
+ const quiet = resolveQuietMode(options.quiet);
3086
+ const unknownConfigKeys = findUnknownConfigKeys(options);
3087
+ if (unknownConfigKeys.length > 0) {
3088
+ emitWarning(unknownConfigKeysMessage(unknownConfigKeys));
3089
+ }
3311
3090
  function emitWarning(message, opts = {}) {
3312
3091
  if (shouldEmitWarning(quiet, opts.devOnly ?? false, process.env.NODE_ENV === "production")) {
3313
3092
  console.warn(message);
@@ -3317,22 +3096,27 @@ function createCsszyxPlugins(options = {}) {
3317
3096
  configParser: options.build?.parser,
3318
3097
  envParser: process.env.CSSZYX_PARSER,
3319
3098
  defaultParser: types.DEFAULT_BUILD_CONFIG.parser ?? "rust",
3320
- isRustAvailable: compiler.isRustTransformAvailable
3099
+ isRustAvailable: compiler.isRustTransformAvailable,
3100
+ isWasmAvailable: compiler.isWasmTransformAvailable
3321
3101
  });
3322
3102
  function announceActiveParser() {
3323
3103
  if (parserDegraded && !_hasWarnedNativeFallback) {
3324
3104
  _hasWarnedNativeFallback = true;
3325
- console.warn(
3326
- "[csszyx] No prebuilt native binary (@csszyx/core-*) is available for this platform, so the default `rust` parser fell back to `oxc`. Output classes are identical (parity-tested); only parse speed differs. To use the native engine, install the matching @csszyx/core-<platform> package (or do not omit optional dependencies). Set `build.parser` explicitly to silence this."
3327
- );
3105
+ if (parserMode === "wasm") {
3106
+ console.warn(
3107
+ "[csszyx] No prebuilt native binary (@csszyx/core-*) is available for this platform, so the default `rust` parser fell back to its wasm build. Same engine, same output; only parse speed differs. To use the native engine, install the matching @csszyx/core-<platform> package (or do not omit optional dependencies). Set `build.parser` explicitly to silence this."
3108
+ );
3109
+ }
3328
3110
  }
3329
3111
  if (!_loggedActiveParsers.has(parserMode)) {
3330
3112
  _loggedActiveParsers.add(parserMode);
3331
3113
  let detail = parserMode;
3332
3114
  if (parserDegraded) {
3333
- detail = "oxc (degraded from default `rust`: no native binary for this platform)";
3115
+ detail = "wasm (degraded from default `rust`: same engine, wasm build)";
3334
3116
  } else if (parserMode === "rust") {
3335
3117
  detail = "rust (native engine)";
3118
+ } else if (parserMode === "wasm") {
3119
+ detail = "wasm (wasm build of the native engine)";
3336
3120
  }
3337
3121
  console.warn(`[csszyx] active parser: ${detail}`);
3338
3122
  }
@@ -3344,6 +3128,7 @@ function createCsszyxPlugins(options = {}) {
3344
3128
  const state = {
3345
3129
  classes: /* @__PURE__ */ new Set(),
3346
3130
  parsedTheme: null,
3131
+ scanCssTheme: null,
3347
3132
  autoThemeCssFiles: [],
3348
3133
  sawTailwindEntry: false,
3349
3134
  sawAnyCss: false,
@@ -3351,7 +3136,9 @@ function createCsszyxPlugins(options = {}) {
3351
3136
  tailwindEntryScoped: false,
3352
3137
  contentScopeWarningEmitted: false,
3353
3138
  spreadWarnings: /* @__PURE__ */ new Set(),
3139
+ suppressedAdvisories: 0,
3354
3140
  skippedSzFiles: /* @__PURE__ */ new Set(),
3141
+ skippedSzvExportFiles: /* @__PURE__ */ new Set(),
3355
3142
  skipWarningEmitted: false,
3356
3143
  classesCapped: false,
3357
3144
  ownedClasses: /* @__PURE__ */ new Set(),
@@ -3411,7 +3198,7 @@ function createCsszyxPlugins(options = {}) {
3411
3198
  const result = validateGlobalVarAliasInputs(
3412
3199
  createGlobalVarAliasValidationOptions({
3413
3200
  rootDir: state.rootDir,
3414
- cssAssets: [...configuredCssAssets, ...cssAssets],
3201
+ cssAssets: dedupeCssAssetsByName([...configuredCssAssets, ...cssAssets]),
3415
3202
  sourceFiles: buildGlobalVarSourceFiles(state),
3416
3203
  tokens: globalVarMangleConfig.tokens,
3417
3204
  autoPrefix: globalVarMangleConfig.autoPrefix,
@@ -3424,6 +3211,25 @@ function createCsszyxPlugins(options = {}) {
3424
3211
  assertGlobalVarPlanMatchesEarlyAliases(result, earlyGlobalVarAliasEntries);
3425
3212
  return result;
3426
3213
  }
3214
+ function revalidateFrozenGlobalVarPlan() {
3215
+ if (!cssRewrittenInTransform) return;
3216
+ validateGlobalVarBundleInputs(collectProjectGlobalVarCssSources());
3217
+ }
3218
+ function collectProjectGlobalVarCssSources() {
3219
+ const sources = [];
3220
+ for (const file of compiler.sortStrings(projectCssFiles)) {
3221
+ try {
3222
+ const snapshot = readStableTextFileSnapshotSync(file);
3223
+ sources.push({
3224
+ fileName: file,
3225
+ source: snapshot.source,
3226
+ mtimeMs: snapshot.mtimeMs
3227
+ });
3228
+ } catch {
3229
+ }
3230
+ }
3231
+ return sources;
3232
+ }
3427
3233
  function trackGlobalVarSourceFile(filename, code) {
3428
3234
  if (!globalVarSourceTrackingEnabled) {
3429
3235
  return;
@@ -3446,56 +3252,15 @@ function createCsszyxPlugins(options = {}) {
3446
3252
  }
3447
3253
  }
3448
3254
  function runAutoThemeScan(rootDir) {
3449
- if (options.build?.scanCss) {
3450
- return;
3451
- }
3452
3255
  refreshCompileSourceDirs();
3453
- const cssFiles = [];
3454
- const walk = (dir) => {
3455
- let entries;
3456
- try {
3457
- entries = fs__namespace.readdirSync(dir, { withFileTypes: true });
3458
- } catch {
3459
- return;
3460
- }
3461
- for (const entry of entries) {
3462
- if (entry.isDirectory()) {
3463
- if (!IGNORE_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
3464
- walk(path__namespace.join(dir, entry.name));
3465
- }
3466
- continue;
3467
- }
3468
- if (entry.name.endsWith(".css")) {
3469
- cssFiles.push(path__namespace.join(dir, entry.name));
3470
- }
3471
- }
3472
- };
3473
- walk(rootDir);
3474
- const normRoot = normalizeForMatch(rootDir);
3475
- for (const sourceDir of compileSourceDirs) {
3476
- if (sourceDir === normRoot || sourceDir.startsWith(`${normRoot}/`)) {
3477
- continue;
3478
- }
3479
- walk(sourceDir);
3480
- }
3481
- const themes = [];
3482
- const themeFiles = [];
3483
- for (const file of cssFiles) {
3484
- let content;
3485
- try {
3486
- content = fs__namespace.readFileSync(file, "utf-8");
3487
- } catch {
3488
- continue;
3489
- }
3490
- if (!content.includes("@theme")) {
3491
- continue;
3492
- }
3493
- themes.push(parseThemeBlocks(content));
3494
- themeFiles.push(file);
3495
- }
3496
- state.autoThemeCssFiles = themeFiles;
3497
- if (themes.length > 0) {
3498
- state.parsedTheme = mergeThemes(themes);
3256
+ const discovered = themeGroupsFile.discoverProjectTheme(rootDir, [...compileSourceDirs]);
3257
+ state.autoThemeCssFiles = discovered.files;
3258
+ projectCssFiles = discovered.scanned;
3259
+ const sources = [state.scanCssTheme, discovered.theme].filter(
3260
+ (theme) => theme !== null
3261
+ );
3262
+ if (sources.length > 0) {
3263
+ state.parsedTheme = themeGroupsFile.mergeThemes(sources);
3499
3264
  }
3500
3265
  }
3501
3266
  function isHardIgnored(id) {
@@ -3511,13 +3276,17 @@ function createCsszyxPlugins(options = {}) {
3511
3276
  function transformConfiguredSource(source, filename, astBudget) {
3512
3277
  const compilerOptions = createCompilerOptions(astBudget);
3513
3278
  const effectiveFilename = normalizeSourceFilename(filename);
3514
- const crossModuleStatics = resolveCrossModuleStaticsFor(
3279
+ const crossModuleStatics = transformCache.resolveCrossModuleStaticsFor(
3515
3280
  szvCrossModuleRegistry,
3516
3281
  filename,
3517
- source
3282
+ source,
3283
+ specifierAliases
3518
3284
  );
3519
- if (crossModuleStatics !== void 0) {
3520
- compilerOptions.crossModuleStatics = crossModuleStatics;
3285
+ if (crossModuleStatics.szvConfigs !== void 0) {
3286
+ compilerOptions.crossModuleStatics = crossModuleStatics.szvConfigs;
3287
+ }
3288
+ if (crossModuleStatics.szObjects !== void 0) {
3289
+ compilerOptions.crossModuleSzObjects = crossModuleStatics.szObjects;
3521
3290
  }
3522
3291
  const cacheRoot = transformCache.resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
3523
3292
  if (cacheEnabled) {
@@ -3568,43 +3337,16 @@ function createCsszyxPlugins(options = {}) {
3568
3337
  return handoff.inputSha256 === cacheKey.inputSha256 ? handoff.result : null;
3569
3338
  }
3570
3339
  function runConfiguredParser(source, effectiveFilename, compilerOptions) {
3571
- if (parserMode === "babel") {
3572
- return {
3573
- result: compiler.transformSourceCode(source, effectiveFilename, compilerOptions),
3574
- cacheable: true
3575
- };
3576
- }
3577
3340
  if (parserMode === "rust") {
3578
3341
  return {
3579
3342
  result: compiler.transformRust(source, effectiveFilename, compilerOptions),
3580
3343
  cacheable: true
3581
3344
  };
3582
3345
  }
3583
- try {
3584
- return {
3585
- result: compiler.transformOxc(source, effectiveFilename, compilerOptions),
3586
- cacheable: true
3587
- };
3588
- } catch (error) {
3589
- return {
3590
- result: runBabelFallback(source, effectiveFilename, compilerOptions, error),
3591
- cacheable: false
3592
- };
3593
- }
3594
- }
3595
- function runBabelFallback(source, effectiveFilename, compilerOptions, error) {
3596
- const result = compiler.transformSourceCode(source, effectiveFilename, compilerOptions);
3597
- const reason = transformCache.babelFallbackReason(error);
3598
- result.diagnostics.push(
3599
- `[csszyx] oxc parser fell back to Babel for ${effectiveFilename}: ${reason}`
3600
- );
3601
- if (!_babelFallbackFiles.has(effectiveFilename)) {
3602
- _babelFallbackFiles.add(effectiveFilename);
3603
- console.warn(
3604
- `[csszyx] oxc parser fell back to Babel for ${effectiveFilename}: ${reason} (${_babelFallbackFiles.size} file(s) so far). Output is still correct; this usually means the file uses a syntax the oxc lane does not yet handle.`
3605
- );
3606
- }
3607
- return result;
3346
+ return {
3347
+ result: compiler.transformWasm(source, effectiveFilename, compilerOptions),
3348
+ cacheable: true
3349
+ };
3608
3350
  }
3609
3351
  function createCompilerOptions(astBudget = astBudgetOverride) {
3610
3352
  return {
@@ -3634,6 +3376,7 @@ function createCsszyxPlugins(options = {}) {
3634
3376
  // module A's config change must miss B's cached transform, or the
3635
3377
  // cache serves a stale table.
3636
3378
  crossModuleStatics: compilerOptions.crossModuleStatics === void 0 ? void 0 : JSON.stringify(compilerOptions.crossModuleStatics),
3379
+ crossModuleSzObjects: compilerOptions.crossModuleSzObjects === void 0 ? void 0 : JSON.stringify(compilerOptions.crossModuleSzObjects),
3637
3380
  filename: effectiveFilename,
3638
3381
  source
3639
3382
  };
@@ -3642,19 +3385,35 @@ function createCsszyxPlugins(options = {}) {
3642
3385
  if (parserMode !== "rust" || files.length <= 1) {
3643
3386
  return transformPrescanSourcesIndividually(files);
3644
3387
  }
3388
+ const perFile = [];
3389
+ const batchable = [];
3390
+ for (const file of files) {
3391
+ (hasCrossModuleStatics(file) ? perFile : batchable).push(file);
3392
+ }
3393
+ const individual = transformPrescanSourcesIndividually(perFile);
3645
3394
  const compilerOptions = createCompilerOptions(prescanAstBudget);
3646
3395
  const cacheRoot = transformCache.resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
3647
3396
  const results = /* @__PURE__ */ new Map();
3648
3397
  if (cacheEnabled) evictTransformCacheOnce();
3649
3398
  compiler.ensureRustTransformAvailable();
3650
- const misses = collectRustPrescanMisses(files, compilerOptions, cacheRoot, results);
3651
- if (misses.length === 0) return orderPrescanResults(files, results);
3652
- try {
3653
- runRustPrescanBatch(misses, compilerOptions, cacheRoot, results);
3654
- } catch {
3655
- runRustPrescanFallback(misses, results);
3399
+ const misses = collectRustPrescanMisses(batchable, compilerOptions, cacheRoot, results);
3400
+ if (misses.length > 0) {
3401
+ try {
3402
+ runRustPrescanBatch(misses, compilerOptions, cacheRoot, results);
3403
+ } catch {
3404
+ runRustPrescanFallback(misses, results);
3405
+ }
3656
3406
  }
3657
- return orderPrescanResults(files, results);
3407
+ return [...individual, ...orderPrescanResults(batchable, results)];
3408
+ }
3409
+ function hasCrossModuleStatics(file) {
3410
+ const resolved = transformCache.resolveCrossModuleStaticsFor(
3411
+ szvCrossModuleRegistry,
3412
+ file.filePath,
3413
+ file.content,
3414
+ specifierAliases
3415
+ );
3416
+ return resolved.szvConfigs !== void 0 || resolved.szObjects !== void 0;
3658
3417
  }
3659
3418
  function collectRustPrescanMisses(files, compilerOptions, cacheRoot, results) {
3660
3419
  const misses = [];
@@ -3802,7 +3561,7 @@ function createCsszyxPlugins(options = {}) {
3802
3561
  }
3803
3562
  }
3804
3563
  function recordPackagesSkipIfSz(filePath) {
3805
- if (!isPackagesSkippedSource(filePath, compileSourceDirs)) {
3564
+ if (state.skippedSzFiles.has(filePath) || !isPackagesSkippedSource(filePath, compileSourceDirs)) {
3806
3565
  return;
3807
3566
  }
3808
3567
  let content;
@@ -3811,8 +3570,12 @@ function createCsszyxPlugins(options = {}) {
3811
3570
  } catch {
3812
3571
  return;
3813
3572
  }
3814
- if (content.includes("sz=") || content.includes("szs=") || content.includes("sz:")) {
3815
- state.skippedSzFiles.add(filePath);
3573
+ if (!fileMayContainSafelistableSz(content)) {
3574
+ return;
3575
+ }
3576
+ state.skippedSzFiles.add(filePath);
3577
+ if (transformCache.mayExportSzvFactories(content)) {
3578
+ state.skippedSzvExportFiles.add(filePath);
3816
3579
  }
3817
3580
  }
3818
3581
  function processPrescanTransform(filePath, content, result, discoveredClasses, rawDiscoveredClasses) {
@@ -3843,13 +3606,73 @@ function createCsszyxPlugins(options = {}) {
3843
3606
  }
3844
3607
  collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses);
3845
3608
  }
3609
+ function refreshSzvRegistryEntry(filePath, content) {
3610
+ if (!shouldProcessSource(filePath)) return;
3611
+ if (content === null) {
3612
+ szvCrossModuleRegistry.delete(transformCache.normalizePathSeparators(filePath));
3613
+ return;
3614
+ }
3615
+ transformCache.recordSzvRegistryFile(szvCrossModuleRegistry, filePath, content);
3616
+ if (importedStaticSzEnabled) {
3617
+ transformCache.recordSzObjectRegistryFile(szvCrossModuleRegistry, filePath, content);
3618
+ szObjectProvidersExamined.add(transformCache.normalizePathSeparators(filePath));
3619
+ recordProvidersDemandedBy(filePath, content);
3620
+ }
3621
+ }
3622
+ function recordProvidersDemandedBy(filePath, content) {
3623
+ if (!fileMayContainSafelistableSz(content)) return;
3624
+ const directory = path__namespace.dirname(filePath);
3625
+ for (const specifier of transformCache.importedSpecifiersIn(content)) {
3626
+ for (const base of transformCache.specifierBases(specifier, directory, specifierAliases)) {
3627
+ const providerPath = transformCache.resolveProviderPathWith(base, transformCache.isReadableProviderFile);
3628
+ if (providerPath === void 0) continue;
3629
+ const key = transformCache.normalizePathSeparators(providerPath);
3630
+ if (!szObjectProvidersExamined.has(key)) {
3631
+ szObjectProvidersExamined.add(key);
3632
+ readAndRecordSzObjectProvider(providerPath);
3633
+ }
3634
+ break;
3635
+ }
3636
+ }
3637
+ }
3638
+ function readAndRecordSzObjectProvider(providerPath) {
3639
+ let content;
3640
+ try {
3641
+ content = fs__namespace.readFileSync(providerPath, "utf-8");
3642
+ } catch {
3643
+ return;
3644
+ }
3645
+ transformCache.recordSzObjectRegistryFile(szvCrossModuleRegistry, providerPath, content);
3646
+ }
3647
+ function recordDemandedSzObjectProviders(seenSourcePaths, demand) {
3648
+ for (const base of demand) {
3649
+ const providerPath = transformCache.resolveProviderPath(seenSourcePaths, base);
3650
+ if (providerPath === void 0) continue;
3651
+ szObjectProvidersExamined.add(transformCache.normalizePathSeparators(providerPath));
3652
+ readAndRecordSzObjectProvider(providerPath);
3653
+ }
3654
+ }
3655
+ function refreshSzvRegistryEntryFromDisk(filePath) {
3656
+ if (!shouldProcessSource(filePath)) return;
3657
+ let content;
3658
+ try {
3659
+ content = fs__namespace.readFileSync(filePath, "utf-8");
3660
+ } catch {
3661
+ refreshSzvRegistryEntry(filePath, null);
3662
+ return;
3663
+ }
3664
+ refreshSzvRegistryEntry(filePath, content);
3665
+ }
3846
3666
  function prescanAndWriteClasses() {
3847
3667
  refreshCompileSourceDirs();
3848
3668
  szvCrossModuleRegistry.clear();
3669
+ szObjectProvidersExamined.clear();
3849
3670
  const prescanStarted = node_perf_hooks.performance.now();
3850
3671
  const discoveredClasses = /* @__PURE__ */ new Set();
3851
3672
  const rawDiscoveredClasses = /* @__PURE__ */ new Set();
3852
3673
  const prescanSources = [];
3674
+ const seenSourcePaths = /* @__PURE__ */ new Set();
3675
+ const szObjectDemand = /* @__PURE__ */ new Set();
3853
3676
  function collectPrescanSource(filePath) {
3854
3677
  if (!shouldProcessSource(filePath)) {
3855
3678
  recordPackagesSkipIfSz(filePath);
@@ -3863,13 +3686,23 @@ function createCsszyxPlugins(options = {}) {
3863
3686
  }
3864
3687
  recordAuthoredClasses(content);
3865
3688
  recordSzvRegistryEntries(filePath, content);
3689
+ seenSourcePaths.add(transformCache.normalizePathSeparators(filePath));
3866
3690
  if (fileMayContainSafelistableSz(content)) {
3867
3691
  prescanSources.push({ filePath, content });
3692
+ recordSzObjectDemand(filePath, content);
3693
+ }
3694
+ }
3695
+ function recordSzObjectDemand(filePath, content) {
3696
+ if (!importedStaticSzEnabled) return;
3697
+ const directory = path__namespace.dirname(filePath);
3698
+ for (const specifier of transformCache.importedSpecifiersIn(content)) {
3699
+ for (const base of transformCache.specifierBases(specifier, directory, specifierAliases)) {
3700
+ szObjectDemand.add(base);
3701
+ }
3868
3702
  }
3869
3703
  }
3870
3704
  function recordSzvRegistryEntries(filePath, content) {
3871
- if (!crossModuleRegistryEnabled) return;
3872
- recordSzvRegistryFile(szvCrossModuleRegistry, filePath, content);
3705
+ transformCache.recordSzvRegistryFile(szvCrossModuleRegistry, filePath, content);
3873
3706
  }
3874
3707
  function scanDir(dir) {
3875
3708
  let entries;
@@ -3898,6 +3731,7 @@ function createCsszyxPlugins(options = {}) {
3898
3731
  }
3899
3732
  scanDir(sourceDir);
3900
3733
  }
3734
+ recordDemandedSzObjectProviders(seenSourcePaths, szObjectDemand);
3901
3735
  const prescanContentByPath = new Map(
3902
3736
  prescanSources.map((file) => [file.filePath, file.content])
3903
3737
  );
@@ -4028,16 +3862,39 @@ function createCsszyxPlugins(options = {}) {
4028
3862
  state.authoredClasses.add(className);
4029
3863
  }
4030
3864
  }
4031
- function finalizeMangleMap() {
3865
+ function computeMangleMap() {
4032
3866
  const forbiddenTokens = /* @__PURE__ */ new Set([
4033
3867
  ...mangleReserved,
4034
3868
  ...state.authoredClasses,
4035
3869
  ...state.ownedClasses
4036
3870
  ]);
4037
- state.mangleMap = allocateMangleTokens(
3871
+ return allocateMangleTokens(
4038
3872
  mangleEligibleClasses(state.ownedClasses, state.authoredClasses),
4039
3873
  forbiddenTokens
4040
3874
  );
3875
+ }
3876
+ function freezeMangleMap() {
3877
+ state.mangleMap = computeMangleMap();
3878
+ frozenOwnedClasses = new Set(state.ownedClasses);
3879
+ frozenAuthoredClasses = new Set(state.authoredClasses);
3880
+ mangleMapFrozen = true;
3881
+ }
3882
+ function assertMangleCensusUnchanged() {
3883
+ if (!mangleMapFrozen) return;
3884
+ const current = computeMangleMap();
3885
+ if (JSON.stringify(current) === JSON.stringify(state.mangleMap)) return;
3886
+ const lateOwned = compiler.sortStrings(
3887
+ [...state.ownedClasses].filter((className) => !frozenOwnedClasses.has(className))
3888
+ );
3889
+ const lateAuthored = compiler.sortStrings(
3890
+ [...state.authoredClasses].filter((className) => !frozenAuthoredClasses.has(className))
3891
+ );
3892
+ throw new Error(lateMangleCensusMessage(lateOwned, lateAuthored));
3893
+ }
3894
+ function finalizeMangleMap() {
3895
+ if (!mangleMapFrozen) {
3896
+ state.mangleMap = computeMangleMap();
3897
+ }
4041
3898
  assertVarMangleMapSize(state.varMangleMap, varMangleMapMaxBytes);
4042
3899
  state.checksum = core.compute_mangle_checksum(
4043
3900
  createHydrationMangleMap(state.mangleMap, state.varMangleMap)
@@ -4067,19 +3924,19 @@ function createCsszyxPlugins(options = {}) {
4067
3924
  }
4068
3925
  function replacePlaceholders(code) {
4069
3926
  let result = code;
4070
- if (result.includes(CHECKSUM_PLACEHOLDER)) {
4071
- result = result.split(CHECKSUM_PLACEHOLDER).join(state.checksum);
3927
+ if (result.includes(themeGroupsFile.CHECKSUM_PLACEHOLDER)) {
3928
+ result = result.split(themeGroupsFile.CHECKSUM_PLACEHOLDER).join(state.checksum);
4072
3929
  }
4073
3930
  const isEvalWrapped = result.includes("eval(") && result.includes("sourceURL=webpack");
4074
- if (result.includes(MANGLE_MAP_PLACEHOLDER)) {
3931
+ if (result.includes(themeGroupsFile.MANGLE_MAP_PLACEHOLDER)) {
4075
3932
  const jsonMap = escapeJsonForInlineScript(JSON.stringify(state.mangleMap));
4076
3933
  const escapedMap = isEvalWrapped ? escapeForDoubleQuotedString(jsonMap) : jsonMap;
4077
- result = result.split(MANGLE_MAP_PLACEHOLDER).join(escapedMap);
3934
+ result = result.split(themeGroupsFile.MANGLE_MAP_PLACEHOLDER).join(escapedMap);
4078
3935
  }
4079
- if (result.includes(VAR_MANGLE_MAP_PLACEHOLDER)) {
3936
+ if (result.includes(themeGroupsFile.VAR_MANGLE_MAP_PLACEHOLDER)) {
4080
3937
  const jsonMap = escapeJsonForInlineScript(JSON.stringify(state.varMangleMap));
4081
3938
  const escapedMap = isEvalWrapped ? escapeForDoubleQuotedString(jsonMap) : jsonMap;
4082
- result = result.split(VAR_MANGLE_MAP_PLACEHOLDER).join(escapedMap);
3939
+ result = result.split(themeGroupsFile.VAR_MANGLE_MAP_PLACEHOLDER).join(escapedMap);
4083
3940
  }
4084
3941
  return result;
4085
3942
  }
@@ -4096,7 +3953,8 @@ function createCsszyxPlugins(options = {}) {
4096
3953
  szPartArgsProvable: true,
4097
3954
  usesColorVar: false,
4098
3955
  usesSpacingVar: false,
4099
- usesUnitVar: false
3956
+ usesUnitVar: false,
3957
+ usesBoolClass: false
4100
3958
  };
4101
3959
  }
4102
3960
  function transformTailwindCssEntry(code, id) {
@@ -4123,13 +3981,13 @@ function createCsszyxPlugins(options = {}) {
4123
3981
  }
4124
3982
  emitMissingCssFallback(quiet, message, id, console.warn);
4125
3983
  }
4126
- if (quiet || result.diagnostics.length === 0 || process.env.NODE_ENV === "production") {
3984
+ const advisories = result.diagnostics.filter(isAdvisoryDiagnostic);
3985
+ if (advisories.length === 0) return;
3986
+ if (quiet !== "off" || process.env.NODE_ENV === "production") {
3987
+ state.suppressedAdvisories += advisories.length;
4127
3988
  return;
4128
3989
  }
4129
- for (const message of result.diagnostics) {
4130
- if (message.includes("unresolvable sz spread") || message.includes("AST budget exceeded") || compiler.szFallbackConsequenceOf(message) === "missing-css") {
4131
- continue;
4132
- }
3990
+ for (const message of advisories) {
4133
3991
  warn(`[csszyx] ${id}
4134
3992
  ${message}`);
4135
3993
  }
@@ -4148,6 +4006,7 @@ function createCsszyxPlugins(options = {}) {
4148
4006
  usesColorVar: result.usesColorVar,
4149
4007
  usesSpacingVar: result.usesSpacingVar,
4150
4008
  usesUnitVar: result.usesUnitVar,
4009
+ usesBoolClass: result.usesBoolClass,
4151
4010
  szClasses: result.classes
4152
4011
  };
4153
4012
  }
@@ -4177,9 +4036,9 @@ function createCsszyxPlugins(options = {}) {
4177
4036
  const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
4178
4037
  const htmlTag = findOpeningTag(transformedCode, "html");
4179
4038
  if (htmlTag) {
4180
- transformedCode = `${transformedCode.slice(0, htmlTag.close)} ${attrName}="${CHECKSUM_PLACEHOLDER}"${transformedCode.slice(htmlTag.close)}`;
4039
+ transformedCode = `${transformedCode.slice(0, htmlTag.close)} ${attrName}="${themeGroupsFile.CHECKSUM_PLACEHOLDER}"${transformedCode.slice(htmlTag.close)}`;
4181
4040
  }
4182
- const debugScript = `<script dangerouslySetInnerHTML={{__html: \`(function(){var m=${MANGLE_MAP_PLACEHOLDER};var vm=${VAR_MANGLE_MAP_PLACEHOLDER};var gp=decodeURIComponent(${escapeJsonForInlineScript(JSON.stringify(encodedGlobalVarAliasPrefix))});var r={};var vr={};for(var k in m)r[m[k]]=k;for(var vk in vm){var vv=vm[vk];var vs=Array.isArray(vv)?vv:[vv];for(var vi=0;vi<vs.length;vi++)(vr[vs[vi]]||(vr[vs[vi]]=[])).push(vk)}window.__csszyx={mangleMap:m,varMangleMap:vm,checksum:"${CHECKSUM_PLACEHOLDER}",decode:function(c){return r[c]},encode:function(c){return m[c]},decodeVar:function(v){return vr[v]||[]},encodeVar:function(v){return vm[v]},decodeGlobalVar:function(v){var a=vr[v]||[];return v.indexOf(gp)===0?a[0]:void 0},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()\`}} />`;
4041
+ const debugScript = `<script dangerouslySetInnerHTML={{__html: \`(function(){var m=${themeGroupsFile.MANGLE_MAP_PLACEHOLDER};var vm=${themeGroupsFile.VAR_MANGLE_MAP_PLACEHOLDER};var gp=decodeURIComponent(${escapeJsonForInlineScript(JSON.stringify(encodedGlobalVarAliasPrefix))});var r={};var vr={};for(var k in m)r[m[k]]=k;for(var vk in vm){var vv=vm[vk];var vs=Array.isArray(vv)?vv:[vv];for(var vi=0;vi<vs.length;vi++)(vr[vs[vi]]||(vr[vs[vi]]=[])).push(vk)}window.__csszyx={mangleMap:m,varMangleMap:vm,checksum:"${themeGroupsFile.CHECKSUM_PLACEHOLDER}",decode:function(c){return r[c]},encode:function(c){return m[c]},decodeVar:function(v){return vr[v]||[]},encodeVar:function(v){return vm[v]},decodeGlobalVar:function(v){var a=vr[v]||[];return v.indexOf(gp)===0?a[0]:void 0},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()\`}} />`;
4183
4042
  const bodyTag = findOpeningTag(transformedCode, "body");
4184
4043
  if (bodyTag) {
4185
4044
  transformedCode = `${transformedCode.slice(0, bodyTag.close + 1)}${debugScript}${transformedCode.slice(bodyTag.close + 1)}`;
@@ -4187,7 +4046,7 @@ function createCsszyxPlugins(options = {}) {
4187
4046
  return transformedCode;
4188
4047
  }
4189
4048
  function requiredRuntimeHelpers(output) {
4190
- return nextRuntimeInjection.runtimeHelperGroupsFromUsage(output);
4049
+ return themeGroupsFile.runtimeHelperGroupsFromUsage(output);
4191
4050
  }
4192
4051
  function injectRuntimeHelpers(code, output) {
4193
4052
  const groups = requiredRuntimeHelpers(output);
@@ -4203,9 +4062,9 @@ function createCsszyxPlugins(options = {}) {
4203
4062
  }
4204
4063
  const imports = groups.barrel;
4205
4064
  const hasRuntimeImport = imports.length > 0 && current.includes("@csszyx/runtime");
4206
- const needed = hasRuntimeImport ? imports.filter((name) => !nextRuntimeInjection.importsRuntimeHelper(current, name)) : imports;
4065
+ const needed = hasRuntimeImport ? imports.filter((name) => !themeGroupsFile.importsRuntimeHelper(current, name)) : imports;
4207
4066
  if (needed.length === 0) return result;
4208
- const existingImport = nextRuntimeInjection.findRuntimeImportClause(current);
4067
+ const existingImport = themeGroupsFile.findRuntimeImportClause(current);
4209
4068
  if (existingImport) {
4210
4069
  return current.replace(
4211
4070
  existingImport.statement,
@@ -4216,11 +4075,30 @@ function createCsszyxPlugins(options = {}) {
4216
4075
  `;
4217
4076
  return insertRuntimeImport(current, importStatement);
4218
4077
  }
4078
+ function themeGroupTokens() {
4079
+ const theme = state.parsedTheme;
4080
+ return {
4081
+ colors: theme?.colors ?? [],
4082
+ textSizes: theme?.textSizes ?? [],
4083
+ fontFamilies: theme?.fonts ?? [],
4084
+ fontWeights: theme?.fontWeights ?? []
4085
+ };
4086
+ }
4219
4087
  function injectThemeGroups(code, transformedCode, id, usesSzcn) {
4220
- if (!usesSzcn && !/\bszcn\s*\(/.test(code) || transformedCode.includes(THEME_GROUPS_VIRTUAL_ID) || !shouldProcessSource(id)) {
4088
+ if (!usesSzcn && !/\bszcn\s*\(/.test(code) || transformedCode.includes(themeGroupsFile.THEME_GROUPS_VIRTUAL_ID) || transformedCode.includes(themeGroupsFile.THEME_GROUPS_FILE_MARKER) || !shouldProcessSource(id)) {
4221
4089
  return null;
4222
4090
  }
4223
- return `import '${THEME_GROUPS_VIRTUAL_ID}';
4091
+ if (activeFramework === "webpack") {
4092
+ const groups = themeGroupsFile.ensureThemeGroupsFile(
4093
+ state.rootDir,
4094
+ path__namespace.join(state.rootDir, ".csszyx")
4095
+ );
4096
+ if (groups.file === null) return null;
4097
+ const [from] = id.split("?");
4098
+ return `import '${themeGroupsFile.themeGroupsSpecifier(from, groups.file)}';
4099
+ ${transformedCode}`;
4100
+ }
4101
+ return `import '${themeGroupsFile.THEME_GROUPS_VIRTUAL_ID}';
4224
4102
  ${transformedCode}`;
4225
4103
  }
4226
4104
  const MANGLE_RUNTIME_CONSUMER_RE = /from\s*['"](?:csszyx|@csszyx\/runtime)['"]/;
@@ -4229,10 +4107,10 @@ ${transformedCode}`;
4229
4107
  if (activeFramework !== "vite" && activeFramework !== "rollup") {
4230
4108
  return null;
4231
4109
  }
4232
- if (!manglingEnabled || !deliverMapInBundle || !shouldProcessSource(id) || !MANGLE_RUNTIME_CONSUMER_RE.test(transformedCode) || transformedCode.includes(MANGLE_RUNTIME_VIRTUAL_ID)) {
4110
+ if (!manglingEnabled || !deliverMapInBundle || !shouldProcessSource(id) || !MANGLE_RUNTIME_CONSUMER_RE.test(transformedCode) || transformedCode.includes(themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID)) {
4233
4111
  return null;
4234
4112
  }
4235
- return insertRuntimeImport(transformedCode, `import '${MANGLE_RUNTIME_VIRTUAL_ID}';
4113
+ return insertRuntimeImport(transformedCode, `import '${themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID}';
4236
4114
  `);
4237
4115
  }
4238
4116
  function collectPreTransformClasses(output) {
@@ -4259,8 +4137,8 @@ ${transformedCode}`;
4259
4137
  * @returns resolved ID if virtual, null otherwise
4260
4138
  */
4261
4139
  resolveId(id) {
4262
- if (isVirtualModule(id)) {
4263
- return resolveVirtualModule(id);
4140
+ if (themeGroupsFile.isVirtualModule(id)) {
4141
+ return themeGroupsFile.resolveVirtualModule(id);
4264
4142
  }
4265
4143
  return null;
4266
4144
  },
@@ -4277,7 +4155,7 @@ ${transformedCode}`;
4277
4155
  * @returns true only for csszyx virtual modules
4278
4156
  */
4279
4157
  loadInclude(id) {
4280
- return id === RESOLVED_VIRTUAL_MODULE_ID || id === RESOLVED_VIRTUAL_CHECKSUM_ID || id === RESOLVED_THEME_GROUPS_VIRTUAL_ID || id === RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID;
4158
+ return id === themeGroupsFile.RESOLVED_VIRTUAL_MODULE_ID || id === themeGroupsFile.RESOLVED_VIRTUAL_CHECKSUM_ID || id === themeGroupsFile.RESOLVED_THEME_GROUPS_VIRTUAL_ID || id === themeGroupsFile.RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID;
4281
4159
  },
4282
4160
  /**
4283
4161
  * Loads virtual module content — generates mangle map or checksum module code.
@@ -4285,31 +4163,25 @@ ${transformedCode}`;
4285
4163
  * @returns generated module source if virtual, null otherwise
4286
4164
  */
4287
4165
  load(id) {
4288
- if (id === RESOLVED_VIRTUAL_MODULE_ID) {
4166
+ if (id === themeGroupsFile.RESOLVED_VIRTUAL_MODULE_ID) {
4289
4167
  finalizeMangleMap();
4290
- return createMangleMapModule(
4168
+ return themeGroupsFile.createMangleMapModule(
4291
4169
  state.mangleMap,
4292
4170
  state.checksum,
4293
4171
  state.varMangleMap,
4294
4172
  state.cssVarMetrics
4295
4173
  );
4296
4174
  }
4297
- if (id === RESOLVED_VIRTUAL_CHECKSUM_ID) {
4175
+ if (id === themeGroupsFile.RESOLVED_VIRTUAL_CHECKSUM_ID) {
4298
4176
  finalizeMangleMap();
4299
- return createChecksumModule(state.checksum);
4177
+ return themeGroupsFile.createChecksumModule(state.checksum);
4300
4178
  }
4301
- if (id === RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID) {
4179
+ if (id === themeGroupsFile.RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID) {
4302
4180
  sizeAccount.channels.add("bundle");
4303
- return createMangleRuntimeModule(globalVarAliasPrefix);
4181
+ return themeGroupsFile.createMangleRuntimeModule(globalVarAliasPrefix);
4304
4182
  }
4305
- if (id === RESOLVED_THEME_GROUPS_VIRTUAL_ID) {
4306
- const theme = state.parsedTheme;
4307
- return createThemeGroupsModule({
4308
- colors: theme?.colors ?? [],
4309
- textSizes: theme?.textSizes ?? [],
4310
- fontFamilies: theme?.fonts ?? [],
4311
- fontWeights: theme?.fontWeights ?? []
4312
- });
4183
+ if (id === themeGroupsFile.RESOLVED_THEME_GROUPS_VIRTUAL_ID) {
4184
+ return themeGroupsFile.createThemeGroupsModule(themeGroupTokens());
4313
4185
  }
4314
4186
  return null;
4315
4187
  },
@@ -4323,7 +4195,11 @@ ${transformedCode}`;
4323
4195
  if (shouldProcessCss(id)) {
4324
4196
  return true;
4325
4197
  }
4326
- return shouldProcessSource(id);
4198
+ if (shouldProcessSource(id)) {
4199
+ return true;
4200
+ }
4201
+ recordPackagesSkipIfSz(id);
4202
+ return false;
4327
4203
  },
4328
4204
  /**
4329
4205
  * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
@@ -4388,6 +4264,8 @@ ${transformedCode}`;
4388
4264
  /** Finalizes the mangle map after all source modules have been processed. */
4389
4265
  buildEnd() {
4390
4266
  finalizeMangleMap();
4267
+ assertMangleCensusUnchanged();
4268
+ revalidateFrozenGlobalVarPlan();
4391
4269
  assertNoRSCGraphViolation(state.rscModules);
4392
4270
  if (!state.tailwindWarningEmitted && shouldWarnMissingTailwindEntry(
4393
4271
  state.ownedClasses.size,
@@ -4410,9 +4288,13 @@ ${transformedCode}`;
4410
4288
  }
4411
4289
  if (!state.skipWarningEmitted && state.skippedSzFiles.size > 0) {
4412
4290
  state.skipWarningEmitted = true;
4413
- emitWarning(skippedSzFilesMessage(compiler.sortStrings(state.skippedSzFiles)), {
4414
- devOnly: true
4415
- });
4291
+ emitWarning(
4292
+ skippedSzFilesMessage(
4293
+ compiler.sortStrings(state.skippedSzFiles),
4294
+ compiler.sortStrings(state.skippedSzvExportFiles)
4295
+ ),
4296
+ { devOnly: state.skippedSzvExportFiles.size === 0 }
4297
+ );
4416
4298
  }
4417
4299
  if (state.classesCapped) {
4418
4300
  emitWarning(
@@ -4434,7 +4316,10 @@ ${transformedCode}`;
4434
4316
  recordGlobalVarSourceFile(state, id, null);
4435
4317
  recordFileVarMangleEntries(state, id, []);
4436
4318
  recordFileCSSVariableMetrics(state, id, null);
4319
+ refreshSzvRegistryEntry(id, null);
4320
+ return;
4437
4321
  }
4322
+ refreshSzvRegistryEntryFromDisk(id);
4438
4323
  },
4439
4324
  /**
4440
4325
  * Webpack hook: pre-scans source files before compilation for Tailwind class discovery.
@@ -4442,12 +4327,13 @@ ${transformedCode}`;
4442
4327
  */
4443
4328
  webpack(compiler) {
4444
4329
  activeFramework = "webpack";
4330
+ compiler.hooks?.beforeCompile?.tap?.("csszyx:theme-groups", () => {
4331
+ const root = compiler.context || process.cwd();
4332
+ themeGroupsFile.ensureThemeGroupsFile(root, path__namespace.join(root, ".csszyx"));
4333
+ });
4445
4334
  if (compiler.options?.mode === "development") {
4446
4335
  manglingEnabled = false;
4447
4336
  }
4448
- if (compiler.watchMode === true || compiler.options?.watch === true) {
4449
- crossModuleRegistryEnabled = false;
4450
- }
4451
4337
  if (manglingEnabled && mangleMapDelivery !== "both") {
4452
4338
  console.warn(
4453
4339
  `[csszyx] production.mangleMapDelivery: '${mangleMapDelivery}' has no effect on the webpack lane \u2014 map delivery only narrows on vite/rollup builds.`
@@ -4457,11 +4343,21 @@ ${transformedCode}`;
4457
4343
  announceActiveParser();
4458
4344
  const root = compiler.context || process.cwd();
4459
4345
  state.rootDir = root;
4346
+ specifierAliases = transformCache.collectSpecifierAliases(
4347
+ root,
4348
+ compiler.options?.resolve?.alias
4349
+ );
4460
4350
  evictTransformCacheOnce();
4461
4351
  if (state.classes.size === 0) {
4462
4352
  prescanAndWriteClasses();
4463
4353
  }
4464
- state.parsedTheme = runThemeScan(root, options.build?.scanCss) ?? state.parsedTheme;
4354
+ for (const changed of compiler.modifiedFiles ?? []) {
4355
+ refreshSzvRegistryEntryFromDisk(changed);
4356
+ }
4357
+ for (const removed of compiler.removedFiles ?? []) {
4358
+ refreshSzvRegistryEntry(removed, null);
4359
+ }
4360
+ state.scanCssTheme = runThemeScan(root, options.build?.scanCss) ?? state.scanCssTheme;
4465
4361
  runAutoThemeScan(root);
4466
4362
  });
4467
4363
  if (options.build?.scanCss) {
@@ -4477,10 +4373,6 @@ ${transformedCode}`;
4477
4373
  /** Records the rollup lane for the mangle-runtime gate. */
4478
4374
  buildStart() {
4479
4375
  activeFramework = "rollup";
4480
- const meta = this.meta;
4481
- if (meta?.watchMode) {
4482
- crossModuleRegistryEnabled = false;
4483
- }
4484
4376
  }
4485
4377
  },
4486
4378
  vite: {
@@ -4494,17 +4386,26 @@ ${transformedCode}`;
4494
4386
  announceActiveParser();
4495
4387
  const root = config.root || process.cwd();
4496
4388
  state.rootDir = root;
4389
+ specifierAliases = transformCache.collectSpecifierAliases(root, config.resolve?.alias);
4497
4390
  if (config.command === "serve") {
4498
4391
  manglingEnabled = false;
4499
- crossModuleRegistryEnabled = false;
4500
4392
  }
4501
- if (config.build?.watch) {
4502
- crossModuleRegistryEnabled = false;
4393
+ if (manglingEnabled && config.build?.watch) {
4394
+ manglingEnabled = false;
4395
+ emitWarning(watchModeMangleMessage());
4503
4396
  }
4504
4397
  evictTransformCacheOnce();
4505
4398
  prescanAndWriteClasses();
4506
- state.parsedTheme = runThemeScan(root, options.build?.scanCss) ?? state.parsedTheme;
4399
+ state.scanCssTheme = runThemeScan(root, options.build?.scanCss) ?? state.scanCssTheme;
4507
4400
  runAutoThemeScan(root);
4401
+ if (config.command === "build") {
4402
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
4403
+ collectProjectGlobalVarCssSources()
4404
+ );
4405
+ }
4406
+ if (manglingEnabled && config.command === "build") {
4407
+ freezeMangleMap();
4408
+ }
4508
4409
  },
4509
4410
  /**
4510
4411
  * Vite HMR hook: re-runs theme scan when a watched CSS file changes,
@@ -4516,21 +4417,23 @@ ${transformedCode}`;
4516
4417
  const scanCss = options.build?.scanCss;
4517
4418
  const reloadThemeGroupsModule = () => {
4518
4419
  const themeGroupsModule = ctx.server.moduleGraph.getModuleById(
4519
- RESOLVED_THEME_GROUPS_VIRTUAL_ID
4420
+ themeGroupsFile.RESOLVED_THEME_GROUPS_VIRTUAL_ID
4520
4421
  );
4521
4422
  if (themeGroupsModule) {
4522
4423
  ctx.server.moduleGraph.invalidateModule(themeGroupsModule);
4523
4424
  }
4524
4425
  };
4525
- if (scanCss) {
4426
+ if (ctx.file.endsWith(".css")) {
4526
4427
  const root = ctx.server.config.root || process.cwd();
4527
- if (matchesAnyPattern(ctx.file, scanCss, root)) {
4528
- state.parsedTheme = runThemeScan(root, scanCss) ?? state.parsedTheme;
4529
- reloadThemeGroupsModule();
4428
+ const before = themeGroupsFile.createThemeGroupsModule(themeGroupTokens());
4429
+ if (scanCss && matchesAnyPattern(ctx.file, scanCss, root)) {
4430
+ state.scanCssTheme = runThemeScan(root, scanCss) ?? state.scanCssTheme;
4530
4431
  }
4531
- } else if (ctx.file.endsWith(".css")) {
4532
- runAutoThemeScan(ctx.server.config.root || process.cwd());
4432
+ runAutoThemeScan(root);
4533
4433
  reloadThemeGroupsModule();
4434
+ if (themeGroupsFile.createThemeGroupsModule(themeGroupTokens()) !== before) {
4435
+ ctx.server.ws.send({ type: "full-reload" });
4436
+ }
4534
4437
  }
4535
4438
  if (!shouldProcessSource(ctx.file)) {
4536
4439
  return;
@@ -4539,8 +4442,10 @@ ${transformedCode}`;
4539
4442
  try {
4540
4443
  fileContent = fs__namespace.readFileSync(ctx.file, "utf-8");
4541
4444
  } catch {
4445
+ refreshSzvRegistryEntry(ctx.file, null);
4542
4446
  return;
4543
4447
  }
4448
+ refreshSzvRegistryEntry(ctx.file, fileContent);
4544
4449
  if (!fileContent.includes("sz=") && !fileContent.includes("szs=") && !/\bsz\s*:\s*["'{]/.test(fileContent)) {
4545
4450
  trackGlobalVarSourceFile(ctx.file, fileContent);
4546
4451
  recordFileVarMangleEntries(state, ctx.file, []);
@@ -4654,6 +4559,13 @@ ${transformedCode}`;
4654
4559
  }
4655
4560
  return manifest;
4656
4561
  }
4562
+ function rewriteCodeAsset(source, shouldMangle) {
4563
+ if (!shouldMangle) return replacePlaceholders(source);
4564
+ const before = replacePlaceholders(source);
4565
+ const after = replacePlaceholders(mangleCodeClasses(source));
4566
+ recordCodePair(sizeAccount, before, after);
4567
+ return after;
4568
+ }
4657
4569
  function rewriteOutputCss(source, file, shouldMangle, mangledSources, externalClasses) {
4658
4570
  const css = rewriteCssWithValidatedGlobalVarPlan(
4659
4571
  source,
@@ -4682,7 +4594,14 @@ ${transformedCode}`;
4682
4594
  collectMangleHybridHazards(state.mangleMap, mangledSources, externalClasses)
4683
4595
  );
4684
4596
  if (message) console.warn(message);
4597
+ }
4598
+ function reportBuildSummary() {
4685
4599
  reportMangleSize();
4600
+ if (resolveQuietMode(quiet) !== "all") {
4601
+ const message = suppressedAdvisoryMessage(state.suppressedAdvisories);
4602
+ if (message) console.warn(message);
4603
+ }
4604
+ state.suppressedAdvisories = 0;
4686
4605
  }
4687
4606
  function reportMangleSize() {
4688
4607
  const verdict = computeMangleSizeVerdict(
@@ -4702,7 +4621,7 @@ ${transformedCode}`;
4702
4621
  return;
4703
4622
  }
4704
4623
  if (!file.endsWith(".js")) return;
4705
- const rewritten = shouldMangle ? replacePlaceholders(mangleCodeClasses(source)) : replacePlaceholders(source);
4624
+ const rewritten = rewriteCodeAsset(source, shouldMangle);
4706
4625
  if (rewritten !== source) {
4707
4626
  compilation.updateAsset(file, new compiler.webpack.sources.RawSource(rewritten));
4708
4627
  }
@@ -4751,31 +4670,44 @@ ${transformedCode}`;
4751
4670
  }
4752
4671
  }
4753
4672
  reportOutputMangleHazards(shouldMangle, mangledSources, externalClasses);
4673
+ reportBuildSummary();
4754
4674
  }
4755
4675
  function rewriteViteBundleEntry(chunk, file, shouldMangle, mangledSources, externalClasses) {
4756
- if (chunk.type === "asset" && chunk.fileName.endsWith(".css") && chunk.source !== void 0) {
4757
- const originalCss = chunk.source.toString();
4758
- const css = rewriteOutputCss(
4759
- originalCss,
4760
- file,
4761
- shouldMangle,
4762
- mangledSources,
4763
- externalClasses
4764
- );
4765
- if (css !== originalCss) chunk.source = css;
4676
+ if (chunk.type !== "asset" || !chunk.fileName.endsWith(".css") || chunk.source === void 0) {
4766
4677
  return;
4767
4678
  }
4768
- if (chunk.type !== "chunk" || chunk.code === void 0) return;
4769
- const rewritten = shouldMangle ? replacePlaceholders(mangleCodeClasses(chunk.code)) : replacePlaceholders(chunk.code);
4770
- if (rewritten !== chunk.code) chunk.code = rewritten;
4679
+ const originalCss = chunk.source.toString();
4680
+ const css = rewriteOutputCss(
4681
+ originalCss,
4682
+ file,
4683
+ shouldMangle,
4684
+ mangledSources,
4685
+ externalClasses
4686
+ );
4687
+ if (css !== originalCss) chunk.source = css;
4688
+ }
4689
+ function mangleCssModule(code, id) {
4690
+ const shouldMangle = manglingEnabled && mangleMapFrozen && Object.keys(state.mangleMap).length > 0;
4691
+ const css = rewriteOutputCss(
4692
+ code,
4693
+ id,
4694
+ shouldMangle,
4695
+ transformMangledSources,
4696
+ transformExternalClasses
4697
+ );
4698
+ return css === code ? null : { code: css, map: null };
4771
4699
  }
4772
4700
  function processRollupBundle(bundle, emitAsset) {
4773
4701
  finalizeMangleMap();
4774
- state.globalVarValidationResult = validateGlobalVarBundleInputs(
4775
- collectRollupGlobalVarCssAssets(bundle)
4776
- );
4702
+ if (!cssRewrittenInTransform) {
4703
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
4704
+ collectRollupGlobalVarCssAssets(bundle)
4705
+ );
4706
+ }
4777
4707
  const shouldMangle = manglingEnabled && Object.keys(state.mangleMap).length > 0;
4778
- emitAsset("csszyx-manifest.json", JSON.stringify(createBundleManifest(shouldMangle)));
4708
+ if (options.build?.emitManifest === true) {
4709
+ emitAsset("csszyx-manifest.json", JSON.stringify(createBundleManifest(shouldMangle)));
4710
+ }
4779
4711
  if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
4780
4712
  const globalVarMap = createGlobalVarMapAssetSource(
4781
4713
  state.varMangleMap,
@@ -4784,16 +4716,18 @@ ${transformedCode}`;
4784
4716
  );
4785
4717
  if (globalVarMap) emitAsset(".csszyx/global-var-map.json", globalVarMap);
4786
4718
  }
4787
- const mangledSources = /* @__PURE__ */ new Set();
4788
- const externalClasses = /* @__PURE__ */ new Set();
4789
- for (const file in bundle) {
4790
- rewriteViteBundleEntry(
4791
- bundle[file],
4792
- file,
4793
- shouldMangle,
4794
- mangledSources,
4795
- externalClasses
4796
- );
4719
+ const mangledSources = new Set(transformMangledSources);
4720
+ const externalClasses = new Set(transformExternalClasses);
4721
+ if (!cssRewrittenInTransform) {
4722
+ for (const file in bundle) {
4723
+ rewriteViteBundleEntry(
4724
+ bundle[file],
4725
+ file,
4726
+ shouldMangle,
4727
+ mangledSources,
4728
+ externalClasses
4729
+ );
4730
+ }
4797
4731
  }
4798
4732
  reportOutputMangleHazards(shouldMangle, mangledSources, externalClasses);
4799
4733
  }
@@ -4807,8 +4741,38 @@ ${transformedCode}`;
4807
4741
  * @param compiler - the Webpack compiler instance
4808
4742
  */
4809
4743
  webpack(compiler) {
4744
+ if (manglingEnabled && compiler.options?.optimization?.realContentHash === false) {
4745
+ emitWarning(realContentHashDisabledMessage());
4746
+ }
4810
4747
  registerWebpackAssetProcessor(compiler, processWebpackAssets);
4811
4748
  },
4749
+ /**
4750
+ * Settle the map once, before the first chunk is rendered.
4751
+ *
4752
+ * `renderChunk` is where the class rewrite has to happen, and Rollup
4753
+ * offers no ordering guarantee among chunks — so the map is completed
4754
+ * here rather than from whichever chunk arrives first.
4755
+ */
4756
+ renderStart() {
4757
+ finalizeMangleMap();
4758
+ },
4759
+ /**
4760
+ * Rewrite a JS chunk while its bytes still decide its filename hash.
4761
+ *
4762
+ * Rollup renders every chunk, hashes the result, substitutes the
4763
+ * filename placeholders and only then calls `generateBundle` — so the
4764
+ * rewrite this used to do there produced a file whose name described
4765
+ * the un-mangled bytes. The map is complete by `buildEnd`, which is
4766
+ * before the render phase, so nothing forces the later hook.
4767
+ *
4768
+ * @param code Rendered chunk source.
4769
+ * @returns Rewritten chunk, or null when nothing changed.
4770
+ */
4771
+ renderChunk(code) {
4772
+ const shouldMangle = manglingEnabled && Object.keys(state.mangleMap).length > 0;
4773
+ const rewritten = rewriteCodeAsset(code, shouldMangle);
4774
+ return rewritten === code ? null : { code: rewritten, map: null };
4775
+ },
4812
4776
  /**
4813
4777
  * Rollup-compatible hook used by both pure Rollup and Vite adapters.
4814
4778
  *
@@ -4821,15 +4785,54 @@ ${transformedCode}`;
4821
4785
  processRollupBundle(bundle, (fileName, source) => {
4822
4786
  this.emitFile({ type: "asset", fileName, source });
4823
4787
  });
4788
+ },
4789
+ /**
4790
+ * Report what mangling cost, after the bundler has printed its assets.
4791
+ *
4792
+ * Vite's reporter prints the asset table from `writeBundle`, which runs
4793
+ * before this hook — so the size verdict lands where a reader is
4794
+ * already looking at sizes, instead of scrolling past mid-build among
4795
+ * the other diagnostics.
4796
+ */
4797
+ closeBundle() {
4798
+ reportBuildSummary();
4824
4799
  }
4825
4800
  }));
4826
- return { prePlugin, postPlugin };
4801
+ const cssPlugin = unplugin$1.createUnplugin(() => ({
4802
+ name: "csszyx:css-mangle",
4803
+ transformInclude(id) {
4804
+ return cssRewrittenInTransform && isMangleableCssId(id);
4805
+ },
4806
+ transform(code, id) {
4807
+ return mangleCssModule(code, id);
4808
+ },
4809
+ vite: {
4810
+ /**
4811
+ * Claim the CSS rewrite for the transform phase on this lane.
4812
+ *
4813
+ * A dev server never reaches an output hook, and mangling is off
4814
+ * there anyway; claiming it only for `build` keeps `vite serve`
4815
+ * exactly as it was.
4816
+ *
4817
+ * @param config - the resolved Vite configuration object
4818
+ * @param config.command - `'build'` or `'serve'`
4819
+ */
4820
+ configResolved(config) {
4821
+ cssRewrittenInTransform = config.command === "build";
4822
+ }
4823
+ }
4824
+ }));
4825
+ return { prePlugin, postPlugin, cssPlugin };
4827
4826
  }
4828
4827
  const defaultInstance = createCsszyxPlugins();
4829
4828
  const unplugin = defaultInstance.prePlugin;
4830
4829
  const vitePlugin = (options = {}) => {
4831
- const { prePlugin, postPlugin } = createCsszyxPlugins(options);
4832
- return [prePlugin.vite(options), postPlugin.vite(options)];
4830
+ const { prePlugin, postPlugin, cssPlugin } = createCsszyxPlugins(options);
4831
+ return [
4832
+ prePlugin.vite(options),
4833
+ cssPlugin.vite(options),
4834
+ postPlugin.vite(options)
4835
+ ];
4833
4836
  };
4834
4837
  const webpackPlugin = (options = {}) => {
4835
4838
  const { prePlugin, postPlugin } = createCsszyxPlugins(options);
@@ -4897,31 +4900,32 @@ exports.findLocalImportSources = findLocalImportSources;
4897
4900
  exports.findRSCBoundaryViolation = findRSCBoundaryViolation;
4898
4901
  exports.findRSCGraphViolation = findRSCGraphViolation;
4899
4902
  exports.hasInjectableTailwindCandidate = hasInjectableTailwindCandidate;
4900
- exports.hasTokens = hasTokens;
4901
4903
  exports.hasUseClientDirective = hasUseClientDirective;
4902
4904
  exports.hasUseServerDirective = hasUseServerDirective;
4905
+ exports.isAdvisoryDiagnostic = isAdvisoryDiagnostic;
4903
4906
  exports.isCompileSourceOptedIn = isCompileSourceOptedIn;
4904
4907
  exports.isHardIgnoredPath = isHardIgnoredPath;
4908
+ exports.isMangleableCssId = isMangleableCssId;
4905
4909
  exports.isMonorepoPackage = isMonorepoPackage;
4906
4910
  exports.isPackagesSkippedSource = isPackagesSkippedSource;
4907
4911
  exports.isRSCServerModule = isRSCServerModule;
4908
4912
  exports.isTailwindReservedGlobalVar = isTailwindReservedGlobalVar;
4913
+ exports.lateMangleCensusMessage = lateMangleCensusMessage;
4909
4914
  exports.mangleCodeClassesSync = mangleCodeClassesSync;
4910
4915
  exports.mangleEligibleClasses = mangleEligibleClasses;
4911
4916
  exports.mangleHybridHazardMessage = mangleHybridHazardMessage;
4912
- exports.mergeThemes = mergeThemes;
4913
4917
  exports.missingTailwindEntryMessage = missingTailwindEntryMessage;
4914
4918
  exports.normalizeGlobalVarAliasesForCache = normalizeGlobalVarAliasesForCache;
4915
- exports.parseThemeBlocks = parseThemeBlocks;
4916
4919
  exports.planGlobalVarAliases = planGlobalVarAliases;
4917
4920
  exports.readGlobalVarScanCache = readGlobalVarScanCache;
4921
+ exports.realContentHashDisabledMessage = realContentHashDisabledMessage;
4918
4922
  exports.recordGlobalVarSourceFile = recordGlobalVarSourceFile;
4919
4923
  exports.resolveCompileSourceDirs = resolveCompileSourceDirs;
4920
4924
  exports.resolveGlobalVarScanCacheDir = resolveGlobalVarScanCacheDir;
4921
4925
  exports.resolveNativeCacheIdentity = resolveNativeCacheIdentity;
4926
+ exports.resolveQuietMode = resolveQuietMode;
4922
4927
  exports.rewriteGlobalVarCssAliases = rewriteGlobalVarCssAliases;
4923
4928
  exports.rollupPlugin = rollupPlugin;
4924
- exports.scanCustomPropertyNames = scanCustomPropertyNames;
4925
4929
  exports.scanGlobalVarCss = scanGlobalVarCss;
4926
4930
  exports.shouldEmitMissingCssFallback = shouldEmitMissingCssFallback;
4927
4931
  exports.shouldEmitWarning = shouldEmitWarning;
@@ -4929,9 +4933,11 @@ exports.shouldTrackGlobalVarSources = shouldTrackGlobalVarSources;
4929
4933
  exports.shouldWarnMissingTailwindEntry = shouldWarnMissingTailwindEntry;
4930
4934
  exports.shouldWarnUnscopedMonorepo = shouldWarnUnscopedMonorepo;
4931
4935
  exports.skippedSzFilesMessage = skippedSzFilesMessage;
4936
+ exports.suppressedAdvisoryMessage = suppressedAdvisoryMessage;
4932
4937
  exports.unplugin = unplugin;
4933
4938
  exports.unscopedMonorepoMessage = unscopedMonorepoMessage;
4934
4939
  exports.validateGlobalVarAliasInputs = validateGlobalVarAliasInputs;
4935
4940
  exports.vitePlugin = vitePlugin;
4941
+ exports.watchModeMangleMessage = watchModeMangleMessage;
4936
4942
  exports.webpackPlugin = webpackPlugin;
4937
4943
  exports.writeGlobalVarScanCache = writeGlobalVarScanCache;