@csszyx/unplugin 0.11.7 → 0.11.8

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 (41) hide show
  1. package/README.md +6 -1
  2. package/dist/css-mangler.cjs +9 -6
  3. package/dist/css-mangler.mjs +9 -6
  4. package/dist/index.cjs +5 -4
  5. package/dist/index.d.cts +2 -2
  6. package/dist/index.d.mts +2 -2
  7. package/dist/index.mjs +4 -4
  8. package/dist/next-config.cjs +1 -1
  9. package/dist/next-config.mjs +1 -1
  10. package/dist/next-prebuild.cjs +5 -5
  11. package/dist/next-prebuild.mjs +5 -5
  12. package/dist/next-turbo-loader.cjs +7 -12
  13. package/dist/next-turbo-loader.mjs +7 -12
  14. package/dist/next-watcher.cjs +2 -2
  15. package/dist/next-watcher.mjs +2 -2
  16. package/dist/shared/{unplugin.D6hes1O8.cjs → unplugin.C9dMG7ye.cjs} +5 -3
  17. package/dist/shared/{unplugin.PhOFTQpB.d.cts → unplugin.CNwV3RrQ.d.cts} +18 -5
  18. package/dist/shared/{unplugin.PhOFTQpB.d.mts → unplugin.CNwV3RrQ.d.mts} +18 -5
  19. package/dist/shared/unplugin.CcA7jP1r.cjs +48 -0
  20. package/dist/shared/{unplugin.CwcOd1q3.mjs → unplugin.D-K57LNR.mjs} +6 -1
  21. package/dist/shared/{unplugin.D8vSG36M.cjs → unplugin.DVCQC5wq.cjs} +6 -0
  22. package/dist/shared/{unplugin.CZKUWN1J.cjs → unplugin.DdtOZANG.cjs} +51 -50
  23. package/dist/shared/{unplugin.Dqt1aLCX.mjs → unplugin.Dg1tGPSd.mjs} +5 -3
  24. package/dist/shared/{unplugin.Rov-j_Wm.cjs → unplugin.DmuOKVS4.cjs} +21 -0
  25. package/dist/shared/{unplugin.ByAzFdqO.cjs → unplugin.DtPQz8Kg.cjs} +1072 -754
  26. package/dist/shared/{unplugin.CtHwCYxE.mjs → unplugin.DtYxS8M8.mjs} +1071 -754
  27. package/dist/shared/{unplugin.VSslRpfN.mjs → unplugin.Rl8sIkHi.mjs} +51 -50
  28. package/dist/shared/unplugin.TtmP77BS.mjs +40 -0
  29. package/dist/shared/unplugin.nnsa7OVW.mjs +49 -0
  30. package/dist/vite.cjs +4 -4
  31. package/dist/vite.d.cts +2 -25
  32. package/dist/vite.d.mts +1 -25
  33. package/dist/vite.mjs +4 -8
  34. package/dist/webpack.cjs +4 -4
  35. package/dist/webpack.d.cts +2 -5
  36. package/dist/webpack.d.mts +1 -5
  37. package/dist/webpack.mjs +4 -8
  38. package/package.json +7 -7
  39. package/dist/shared/unplugin.B1mblcm-.mjs +0 -9
  40. package/dist/shared/unplugin.B3RHYokB.mjs +0 -29
  41. package/dist/shared/unplugin.BCwRIUs_.cjs +0 -12
@@ -6,7 +6,7 @@ import * as path from 'node:path';
6
6
  import { dirname } from 'node:path';
7
7
  import { performance } from 'node:perf_hooks';
8
8
  import { fileURLToPath } from 'node:url';
9
- import { scanGlobalVarUsages, sortStrings as sortStrings$1, ensureRustTransformAvailable, transformSourceCode, transformRust, transformOxc, transformRustBatch, ASTBudgetExceededError, transform, isRustTransformAvailable } from '@csszyx/compiler';
9
+ import { scanGlobalVarUsages, sortStrings as sortStrings$1, ensureRustTransformAvailable, transformSourceCode, transformRust, transformOxc, ASTBudgetExceededError, transformRustBatch, transform, isRustTransformAvailable } from '@csszyx/compiler';
10
10
  import { encode, compute_mangle_checksum } from '@csszyx/core';
11
11
  import { getNativePackageName } from '@csszyx/core/native';
12
12
  import { preprocess as preprocess$1 } from '@csszyx/svelte-adapter';
@@ -14,9 +14,9 @@ import { isTailwindReservedCustomProperty, CSSZYX_GLOBAL_ALIAS_PREFIX, isCsszyxG
14
14
  import { preprocess } from '@csszyx/vue-adapter';
15
15
  import { createUnplugin } from 'unplugin';
16
16
  import { mangleCSSSync } from '../css-mangler.mjs';
17
- import { s as sortStrings, e as escapeHtmlAttribute } from './unplugin.B1mblcm-.mjs';
18
- import { i as importsRuntimeHelper, f as findRuntimeImportClause } from './unplugin.B3RHYokB.mjs';
19
- import { r as resolveTransformCacheDir, c as createTransformCacheKey, a as readTransformCache, w as writeTransformCache, e as evictOldTransformCacheEntries, b as evictMemoryCacheToBudget } from './unplugin.CwcOd1q3.mjs';
17
+ import { i as importsRuntimeHelper, f as findRuntimeImportClause, a as insertAfterUseDirective } from './unplugin.nnsa7OVW.mjs';
18
+ import { n as normalizePathSeparators, r as resolveTransformCacheDir, c as createTransformCacheKey, w as writeTransformCache, e as evictOldTransformCacheEntries, a as readTransformCache, b as evictMemoryCacheToBudget } from './unplugin.D-K57LNR.mjs';
19
+ import { s as sortStrings, a as replaceEveryLiteral, u as unicodeEscape, b as escapeDoubleQuotedString, c as escapeSingleQuotedString, e as escapeHtmlAttribute, r as renderTailwindScannerCandidates } from './unplugin.TtmP77BS.mjs';
20
20
  import postcss from 'postcss';
21
21
  import valueParser from 'postcss-value-parser';
22
22
 
@@ -96,7 +96,8 @@ function buildScopeId(node) {
96
96
  }
97
97
  current = current.parent;
98
98
  }
99
- return parts.reverse().join(" > ") || DEFAULT_SCOPE_ID;
99
+ parts.reverse();
100
+ return parts.join(" > ") || DEFAULT_SCOPE_ID;
100
101
  }
101
102
 
102
103
  const VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
@@ -369,7 +370,7 @@ function rewriteGlobalVarValue(value, aliases) {
369
370
  return;
370
371
  }
371
372
  const firstArgument = node.nodes.find((child) => child.type !== "space");
372
- if (!firstArgument || firstArgument.type !== "word") {
373
+ if (firstArgument?.type !== "word") {
373
374
  return;
374
375
  }
375
376
  const alias = aliases.get(firstArgument.value);
@@ -519,8 +520,8 @@ function createRSCModuleRecord(code, id) {
519
520
  }
520
521
  function deleteRSCModuleRecord(records, id) {
521
522
  const normalized = normalizeModuleId(id);
522
- const clean = id.split("?")[0]?.replace(/\\/g, "/") ?? id;
523
- const resolved = path.resolve(clean).replace(/\\/g, "/");
523
+ const clean = normalizePathSeparators(id.split("?")[0] ?? id);
524
+ const resolved = normalizePathSeparators(path.resolve(clean));
524
525
  pruneRSCModulePathCaches(/* @__PURE__ */ new Set([normalized, resolved, clean]));
525
526
  let deleted = records.delete(normalized);
526
527
  if (resolved !== normalized) {
@@ -566,7 +567,7 @@ const APP_ROUTER_ENTRIES = /* @__PURE__ */ new Set([
566
567
  "route"
567
568
  ]);
568
569
  function isNextAppRouterEntry(id) {
569
- const clean = id.split("?")[0]?.replace(/\\/g, "/") ?? id;
570
+ const clean = normalizePathSeparators(id.split("?")[0] ?? id);
570
571
  if (!clean.includes("/app/") && !clean.startsWith("app/")) return false;
571
572
  const basename = clean.split("/").pop() ?? "";
572
573
  const dotIdx = basename.indexOf(".");
@@ -638,7 +639,7 @@ function findDirectiveStatementEnd(code, start) {
638
639
  }
639
640
  function readDirectivePrologue(code) {
640
641
  const out = [];
641
- let i = code.charCodeAt(0) === 65279 ? 1 : 0;
642
+ let i = readCodePoint(code, 0) === 65279 ? 1 : 0;
642
643
  while (i < code.length) {
643
644
  i = skipWhitespaceAndComments(code, i);
644
645
  const quote = code[i];
@@ -705,55 +706,50 @@ function findStaticImports(code) {
705
706
  let cursor = 0;
706
707
  while (cursor < code.length) {
707
708
  const importStart = code.indexOf("import", cursor);
708
- if (importStart === -1) {
709
- break;
710
- }
711
- cursor = importStart + 6;
712
- if (importStart > 0 && isIdentifierPart(code.charCodeAt(importStart - 1)) || isIdentifierPart(code.charCodeAt(cursor))) {
713
- continue;
714
- }
715
- let position = skipAsciiWhitespace(code, cursor);
716
- const opener = code.charAt(position);
717
- if (opener === "(") {
718
- continue;
719
- }
720
- if (opener === '"' || opener === "'") {
721
- const literal2 = readQuotedString(code, position);
722
- if (literal2) {
723
- imports.push({ clause: null, source: literal2.value });
724
- cursor = literal2.end;
725
- }
726
- continue;
727
- }
728
- const clauseStart = position;
729
- let fromStart = -1;
730
- while (position < code.length) {
731
- if (code.startsWith("from", position) && (position === clauseStart || !isIdentifierPart(code.charCodeAt(position - 1))) && !isIdentifierPart(code.charCodeAt(position + 4))) {
732
- fromStart = position;
733
- break;
734
- }
735
- if (code.charAt(position) === ";") {
736
- break;
737
- }
738
- position += 1;
739
- }
740
- if (fromStart === -1) {
741
- continue;
742
- }
743
- const clause = code.slice(clauseStart, fromStart).trim();
744
- if (splitAsciiWhitespace(clause)[0] === "type") {
745
- cursor = fromStart + 4;
746
- continue;
747
- }
748
- position = skipAsciiWhitespace(code, fromStart + 4);
749
- const literal = readQuotedString(code, position);
750
- if (literal) {
751
- imports.push({ clause, source: literal.value });
752
- cursor = literal.end;
753
- }
709
+ if (importStart === -1) break;
710
+ const result = scanStaticImport(code, importStart);
711
+ cursor = result.nextCursor;
712
+ if (result.value) imports.push(result.value);
754
713
  }
755
714
  return imports;
756
715
  }
716
+ function scanStaticImport(code, importStart) {
717
+ const afterKeyword = importStart + 6;
718
+ if (importStart > 0 && isIdentifierPart(readCodePoint(code, importStart - 1)) || isIdentifierPart(readCodePoint(code, afterKeyword))) {
719
+ return { nextCursor: afterKeyword };
720
+ }
721
+ const clauseStart = skipAsciiWhitespace(code, afterKeyword);
722
+ const opener = code.charAt(clauseStart);
723
+ if (opener === "(") return { nextCursor: afterKeyword };
724
+ if (opener === '"' || opener === "'") {
725
+ return scanSideEffectImport(code, clauseStart, afterKeyword);
726
+ }
727
+ return scanImportClause(code, clauseStart, afterKeyword);
728
+ }
729
+ function scanSideEffectImport(code, literalStart, fallbackCursor) {
730
+ const literal = readQuotedString(code, literalStart);
731
+ return literal ? { nextCursor: literal.end, value: { clause: null, source: literal.value } } : { nextCursor: fallbackCursor };
732
+ }
733
+ function scanImportClause(code, clauseStart, fallbackCursor) {
734
+ const fromStart = findImportFromKeyword(code, clauseStart);
735
+ if (fromStart === -1) return { nextCursor: fallbackCursor };
736
+ const clause = code.slice(clauseStart, fromStart).trim();
737
+ if (splitAsciiWhitespace(clause)[0] === "type") {
738
+ return { nextCursor: fromStart + 4 };
739
+ }
740
+ const literalStart = skipAsciiWhitespace(code, fromStart + 4);
741
+ const literal = readQuotedString(code, literalStart);
742
+ return literal ? { nextCursor: literal.end, value: { clause, source: literal.value } } : { nextCursor: fallbackCursor };
743
+ }
744
+ function findImportFromKeyword(code, clauseStart) {
745
+ for (let position = clauseStart; position < code.length; position += 1) {
746
+ if (code.charAt(position) === ";") return -1;
747
+ if (code.startsWith("from", position) && (position === clauseStart || !isIdentifierPart(readCodePoint(code, position - 1))) && !isIdentifierPart(readCodePoint(code, position + 4))) {
748
+ return position;
749
+ }
750
+ }
751
+ return -1;
752
+ }
757
753
  function readQuotedString(code, start) {
758
754
  const quote = code.charAt(start);
759
755
  if (quote !== '"' && quote !== "'") {
@@ -781,7 +777,7 @@ function readQuotedString(code, start) {
781
777
  function skipAsciiWhitespace(code, start) {
782
778
  let index = start;
783
779
  while (index < code.length) {
784
- const charCode = code.charCodeAt(index);
780
+ const charCode = readCodePoint(code, index);
785
781
  if (charCode !== 9 && charCode !== 10 && charCode !== 13 && charCode !== 32) {
786
782
  break;
787
783
  }
@@ -926,9 +922,9 @@ function normalizeModuleId(id) {
926
922
  }
927
923
  let normalized;
928
924
  try {
929
- normalized = fs.realpathSync.native(clean).replace(/\\/g, "/");
925
+ normalized = normalizePathSeparators(fs.realpathSync.native(clean));
930
926
  } catch {
931
- normalized = path.resolve(clean).replace(/\\/g, "/");
927
+ normalized = normalizePathSeparators(path.resolve(clean));
932
928
  }
933
929
  normalizedModuleIdCache.set(clean, normalized);
934
930
  return normalized;
@@ -974,7 +970,7 @@ function resolveLocalModule(importer, source) {
974
970
  }
975
971
  function pruneRSCModulePathCaches(moduleIds) {
976
972
  for (const [key, value] of normalizedModuleIdCache) {
977
- const normalizedKey = key.replace(/\\/g, "/");
973
+ const normalizedKey = normalizePathSeparators(key);
978
974
  if (moduleIds.has(value) || moduleIds.has(normalizedKey)) {
979
975
  normalizedModuleIdCache.delete(key);
980
976
  }
@@ -1018,11 +1014,11 @@ function readImportedSymbols(clause) {
1018
1014
  return symbols;
1019
1015
  }
1020
1016
  function isIdentifier(value) {
1021
- if (value.length === 0 || !isIdentifierStart(value.charCodeAt(0))) {
1017
+ if (value.length === 0 || !isIdentifierStart(readCodePoint(value, 0))) {
1022
1018
  return false;
1023
1019
  }
1024
1020
  for (let index = 1; index < value.length; index += 1) {
1025
- const code = value.charCodeAt(index);
1021
+ const code = readCodePoint(value, index);
1026
1022
  if (!isIdentifierStart(code) && (code < 48 || code > 57)) {
1027
1023
  return false;
1028
1024
  }
@@ -1032,11 +1028,14 @@ function isIdentifier(value) {
1032
1028
  function isIdentifierStart(code) {
1033
1029
  return code === 36 || code === 95 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
1034
1030
  }
1031
+ function readCodePoint(value, index) {
1032
+ return value.codePointAt(index) ?? -1;
1033
+ }
1035
1034
  function splitAsciiWhitespace(value) {
1036
1035
  const parts = [];
1037
1036
  let start = -1;
1038
1037
  for (let index = 0; index <= value.length; index += 1) {
1039
- const code = index < value.length ? value.charCodeAt(index) : 32;
1038
+ const code = index < value.length ? readCodePoint(value, index) : 32;
1040
1039
  const whitespace = code === 9 || code === 10 || code === 13 || code === 32;
1041
1040
  if (whitespace) {
1042
1041
  if (start !== -1) {
@@ -1059,13 +1058,7 @@ function stripCommentsForImportScan(code) {
1059
1058
  const next = code[i + 1];
1060
1059
  if (quote) {
1061
1060
  out += ch;
1062
- if (escaped) {
1063
- escaped = false;
1064
- } else if (ch === "\\") {
1065
- escaped = true;
1066
- } else if (ch === quote) {
1067
- quote = null;
1068
- }
1061
+ ({ quote, escaped } = advanceQuotedImportScan(ch, quote, escaped));
1069
1062
  i++;
1070
1063
  continue;
1071
1064
  }
@@ -1076,28 +1069,15 @@ function stripCommentsForImportScan(code) {
1076
1069
  continue;
1077
1070
  }
1078
1071
  if (ch === "/" && next === "/") {
1079
- out += " ";
1080
- i += 2;
1081
- while (i < code.length && code[i] !== "\n") {
1082
- out += " ";
1083
- i++;
1084
- }
1072
+ const masked = maskLineComment(code, i);
1073
+ out += masked.value;
1074
+ i = masked.end;
1085
1075
  continue;
1086
1076
  }
1087
1077
  if (ch === "/" && next === "*") {
1088
- out += " ";
1089
- i += 2;
1090
- while (i < code.length) {
1091
- const blockCh = code[i];
1092
- const blockNext = code[i + 1];
1093
- if (blockCh === "*" && blockNext === "/") {
1094
- out += " ";
1095
- i += 2;
1096
- break;
1097
- }
1098
- out += blockCh === "\n" ? "\n" : " ";
1099
- i++;
1100
- }
1078
+ const masked = maskBlockComment(code, i);
1079
+ out += masked.value;
1080
+ i = masked.end;
1101
1081
  continue;
1102
1082
  }
1103
1083
  out += ch;
@@ -1105,6 +1085,31 @@ function stripCommentsForImportScan(code) {
1105
1085
  }
1106
1086
  return out;
1107
1087
  }
1088
+ function advanceQuotedImportScan(character, quote, escaped) {
1089
+ if (escaped) return { quote, escaped: false };
1090
+ if (character === "\\") return { quote, escaped: true };
1091
+ return { quote: character === quote ? null : quote, escaped: false };
1092
+ }
1093
+ function maskLineComment(code, start) {
1094
+ const newline = code.indexOf("\n", start + 2);
1095
+ const end = newline === -1 ? code.length : newline;
1096
+ return { end, value: " ".repeat(end - start) };
1097
+ }
1098
+ function maskBlockComment(code, start) {
1099
+ let end = start + 2;
1100
+ while (end < code.length) {
1101
+ if (code.charAt(end) === "*" && code.charAt(end + 1) === "/") {
1102
+ end += 2;
1103
+ break;
1104
+ }
1105
+ end += 1;
1106
+ }
1107
+ let value = "";
1108
+ for (let index = start; index < end; index += 1) {
1109
+ value += code.charAt(index) === "\n" ? "\n" : " ";
1110
+ }
1111
+ return { end, value };
1112
+ }
1108
1113
 
1109
1114
  const EMPTY_THEME = {
1110
1115
  colors: [],
@@ -1308,13 +1313,376 @@ function scanCustomPropertyNames(block) {
1308
1313
  return names;
1309
1314
  }
1310
1315
 
1316
+ const REGEX_PREFIXES = new Set("([{:,;=!?&|+-*%^~<>/");
1317
+ const REGEX_PREFIX_KEYWORDS = /* @__PURE__ */ new Set([
1318
+ "await",
1319
+ "case",
1320
+ "delete",
1321
+ "do",
1322
+ "else",
1323
+ "in",
1324
+ "instanceof",
1325
+ "of",
1326
+ "return",
1327
+ "throw",
1328
+ "typeof",
1329
+ "void",
1330
+ "yield"
1331
+ ]);
1332
+ const SIMPLE_ESCAPES = {
1333
+ b: "\b",
1334
+ f: "\f",
1335
+ n: "\n",
1336
+ r: "\r",
1337
+ t: " ",
1338
+ v: "\v",
1339
+ "0": "\0"
1340
+ };
1341
+ function isFixedHex(value, width) {
1342
+ if (value.length !== width) return false;
1343
+ for (const character of value) {
1344
+ if (!"0123456789abcdefABCDEF".includes(character)) return false;
1345
+ }
1346
+ return true;
1347
+ }
1348
+ function decodeEscape(value, cursor) {
1349
+ const escaped = value[cursor];
1350
+ if (SIMPLE_ESCAPES[escaped] !== void 0) {
1351
+ return { value: SIMPLE_ESCAPES[escaped], cursor };
1352
+ }
1353
+ if (escaped === "\r" && value[cursor + 1] === "\n") {
1354
+ return { value: "", cursor: cursor + 1 };
1355
+ }
1356
+ if (escaped === "u" && value[cursor + 1] === "{") {
1357
+ const close = value.indexOf("}", cursor + 2);
1358
+ const hex2 = close === -1 ? "" : value.slice(cursor + 2, close);
1359
+ const codePoint = hex2 && /^[\dA-F]+$/i.test(hex2) ? Number.parseInt(hex2, 16) : -1;
1360
+ if (codePoint >= 0 && codePoint <= 1114111) {
1361
+ return { value: String.fromCodePoint(codePoint), cursor: close };
1362
+ }
1363
+ }
1364
+ let width = 0;
1365
+ if (escaped === "x") width = 2;
1366
+ else if (escaped === "u") width = 4;
1367
+ const hex = value.slice(cursor + 1, cursor + width + 1);
1368
+ if (width > 0 && isFixedHex(hex, width)) {
1369
+ return {
1370
+ value: String.fromCodePoint(Number.parseInt(hex, 16)),
1371
+ cursor: cursor + width
1372
+ };
1373
+ }
1374
+ const decoded = escaped === "\n" || escaped === "\r" ? "" : escaped;
1375
+ return { value: decoded, cursor };
1376
+ }
1377
+ function decodeJavaScriptString(value) {
1378
+ let output = "";
1379
+ let cursor = 0;
1380
+ while (cursor < value.length) {
1381
+ if (value[cursor] !== "\\" || cursor + 1 >= value.length) {
1382
+ output += value[cursor++];
1383
+ continue;
1384
+ }
1385
+ const decoded = decodeEscape(value, cursor + 1);
1386
+ output += decoded.value;
1387
+ cursor = decoded.cursor + 1;
1388
+ }
1389
+ return output;
1390
+ }
1391
+ function decodeAttributeWhitespace(value) {
1392
+ return value.replace(
1393
+ /&#(?:(\d+)|x([\da-f]+));|&(?:Tab|NewLine);/gi,
1394
+ (entity, decimal, hexadecimal) => {
1395
+ if (!decimal && !hexadecimal) return " ";
1396
+ const codePoint = Number.parseInt(decimal ?? hexadecimal ?? "", decimal ? 10 : 16);
1397
+ return [9, 10, 12, 13, 32].includes(codePoint) ? " " : entity;
1398
+ }
1399
+ );
1400
+ }
1401
+ function collectClassTokens(target, value) {
1402
+ for (const className of value.split(/\s+/)) {
1403
+ if (className) target.add(className);
1404
+ }
1405
+ }
1406
+ function quotedEnd(source, start, quote) {
1407
+ let cursor = start + 1;
1408
+ while (cursor < source.length) {
1409
+ if (source[cursor] === "\\") cursor += 2;
1410
+ else if (source[cursor++] === quote) break;
1411
+ }
1412
+ return cursor;
1413
+ }
1414
+ function commentEnd(source, start) {
1415
+ if (source[start + 1] === "/") {
1416
+ const end2 = source.indexOf("\n", start + 2);
1417
+ return end2 === -1 ? source.length : end2 + 1;
1418
+ }
1419
+ const end = source.indexOf("*/", start + 2);
1420
+ return end === -1 ? source.length : end + 2;
1421
+ }
1422
+ function isRegexStart(source, start) {
1423
+ let cursor = start - 1;
1424
+ while (cursor >= 0 && /\s/.test(source[cursor])) cursor--;
1425
+ if (source[cursor] === "<" && /[A-Z]/i.test(source[start + 1] ?? "")) return false;
1426
+ if (cursor < 0 || REGEX_PREFIXES.has(source[cursor])) return true;
1427
+ if (!/[\w$]/.test(source[cursor])) return false;
1428
+ const end = cursor + 1;
1429
+ while (cursor >= 0 && /[\w$]/.test(source[cursor])) cursor--;
1430
+ return REGEX_PREFIX_KEYWORDS.has(source.slice(cursor + 1, end));
1431
+ }
1432
+ function regexEnd(source, start) {
1433
+ let cursor = start + 1;
1434
+ let inCharacterClass = false;
1435
+ while (cursor < source.length) {
1436
+ const character = source[cursor];
1437
+ if (character === "\\") cursor += 2;
1438
+ else if (character === "[") {
1439
+ inCharacterClass = true;
1440
+ cursor++;
1441
+ } else if (character === "]") {
1442
+ inCharacterClass = false;
1443
+ cursor++;
1444
+ } else if (character === "/" && !inCharacterClass) {
1445
+ cursor++;
1446
+ while (/[A-Z]/i.test(source[cursor] ?? "")) cursor++;
1447
+ break;
1448
+ } else cursor++;
1449
+ }
1450
+ return cursor;
1451
+ }
1452
+ function templateEnd(source, start) {
1453
+ let cursor = start + 1;
1454
+ while (cursor < source.length) {
1455
+ if (source[cursor] === "\\") cursor += 2;
1456
+ else if (source[cursor] === "`") return cursor + 1;
1457
+ else if (source[cursor] === "$" && source[cursor + 1] === "{") {
1458
+ cursor = findBalancedCodeEnd(source, cursor + 2);
1459
+ } else cursor++;
1460
+ }
1461
+ return source.length;
1462
+ }
1463
+ function lexicalRegionEnd(source, start) {
1464
+ const character = source[start];
1465
+ if (character === '"' || character === "'") return quotedEnd(source, start, character);
1466
+ if (character === "`") return templateEnd(source, start);
1467
+ if (character === "/" && (source[start + 1] === "/" || source[start + 1] === "*")) {
1468
+ return commentEnd(source, start);
1469
+ }
1470
+ if (character === "/" && isRegexStart(source, start)) return regexEnd(source, start);
1471
+ return start;
1472
+ }
1473
+ function findBalancedCodeEnd(source, bodyStart) {
1474
+ let depth = 1;
1475
+ let cursor = bodyStart;
1476
+ while (cursor < source.length) {
1477
+ const regionEnd = lexicalRegionEnd(source, cursor);
1478
+ if (regionEnd !== cursor) {
1479
+ cursor = regionEnd;
1480
+ continue;
1481
+ }
1482
+ if (source[cursor] === "{") depth++;
1483
+ else if (source[cursor] === "}" && --depth === 0) return cursor;
1484
+ cursor++;
1485
+ }
1486
+ return source.length;
1487
+ }
1488
+ function collectTemplateTokens(target, source, start) {
1489
+ let cursor = start + 1;
1490
+ let quasiStart = cursor;
1491
+ while (cursor < source.length) {
1492
+ if (source[cursor] === "\\") {
1493
+ cursor += 2;
1494
+ continue;
1495
+ }
1496
+ if (source[cursor] === "`") {
1497
+ collectClassTokens(target, decodeJavaScriptString(source.slice(quasiStart, cursor)));
1498
+ return cursor + 1;
1499
+ }
1500
+ if (source[cursor] === "$" && source[cursor + 1] === "{") {
1501
+ collectClassTokens(target, decodeJavaScriptString(source.slice(quasiStart, cursor)));
1502
+ const expressionEnd = findBalancedCodeEnd(source, cursor + 2);
1503
+ collectExpressionTokens(target, source.slice(cursor + 2, expressionEnd));
1504
+ cursor = expressionEnd + 1;
1505
+ quasiStart = cursor;
1506
+ continue;
1507
+ }
1508
+ cursor++;
1509
+ }
1510
+ collectClassTokens(target, decodeJavaScriptString(source.slice(quasiStart)));
1511
+ return source.length;
1512
+ }
1513
+ function collectExpressionTokens(target, expression) {
1514
+ let cursor = 0;
1515
+ let pendingLiteral = "";
1516
+ let previousLiteralEnd = -1;
1517
+ const flushPending = () => {
1518
+ if (pendingLiteral) collectClassTokens(target, pendingLiteral);
1519
+ pendingLiteral = "";
1520
+ };
1521
+ while (cursor < expression.length) {
1522
+ const character = expression[cursor];
1523
+ if (character === "/" && (expression[cursor + 1] === "/" || expression[cursor + 1] === "*")) {
1524
+ cursor = commentEnd(expression, cursor);
1525
+ continue;
1526
+ }
1527
+ if (character === "/" && isRegexStart(expression, cursor)) {
1528
+ cursor = regexEnd(expression, cursor);
1529
+ continue;
1530
+ }
1531
+ if (character === "`") {
1532
+ flushPending();
1533
+ cursor = collectTemplateTokens(target, expression, cursor);
1534
+ previousLiteralEnd = -1;
1535
+ continue;
1536
+ }
1537
+ if (character !== '"' && character !== "'") {
1538
+ cursor++;
1539
+ continue;
1540
+ }
1541
+ const end = quotedEnd(expression, cursor, character);
1542
+ const decoded = decodeJavaScriptString(expression.slice(cursor + 1, end - 1));
1543
+ const joinsPrevious = previousLiteralEnd >= 0 && expression.slice(previousLiteralEnd, cursor).trim() === "+";
1544
+ if (!joinsPrevious) flushPending();
1545
+ pendingLiteral += decoded;
1546
+ previousLiteralEnd = end;
1547
+ cursor = end;
1548
+ }
1549
+ flushPending();
1550
+ }
1551
+ function triviaEnd(source, start) {
1552
+ let cursor = start;
1553
+ while (cursor < source.length) {
1554
+ if (/\s/.test(source[cursor])) cursor++;
1555
+ else if (source[cursor] === "/" && (source[cursor + 1] === "/" || source[cursor + 1] === "*")) {
1556
+ cursor = commentEnd(source, cursor);
1557
+ } else break;
1558
+ }
1559
+ return cursor;
1560
+ }
1561
+ function propertyExpressionEnd(source, start) {
1562
+ let cursor = start;
1563
+ let parenDepth = 0;
1564
+ let bracketDepth = 0;
1565
+ let braceDepth = 0;
1566
+ while (cursor < source.length) {
1567
+ const regionEnd = lexicalRegionEnd(source, cursor);
1568
+ if (regionEnd !== cursor) {
1569
+ cursor = regionEnd;
1570
+ continue;
1571
+ }
1572
+ const character = source[cursor];
1573
+ if (character === "(") parenDepth++;
1574
+ else if (character === ")") parenDepth--;
1575
+ else if (character === "[") bracketDepth++;
1576
+ else if (character === "]") bracketDepth--;
1577
+ else if (character === "{") braceDepth++;
1578
+ else if (character === "}" && braceDepth > 0) braceDepth--;
1579
+ else if ((character === "," || character === ";" || character === "}") && parenDepth === 0 && bracketDepth === 0 && braceDepth === 0)
1580
+ return cursor;
1581
+ cursor++;
1582
+ }
1583
+ return source.length;
1584
+ }
1585
+ function isClassSink(source, start, end) {
1586
+ const name = source.slice(start, end);
1587
+ if (name !== "class" && name !== "className") return false;
1588
+ let previous = start - 1;
1589
+ while (previous >= 0 && /\s/.test(source[previous])) previous--;
1590
+ return source[previous] !== "." && source[previous] !== "-";
1591
+ }
1592
+ function collectClassDirective(target, source, sinkStart, valueStart) {
1593
+ if (!/[\w$-]/.test(source[valueStart] ?? "")) return null;
1594
+ let directiveEnd = valueStart;
1595
+ while (/[\w$-]/.test(source[directiveEnd] ?? "")) directiveEnd++;
1596
+ const equals = triviaEnd(source, directiveEnd);
1597
+ if (source[equals] !== "=") {
1598
+ const insideMarkupTag = source.lastIndexOf("<", sinkStart) > source.lastIndexOf(">", sinkStart);
1599
+ const next = source[equals] ?? "";
1600
+ const continuesMarkupTag = next === "/" || next === ">" || next === "{" || /[A-Z_:]/i.test(next);
1601
+ if (!insideMarkupTag || !continuesMarkupTag) return null;
1602
+ collectClassTokens(target, source.slice(valueStart, directiveEnd));
1603
+ return directiveEnd;
1604
+ }
1605
+ const directive = source.slice(valueStart, directiveEnd);
1606
+ const directiveValueStart = triviaEnd(source, equals + 1);
1607
+ const directiveQuote = source[directiveValueStart];
1608
+ if (directive !== "list") collectClassTokens(target, directive);
1609
+ if (directiveQuote === "{") {
1610
+ const end = findBalancedCodeEnd(source, directiveValueStart + 1);
1611
+ if (directive === "list") {
1612
+ collectExpressionTokens(target, source.slice(directiveValueStart + 1, end));
1613
+ }
1614
+ return end + 1;
1615
+ }
1616
+ if (directive === "list" && (directiveQuote === '"' || directiveQuote === "'")) {
1617
+ const end = quotedEnd(source, directiveValueStart, directiveQuote);
1618
+ collectExpressionTokens(target, source.slice(directiveValueStart, end));
1619
+ return end;
1620
+ }
1621
+ return directiveValueStart;
1622
+ }
1623
+ function collectClassSink(target, source, start, nameEnd) {
1624
+ const operatorStart = triviaEnd(source, nameEnd);
1625
+ const operator = source[operatorStart];
1626
+ if (operator !== "=" && operator !== ":") return nameEnd;
1627
+ const valueStart = triviaEnd(source, operatorStart + 1);
1628
+ const quote = source[valueStart];
1629
+ const vueBinding = operator === "=" && source.slice(Math.max(0, start - 1), start) === ":";
1630
+ if (operator === ":" && valueStart === operatorStart + 1) {
1631
+ const directiveEnd = collectClassDirective(target, source, start, valueStart);
1632
+ if (directiveEnd !== null) return directiveEnd;
1633
+ }
1634
+ if (quote === '"' || quote === "'") {
1635
+ const end = quotedEnd(source, valueStart, quote);
1636
+ const value = source.slice(valueStart + 1, end - 1);
1637
+ if (vueBinding) collectExpressionTokens(target, decodeAttributeWhitespace(value));
1638
+ else collectClassTokens(target, decodeAttributeWhitespace(value));
1639
+ return end;
1640
+ }
1641
+ if (operator === "=" && quote === "{") {
1642
+ const end = findBalancedCodeEnd(source, valueStart + 1);
1643
+ collectExpressionTokens(target, source.slice(valueStart + 1, end));
1644
+ return end + 1;
1645
+ }
1646
+ if (operator === ":") {
1647
+ const end = propertyExpressionEnd(source, valueStart);
1648
+ collectExpressionTokens(target, source.slice(valueStart, end));
1649
+ return end;
1650
+ }
1651
+ return valueStart;
1652
+ }
1653
+ function collectAuthoredClassNames(source) {
1654
+ const classes = /* @__PURE__ */ new Set();
1655
+ let cursor = 0;
1656
+ while (cursor < source.length) {
1657
+ if (source[cursor] === '"' || source[cursor] === "'") {
1658
+ const keyEnd = quotedEnd(source, cursor, source[cursor]);
1659
+ const key = decodeJavaScriptString(source.slice(cursor + 1, keyEnd - 1));
1660
+ cursor = key === "class" || key === "className" ? collectClassSink(classes, source, cursor, keyEnd) : keyEnd;
1661
+ continue;
1662
+ }
1663
+ const regionEnd = lexicalRegionEnd(source, cursor);
1664
+ if (regionEnd !== cursor) {
1665
+ cursor = regionEnd;
1666
+ continue;
1667
+ }
1668
+ if (!/[A-Z_$]/i.test(source[cursor])) {
1669
+ cursor++;
1670
+ continue;
1671
+ }
1672
+ let nameEnd = cursor + 1;
1673
+ while (/[\w$]/.test(source[nameEnd] ?? "")) nameEnd++;
1674
+ cursor = isClassSink(source, cursor, nameEnd) ? collectClassSink(classes, source, cursor, nameEnd) : nameEnd;
1675
+ }
1676
+ return classes;
1677
+ }
1678
+
1311
1679
  const GLOB_MAGIC_RE = /[*?[\]{}]/;
1312
1680
  const DEFAULT_IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", ".turbo", "dist", "build"]);
1313
1681
  function normalizeFileId(id) {
1314
- return id.split(/[?#]/, 1)[0].replace(/\\/g, "/");
1682
+ return normalizePathSeparators(id.split(/[?#]/, 1)[0]);
1315
1683
  }
1316
1684
  function normalizeRoot(rootDir) {
1317
- return path.resolve(rootDir).replace(/\\/g, "/");
1685
+ return normalizePathSeparators(path.resolve(rootDir));
1318
1686
  }
1319
1687
  function hasGlobMagic(pattern) {
1320
1688
  return GLOB_MAGIC_RE.test(pattern);
@@ -1323,7 +1691,7 @@ function escapeRegExp(ch) {
1323
1691
  return /[|\\{}()[\]^$+?.]/.test(ch) ? `\\${ch}` : ch;
1324
1692
  }
1325
1693
  function globToRegExp(pattern) {
1326
- const normalized = pattern.replace(/\\/g, "/");
1694
+ const normalized = normalizePathSeparators(pattern);
1327
1695
  let out = "^";
1328
1696
  for (let i = 0; i < normalized.length; i++) {
1329
1697
  const ch = normalized[i];
@@ -1346,7 +1714,7 @@ function globToRegExp(pattern) {
1346
1714
  function relativeToRoot(file, rootDir) {
1347
1715
  const root = normalizeRoot(rootDir);
1348
1716
  const normalizedFile = normalizeFileId(file);
1349
- return path.posix.relative(root, normalizedFile).replace(/\\/g, "/");
1717
+ return normalizePathSeparators(path.posix.relative(root, normalizedFile));
1350
1718
  }
1351
1719
  function matchesPattern(id, pattern, rootDir) {
1352
1720
  const file = normalizeFileId(id);
@@ -1355,7 +1723,7 @@ function matchesPattern(id, pattern, rootDir) {
1355
1723
  pattern.lastIndex = 0;
1356
1724
  return pattern.test(file) || pattern.test(relative);
1357
1725
  }
1358
- const normalizedPattern = pattern.replace(/\\/g, "/");
1726
+ const normalizedPattern = normalizePathSeparators(pattern);
1359
1727
  if (hasGlobMagic(normalizedPattern)) {
1360
1728
  const re = globToRegExp(normalizedPattern);
1361
1729
  return re.test(file) || re.test(relative);
@@ -1422,9 +1790,15 @@ function expandFilePatterns(rootDir, patterns) {
1422
1790
  return sortStrings(files);
1423
1791
  }
1424
1792
 
1793
+ const LINE_SEPARATOR$1 = String.fromCodePoint(8232);
1794
+ const PARAGRAPH_SEPARATOR$1 = String.fromCodePoint(8233);
1425
1795
  function safeJsonForScriptTag(value, prettyPrint = false) {
1426
1796
  const json = prettyPrint ? JSON.stringify(value, null, 2) : JSON.stringify(value);
1427
- return json.replace(/</g, "\\u003C").replace(/>/g, "\\u003E").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1797
+ let escaped = replaceEveryLiteral(json, "<", unicodeEscape("003C"));
1798
+ escaped = replaceEveryLiteral(escaped, ">", unicodeEscape("003E"));
1799
+ escaped = replaceEveryLiteral(escaped, "&", unicodeEscape("0026"));
1800
+ escaped = replaceEveryLiteral(escaped, LINE_SEPARATOR$1, unicodeEscape("2028"));
1801
+ return replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR$1, unicodeEscape("2029"));
1428
1802
  }
1429
1803
  function injectHtmlOpeningAttr(html, attr) {
1430
1804
  const lower = html.toLowerCase();
@@ -1556,11 +1930,17 @@ function injectRecoveryManifest(html, manifest) {
1556
1930
  return html + scriptTag;
1557
1931
  }
1558
1932
 
1933
+ const LINE_SEPARATOR = String.fromCodePoint(8232);
1934
+ const PARAGRAPH_SEPARATOR = String.fromCodePoint(8233);
1559
1935
  function escapeJsonForInlineScript(json) {
1560
- return json.replace(/`/g, "\\u0060").replace(/\$/g, "\\u0024").replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1936
+ let escaped = replaceEveryLiteral(json, "`", unicodeEscape("0060"));
1937
+ escaped = replaceEveryLiteral(escaped, "$", unicodeEscape("0024"));
1938
+ escaped = replaceEveryLiteral(escaped, "<", unicodeEscape("003c"));
1939
+ escaped = replaceEveryLiteral(escaped, LINE_SEPARATOR, unicodeEscape("2028"));
1940
+ return replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR, unicodeEscape("2029"));
1561
1941
  }
1562
1942
  function escapeForDoubleQuotedString(value) {
1563
- return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
1943
+ return escapeDoubleQuotedString(value);
1564
1944
  }
1565
1945
 
1566
1946
  function isParserMode(value) {
@@ -1607,15 +1987,13 @@ function isSameFileVersion(before, after) {
1607
1987
  return before.dev === after.dev && before.ino === after.ino && before.size === after.size && before.mtimeNs === after.mtimeNs && before.ctimeNs === after.ctimeNs;
1608
1988
  }
1609
1989
 
1610
- function escapeTsString(value) {
1611
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
1612
- }
1613
1990
  function generateThemeDts(opts) {
1614
1991
  const { theme, sourceFiles } = opts;
1615
1992
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1616
- const sources = sourceFiles.join(", ").replace(/[\r\n]/g, " ");
1617
- const toUnion = (tokens) => tokens.map((t) => `'${escapeTsString(t)}'`).join(" | ");
1618
- const quoteKey = (key) => /^[a-z_$][\w$]*$/i.test(key) ? key : `'${escapeTsString(key)}'`;
1993
+ const withoutCarriageReturns = replaceEveryLiteral(sourceFiles.join(", "), "\r", " ");
1994
+ const sources = replaceEveryLiteral(withoutCarriageReturns, "\n", " ");
1995
+ const toUnion = (tokens) => tokens.map((t) => `'${escapeSingleQuotedString(t)}'`).join(" | ");
1996
+ const quoteKey = (key) => /^[a-z_$][\w$]*$/i.test(key) ? key : `'${escapeSingleQuotedString(key)}'`;
1619
1997
  const entries = [];
1620
1998
  if (theme.colors.length > 0) {
1621
1999
  entries.push(` colors: ${toUnion(theme.colors)};`);
@@ -1753,6 +2131,15 @@ function createThemeGroupsModule(tokens) {
1753
2131
  ].join("\n");
1754
2132
  }
1755
2133
 
2134
+ function registerWebpackAssetProcessor(compiler, processAssets) {
2135
+ compiler.hooks.compilation.tap("csszyx:post", (compilation) => {
2136
+ const stage = compiler.webpack?.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE || compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE;
2137
+ compilation.hooks.processAssets.tap(
2138
+ { name: "csszyx:post", stage: stage || 400 },
2139
+ (assets) => processAssets(assets, compilation, compiler)
2140
+ );
2141
+ });
2142
+ }
1756
2143
  const CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
1757
2144
  const MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
1758
2145
  const VAR_MANGLE_MAP_PLACEHOLDER = "___CSSZYX_VAR_MANGLE_MAP___";
@@ -1764,7 +2151,6 @@ const TRANSFORM_MEMORY_CACHE_MAX_CODE_CHARS = 32e6;
1764
2151
  const MAX_SAFELIST_CLASSES = 1e5;
1765
2152
  const DEFAULT_VAR_MANGLE_MAP_MAX_BYTES = 100 * 1024;
1766
2153
  const GLOBAL_VAR_ALIAS_MAP_OWNER = "\0csszyx:global-var-aliases";
1767
- const DIRECTIVE_PROLOGUE_PREFIX_RE = /^((?:\s|\/\/[^\n]*\n|\/\*(?:[^*]|\*(?!\/))*\*\/)*)(['"]use (?:client|server)['"];?\s*)/;
1768
2154
  function findOpeningTag(source, tag) {
1769
2155
  const lower = source.toLowerCase();
1770
2156
  const marker = `<${tag}`;
@@ -1837,10 +2223,10 @@ function stripCssBlockComments(code) {
1837
2223
  let i = 0;
1838
2224
  const n = code.length;
1839
2225
  while (i < n) {
1840
- if (code.charCodeAt(i) === SLASH && code.charCodeAt(i + 1) === STAR) {
2226
+ if (code.codePointAt(i) === SLASH && code.codePointAt(i + 1) === STAR) {
1841
2227
  out += code.slice(last, i);
1842
2228
  i += 2;
1843
- while (i < n && !(code.charCodeAt(i) === STAR && code.charCodeAt(i + 1) === SLASH)) {
2229
+ while (i < n && !(code.codePointAt(i) === STAR && code.codePointAt(i + 1) === SLASH)) {
1844
2230
  i++;
1845
2231
  }
1846
2232
  i += 2;
@@ -1946,9 +2332,17 @@ function shouldEmitWarning(quiet, devOnly, isProduction) {
1946
2332
  return true;
1947
2333
  }
1948
2334
  function normalizeForMatch(p) {
1949
- const n = p.replace(/\\/g, "/");
2335
+ const n = normalizePathSeparators(p);
1950
2336
  return n.length > 1 && n.endsWith("/") ? n.slice(0, -1) : n;
1951
2337
  }
2338
+ function findJsxExpressionEnd(code, bodyStart) {
2339
+ return findBalancedCodeEnd(code, bodyStart);
2340
+ }
2341
+ function warnPrescanBudgetSkip(filePath) {
2342
+ console.warn(
2343
+ `[csszyx] prescan skipped ${filePath}: the file exceeds the AST node budget, so NONE of its classes reached the safelist and their CSS will not be generated. Raise \`build.astBudgetLimit\` in the csszyx plugin options, or split the file.`
2344
+ );
2345
+ }
1952
2346
  function resolveCompileSourceDirs(root, sources, realpathDir = (p) => {
1953
2347
  try {
1954
2348
  const real = fs.realpathSync(p);
@@ -2001,6 +2395,9 @@ function fileMayContainSafelistableSz(content) {
2001
2395
  // engine-parity harness caught its classes missing on all engines.
2002
2396
  content.includes("dynamic(");
2003
2397
  }
2398
+ function mangleEligibleClasses(ownedClasses, authoredClasses) {
2399
+ return sortStrings$1([...ownedClasses].filter((className) => !authoredClasses.has(className)));
2400
+ }
2004
2401
  function isPackagesSkippedSource(id, sourceDirs = []) {
2005
2402
  const p = normalizeForMatch(id);
2006
2403
  if (p.includes("node_modules")) {
@@ -2021,8 +2418,8 @@ ${list}
2021
2418
  Add the package directory to \`compileSources\` (or move the file out of packages/) \u2014 otherwise their \`sz\` produces no CSS.`;
2022
2419
  }
2023
2420
  function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
2024
- const safelistPath = path.join(rootDir, safelistFilename).replace(/\\/g, "/");
2025
- const cssDir = path.dirname(cssId).replace(/\\/g, "/");
2421
+ const safelistPath = normalizePathSeparators(path.join(rootDir, safelistFilename));
2422
+ const cssDir = normalizePathSeparators(path.dirname(cssId));
2026
2423
  let relPath = path.posix.relative(cssDir, safelistPath);
2027
2424
  if (!relPath.startsWith(".")) {
2028
2425
  relPath = `./${relPath}`;
@@ -2196,7 +2593,10 @@ function normalizeGlobalVarAliasesForCache(aliases) {
2196
2593
  if (!aliases) {
2197
2594
  return [];
2198
2595
  }
2199
- const entries = aliases instanceof Map ? aliases.entries() : Array.isArray(aliases) ? aliases : Object.entries(aliases);
2596
+ let entries;
2597
+ if (aliases instanceof Map) entries = aliases.entries();
2598
+ else if (Array.isArray(aliases)) entries = aliases;
2599
+ else entries = Object.entries(aliases);
2200
2600
  const normalized = /* @__PURE__ */ new Map();
2201
2601
  for (const [original, alias] of entries) {
2202
2602
  if (original.startsWith("--") && alias.startsWith("--")) {
@@ -2401,7 +2801,7 @@ function findPackageVersionFromFile(file, fallback) {
2401
2801
  }
2402
2802
  }
2403
2803
  function normalizeSourceFilename(filename) {
2404
- return filename.replace(/\\/g, "/");
2804
+ return normalizePathSeparators(filename);
2405
2805
  }
2406
2806
  const SCRIPT_ID_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
2407
2807
  const SOURCE_MODULE_EXTENSIONS = [...SCRIPT_ID_EXTENSIONS, ".cts", ".mts", ".cjs", ".mjs"];
@@ -2409,11 +2809,26 @@ function matchesScriptExtension(id, extensions) {
2409
2809
  return extensions.some((ext) => id.endsWith(ext) || id.includes(`${ext}?`));
2410
2810
  }
2411
2811
  function insertRuntimeImport(code, importStmt) {
2412
- const directiveMatch = code.match(DIRECTIVE_PROLOGUE_PREFIX_RE);
2413
- if (!directiveMatch) {
2414
- return `${importStmt}${code}`;
2812
+ return insertAfterUseDirective(code, importStmt);
2813
+ }
2814
+ function scanClassExpression(source, from) {
2815
+ let depth = 0;
2816
+ let index = from;
2817
+ while (index < source.length) {
2818
+ const char = source[index];
2819
+ if (char === "(" || char === "[") {
2820
+ depth++;
2821
+ } else if (char === ")" || char === "]") {
2822
+ if (depth === 0) {
2823
+ break;
2824
+ }
2825
+ depth--;
2826
+ } else if (depth === 0 && (char === "," || char === ";" || char === "\n" || char === "}")) {
2827
+ break;
2828
+ }
2829
+ index++;
2415
2830
  }
2416
- return code.replace(directiveMatch[0], `${directiveMatch[1]}${directiveMatch[2]}${importStmt}`);
2831
+ return index;
2417
2832
  }
2418
2833
  function mangleCodeClassesSync(code, mangleMap) {
2419
2834
  function mangleClassString(classString) {
@@ -2421,6 +2836,58 @@ function mangleCodeClassesSync(code, mangleMap) {
2421
2836
  return mangleMap[cls.replace(/\\(.)/g, "$1")] || cls;
2422
2837
  }).join(" ");
2423
2838
  }
2839
+ function mangleClassTemplate(fullMatch, templateContent) {
2840
+ let changed = false;
2841
+ let output = "";
2842
+ let cursor = 0;
2843
+ while (cursor < templateContent.length) {
2844
+ const interpolationStart = templateContent.indexOf("${", cursor);
2845
+ const quasiEnd = interpolationStart === -1 ? templateContent.length : interpolationStart;
2846
+ const quasi = mangleTemplateQuasi(templateContent.slice(cursor, quasiEnd));
2847
+ output += quasi.value;
2848
+ changed ||= quasi.changed;
2849
+ if (interpolationStart === -1) break;
2850
+ const interpolationEnd = findTemplateInterpolationEnd(
2851
+ templateContent,
2852
+ interpolationStart + 2
2853
+ );
2854
+ const inner = templateContent.slice(interpolationStart + 2, interpolationEnd - 1);
2855
+ const interpolation = mangleTemplateInterpolation(inner);
2856
+ output += `\${${interpolation.value}}`;
2857
+ changed ||= interpolation.changed;
2858
+ cursor = interpolationEnd;
2859
+ }
2860
+ return changed ? `className:\`${output}\`` : fullMatch;
2861
+ }
2862
+ function mangleTemplateQuasi(quasi) {
2863
+ const trimmed = quasi.trim();
2864
+ if (!trimmed) return { value: quasi, changed: false };
2865
+ const mangled = mangleClassString(trimmed);
2866
+ return {
2867
+ value: mangled === trimmed ? quasi : quasi.replace(trimmed, mangled),
2868
+ changed: mangled !== trimmed
2869
+ };
2870
+ }
2871
+ function findTemplateInterpolationEnd(templateContent, bodyStart) {
2872
+ let depth = 0;
2873
+ for (let cursor = bodyStart; cursor < templateContent.length; cursor++) {
2874
+ if (templateContent[cursor] === "{") depth++;
2875
+ else if (templateContent[cursor] === "}" && depth-- === 0) return cursor + 1;
2876
+ }
2877
+ return templateContent.length;
2878
+ }
2879
+ function mangleTemplateInterpolation(inner) {
2880
+ let changed = false;
2881
+ const value = inner.replace(/"([^"]*)"/g, (quoted, classString) => {
2882
+ const parts = classString.split(/\s+/).filter(Boolean);
2883
+ if (parts.length === 0) return quoted;
2884
+ const mangled = parts.map((className) => mangleMap[className] || className).join(" ");
2885
+ if (mangled === classString) return quoted;
2886
+ changed = true;
2887
+ return `"${mangled}"`;
2888
+ });
2889
+ return { value, changed };
2890
+ }
2424
2891
  let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*"((?:[^"\\]|\\.)*)"/g, (match, classes) => {
2425
2892
  const mangled = mangleClassString(classes);
2426
2893
  if (mangled === classes) {
@@ -2434,92 +2901,7 @@ function mangleCodeClassesSync(code, mangleMap) {
2434
2901
  }
2435
2902
  return match.replace(classes, mangled);
2436
2903
  });
2437
- result = result.replace(/className:\s*`([^`]+)`/g, (fullMatch, tplContent) => {
2438
- let changed = false;
2439
- let out = "";
2440
- let i = 0;
2441
- while (i < tplContent.length) {
2442
- const interStart = tplContent.indexOf("${", i);
2443
- if (interStart === -1) {
2444
- const quasi2 = tplContent.slice(i);
2445
- const trimmed2 = quasi2.trim();
2446
- if (trimmed2) {
2447
- const m = mangleClassString(trimmed2);
2448
- if (m !== trimmed2) {
2449
- changed = true;
2450
- out += quasi2.replace(trimmed2, m);
2451
- } else {
2452
- out += quasi2;
2453
- }
2454
- } else {
2455
- out += quasi2;
2456
- }
2457
- break;
2458
- }
2459
- const quasi = tplContent.slice(i, interStart);
2460
- const trimmed = quasi.trim();
2461
- if (trimmed) {
2462
- const m = mangleClassString(trimmed);
2463
- if (m !== trimmed) {
2464
- changed = true;
2465
- out += quasi.replace(trimmed, m);
2466
- } else {
2467
- out += quasi;
2468
- }
2469
- } else {
2470
- out += quasi;
2471
- }
2472
- let j = interStart + 2;
2473
- let depth = 0;
2474
- while (j < tplContent.length) {
2475
- if (tplContent[j] === "{") {
2476
- depth++;
2477
- } else if (tplContent[j] === "}") {
2478
- if (depth === 0) {
2479
- j++;
2480
- break;
2481
- }
2482
- depth--;
2483
- }
2484
- j++;
2485
- }
2486
- const interInner = tplContent.slice(interStart + 2, j - 1);
2487
- const mangledInner = interInner.replace(/"([^"]*)"/g, (qm, inner) => {
2488
- const parts = inner.split(/\s+/).filter(Boolean);
2489
- if (parts.length === 0) {
2490
- return qm;
2491
- }
2492
- const m = parts.map((p) => mangleMap[p] || p).join(" ");
2493
- if (m === inner) {
2494
- return qm;
2495
- }
2496
- changed = true;
2497
- return `"${m}"`;
2498
- });
2499
- out += `\${${mangledInner}}`;
2500
- i = j;
2501
- }
2502
- return changed ? `className:\`${out}\`` : fullMatch;
2503
- });
2504
- function scanClassExpression(source, from) {
2505
- let depth = 0;
2506
- let j = from;
2507
- while (j < source.length) {
2508
- const ch = source[j];
2509
- if (ch === "(" || ch === "[") {
2510
- depth++;
2511
- } else if (ch === ")" || ch === "]") {
2512
- if (depth === 0) {
2513
- break;
2514
- }
2515
- depth--;
2516
- } else if (depth === 0 && (ch === "," || ch === ";" || ch === "\n" || ch === "}")) {
2517
- break;
2518
- }
2519
- j++;
2520
- }
2521
- return j;
2522
- }
2904
+ result = result.replace(/className:\s*`([^`]+)`/g, mangleClassTemplate);
2523
2905
  function mangleTernaryClassStrings(expr) {
2524
2906
  const qIdx = expr.indexOf("?");
2525
2907
  if (qIdx === -1 || !expr.slice(qIdx).includes(":")) {
@@ -2727,7 +3109,12 @@ function createCsszyxPlugins(options = {}) {
2727
3109
  }
2728
3110
  if (!_loggedActiveParsers.has(parserMode)) {
2729
3111
  _loggedActiveParsers.add(parserMode);
2730
- const detail = parserDegraded ? "oxc (degraded from default `rust`: no native binary for this platform)" : parserMode === "rust" ? "rust (native engine)" : parserMode;
3112
+ let detail = parserMode;
3113
+ if (parserDegraded) {
3114
+ detail = "oxc (degraded from default `rust`: no native binary for this platform)";
3115
+ } else if (parserMode === "rust") {
3116
+ detail = "rust (native engine)";
3117
+ }
2731
3118
  console.warn(`[csszyx] active parser: ${detail}`);
2732
3119
  }
2733
3120
  }
@@ -2748,6 +3135,7 @@ function createCsszyxPlugins(options = {}) {
2748
3135
  skipWarningEmitted: false,
2749
3136
  classesCapped: false,
2750
3137
  ownedClasses: /* @__PURE__ */ new Set(),
3138
+ authoredClasses: /* @__PURE__ */ new Set(),
2751
3139
  mangleMap: {},
2752
3140
  varMangleEntriesByFile: /* @__PURE__ */ new Map(),
2753
3141
  varMangleMap: Object.fromEntries(earlyGlobalVarAliasEntries),
@@ -2864,53 +3252,76 @@ function createCsszyxPlugins(options = {}) {
2864
3252
  }
2865
3253
  const cacheKey = cacheEnabled ? createTransformCacheKey(cacheInput) : null;
2866
3254
  if (cacheEnabled && cacheKey) {
2867
- const memoryCached = transformMemoryCache.get(cacheKey.key);
2868
- if (memoryCached) {
2869
- transformMemoryCache.delete(cacheKey.key);
2870
- transformMemoryCache.set(cacheKey.key, memoryCached);
2871
- return memoryCached;
2872
- }
2873
- const cached = readTransformCache(cacheRoot, cacheInput, cacheKey);
2874
- if (cached) {
2875
- rememberTransformCacheEntry(cacheKey.key, cached);
2876
- return cached;
2877
- }
2878
- if (astBudget === void 0) {
2879
- const handoff = prescanResultHandoff.get(effectiveFilename);
2880
- if (handoff) {
2881
- prescanResultHandoff.delete(effectiveFilename);
2882
- if (handoff.inputSha256 === cacheKey.inputSha256) {
2883
- return handoff.result;
2884
- }
2885
- }
2886
- }
2887
- }
2888
- let result;
3255
+ const cached = findConfiguredTransformCacheEntry(
3256
+ cacheRoot,
3257
+ cacheInput,
3258
+ cacheKey,
3259
+ effectiveFilename,
3260
+ astBudget
3261
+ );
3262
+ if (cached) return cached;
3263
+ }
3264
+ const execution = runConfiguredParser(source, effectiveFilename, compilerOptions);
3265
+ if (cacheEnabled && cacheKey && execution.cacheable) {
3266
+ writeTransformCache(cacheRoot, cacheInput, execution.result, cacheKey);
3267
+ rememberTransformCacheEntry(cacheKey.key, execution.result);
3268
+ }
3269
+ return execution.result;
3270
+ }
3271
+ function findConfiguredTransformCacheEntry(cacheRoot, cacheInput, cacheKey, effectiveFilename, astBudget) {
3272
+ const memoryCached = transformMemoryCache.get(cacheKey.key);
3273
+ if (memoryCached) {
3274
+ transformMemoryCache.delete(cacheKey.key);
3275
+ transformMemoryCache.set(cacheKey.key, memoryCached);
3276
+ return memoryCached;
3277
+ }
3278
+ const diskCached = readTransformCache(cacheRoot, cacheInput, cacheKey);
3279
+ if (diskCached) {
3280
+ rememberTransformCacheEntry(cacheKey.key, diskCached);
3281
+ return diskCached;
3282
+ }
3283
+ if (astBudget !== void 0) return null;
3284
+ const handoff = prescanResultHandoff.get(effectiveFilename);
3285
+ if (!handoff) return null;
3286
+ prescanResultHandoff.delete(effectiveFilename);
3287
+ return handoff.inputSha256 === cacheKey.inputSha256 ? handoff.result : null;
3288
+ }
3289
+ function runConfiguredParser(source, effectiveFilename, compilerOptions) {
2889
3290
  if (parserMode === "babel") {
2890
- result = transformSourceCode(source, effectiveFilename, compilerOptions);
2891
- } else if (parserMode === "rust") {
2892
- result = transformRust(source, effectiveFilename, compilerOptions);
2893
- } else {
2894
- try {
2895
- result = transformOxc(source, effectiveFilename, compilerOptions);
2896
- } catch (err) {
2897
- result = transformSourceCode(source, effectiveFilename, compilerOptions);
2898
- const reason = err instanceof Error ? err.message : String(err);
2899
- result.diagnostics.push(
2900
- `[csszyx] oxc parser fell back to Babel for ${effectiveFilename}: ${reason}`
2901
- );
2902
- if (!_babelFallbackFiles.has(effectiveFilename)) {
2903
- _babelFallbackFiles.add(effectiveFilename);
2904
- console.warn(
2905
- `[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.`
2906
- );
2907
- }
2908
- return result;
2909
- }
3291
+ return {
3292
+ result: transformSourceCode(source, effectiveFilename, compilerOptions),
3293
+ cacheable: true
3294
+ };
2910
3295
  }
2911
- if (cacheEnabled && cacheKey) {
2912
- writeTransformCache(cacheRoot, cacheInput, result, cacheKey);
2913
- rememberTransformCacheEntry(cacheKey.key, result);
3296
+ if (parserMode === "rust") {
3297
+ return {
3298
+ result: transformRust(source, effectiveFilename, compilerOptions),
3299
+ cacheable: true
3300
+ };
3301
+ }
3302
+ try {
3303
+ return {
3304
+ result: transformOxc(source, effectiveFilename, compilerOptions),
3305
+ cacheable: true
3306
+ };
3307
+ } catch (error) {
3308
+ return {
3309
+ result: runBabelFallback(source, effectiveFilename, compilerOptions, error),
3310
+ cacheable: false
3311
+ };
3312
+ }
3313
+ }
3314
+ function runBabelFallback(source, effectiveFilename, compilerOptions, error) {
3315
+ const result = transformSourceCode(source, effectiveFilename, compilerOptions);
3316
+ const reason = error instanceof Error ? error.message : String(error);
3317
+ result.diagnostics.push(
3318
+ `[csszyx] oxc parser fell back to Babel for ${effectiveFilename}: ${reason}`
3319
+ );
3320
+ if (!_babelFallbackFiles.has(effectiveFilename)) {
3321
+ _babelFallbackFiles.add(effectiveFilename);
3322
+ console.warn(
3323
+ `[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.`
3324
+ );
2914
3325
  }
2915
3326
  return result;
2916
3327
  }
@@ -2949,11 +3360,19 @@ function createCsszyxPlugins(options = {}) {
2949
3360
  const compilerOptions = createCompilerOptions(prescanAstBudget);
2950
3361
  const cacheRoot = resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
2951
3362
  const results = /* @__PURE__ */ new Map();
2952
- const misses = [];
2953
- if (cacheEnabled) {
2954
- evictTransformCacheOnce();
2955
- }
3363
+ if (cacheEnabled) evictTransformCacheOnce();
2956
3364
  ensureRustTransformAvailable();
3365
+ const misses = collectRustPrescanMisses(files, compilerOptions, cacheRoot, results);
3366
+ if (misses.length === 0) return orderPrescanResults(files, results);
3367
+ try {
3368
+ runRustPrescanBatch(misses, compilerOptions, cacheRoot, results);
3369
+ } catch {
3370
+ runRustPrescanFallback(misses, results);
3371
+ }
3372
+ return orderPrescanResults(files, results);
3373
+ }
3374
+ function collectRustPrescanMisses(files, compilerOptions, cacheRoot, results) {
3375
+ const misses = [];
2957
3376
  for (const file of files) {
2958
3377
  const effectiveFilename = normalizeSourceFilename(file.filePath);
2959
3378
  const cacheInput = createConfiguredTransformCacheInput(
@@ -2962,79 +3381,54 @@ function createCsszyxPlugins(options = {}) {
2962
3381
  compilerOptions
2963
3382
  );
2964
3383
  const cacheKey = cacheEnabled ? createTransformCacheKey(cacheInput) : null;
2965
- if (cacheEnabled && cacheKey) {
2966
- const memoryCached = transformMemoryCache.get(cacheKey.key);
2967
- if (memoryCached) {
2968
- transformMemoryCache.delete(cacheKey.key);
2969
- transformMemoryCache.set(cacheKey.key, memoryCached);
2970
- results.set(file.filePath, memoryCached);
2971
- continue;
2972
- }
2973
- const cached = readTransformCache(cacheRoot, cacheInput, cacheKey);
2974
- if (cached) {
2975
- rememberTransformCacheEntry(cacheKey.key, cached);
2976
- results.set(file.filePath, cached);
2977
- continue;
2978
- }
2979
- }
2980
- misses.push({
2981
- filePath: file.filePath,
2982
- effectiveFilename,
2983
- content: file.content,
3384
+ const cached = cacheKey ? findConfiguredTransformCacheEntry(
3385
+ cacheRoot,
2984
3386
  cacheInput,
2985
- cacheKey
2986
- });
3387
+ cacheKey,
3388
+ effectiveFilename,
3389
+ prescanAstBudget
3390
+ ) : null;
3391
+ if (cached) results.set(file.filePath, cached);
3392
+ else misses.push({ ...file, effectiveFilename, cacheInput, cacheKey });
2987
3393
  }
2988
- if (misses.length === 0) {
2989
- return files.map((file) => {
2990
- const result = results.get(file.filePath);
2991
- return result ? { filePath: file.filePath, result } : null;
2992
- }).filter((entry) => entry !== null);
3394
+ return misses;
3395
+ }
3396
+ function runRustPrescanBatch(misses, compilerOptions, cacheRoot, results) {
3397
+ const batchResults = transformRustBatch(
3398
+ misses.map((file) => ({ filename: file.effectiveFilename, source: file.content })),
3399
+ compilerOptions
3400
+ );
3401
+ for (let index = 0; index < misses.length; index++) {
3402
+ const miss = misses[index];
3403
+ const result = batchResults[index];
3404
+ if (!miss || !result) continue;
3405
+ cacheRustPrescanResult(miss, result, cacheRoot);
3406
+ results.set(miss.filePath, result);
2993
3407
  }
2994
- try {
2995
- const batchResults = transformRustBatch(
2996
- misses.map((file) => ({
2997
- filename: file.effectiveFilename,
2998
- source: file.content
2999
- })),
3000
- compilerOptions
3001
- );
3002
- for (let index = 0; index < misses.length; index++) {
3003
- const miss = misses[index];
3004
- const result = batchResults[index];
3005
- if (!miss || !result) {
3006
- continue;
3007
- }
3008
- if (cacheEnabled && miss.cacheKey) {
3009
- writeTransformCache(cacheRoot, miss.cacheInput, result, miss.cacheKey);
3010
- rememberTransformCacheEntry(miss.cacheKey.key, result);
3011
- }
3408
+ }
3409
+ function cacheRustPrescanResult(miss, result, cacheRoot) {
3410
+ if (!cacheEnabled || !miss.cacheKey) return;
3411
+ writeTransformCache(cacheRoot, miss.cacheInput, result, miss.cacheKey);
3412
+ rememberTransformCacheEntry(miss.cacheKey.key, result);
3413
+ }
3414
+ function runRustPrescanFallback(misses, results) {
3415
+ for (const miss of misses) {
3416
+ try {
3417
+ const result = transformConfiguredSource(
3418
+ miss.content,
3419
+ miss.effectiveFilename,
3420
+ prescanAstBudget
3421
+ );
3012
3422
  results.set(miss.filePath, result);
3013
- }
3014
- } catch {
3015
- for (const miss of misses) {
3016
- try {
3017
- results.set(
3018
- miss.filePath,
3019
- transformConfiguredSource(
3020
- miss.content,
3021
- miss.effectiveFilename,
3022
- prescanAstBudget
3023
- )
3024
- );
3025
- } catch {
3026
- }
3423
+ } catch {
3027
3424
  }
3028
3425
  }
3029
- return files.map((file) => {
3030
- const result = results.get(file.filePath);
3031
- return result ? { filePath: file.filePath, result } : null;
3032
- }).filter((entry) => entry !== null);
3033
3426
  }
3034
- function warnPrescanBudgetSkip(filePath) {
3035
- console.warn(
3036
- `[csszyx] prescan skipped ${filePath}: the file exceeds the AST node budget, so NONE of its classes reached the safelist and their CSS will not be generated. Raise \`build.astBudgetLimit\` in the csszyx plugin options, or split the file.`
3037
- );
3427
+ function orderPrescanResults(files, results) {
3428
+ return files.flatMap((file) => {
3429
+ const result = results.get(file.filePath);
3430
+ return result ? [{ filePath: file.filePath, result }] : [];
3431
+ });
3038
3432
  }
3039
3433
  function transformPrescanSourcesIndividually(files) {
3040
3434
  const results = [];
@@ -3101,11 +3495,12 @@ function createCsszyxPlugins(options = {}) {
3101
3495
  return;
3102
3496
  }
3103
3497
  const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
3104
- const classList = escapeHtmlAttribute(Array.from(classes).join(" "));
3498
+ const classNames = Array.from(classes);
3499
+ const classList = escapeHtmlAttribute(classNames.join(" "));
3105
3500
  const content = `<!-- Auto-generated by csszyx \u2014 DO NOT EDIT -->
3106
3501
  <!-- Tailwind CSS scans this file for class name detection -->
3107
3502
  <div class="${classList}"><div class="${classList}">x</div><div class="${classList}">x</div></div>
3108
- `;
3503
+ ` + renderTailwindScannerCandidates(classNames);
3109
3504
  try {
3110
3505
  let existing = "";
3111
3506
  try {
@@ -3180,6 +3575,7 @@ function createCsszyxPlugins(options = {}) {
3180
3575
  } catch {
3181
3576
  return;
3182
3577
  }
3578
+ recordAuthoredClasses(content);
3183
3579
  if (fileMayContainSafelistableSz(content)) {
3184
3580
  prescanSources.push({ filePath, content });
3185
3581
  }
@@ -3282,7 +3678,7 @@ function createCsszyxPlugins(options = {}) {
3282
3678
  for (const kv of objStr.matchAll(numKv)) {
3283
3679
  try {
3284
3680
  collectTransformClasses(
3285
- transform({ [kv[1]]: parseFloat(kv[2]) }),
3681
+ transform({ [kv[1]]: Number.parseFloat(kv[2]) }),
3286
3682
  discoveredClasses
3287
3683
  );
3288
3684
  } catch {
@@ -3322,19 +3718,6 @@ function createCsszyxPlugins(options = {}) {
3322
3718
  }
3323
3719
  }
3324
3720
  }
3325
- function findJsxExpressionEnd(code, bodyStart) {
3326
- let depth = 1;
3327
- let index = bodyStart;
3328
- while (index < code.length && depth > 0) {
3329
- if (code[index] === "{") {
3330
- depth++;
3331
- } else if (code[index] === "}") {
3332
- depth--;
3333
- }
3334
- index++;
3335
- }
3336
- return index - 1;
3337
- }
3338
3721
  function collectExpressionClasses(code) {
3339
3722
  for (const match of code.matchAll(/className=\{/g)) {
3340
3723
  const bodyStart = (match.index ?? 0) + match[0].length;
@@ -3348,17 +3731,22 @@ function createCsszyxPlugins(options = {}) {
3348
3731
  collectQuotedAttributeClasses(code);
3349
3732
  collectExpressionClasses(code);
3350
3733
  }
3734
+ function recordAuthoredClasses(code) {
3735
+ for (const className of collectAuthoredClassNames(code)) {
3736
+ addSafelistClass(className);
3737
+ state.authoredClasses.add(className);
3738
+ }
3739
+ }
3351
3740
  function finalizeMangleMap() {
3352
- const sortedClasses = Array.from(state.ownedClasses);
3353
3741
  const newMap = {};
3354
3742
  let tokenIndex = 0;
3355
- for (let i = 0; i < sortedClasses.length; i++) {
3743
+ for (const className of mangleEligibleClasses(state.ownedClasses, state.authoredClasses)) {
3356
3744
  let token = encode(tokenIndex);
3357
- while (mangleReserved.has(token)) {
3745
+ while (mangleReserved.has(token) || state.authoredClasses.has(token)) {
3358
3746
  tokenIndex++;
3359
3747
  token = encode(tokenIndex);
3360
3748
  }
3361
- newMap[sortedClasses[i]] = token;
3749
+ newMap[className] = token;
3362
3750
  tokenIndex++;
3363
3751
  }
3364
3752
  state.mangleMap = newMap;
@@ -3406,6 +3794,147 @@ function createCsszyxPlugins(options = {}) {
3406
3794
  }
3407
3795
  return result;
3408
3796
  }
3797
+ function unchangedPreTransform(code) {
3798
+ return {
3799
+ code,
3800
+ transformed: false,
3801
+ usesRuntime: false,
3802
+ usesMerge: false,
3803
+ usesSzcn: false,
3804
+ usesSzPart: false,
3805
+ usesColorVar: false,
3806
+ usesSpacingVar: false,
3807
+ usesUnitVar: false
3808
+ };
3809
+ }
3810
+ function transformTailwindCssEntry(code, id) {
3811
+ state.sawAnyCss = true;
3812
+ if (!cssImportsTailwind(code)) return null;
3813
+ state.sawTailwindEntry = true;
3814
+ if (cssHasContentScope(code)) state.tailwindEntryScoped = true;
3815
+ if (!hasInjectableTailwindCandidate(state.classes)) return null;
3816
+ const relPath = computeSafelistRelPath(state.rootDir, SAFELIST_FILENAME, id);
3817
+ const transformed = appendTailwindSourceDirective(code, relPath);
3818
+ return transformed === null ? null : { code: transformed, map: null };
3819
+ }
3820
+ function reportTransformDiagnostics(result, id, warn) {
3821
+ for (const message of result.diagnostics) {
3822
+ if (message.includes("unresolvable sz spread")) {
3823
+ state.spreadWarnings.add(`${id}
3824
+ ${message}`);
3825
+ } else if (message.includes("AST budget exceeded")) {
3826
+ console.warn(`[csszyx] ${id}
3827
+ ${message}`);
3828
+ }
3829
+ }
3830
+ if (quiet || result.diagnostics.length === 0 || process.env.NODE_ENV === "production") {
3831
+ return;
3832
+ }
3833
+ for (const message of result.diagnostics) {
3834
+ if (message.includes("unresolvable sz spread") || message.includes("AST budget exceeded")) {
3835
+ continue;
3836
+ }
3837
+ warn(`[csszyx] ${id}
3838
+ ${message}`);
3839
+ }
3840
+ }
3841
+ function compilerPreTransformOutput(result) {
3842
+ return {
3843
+ code: result.code,
3844
+ transformed: result.transformed,
3845
+ usesRuntime: result.usesRuntime,
3846
+ usesMerge: result.usesMerge,
3847
+ usesSzcn: result.usesSzcn,
3848
+ usesSzPart: result.usesSzPart,
3849
+ usesColorVar: result.usesColorVar,
3850
+ usesSpacingVar: result.usesSpacingVar,
3851
+ usesUnitVar: result.usesUnitVar,
3852
+ szClasses: result.classes
3853
+ };
3854
+ }
3855
+ function transformSzSource(code, id, warn) {
3856
+ if (id.endsWith(".vue")) {
3857
+ const result2 = preprocess(code, options);
3858
+ return { ...unchangedPreTransform(result2.code), transformed: result2.transformed };
3859
+ }
3860
+ if (id.endsWith(".svelte")) {
3861
+ const result2 = preprocess$1(code, options);
3862
+ return result2 ? { ...unchangedPreTransform(result2.code), transformed: true } : unchangedPreTransform(code);
3863
+ }
3864
+ const transformStarted = performance.now();
3865
+ const result = transformConfiguredSource(code, id);
3866
+ traceBenchTiming("transform-hook", id, performance.now() - transformStarted);
3867
+ recordFileVarMangleEntries(state, id, cssVariableEntries(result));
3868
+ recordFileCSSVariableMetrics(state, id, result.code);
3869
+ reportTransformDiagnostics(result, id, warn);
3870
+ for (const [token, data] of result.recoveryTokens) state.recoveryTokens.set(token, data);
3871
+ return compilerPreTransformOutput(result);
3872
+ }
3873
+ function injectLayoutHydration(code, id) {
3874
+ if (!code.includes("<html") || !/(?:layout|Root|Document|app)\.tsx?$/i.test(id)) {
3875
+ return null;
3876
+ }
3877
+ let transformedCode = code;
3878
+ const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
3879
+ const htmlTag = findOpeningTag(transformedCode, "html");
3880
+ if (htmlTag) {
3881
+ transformedCode = `${transformedCode.slice(0, htmlTag.close)} ${attrName}="${CHECKSUM_PLACEHOLDER}"${transformedCode.slice(htmlTag.close)}`;
3882
+ }
3883
+ 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})}}})()\`}} />`;
3884
+ const bodyTag = findOpeningTag(transformedCode, "body");
3885
+ if (bodyTag) {
3886
+ transformedCode = `${transformedCode.slice(0, bodyTag.close + 1)}${debugScript}${transformedCode.slice(bodyTag.close + 1)}`;
3887
+ }
3888
+ return transformedCode;
3889
+ }
3890
+ function requiredRuntimeHelpers(output) {
3891
+ const helpers = [];
3892
+ if (output.usesRuntime) helpers.push("_sz");
3893
+ if (output.usesMerge) helpers.push("_szMerge");
3894
+ if (output.usesSzcn) helpers.push("_szcn");
3895
+ if (output.usesSzPart) helpers.push("_szPart");
3896
+ if (output.usesColorVar) helpers.push("__szColorVar");
3897
+ if (output.usesSpacingVar) helpers.push("__szSpacingVar");
3898
+ if (output.usesUnitVar) helpers.push("__szUnitVar");
3899
+ return helpers;
3900
+ }
3901
+ function injectRuntimeHelpers(code, output) {
3902
+ const imports = requiredRuntimeHelpers(output);
3903
+ const hasRuntimeImport = imports.length > 0 && code.includes("@csszyx/runtime");
3904
+ const needed = hasRuntimeImport ? imports.filter((name) => !importsRuntimeHelper(code, name)) : imports;
3905
+ if (needed.length === 0) return null;
3906
+ const existingImport = findRuntimeImportClause(code);
3907
+ if (existingImport) {
3908
+ return code.replace(
3909
+ existingImport.statement,
3910
+ `${existingImport.prefixWithBody}, ${needed.join(", ")} } from '@csszyx/runtime'`
3911
+ );
3912
+ }
3913
+ const importStatement = `import { ${needed.join(", ")} } from '@csszyx/runtime';
3914
+ `;
3915
+ return insertRuntimeImport(code, importStatement);
3916
+ }
3917
+ function injectThemeGroups(code, transformedCode, id, usesSzcn) {
3918
+ if (!usesSzcn && !/\bszcn\s*\(/.test(code) || transformedCode.includes(THEME_GROUPS_VIRTUAL_ID) || !shouldProcessSource(id)) {
3919
+ return null;
3920
+ }
3921
+ return `import '${THEME_GROUPS_VIRTUAL_ID}';
3922
+ ${transformedCode}`;
3923
+ }
3924
+ function collectPreTransformClasses(output) {
3925
+ if (!output.transformed && !output.code.includes("class=") && !output.code.includes("className=")) {
3926
+ return null;
3927
+ }
3928
+ if (output.szClasses) {
3929
+ for (const className of output.szClasses) {
3930
+ addSafelistClass(className);
3931
+ state.ownedClasses.add(className);
3932
+ }
3933
+ } else {
3934
+ extractClasses(output.code);
3935
+ }
3936
+ return { code: output.code, map: null };
3937
+ }
3409
3938
  const prePlugin = createUnplugin(
3410
3939
  (_pluginOptions) => ({
3411
3940
  name: "csszyx:pre",
@@ -3492,176 +4021,41 @@ function createCsszyxPlugins(options = {}) {
3492
4021
  }
3493
4022
  if (shouldProcessSource(id)) {
3494
4023
  trackGlobalVarSourceFile(id, code);
4024
+ recordAuthoredClasses(code);
3495
4025
  }
3496
4026
  if (matchesScriptExtension(id, SCRIPT_ID_EXTENSIONS)) {
3497
4027
  assertNoRSCBoundaryViolation(code, id);
3498
4028
  }
3499
4029
  if (matchesScriptExtension(id, [".css"])) {
3500
- state.sawAnyCss = true;
3501
- if (cssImportsTailwind(code)) {
3502
- state.sawTailwindEntry = true;
3503
- if (cssHasContentScope(code)) {
3504
- state.tailwindEntryScoped = true;
3505
- }
3506
- if (hasInjectableTailwindCandidate(state.classes)) {
3507
- const relPath = computeSafelistRelPath(
3508
- state.rootDir,
3509
- SAFELIST_FILENAME,
3510
- id
3511
- );
3512
- const transformed2 = appendTailwindSourceDirective(code, relPath);
3513
- if (transformed2 !== null) {
3514
- return { code: transformed2, map: null };
3515
- }
3516
- }
3517
- }
3518
- return null;
4030
+ return transformTailwindCssEntry(code, id);
3519
4031
  }
3520
- let transformedCode = code;
3521
- let usesRuntime = false;
3522
- let usesMerge = false;
3523
- let usesSzcn = false;
3524
- let usesSzPart = false;
3525
- let usesColorVar = false;
3526
- let usesSpacingVar = false;
3527
- let usesUnitVar = false;
3528
- let transformed = false;
3529
- let szClasses;
3530
4032
  const hasSzProp = code.includes("sz=") || code.includes("szs=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
3531
- if (hasSzProp) {
3532
- if (id.endsWith(".vue")) {
3533
- const result = preprocess(code, options);
3534
- if (result.transformed) {
3535
- transformedCode = result.code;
3536
- transformed = true;
3537
- }
3538
- } else if (id.endsWith(".svelte")) {
3539
- const result = preprocess$1(code, options);
3540
- if (result) {
3541
- transformedCode = result.code;
3542
- transformed = true;
3543
- }
3544
- } else {
3545
- const transformStarted = performance.now();
3546
- const result = transformConfiguredSource(code, id);
3547
- traceBenchTiming(
3548
- "transform-hook",
3549
- id,
3550
- performance.now() - transformStarted
3551
- );
3552
- transformedCode = result.code;
3553
- usesRuntime = result.usesRuntime;
3554
- usesMerge = result.usesMerge;
3555
- usesSzcn = result.usesSzcn;
3556
- usesSzPart = result.usesSzPart;
3557
- usesColorVar = result.usesColorVar;
3558
- usesSpacingVar = result.usesSpacingVar;
3559
- usesUnitVar = result.usesUnitVar;
3560
- transformed = result.transformed;
3561
- szClasses = result.classes;
3562
- recordFileVarMangleEntries(state, id, cssVariableEntries(result));
3563
- recordFileCSSVariableMetrics(state, id, result.code);
3564
- for (const msg of result.diagnostics) {
3565
- if (msg.includes("unresolvable sz spread")) {
3566
- state.spreadWarnings.add(`${id}
3567
- ${msg}`);
3568
- } else if (msg.includes("AST budget exceeded")) {
3569
- console.warn(`[csszyx] ${id}
3570
- ${msg}`);
3571
- }
3572
- }
3573
- if (!quiet && result.diagnostics.length > 0 && process.env.NODE_ENV !== "production") {
3574
- for (const msg of result.diagnostics) {
3575
- if (msg.includes("unresolvable sz spread") || msg.includes("AST budget exceeded")) {
3576
- continue;
3577
- }
3578
- this.warn(`[csszyx] ${id}
3579
- ${msg}`);
3580
- }
3581
- }
3582
- for (const [token, data] of result.recoveryTokens) {
3583
- state.recoveryTokens.set(token, data);
3584
- }
3585
- }
3586
- } else if (shouldProcessSource(id)) {
4033
+ const output = hasSzProp ? transformSzSource(code, id, (message) => this.warn(message)) : unchangedPreTransform(code);
4034
+ if (!hasSzProp && shouldProcessSource(id)) {
3587
4035
  recordFileVarMangleEntries(state, id, []);
3588
4036
  recordFileCSSVariableMetrics(state, id, null);
3589
4037
  }
3590
- if (transformedCode.includes("<html") && /(?:layout|Root|Document|app)\.tsx?$/i.test(id)) {
3591
- const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
3592
- const htmlTag = findOpeningTag(transformedCode, "html");
3593
- if (htmlTag) {
3594
- transformedCode = `${transformedCode.slice(0, htmlTag.close)} ${attrName}="${CHECKSUM_PLACEHOLDER}"${transformedCode.slice(htmlTag.close)}`;
3595
- }
3596
- 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})}}})()\`}} />`;
3597
- const bodyTag = findOpeningTag(transformedCode, "body");
3598
- if (bodyTag) {
3599
- transformedCode = `${transformedCode.slice(0, bodyTag.close + 1)}${debugScript}${transformedCode.slice(bodyTag.close + 1)}`;
3600
- }
3601
- transformed = true;
4038
+ const layoutCode = injectLayoutHydration(output.code, id);
4039
+ if (layoutCode !== null) {
4040
+ output.code = layoutCode;
4041
+ output.transformed = true;
3602
4042
  }
3603
- {
3604
- const imports = [];
3605
- if (usesRuntime) {
3606
- imports.push("_sz");
3607
- }
3608
- if (usesMerge) {
3609
- imports.push("_szMerge");
3610
- }
3611
- if (usesSzcn) {
3612
- imports.push("_szcn");
3613
- }
3614
- if (usesSzPart) {
3615
- imports.push("_szPart");
3616
- }
3617
- if (usesColorVar) {
3618
- imports.push("__szColorVar");
3619
- }
3620
- if (usesSpacingVar) {
3621
- imports.push("__szSpacingVar");
3622
- }
3623
- if (usesUnitVar) {
3624
- imports.push("__szUnitVar");
3625
- }
3626
- const hasRuntimeImport = imports.length > 0 && transformedCode.includes("@csszyx/runtime");
3627
- const needed = hasRuntimeImport ? imports.filter((name) => !importsRuntimeHelper(transformedCode, name)) : imports;
3628
- if (needed.length > 0) {
3629
- const existingImport = findRuntimeImportClause(transformedCode);
3630
- if (existingImport) {
3631
- transformedCode = transformedCode.replace(
3632
- existingImport.statement,
3633
- `${existingImport.prefixWithBody}, ${needed.join(", ")} } from '@csszyx/runtime'`
3634
- );
3635
- } else {
3636
- const importStmt = `import { ${needed.join(", ")} } from '@csszyx/runtime';
3637
- `;
3638
- transformedCode = insertRuntimeImport(transformedCode, importStmt);
3639
- }
3640
- transformed = true;
3641
- }
4043
+ const runtimeCode = injectRuntimeHelpers(output.code, output);
4044
+ if (runtimeCode !== null) {
4045
+ output.code = runtimeCode;
4046
+ output.transformed = true;
3642
4047
  }
3643
- if ((usesSzcn || /\bszcn\s*\(/.test(code)) && !transformedCode.includes(THEME_GROUPS_VIRTUAL_ID) && shouldProcessSource(id)) {
3644
- transformedCode = `import '${THEME_GROUPS_VIRTUAL_ID}';
3645
- ${transformedCode}`;
3646
- transformed = true;
4048
+ const themedCode = injectThemeGroups(code, output.code, id, output.usesSzcn);
4049
+ if (themedCode !== null) {
4050
+ output.code = themedCode;
4051
+ output.transformed = true;
3647
4052
  }
3648
4053
  if (matchesScriptExtension(id, SCRIPT_ID_EXTENSIONS)) {
3649
- assertNoRSCBoundaryViolation(transformedCode, id);
3650
- const record = createRSCModuleRecord(transformedCode, id);
4054
+ assertNoRSCBoundaryViolation(output.code, id);
4055
+ const record = createRSCModuleRecord(output.code, id);
3651
4056
  state.rscModules.set(record.id, record);
3652
4057
  }
3653
- if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
3654
- if (szClasses !== void 0) {
3655
- for (const cls of szClasses) {
3656
- addSafelistClass(cls);
3657
- state.ownedClasses.add(cls);
3658
- }
3659
- } else {
3660
- extractClasses(transformedCode);
3661
- }
3662
- return { code: transformedCode, map: null };
3663
- }
3664
- return null;
4058
+ return collectPreTransformClasses(output);
3665
4059
  },
3666
4060
  /** Finalizes the mangle map after all source modules have been processed. */
3667
4061
  buildEnd() {
@@ -3870,6 +4264,166 @@ ${transformedCode}`;
3870
4264
  }
3871
4265
  })
3872
4266
  );
4267
+ function createBundleManifest(includeMangleMap) {
4268
+ const manifest = {
4269
+ version: "0.4.0",
4270
+ buildId: state.checksum,
4271
+ classes: Object.keys(state.mangleMap)
4272
+ };
4273
+ if (includeMangleMap && Object.keys(state.mangleMap).length > 0) {
4274
+ manifest.mangleMap = state.mangleMap;
4275
+ }
4276
+ if (Object.keys(state.varMangleMap).length > 0) {
4277
+ manifest.varMangleMap = state.varMangleMap;
4278
+ }
4279
+ const globalVarAliases = extractGlobalVarAliasesForManifest(
4280
+ state.varMangleMap,
4281
+ globalVarAliasPrefix,
4282
+ state.globalVarValidationResult
4283
+ );
4284
+ if (Object.keys(globalVarAliases).length > 0) {
4285
+ manifest.globalVarAliases = globalVarAliases;
4286
+ }
4287
+ if (hasCSSVariableMetrics(state.cssVarMetrics)) {
4288
+ manifest.cssVarMetrics = state.cssVarMetrics;
4289
+ }
4290
+ return manifest;
4291
+ }
4292
+ function isCssSyntaxError(error) {
4293
+ return !!error && typeof error === "object" && "name" in error && error.name === "CssSyntaxError";
4294
+ }
4295
+ function rewriteOutputCss(source, file, shouldMangle, mangledSources, externalClasses) {
4296
+ let css = rewriteCssWithValidatedGlobalVarPlan(
4297
+ source,
4298
+ file,
4299
+ state.globalVarValidationResult
4300
+ );
4301
+ if (!shouldMangle) return css;
4302
+ try {
4303
+ const result = mangleCSSSync(css, state.mangleMap, {
4304
+ debug: options.development?.debug,
4305
+ from: file
4306
+ });
4307
+ for (const className of result.mangledClasses) mangledSources.add(className);
4308
+ for (const className of result.unmangledClasses) externalClasses.add(className);
4309
+ if (result.transformedCount > 0) css = result.css;
4310
+ return css;
4311
+ } catch (error) {
4312
+ if (isCssSyntaxError(error)) return css;
4313
+ throw error;
4314
+ }
4315
+ }
4316
+ function reportOutputMangleHazards(shouldMangle, mangledSources, externalClasses) {
4317
+ if (!shouldMangle) return;
4318
+ const message = mangleHybridHazardMessage(
4319
+ collectMangleHybridHazards(state.mangleMap, mangledSources, externalClasses)
4320
+ );
4321
+ if (message) console.warn(message);
4322
+ }
4323
+ function rewriteWebpackCodeAsset(file, source, shouldMangle, compilation, compiler) {
4324
+ if (shouldMangle && file.endsWith(".html")) {
4325
+ const mangledHtml = mangleHtmlClasses(source);
4326
+ if (mangledHtml !== source) {
4327
+ compilation.updateAsset(file, new compiler.webpack.sources.RawSource(mangledHtml));
4328
+ }
4329
+ return;
4330
+ }
4331
+ if (!file.endsWith(".js")) return;
4332
+ const rewritten = shouldMangle ? replacePlaceholders(mangleCodeClasses(source)) : replacePlaceholders(source);
4333
+ if (rewritten !== source) {
4334
+ compilation.updateAsset(file, new compiler.webpack.sources.RawSource(rewritten));
4335
+ }
4336
+ }
4337
+ function processWebpackAssets(assets, compilation, compiler) {
4338
+ finalizeMangleMap();
4339
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
4340
+ collectWebpackGlobalVarCssAssets(assets)
4341
+ );
4342
+ const shouldMangle = manglingEnabled && compiler.options.mode !== "development" && Object.keys(state.mangleMap).length > 0;
4343
+ const manifest = createBundleManifest(shouldMangle);
4344
+ compilation.emitAsset(
4345
+ "csszyx-manifest.json",
4346
+ new compiler.webpack.sources.RawSource(JSON.stringify(manifest))
4347
+ );
4348
+ if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
4349
+ const globalVarMap = createGlobalVarMapAssetSource(
4350
+ state.varMangleMap,
4351
+ globalVarAliasPrefix,
4352
+ state.globalVarValidationResult
4353
+ );
4354
+ if (globalVarMap) {
4355
+ compilation.emitAsset(
4356
+ ".csszyx/global-var-map.json",
4357
+ new compiler.webpack.sources.RawSource(globalVarMap)
4358
+ );
4359
+ }
4360
+ }
4361
+ const mangledSources = /* @__PURE__ */ new Set();
4362
+ const externalClasses = /* @__PURE__ */ new Set();
4363
+ for (const file in assets) {
4364
+ const source = assets[file].source().toString();
4365
+ if (file.endsWith(".css")) {
4366
+ const css = rewriteOutputCss(
4367
+ source,
4368
+ file,
4369
+ shouldMangle,
4370
+ mangledSources,
4371
+ externalClasses
4372
+ );
4373
+ if (css !== source) {
4374
+ compilation.updateAsset(file, new compiler.webpack.sources.RawSource(css));
4375
+ }
4376
+ } else {
4377
+ rewriteWebpackCodeAsset(file, source, shouldMangle, compilation, compiler);
4378
+ }
4379
+ }
4380
+ reportOutputMangleHazards(shouldMangle, mangledSources, externalClasses);
4381
+ }
4382
+ function rewriteViteBundleEntry(chunk, file, shouldMangle, mangledSources, externalClasses) {
4383
+ if (chunk.type === "asset" && chunk.fileName.endsWith(".css") && chunk.source !== void 0) {
4384
+ const originalCss = chunk.source.toString();
4385
+ const css = rewriteOutputCss(
4386
+ originalCss,
4387
+ file,
4388
+ shouldMangle,
4389
+ mangledSources,
4390
+ externalClasses
4391
+ );
4392
+ if (css !== originalCss) chunk.source = css;
4393
+ return;
4394
+ }
4395
+ if (chunk.type !== "chunk" || chunk.code === void 0) return;
4396
+ const rewritten = shouldMangle ? replacePlaceholders(mangleCodeClasses(chunk.code)) : replacePlaceholders(chunk.code);
4397
+ if (rewritten !== chunk.code) chunk.code = rewritten;
4398
+ }
4399
+ function processRollupBundle(bundle, emitAsset) {
4400
+ finalizeMangleMap();
4401
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
4402
+ collectRollupGlobalVarCssAssets(bundle)
4403
+ );
4404
+ const shouldMangle = manglingEnabled && Object.keys(state.mangleMap).length > 0;
4405
+ emitAsset("csszyx-manifest.json", JSON.stringify(createBundleManifest(shouldMangle)));
4406
+ if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
4407
+ const globalVarMap = createGlobalVarMapAssetSource(
4408
+ state.varMangleMap,
4409
+ globalVarAliasPrefix,
4410
+ state.globalVarValidationResult
4411
+ );
4412
+ if (globalVarMap) emitAsset(".csszyx/global-var-map.json", globalVarMap);
4413
+ }
4414
+ const mangledSources = /* @__PURE__ */ new Set();
4415
+ const externalClasses = /* @__PURE__ */ new Set();
4416
+ for (const file in bundle) {
4417
+ rewriteViteBundleEntry(
4418
+ bundle[file],
4419
+ file,
4420
+ shouldMangle,
4421
+ mangledSources,
4422
+ externalClasses
4423
+ );
4424
+ }
4425
+ reportOutputMangleHazards(shouldMangle, mangledSources, externalClasses);
4426
+ }
3873
4427
  const postPlugin = createUnplugin(() => ({
3874
4428
  name: "csszyx:post",
3875
4429
  enforce: "post",
@@ -3880,266 +4434,20 @@ ${transformedCode}`;
3880
4434
  * @param compiler - the Webpack compiler instance
3881
4435
  */
3882
4436
  webpack(compiler) {
3883
- compiler.hooks.compilation.tap("csszyx:post", (compilation) => {
3884
- const stage = compiler.webpack?.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE || compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE;
3885
- compilation.hooks.processAssets.tap(
3886
- {
3887
- name: "csszyx:post",
3888
- stage: stage || 400
3889
- // Fallback integer
3890
- },
3891
- (assets) => {
3892
- finalizeMangleMap();
3893
- state.globalVarValidationResult = validateGlobalVarBundleInputs(
3894
- collectWebpackGlobalVarCssAssets(assets)
3895
- );
3896
- const isWebpackDevMode = compiler.options.mode === "development";
3897
- const manifestData = {
3898
- version: "0.4.0",
3899
- buildId: state.checksum,
3900
- classes: Object.keys(state.mangleMap)
3901
- };
3902
- if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
3903
- manifestData.mangleMap = state.mangleMap;
3904
- }
3905
- if (Object.keys(state.varMangleMap).length > 0) {
3906
- manifestData.varMangleMap = state.varMangleMap;
3907
- }
3908
- const globalVarAliases = extractGlobalVarAliasesForManifest(
3909
- state.varMangleMap,
3910
- globalVarAliasPrefix,
3911
- state.globalVarValidationResult
3912
- );
3913
- if (Object.keys(globalVarAliases).length > 0) {
3914
- manifestData.globalVarAliases = globalVarAliases;
3915
- }
3916
- if (hasCSSVariableMetrics(state.cssVarMetrics)) {
3917
- manifestData.cssVarMetrics = state.cssVarMetrics;
3918
- }
3919
- compilation.emitAsset(
3920
- "csszyx-manifest.json",
3921
- new compiler.webpack.sources.RawSource(JSON.stringify(manifestData))
3922
- );
3923
- if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
3924
- const globalVarMapAsset = createGlobalVarMapAssetSource(
3925
- state.varMangleMap,
3926
- globalVarAliasPrefix,
3927
- state.globalVarValidationResult
3928
- );
3929
- if (globalVarMapAsset) {
3930
- compilation.emitAsset(
3931
- ".csszyx/global-var-map.json",
3932
- new compiler.webpack.sources.RawSource(globalVarMapAsset)
3933
- );
3934
- }
3935
- }
3936
- const mangledSources = /* @__PURE__ */ new Set();
3937
- const externalClasses = /* @__PURE__ */ new Set();
3938
- for (const file in assets) {
3939
- const asset = assets[file];
3940
- const source = asset.source().toString();
3941
- if (file.endsWith(".css")) {
3942
- let css = rewriteCssWithValidatedGlobalVarPlan(
3943
- source,
3944
- file,
3945
- state.globalVarValidationResult
3946
- );
3947
- if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
3948
- try {
3949
- const result = mangleCSSSync(css, state.mangleMap, {
3950
- debug: options.development?.debug,
3951
- from: file
3952
- });
3953
- for (const c of result.mangledClasses) {
3954
- mangledSources.add(c);
3955
- }
3956
- for (const c of result.unmangledClasses) {
3957
- externalClasses.add(c);
3958
- }
3959
- if (result.transformedCount > 0) {
3960
- css = result.css;
3961
- }
3962
- } catch (e) {
3963
- if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") ; else {
3964
- throw e;
3965
- }
3966
- }
3967
- }
3968
- if (css !== source) {
3969
- compilation.updateAsset(
3970
- file,
3971
- new compiler.webpack.sources.RawSource(css)
3972
- );
3973
- }
3974
- continue;
3975
- }
3976
- if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
3977
- if (file.endsWith(".html")) {
3978
- const mangledHtml = mangleHtmlClasses(source);
3979
- if (mangledHtml !== source) {
3980
- compilation.updateAsset(
3981
- file,
3982
- new compiler.webpack.sources.RawSource(mangledHtml)
3983
- );
3984
- continue;
3985
- }
3986
- } else if (file.endsWith(".js")) {
3987
- let mangled = mangleCodeClasses(source);
3988
- mangled = replacePlaceholders(mangled);
3989
- if (mangled !== source) {
3990
- compilation.updateAsset(
3991
- file,
3992
- new compiler.webpack.sources.RawSource(mangled)
3993
- );
3994
- continue;
3995
- }
3996
- }
3997
- }
3998
- if (file.endsWith(".js") && (source.includes(CHECKSUM_PLACEHOLDER) || source.includes(MANGLE_MAP_PLACEHOLDER))) {
3999
- const replaced = replacePlaceholders(source);
4000
- if (replaced !== source) {
4001
- compilation.updateAsset(
4002
- file,
4003
- new compiler.webpack.sources.RawSource(replaced)
4004
- );
4005
- }
4006
- }
4007
- }
4008
- if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
4009
- const hazardMessage = mangleHybridHazardMessage(
4010
- collectMangleHybridHazards(
4011
- state.mangleMap,
4012
- mangledSources,
4013
- externalClasses
4014
- )
4015
- );
4016
- if (hazardMessage) {
4017
- console.warn(hazardMessage);
4018
- }
4019
- }
4020
- }
4021
- );
4022
- });
4437
+ registerWebpackAssetProcessor(compiler, processWebpackAssets);
4023
4438
  },
4024
- vite: {
4025
- /**
4026
- * Vite hook: mangles CSS selectors and JS class strings in the final bundle.
4027
- * @param _options - the output options (unused)
4028
- * @param bundle - the output bundle containing chunks and assets to process
4029
- */
4030
- generateBundle(_options, bundle) {
4031
- finalizeMangleMap();
4032
- state.globalVarValidationResult = validateGlobalVarBundleInputs(
4033
- collectRollupGlobalVarCssAssets(bundle)
4034
- );
4035
- const manifestData = {
4036
- version: "0.4.0",
4037
- buildId: state.checksum,
4038
- classes: Object.keys(state.mangleMap)
4039
- };
4040
- if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
4041
- manifestData.mangleMap = state.mangleMap;
4042
- }
4043
- if (Object.keys(state.varMangleMap).length > 0) {
4044
- manifestData.varMangleMap = state.varMangleMap;
4045
- }
4046
- const globalVarAliases = extractGlobalVarAliasesForManifest(
4047
- state.varMangleMap,
4048
- globalVarAliasPrefix,
4049
- state.globalVarValidationResult
4050
- );
4051
- if (Object.keys(globalVarAliases).length > 0) {
4052
- manifestData.globalVarAliases = globalVarAliases;
4053
- }
4054
- if (hasCSSVariableMetrics(state.cssVarMetrics)) {
4055
- manifestData.cssVarMetrics = state.cssVarMetrics;
4056
- }
4057
- this.emitFile({
4058
- type: "asset",
4059
- fileName: "csszyx-manifest.json",
4060
- source: JSON.stringify(manifestData)
4061
- });
4062
- if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
4063
- const globalVarMapAsset = createGlobalVarMapAssetSource(
4064
- state.varMangleMap,
4065
- globalVarAliasPrefix,
4066
- state.globalVarValidationResult
4067
- );
4068
- if (globalVarMapAsset) {
4069
- this.emitFile({
4070
- type: "asset",
4071
- fileName: ".csszyx/global-var-map.json",
4072
- source: globalVarMapAsset
4073
- });
4074
- }
4075
- }
4076
- const mangledSources = /* @__PURE__ */ new Set();
4077
- const externalClasses = /* @__PURE__ */ new Set();
4078
- for (const file in bundle) {
4079
- const chunk = bundle[file];
4080
- if (chunk.type === "asset" && chunk.fileName.endsWith(".css")) {
4081
- const originalCss = chunk.source.toString();
4082
- let css = rewriteCssWithValidatedGlobalVarPlan(
4083
- originalCss,
4084
- file,
4085
- state.globalVarValidationResult
4086
- );
4087
- if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
4088
- try {
4089
- const result = mangleCSSSync(css, state.mangleMap, {
4090
- debug: options.development?.debug,
4091
- from: file
4092
- });
4093
- for (const c of result.mangledClasses) {
4094
- mangledSources.add(c);
4095
- }
4096
- for (const c of result.unmangledClasses) {
4097
- externalClasses.add(c);
4098
- }
4099
- if (result.transformedCount > 0) {
4100
- css = result.css;
4101
- }
4102
- } catch (e) {
4103
- if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") ; else {
4104
- throw e;
4105
- }
4106
- }
4107
- }
4108
- if (css !== originalCss) {
4109
- chunk.source = css;
4110
- }
4111
- continue;
4112
- }
4113
- if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
4114
- if (chunk.type === "chunk") {
4115
- let mangledCode = mangleCodeClasses(chunk.code);
4116
- mangledCode = replacePlaceholders(mangledCode);
4117
- if (mangledCode !== chunk.code) {
4118
- chunk.code = mangledCode;
4119
- }
4120
- continue;
4121
- }
4122
- }
4123
- if (chunk.type === "chunk" && (chunk.code.includes(CHECKSUM_PLACEHOLDER) || chunk.code.includes(MANGLE_MAP_PLACEHOLDER))) {
4124
- const replaced = replacePlaceholders(chunk.code);
4125
- if (replaced !== chunk.code) {
4126
- chunk.code = replaced;
4127
- }
4128
- }
4129
- }
4130
- if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
4131
- const hazardMessage = mangleHybridHazardMessage(
4132
- collectMangleHybridHazards(
4133
- state.mangleMap,
4134
- mangledSources,
4135
- externalClasses
4136
- )
4137
- );
4138
- if (hazardMessage) {
4139
- console.warn(hazardMessage);
4140
- }
4141
- }
4142
- }
4439
+ /**
4440
+ * Rollup-compatible hook used by both pure Rollup and Vite adapters.
4441
+ *
4442
+ * @param this Rollup-compatible output hook context.
4443
+ * @param this.emitFile Output asset emitter.
4444
+ * @param _options Output options (unused).
4445
+ * @param bundle Complete Rollup output bundle.
4446
+ */
4447
+ generateBundle(_options, bundle) {
4448
+ processRollupBundle(bundle, (fileName, source) => {
4449
+ this.emitFile({ type: "asset", fileName, source });
4450
+ });
4143
4451
  }
4144
4452
  }));
4145
4453
  return { prePlugin, postPlugin };
@@ -4171,7 +4479,16 @@ const rollupPlugin = (options = {}) => {
4171
4479
  ];
4172
4480
  };
4173
4481
  const esbuildPlugin = (options = {}) => {
4174
- const { prePlugin, postPlugin } = createCsszyxPlugins(options);
4482
+ if (options.production?.mangle === true) {
4483
+ console.warn(
4484
+ "[csszyx] production.mangle is not supported by the esbuild adapter; class mangling is disabled so emitted JS and CSS keep matching names."
4485
+ );
4486
+ }
4487
+ const safeOptions = {
4488
+ ...options,
4489
+ production: { ...options.production, mangle: false }
4490
+ };
4491
+ const { prePlugin, postPlugin } = createCsszyxPlugins(safeOptions);
4175
4492
  return {
4176
4493
  name: "csszyx",
4177
4494
  /**
@@ -4180,10 +4497,10 @@ const esbuildPlugin = (options = {}) => {
4180
4497
  */
4181
4498
  setup(build) {
4182
4499
  const b = build;
4183
- prePlugin.esbuild(options).setup(b);
4184
- postPlugin.esbuild(options).setup(b);
4500
+ prePlugin.esbuild(safeOptions).setup(b);
4501
+ postPlugin.esbuild(safeOptions).setup(b);
4185
4502
  }
4186
4503
  };
4187
4504
  };
4188
4505
 
4189
- export { webpackPlugin as $, isPackagesSkippedSource as A, isRSCServerModule as B, isTailwindReservedGlobalVar as C, mangleCodeClassesSync as D, mangleHybridHazardMessage as E, mergeThemes as F, missingTailwindEntryMessage as G, normalizeGlobalVarAliasesForCache as H, parseThemeBlocks as I, planGlobalVarAliases as J, readGlobalVarScanCache as K, recordGlobalVarSourceFile as L, resolveCompileSourceDirs as M, resolveGlobalVarScanCacheDir as N, resolveNativeCacheIdentity as O, rewriteGlobalVarCssAliases as P, rollupPlugin as Q, scanCustomPropertyNames as R, scanGlobalVarCss as S, shouldEmitWarning as T, shouldTrackGlobalVarSources as U, shouldWarnMissingTailwindEntry as V, shouldWarnUnscopedMonorepo as W, skippedSzFilesMessage as X, unscopedMonorepoMessage as Y, validateGlobalVarAliasInputs as Z, vitePlugin as _, appendTailwindSourceDirective as a, writeGlobalVarScanCache as a0, assertNoRSCBoundaryViolation as b, assertNoRSCGraphViolation as c, collectMangleHybridHazards as d, computeSafelistRelPath as e, createGlobalVarAliasValidationOptions as f, createGlobalVarMapAssetSource as g, createGlobalVarScanCacheKey as h, createRSCModuleRecord as i, cssHasContentScope as j, cssImportsTailwind as k, deleteRSCModuleRecord as l, esbuildPlugin as m, extractGlobalVarAliasesForManifest as n, fileMayContainSafelistableSz as o, findLocalImportSources as p, findRSCBoundaryViolation as q, findRSCGraphViolation as r, hasInjectableTailwindCandidate as s, hasTokens as t, unplugin as u, hasUseClientDirective as v, hasUseServerDirective as w, isCompileSourceOptedIn as x, isHardIgnoredPath as y, isMonorepoPackage as z };
4506
+ export { vitePlugin as $, isPackagesSkippedSource as A, isRSCServerModule as B, isTailwindReservedGlobalVar as C, mangleCodeClassesSync as D, mangleEligibleClasses as E, mangleHybridHazardMessage as F, mergeThemes as G, missingTailwindEntryMessage as H, normalizeGlobalVarAliasesForCache as I, parseThemeBlocks as J, planGlobalVarAliases as K, readGlobalVarScanCache as L, recordGlobalVarSourceFile as M, resolveCompileSourceDirs as N, resolveGlobalVarScanCacheDir as O, resolveNativeCacheIdentity as P, rewriteGlobalVarCssAliases as Q, rollupPlugin as R, scanCustomPropertyNames as S, scanGlobalVarCss as T, shouldEmitWarning as U, shouldTrackGlobalVarSources as V, shouldWarnMissingTailwindEntry as W, shouldWarnUnscopedMonorepo as X, skippedSzFilesMessage as Y, unscopedMonorepoMessage as Z, validateGlobalVarAliasInputs as _, appendTailwindSourceDirective as a, webpackPlugin as a0, writeGlobalVarScanCache as a1, assertNoRSCBoundaryViolation as b, assertNoRSCGraphViolation as c, collectMangleHybridHazards as d, computeSafelistRelPath as e, createGlobalVarAliasValidationOptions as f, createGlobalVarMapAssetSource as g, createGlobalVarScanCacheKey as h, createRSCModuleRecord as i, cssHasContentScope as j, cssImportsTailwind as k, deleteRSCModuleRecord as l, esbuildPlugin as m, extractGlobalVarAliasesForManifest as n, fileMayContainSafelistableSz as o, findLocalImportSources as p, findRSCBoundaryViolation as q, findRSCGraphViolation as r, hasInjectableTailwindCandidate as s, hasTokens as t, unplugin as u, hasUseClientDirective as v, hasUseServerDirective as w, isCompileSourceOptedIn as x, isHardIgnoredPath as y, isMonorepoPackage as z };