@csszyx/unplugin 0.9.0 → 0.9.2

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 (43) hide show
  1. package/dist/index.cjs +19 -2
  2. package/dist/index.d.cts +91 -5
  3. package/dist/index.d.mts +90 -3
  4. package/dist/index.mjs +4 -2
  5. package/dist/next-prebuild.cjs +148 -0
  6. package/dist/next-prebuild.d.cts +66 -0
  7. package/dist/next-prebuild.d.mts +66 -0
  8. package/dist/next-prebuild.mjs +131 -0
  9. package/dist/next-turbo-loader.cjs +210 -0
  10. package/dist/next-turbo-loader.d.cts +68 -0
  11. package/dist/next-turbo-loader.d.mts +66 -0
  12. package/dist/next-turbo-loader.mjs +190 -0
  13. package/dist/next-watcher.cjs +237 -0
  14. package/dist/next-watcher.d.cts +106 -0
  15. package/dist/next-watcher.d.mts +106 -0
  16. package/dist/next-watcher.mjs +219 -0
  17. package/dist/shared/unplugin.8er8o6rn.mjs +276 -0
  18. package/dist/shared/unplugin.B_U4rZvG.cjs +281 -0
  19. package/dist/shared/{unplugin.BEOG6ePC.mjs → unplugin.BbtspS8t.mjs} +1436 -324
  20. package/dist/shared/unplugin.BceVw1eW.mjs +184 -0
  21. package/dist/shared/unplugin.BtQzlC2C.mjs +567 -0
  22. package/dist/shared/{unplugin.CL0F6RZa.cjs → unplugin.CFp386gH.cjs} +1456 -327
  23. package/dist/shared/unplugin.CPEWNSA0.d.cts +77 -0
  24. package/dist/shared/unplugin.CPEWNSA0.d.mts +77 -0
  25. package/dist/shared/unplugin.CScQRdTp.d.cts +15 -0
  26. package/dist/shared/unplugin.CScQRdTp.d.mts +15 -0
  27. package/dist/shared/unplugin.CdZxp0x-.d.mts +16 -0
  28. package/dist/shared/unplugin.DLrBgECN.d.cts +282 -0
  29. package/dist/shared/unplugin.DLrBgECN.d.mts +282 -0
  30. package/dist/shared/unplugin.DUxdYaSG.cjs +205 -0
  31. package/dist/shared/unplugin.s62yJbu1.cjs +591 -0
  32. package/dist/shared/unplugin.xeED_qwh.d.cts +16 -0
  33. package/dist/vite.cjs +3 -1
  34. package/dist/vite.d.cts +2 -1
  35. package/dist/vite.d.mts +2 -1
  36. package/dist/vite.mjs +3 -1
  37. package/dist/webpack.cjs +3 -1
  38. package/dist/webpack.d.cts +2 -1
  39. package/dist/webpack.d.mts +2 -1
  40. package/dist/webpack.mjs +3 -1
  41. package/package.json +41 -8
  42. package/dist/shared/unplugin.DUbr5w-N.d.cts +0 -49
  43. package/dist/shared/unplugin.DUbr5w-N.d.mts +0 -49
@@ -13,8 +13,13 @@ const vueAdapter = require('@csszyx/vue-adapter');
13
13
  const unplugin$1 = require('unplugin');
14
14
  const cssMangler = require('../css-mangler.cjs');
15
15
  const node_crypto = require('node:crypto');
16
+ const transformCache = require('./unplugin.DUxdYaSG.cjs');
17
+ const postcss = require('postcss');
18
+ const valueParser = require('postcss-value-parser');
16
19
 
17
20
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
21
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
22
+
18
23
  function _interopNamespaceCompat(e) {
19
24
  if (e && typeof e === 'object' && 'default' in e) return e;
20
25
  const n = Object.create(null);
@@ -29,6 +34,432 @@ function _interopNamespaceCompat(e) {
29
34
 
30
35
  const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
31
36
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
37
+ const postcss__default = /*#__PURE__*/_interopDefaultCompat(postcss);
38
+ const valueParser__default = /*#__PURE__*/_interopDefaultCompat(valueParser);
39
+
40
+ function resolveGlobalVarScanCacheDir(cacheDir) {
41
+ return path__namespace.join(cacheDir, "global-vars");
42
+ }
43
+ function createGlobalVarScanCacheKey(input) {
44
+ const hash = node_crypto.createHash("sha256");
45
+ hash.update(input.filePath);
46
+ hash.update("\0");
47
+ hash.update(String(input.mtimeMs));
48
+ hash.update("\0");
49
+ hash.update(node_crypto.createHash("sha256").update(input.css).digest("hex"));
50
+ return hash.digest("hex");
51
+ }
52
+ function readGlobalVarScanCache(cacheDir, key) {
53
+ try {
54
+ const raw = fs__namespace.readFileSync(globalVarScanCacheFile(cacheDir, key), "utf8");
55
+ const entry = JSON.parse(raw);
56
+ if (entry.key !== key || !entry.result) {
57
+ return null;
58
+ }
59
+ return entry.result;
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+ function writeGlobalVarScanCache(cacheDir, key, result) {
65
+ try {
66
+ fs__namespace.mkdirSync(cacheDir, { recursive: true });
67
+ fs__namespace.writeFileSync(
68
+ globalVarScanCacheFile(cacheDir, key),
69
+ JSON.stringify({ key, result }),
70
+ "utf8"
71
+ );
72
+ } catch {
73
+ }
74
+ }
75
+ function globalVarScanCacheFile(cacheDir, key) {
76
+ return path__namespace.join(cacheDir, `${key}.json`);
77
+ }
78
+
79
+ const DEFAULT_SCOPE_ID = "<root>";
80
+ function isInsideThemeAtRule(node) {
81
+ let current = node.parent;
82
+ while (current && current.type !== "root") {
83
+ if (current.type === "atrule" && current.name === "theme") {
84
+ return true;
85
+ }
86
+ current = current.parent;
87
+ }
88
+ return false;
89
+ }
90
+ function hasSiblingDeclaration(decl, prop) {
91
+ const parent = decl.parent;
92
+ if (!parent || !("nodes" in parent)) {
93
+ return false;
94
+ }
95
+ return parent.nodes.some((node) => node.type === "decl" && node.prop === prop);
96
+ }
97
+ function nodeLocation(node, filePath) {
98
+ return {
99
+ filePath,
100
+ line: node.source?.start?.line ?? 1,
101
+ column: node.source?.start?.column ?? 1
102
+ };
103
+ }
104
+ function buildScopeId(node) {
105
+ const parts = [];
106
+ let current = node.parent;
107
+ while (current && current.type !== "root") {
108
+ if (current.type === "rule") {
109
+ parts.push(`rule:${current.selector}`);
110
+ } else if (current.type === "atrule") {
111
+ const atRule = current;
112
+ parts.push(`@${atRule.name} ${atRule.params}`.trim());
113
+ }
114
+ current = current.parent;
115
+ }
116
+ return parts.reverse().join(" > ") || DEFAULT_SCOPE_ID;
117
+ }
118
+
119
+ const VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
120
+ function scanGlobalVarCss(css, options = {}) {
121
+ const filePath = options.filePath ?? "<inline>";
122
+ const root = postcss__default.parse(css, { from: filePath });
123
+ const registered = collectRegisteredProperties(root);
124
+ const definitions = [];
125
+ const references = [];
126
+ root.walkDecls((decl) => {
127
+ const scopeId = buildScopeId(decl);
128
+ const tailwindOwned = isInsideThemeAtRule(decl);
129
+ if (decl.prop.startsWith("--")) {
130
+ definitions.push({
131
+ name: decl.prop,
132
+ scopeId,
133
+ tailwindOwned,
134
+ registered: registered.has(decl.prop),
135
+ ...nodeLocation(decl, filePath)
136
+ });
137
+ }
138
+ for (const name of extractVarReferences(decl.value)) {
139
+ references.push({
140
+ name,
141
+ scopeId,
142
+ owner: decl.prop,
143
+ tailwindOwned,
144
+ ...nodeLocation(decl, filePath)
145
+ });
146
+ }
147
+ });
148
+ root.walkAtRules((atRule) => {
149
+ if (atRule.name === "property") {
150
+ return;
151
+ }
152
+ for (const name of extractVarReferences(atRule.params)) {
153
+ references.push({
154
+ name,
155
+ scopeId: buildScopeId(atRule),
156
+ owner: `@${atRule.name}`,
157
+ tailwindOwned: isInsideThemeAtRule(atRule),
158
+ ...nodeLocation(atRule, filePath)
159
+ });
160
+ }
161
+ });
162
+ return {
163
+ filePath,
164
+ definitions,
165
+ references,
166
+ registered: [...registered].sort(),
167
+ thirdParty: isThirdPartyCssPath(filePath)
168
+ };
169
+ }
170
+ function collectRegisteredProperties(root) {
171
+ const registered = /* @__PURE__ */ new Set();
172
+ root.walkAtRules("property", (atRule) => {
173
+ const name = atRule.params.trim();
174
+ if (name.startsWith("--")) {
175
+ registered.add(name);
176
+ }
177
+ });
178
+ return registered;
179
+ }
180
+ function extractVarReferences(value) {
181
+ const references = /* @__PURE__ */ new Set();
182
+ for (const match of value.matchAll(VAR_REFERENCE_RE)) {
183
+ references.add(match[1]);
184
+ }
185
+ return [...references].sort();
186
+ }
187
+ function isThirdPartyCssPath(filePath) {
188
+ return filePath.split(/[\\/]/).includes("node_modules");
189
+ }
190
+
191
+ function planGlobalVarAliases(input) {
192
+ const definitions = flattenDefinitions(input.scans);
193
+ const candidates = collectCandidates(input, definitions);
194
+ const aliasPrefix = input.aliasPrefix ?? types.CSSZYX_GLOBAL_ALIAS_PREFIX;
195
+ const diagnostics = validateCandidates(
196
+ candidates,
197
+ definitions,
198
+ input.reserved ?? [],
199
+ aliasPrefix
200
+ );
201
+ if (diagnostics.length > 0) {
202
+ return { entries: [], aliases: /* @__PURE__ */ new Map(), diagnostics };
203
+ }
204
+ const definitionNames = new Set(definitions.keys());
205
+ const entries = [];
206
+ for (const [index, original] of candidates.entries()) {
207
+ const alias = `${aliasPrefix}${core.encode(index)}`;
208
+ if (definitionNames.has(alias)) {
209
+ return {
210
+ entries: [],
211
+ aliases: /* @__PURE__ */ new Map(),
212
+ diagnostics: [
213
+ {
214
+ code: "alias-collision",
215
+ severity: "error",
216
+ name: alias,
217
+ message: `Generated alias ${alias} collides with an existing CSS custom property.`,
218
+ location: definitions.get(alias)?.[0]
219
+ }
220
+ ]
221
+ };
222
+ }
223
+ entries.push({
224
+ original,
225
+ alias,
226
+ scopes: [
227
+ ...new Set((definitions.get(original) ?? []).map((definition) => definition.scopeId))
228
+ ].sort()
229
+ });
230
+ }
231
+ return {
232
+ entries,
233
+ aliases: new Map(entries.map((entry) => [entry.original, entry.alias])),
234
+ diagnostics: []
235
+ };
236
+ }
237
+ function isTailwindReservedGlobalVar(name) {
238
+ return types.isTailwindReservedCustomProperty(name);
239
+ }
240
+ function flattenDefinitions(scans) {
241
+ const definitions = /* @__PURE__ */ new Map();
242
+ for (const scan of scans) {
243
+ for (const definition of scan.definitions) {
244
+ const existing = definitions.get(definition.name) ?? [];
245
+ existing.push(definition);
246
+ definitions.set(definition.name, existing);
247
+ }
248
+ }
249
+ return definitions;
250
+ }
251
+ function collectCandidates(input, definitions) {
252
+ const candidates = new Set(input.tokens ?? []);
253
+ const autoPrefix = input.autoPrefix ?? "";
254
+ if (autoPrefix !== "") {
255
+ for (const name of definitions.keys()) {
256
+ if (name.startsWith(autoPrefix)) {
257
+ candidates.add(name);
258
+ }
259
+ }
260
+ }
261
+ return [...candidates].sort();
262
+ }
263
+ function validateCandidates(candidates, definitions, reserved, aliasPrefix) {
264
+ const diagnostics = [];
265
+ for (const name of candidates) {
266
+ const tokenDefinitions = definitions.get(name) ?? [];
267
+ if (tokenDefinitions.length === 0) {
268
+ diagnostics.push({
269
+ code: "missing-definition",
270
+ severity: "error",
271
+ name,
272
+ message: `Global variable token ${name} is not defined in scanned CSS.`
273
+ });
274
+ continue;
275
+ }
276
+ if (isTailwindReservedGlobalVar(name) || matchesUserReserved(name, reserved)) {
277
+ diagnostics.push({
278
+ code: "tailwind-reserved",
279
+ severity: "error",
280
+ name,
281
+ message: `Global variable token ${name} is reserved and cannot be aliased.`,
282
+ location: tokenDefinitions[0]
283
+ });
284
+ }
285
+ if (types.isCsszyxGlobalAliasCustomProperty(name, aliasPrefix)) {
286
+ diagnostics.push({
287
+ code: "tailwind-reserved",
288
+ severity: "error",
289
+ name,
290
+ message: `Global variable token ${name} uses csszyx reserved namespace ${aliasPrefix}* and cannot be aliased.`,
291
+ location: tokenDefinitions[0]
292
+ });
293
+ }
294
+ const tailwindDefinition = tokenDefinitions.find((definition) => definition.tailwindOwned);
295
+ if (tailwindDefinition) {
296
+ diagnostics.push({
297
+ code: "tailwind-owned",
298
+ severity: "error",
299
+ name,
300
+ message: `Global variable token ${name} is declared inside @theme and cannot be aliased.`,
301
+ location: tailwindDefinition
302
+ });
303
+ }
304
+ const registeredDefinition = tokenDefinitions.find((definition) => definition.registered);
305
+ if (registeredDefinition) {
306
+ diagnostics.push({
307
+ code: "registered-property",
308
+ severity: "error",
309
+ name,
310
+ message: `Registered custom property ${name} is not aliasable in Phase H v1.`,
311
+ location: registeredDefinition
312
+ });
313
+ }
314
+ }
315
+ return diagnostics;
316
+ }
317
+ function matchesUserReserved(name, reserved) {
318
+ return reserved.some((pattern) => {
319
+ if (pattern.endsWith("*")) {
320
+ return name.startsWith(pattern.slice(0, -1));
321
+ }
322
+ return name === pattern;
323
+ });
324
+ }
325
+
326
+ function rewriteGlobalVarCssAliases(options) {
327
+ if (options.plan.diagnostics.length > 0 || options.plan.entries.length === 0) {
328
+ return {
329
+ css: options.css,
330
+ aliasDeclarations: 0,
331
+ rewrittenReferences: 0,
332
+ diagnostics: options.plan.diagnostics
333
+ };
334
+ }
335
+ const root = postcss__default.parse(options.css, { from: options.filePath });
336
+ const aliasNames = new Set(options.plan.entries.map((entry) => entry.alias));
337
+ const referenceAliases = new Map(
338
+ options.plan.entries.filter((entry) => canRewriteGlobalVarReferences(entry)).map((entry) => [entry.original, entry.alias])
339
+ );
340
+ let aliasDeclarations = 0;
341
+ let rewrittenReferences = 0;
342
+ root.walkDecls((decl) => {
343
+ if (isInsideThemeAtRule(decl)) {
344
+ return;
345
+ }
346
+ const alias = options.plan.aliases.get(decl.prop);
347
+ if (alias && !hasSiblingDeclaration(decl, alias)) {
348
+ decl.cloneAfter({ prop: alias, value: `var(${decl.prop})` });
349
+ aliasDeclarations++;
350
+ }
351
+ if (options.plan.aliases.has(decl.prop) || aliasNames.has(decl.prop)) {
352
+ return;
353
+ }
354
+ const rewrite = rewriteGlobalVarValue(decl.value, referenceAliases);
355
+ if (rewrite.count > 0) {
356
+ decl.value = rewrite.value;
357
+ rewrittenReferences += rewrite.count;
358
+ }
359
+ });
360
+ return {
361
+ css: root.toString(),
362
+ aliasDeclarations,
363
+ rewrittenReferences,
364
+ diagnostics: []
365
+ };
366
+ }
367
+ function canRewriteGlobalVarReferences(entry) {
368
+ return entry.scopes.some(isInheritedGlobalAliasScope);
369
+ }
370
+ function isInheritedGlobalAliasScope(scope) {
371
+ const leaf = scope.split(" > ").at(-1);
372
+ if (!leaf?.startsWith("rule:")) {
373
+ return false;
374
+ }
375
+ const selector = leaf.slice("rule:".length);
376
+ return selector.split(",").some((part) => {
377
+ const normalized = part.trim();
378
+ return normalized === ":root" || normalized === "html" || normalized === "body";
379
+ });
380
+ }
381
+ function rewriteGlobalVarValue(value, aliases) {
382
+ const parsed = valueParser__default(value);
383
+ let count = 0;
384
+ parsed.walk((node) => {
385
+ if (node.type !== "function" || node.value.toLowerCase() !== "var") {
386
+ return;
387
+ }
388
+ const firstArgument = node.nodes.find((child) => child.type !== "space");
389
+ if (!firstArgument || firstArgument.type !== "word") {
390
+ return;
391
+ }
392
+ const alias = aliases.get(firstArgument.value);
393
+ if (!alias) {
394
+ return;
395
+ }
396
+ firstArgument.value = alias;
397
+ count++;
398
+ });
399
+ return { value: count > 0 ? valueParser__default.stringify(parsed.nodes) : value, count };
400
+ }
401
+
402
+ function validateGlobalVarAliasInputs(options) {
403
+ const scans = options.cssFiles.map(
404
+ (file) => scanCssSourceWithOptionalCache(file, options.cacheDir)
405
+ );
406
+ const plan = planGlobalVarAliases({
407
+ scans,
408
+ tokens: options.tokens,
409
+ autoPrefix: options.autoPrefix,
410
+ aliasPrefix: options.aliasPrefix,
411
+ reserved: options.reserved
412
+ });
413
+ if (plan.diagnostics.length > 0 || plan.entries.length === 0) {
414
+ return { scans, plan, usageDiagnostics: [] };
415
+ }
416
+ const candidateTokens = plan.entries.map((entry) => entry.original);
417
+ const usageDiagnostics = (options.sourceFiles ?? []).flatMap(
418
+ (file) => compiler.scanGlobalVarUsages(file.code, file.filePath, { tokens: candidateTokens })
419
+ );
420
+ return { scans, plan, usageDiagnostics };
421
+ }
422
+ function createGlobalVarAliasValidationOptions(input) {
423
+ return {
424
+ cssFiles: input.cssAssets.filter((asset) => /\.css(?:$|\?)/.test(asset.fileName)).map((asset) => ({
425
+ filePath: normalizeBuildAssetPath(input.rootDir, asset.fileName),
426
+ css: cssAssetSourceToString(asset.source),
427
+ mtimeMs: asset.mtimeMs
428
+ })),
429
+ sourceFiles: input.sourceFiles ?? [],
430
+ tokens: input.tokens,
431
+ autoPrefix: input.autoPrefix,
432
+ aliasPrefix: input.aliasPrefix,
433
+ reserved: input.reserved,
434
+ cacheDir: input.cacheDir
435
+ };
436
+ }
437
+ function scanCssSourceWithOptionalCache(file, cacheDir) {
438
+ if (cacheDir === void 0 || file.mtimeMs === void 0) {
439
+ return scanGlobalVarCss(file.css, { filePath: file.filePath });
440
+ }
441
+ const key = createGlobalVarScanCacheKey({
442
+ filePath: file.filePath,
443
+ css: file.css,
444
+ mtimeMs: file.mtimeMs
445
+ });
446
+ const cached = readGlobalVarScanCache(cacheDir, key);
447
+ if (cached) {
448
+ return cached;
449
+ }
450
+ const result = scanGlobalVarCss(file.css, { filePath: file.filePath });
451
+ writeGlobalVarScanCache(cacheDir, key, result);
452
+ return result;
453
+ }
454
+ function normalizeBuildAssetPath(rootDir, fileName) {
455
+ return (path__namespace.isAbsolute(fileName) ? fileName : path__namespace.join(rootDir, fileName)).replace(
456
+ /\\/g,
457
+ "/"
458
+ );
459
+ }
460
+ function cssAssetSourceToString(source) {
461
+ return typeof source === "string" ? source : Buffer.from(source).toString("utf8");
462
+ }
32
463
 
33
464
  const SERVER_DIRECTIVE_RE = /^['"]use server['"];?$/;
34
465
  const CLIENT_DIRECTIVE_RE = /^['"]use client['"];?$/;
@@ -269,24 +700,18 @@ function skipWhitespaceAndComments(code, start) {
269
700
  function findRuntimeImports(code) {
270
701
  const imports = [];
271
702
  const scanCode = stripCommentsForImportScan(code);
272
- const staticImportRe = /import\s+(?!type\b)(\S(?:.*\S)?)\s+from\s+['"]([^'"]+)['"]/g;
273
- const sideEffectImportRe = /import\s+['"]([^'"]+)['"]/g;
274
703
  const dynamicImportRe = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
275
- for (const match of scanCode.matchAll(staticImportRe)) {
276
- const clause = match[1];
277
- const source = match[2];
704
+ for (const { clause, source } of findStaticImports(scanCode)) {
278
705
  if (!isRuntimeImportSource(source)) {
279
706
  continue;
280
707
  }
281
- imports.push({ source, symbols: readRuntimeImportSymbols(source, clause) });
282
- }
283
- for (const match of scanCode.matchAll(sideEffectImportRe)) {
284
- const source = match[1];
285
- if (isRuntimeImportSource(source)) {
708
+ if (clause === null) {
286
709
  imports.push({
287
710
  source,
288
711
  symbols: isWholeRuntimeModuleForbidden(source) ? Array.from(FORBIDDEN_SYMBOLS) : []
289
712
  });
713
+ } else {
714
+ imports.push({ source, symbols: readRuntimeImportSymbols(source, clause) });
290
715
  }
291
716
  }
292
717
  for (const match of scanCode.matchAll(dynamicImportRe)) {
@@ -297,6 +722,98 @@ function findRuntimeImports(code) {
297
722
  }
298
723
  return imports;
299
724
  }
725
+ function findStaticImports(code) {
726
+ const imports = [];
727
+ let cursor = 0;
728
+ while (cursor < code.length) {
729
+ const importStart = code.indexOf("import", cursor);
730
+ if (importStart === -1) {
731
+ break;
732
+ }
733
+ cursor = importStart + 6;
734
+ if (importStart > 0 && isIdentifierPart(code.charCodeAt(importStart - 1)) || isIdentifierPart(code.charCodeAt(cursor))) {
735
+ continue;
736
+ }
737
+ let position = skipAsciiWhitespace(code, cursor);
738
+ const opener = code.charAt(position);
739
+ if (opener === "(") {
740
+ continue;
741
+ }
742
+ if (opener === '"' || opener === "'") {
743
+ const literal2 = readQuotedString(code, position);
744
+ if (literal2) {
745
+ imports.push({ clause: null, source: literal2.value });
746
+ cursor = literal2.end;
747
+ }
748
+ continue;
749
+ }
750
+ const clauseStart = position;
751
+ let fromStart = -1;
752
+ while (position < code.length) {
753
+ if (code.startsWith("from", position) && (position === clauseStart || !isIdentifierPart(code.charCodeAt(position - 1))) && !isIdentifierPart(code.charCodeAt(position + 4))) {
754
+ fromStart = position;
755
+ break;
756
+ }
757
+ if (code.charAt(position) === ";") {
758
+ break;
759
+ }
760
+ position += 1;
761
+ }
762
+ if (fromStart === -1) {
763
+ continue;
764
+ }
765
+ const clause = code.slice(clauseStart, fromStart).trim();
766
+ if (splitAsciiWhitespace(clause)[0] === "type") {
767
+ cursor = fromStart + 4;
768
+ continue;
769
+ }
770
+ position = skipAsciiWhitespace(code, fromStart + 4);
771
+ const literal = readQuotedString(code, position);
772
+ if (literal) {
773
+ imports.push({ clause, source: literal.value });
774
+ cursor = literal.end;
775
+ }
776
+ }
777
+ return imports;
778
+ }
779
+ function readQuotedString(code, start) {
780
+ const quote = code.charAt(start);
781
+ if (quote !== '"' && quote !== "'") {
782
+ return null;
783
+ }
784
+ let value = "";
785
+ for (let index = start + 1; index < code.length; index += 1) {
786
+ const char = code.charAt(index);
787
+ if (char === "\\") {
788
+ if (index + 1 >= code.length) {
789
+ return null;
790
+ }
791
+ value += code.charAt(index + 1);
792
+ index += 1;
793
+ } else if (char === quote) {
794
+ return { end: index + 1, value };
795
+ } else if (char === "\n" || char === "\r") {
796
+ return null;
797
+ } else {
798
+ value += char;
799
+ }
800
+ }
801
+ return null;
802
+ }
803
+ function skipAsciiWhitespace(code, start) {
804
+ let index = start;
805
+ while (index < code.length) {
806
+ const charCode = code.charCodeAt(index);
807
+ if (charCode !== 9 && charCode !== 10 && charCode !== 13 && charCode !== 32) {
808
+ break;
809
+ }
810
+ index += 1;
811
+ }
812
+ return index;
813
+ }
814
+ function isIdentifierPart(code) {
815
+ return isIdentifierStart(code) || code >= 48 && code <= 57;
816
+ }
300
817
  function isRuntimeImportSource(source) {
301
818
  return RUNTIME_HELPER_MODULES.has(source) || source.startsWith("@csszyx/runtime/") || CLIENT_RUNTIME_MODULES.has(source) || CLIENT_RUNTIME_MODULE_ROOTS.some((root) => source === root || source.startsWith(`${root}/`));
302
819
  }
@@ -360,10 +877,17 @@ function resolveLocalModule(importer, source) {
360
877
  path__namespace.join(base, "index.js")
361
878
  ];
362
879
  for (const candidate of candidates) {
363
- if (fs__namespace.existsSync(candidate) && fs__namespace.statSync(candidate).isFile()) {
880
+ try {
881
+ if (!fs__namespace.statSync(candidate).isFile()) {
882
+ continue;
883
+ }
364
884
  const resolved = normalizeModuleId(candidate);
365
885
  resolvedLocalModuleCache.set(cacheKey, resolved);
366
886
  return resolved;
887
+ } catch (error) {
888
+ if (error.code !== "ENOENT") {
889
+ throw error;
890
+ }
367
891
  }
368
892
  }
369
893
  return null;
@@ -383,32 +907,67 @@ function pruneRSCModulePathCaches(moduleIds) {
383
907
  }
384
908
  function readImportedSymbols(clause) {
385
909
  const symbols = [];
386
- const named = clause.match(/\{([\s\S]*?)\}/);
387
- if (named) {
388
- for (const part of named[1].split(",")) {
910
+ const openBrace = clause.indexOf("{");
911
+ const closeBrace = openBrace === -1 ? -1 : clause.indexOf("}", openBrace);
912
+ if (openBrace !== -1 && closeBrace !== -1) {
913
+ const namedPart = clause.slice(openBrace + 1, closeBrace);
914
+ for (const part of namedPart.split(",")) {
389
915
  const trimmed = part.trim();
390
916
  if (!trimmed || trimmed.startsWith("type ")) {
391
917
  continue;
392
918
  }
393
- const sourceName = trimmed.replace(/^type\s+/, "").split(/\s+as\s+/)[0]?.trim();
919
+ const sourceName = trimmed.replace(/^type[ \t]+/, "").split(/[ \t]+as[ \t]+/)[0]?.trim();
394
920
  if (sourceName) {
395
921
  symbols.push(sourceName);
396
922
  }
397
923
  }
398
924
  }
399
- if (/\*\s+as\s+\w+/.test(clause)) {
925
+ const namespaceParts = splitAsciiWhitespace(clause);
926
+ if (namespaceParts.length >= 3 && namespaceParts[0] === "*" && namespaceParts[1] === "as" && isIdentifier(namespaceParts[2] ?? "")) {
400
927
  symbols.push(...FORBIDDEN_SYMBOLS);
401
928
  }
402
929
  const braceStart = clause.indexOf("{");
403
930
  const braceEnd = clause.indexOf("}", braceStart);
404
931
  const stripped = braceStart !== -1 && braceEnd !== -1 ? clause.slice(0, braceStart) + clause.slice(braceEnd + 1) : clause;
405
- const defaultImport = stripped.match(/^\s*([A-Z_$][\w$]*)\s*(?:,|$)/i);
406
- const defaultSymbol = defaultImport?.[1];
932
+ const defaultCandidate = stripped.trimStart().split(",", 1)[0]?.trim() ?? "";
933
+ const defaultSymbol = isIdentifier(defaultCandidate) ? defaultCandidate : void 0;
407
934
  if (defaultSymbol && FORBIDDEN_SYMBOLS.has(defaultSymbol)) {
408
935
  symbols.push(defaultSymbol);
409
936
  }
410
937
  return symbols;
411
938
  }
939
+ function isIdentifier(value) {
940
+ if (value.length === 0 || !isIdentifierStart(value.charCodeAt(0))) {
941
+ return false;
942
+ }
943
+ for (let index = 1; index < value.length; index += 1) {
944
+ const code = value.charCodeAt(index);
945
+ if (!isIdentifierStart(code) && (code < 48 || code > 57)) {
946
+ return false;
947
+ }
948
+ }
949
+ return true;
950
+ }
951
+ function isIdentifierStart(code) {
952
+ return code === 36 || code === 95 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
953
+ }
954
+ function splitAsciiWhitespace(value) {
955
+ const parts = [];
956
+ let start = -1;
957
+ for (let index = 0; index <= value.length; index += 1) {
958
+ const code = index < value.length ? value.charCodeAt(index) : 32;
959
+ const whitespace = code === 9 || code === 10 || code === 13 || code === 32;
960
+ if (whitespace) {
961
+ if (start !== -1) {
962
+ parts.push(value.slice(start, index));
963
+ start = -1;
964
+ }
965
+ } else if (start === -1) {
966
+ start = index;
967
+ }
968
+ }
969
+ return parts;
970
+ }
412
971
  function stripCommentsForImportScan(code) {
413
972
  let out = "";
414
973
  let i = 0;
@@ -720,6 +1279,10 @@ function expandFilePatterns(rootDir, patterns) {
720
1279
  return Array.from(files).sort();
721
1280
  }
722
1281
 
1282
+ function safeJsonForScriptTag(value, prettyPrint = false) {
1283
+ const json = prettyPrint ? JSON.stringify(value, null, 2) : JSON.stringify(value);
1284
+ return json.replace(/</g, "\\u003C").replace(/>/g, "\\u003E").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1285
+ }
723
1286
  function injectChecksum(html, checksum, minify = false) {
724
1287
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
725
1288
  const htmlTagPattern = /<html([^>]*)>/i;
@@ -732,10 +1295,18 @@ function injectChecksum(html, checksum, minify = false) {
732
1295
  return html.replace(htmlTagPattern, `<html${checksumAttr}${existingAttrs}>`);
733
1296
  }
734
1297
  function injectMangleMapScript(html, mangleMap, options = {}) {
735
- const { prettyPrint = false } = options;
736
- const jsonContent = prettyPrint ? JSON.stringify(mangleMap, null, 2) : JSON.stringify(mangleMap);
1298
+ const {
1299
+ prettyPrint = false,
1300
+ varMangleMap = {},
1301
+ globalVarAliasPrefix = types.CSSZYX_GLOBAL_ALIAS_PREFIX
1302
+ } = options;
1303
+ const checksumMap = createHydrationMangleMap(mangleMap, varMangleMap);
1304
+ const jsonContent = safeJsonForScriptTag(checksumMap, prettyPrint);
1305
+ const classMapContent = safeJsonForScriptTag(mangleMap);
1306
+ const varMapContent = safeJsonForScriptTag(varMangleMap);
737
1307
  const scriptTag = `<script id="__CSSZYX_MANGLE_MAP__" type="application/json">${jsonContent}<\/script>`;
738
- const debugScript = `<script>(function(){var m=${jsonContent};var r={};for(var k in m)r[m[k]]=k;var cs=document.documentElement.getAttribute("data-sz-checksum")||"";window.__csszyx={mangleMap:m,checksum:cs,decode:function(c){return r[c]},encode:function(c){return m[c]},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()<\/script>`;
1308
+ const prefixContent = safeJsonForScriptTag(globalVarAliasPrefix);
1309
+ const debugScript = `<script>(function(){var m=${classMapContent};var vm=${varMapContent};var gp=${prefixContent};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)}var cs=document.documentElement.getAttribute("data-sz-checksum")||"";window.__csszyx={mangleMap:m,varMangleMap:vm,checksum:cs,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})}}})()<\/script>`;
739
1310
  const combined = `${scriptTag}
740
1311
  ${debugScript}`;
741
1312
  if (html.includes("</head>")) {
@@ -747,9 +1318,9 @@ ${debugScript}`;
747
1318
  }
748
1319
  return html + combined;
749
1320
  }
750
- function injectMangleMapAttribute(html, mangleMap, minify = false) {
1321
+ function injectMangleMapAttribute(html, mangleMap, minify = false, varMangleMap = {}) {
751
1322
  const attrName = minify ? "data-sz-m" : "data-sz-map";
752
- const jsonContent = JSON.stringify(mangleMap);
1323
+ const jsonContent = JSON.stringify(createHydrationMangleMap(mangleMap, varMangleMap));
753
1324
  const htmlTagPattern = /<html([^>]*)>/i;
754
1325
  const match = html.match(htmlTagPattern);
755
1326
  if (!match) {
@@ -764,11 +1335,11 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
764
1335
  let result = html;
765
1336
  result = injectChecksum(result, checksum, minify);
766
1337
  if (mode === "inline") {
767
- result = injectMangleMapAttribute(result, mangleMap, minify);
1338
+ result = injectMangleMapAttribute(result, mangleMap, minify, options.varMangleMap);
768
1339
  } else if (mode === "script") {
769
1340
  result = injectMangleMapScript(result, mangleMap, options);
770
1341
  } else if (mode === "both") {
771
- result = injectMangleMapAttribute(result, mangleMap, minify);
1342
+ result = injectMangleMapAttribute(result, mangleMap, minify, options.varMangleMap);
772
1343
  result = injectMangleMapScript(result, mangleMap, options);
773
1344
  }
774
1345
  return result;
@@ -776,6 +1347,25 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
776
1347
  function transformIndexHtml(html, mangleMap, checksum, options = {}) {
777
1348
  return injectHydrationData(html, mangleMap, checksum, options);
778
1349
  }
1350
+ function createHydrationMangleMap(classMap, varMap = {}) {
1351
+ if (Object.keys(varMap).length === 0) {
1352
+ return classMap;
1353
+ }
1354
+ const payload = {};
1355
+ for (const [key, value] of Object.entries(classMap)) {
1356
+ payload[`class:${key}`] = value;
1357
+ }
1358
+ for (const [key, value] of Object.entries(varMap)) {
1359
+ if (Array.isArray(value)) {
1360
+ for (const mangled of value) {
1361
+ payload[`var:${key}:${mangled}`] = mangled;
1362
+ }
1363
+ } else {
1364
+ payload[`var:${key}`] = value;
1365
+ }
1366
+ }
1367
+ return payload;
1368
+ }
779
1369
  function buildRecoveryManifest(tokens, options) {
780
1370
  const stripped = options.production === true;
781
1371
  const strippedDevOnlyPaths = [];
@@ -817,6 +1407,36 @@ function injectRecoveryManifest(html, manifest) {
817
1407
  return html + scriptTag;
818
1408
  }
819
1409
 
1410
+ const DEFAULT_MAX_ATTEMPTS = 3;
1411
+ const NODE_FS = {
1412
+ openSync: fs__namespace.openSync,
1413
+ fstatSync: (fd, options) => fs__namespace.fstatSync(fd, options),
1414
+ readFileSync: (fd, encoding) => fs__namespace.readFileSync(fd, encoding),
1415
+ closeSync: fs__namespace.closeSync
1416
+ };
1417
+ function readStableTextFileSnapshotSync(file, maxAttempts = DEFAULT_MAX_ATTEMPTS, fsApi = NODE_FS) {
1418
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
1419
+ throw new RangeError("maxAttempts must be a positive integer.");
1420
+ }
1421
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
1422
+ const fd = fsApi.openSync(file, "r");
1423
+ try {
1424
+ const before = fsApi.fstatSync(fd, { bigint: true });
1425
+ const source = fsApi.readFileSync(fd, "utf8");
1426
+ const after = fsApi.fstatSync(fd, { bigint: true });
1427
+ if (isSameFileVersion(before, after)) {
1428
+ return { source, mtimeMs: Number(after.mtimeMs) };
1429
+ }
1430
+ } finally {
1431
+ fsApi.closeSync(fd);
1432
+ }
1433
+ }
1434
+ throw new Error(`CSS source changed while being read: ${file}`);
1435
+ }
1436
+ function isSameFileVersion(before, after) {
1437
+ return before.dev === after.dev && before.ino === after.ino && before.size === after.size && before.mtimeNs === after.mtimeNs && before.ctimeNs === after.ctimeNs;
1438
+ }
1439
+
820
1440
  function generateThemeDts(opts) {
821
1441
  const { theme, sourceFiles } = opts;
822
1442
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -863,219 +1483,368 @@ function writeThemeDts(opts) {
863
1483
  fs.writeFileSync(opts.outputPath, content, "utf-8");
864
1484
  }
865
1485
 
866
- const CACHE_SCHEMA_VERSION = 2;
867
- function resolveTransformCacheDir(rootDir, cacheDir) {
868
- return path__namespace.resolve(rootDir, cacheDir ?? ".csszyx/cache", "transform");
869
- }
870
- function createTransformCacheKey(input) {
871
- const inputSha256 = node_crypto.createHash("sha256").update(input.source).digest("hex");
872
- const keyMaterial = [
873
- `schema=${CACHE_SCHEMA_VERSION}`,
874
- `plugin=${input.pluginVersion}`,
875
- `compiler=${input.compilerVersion}`,
876
- `parser=${input.parserMode}`,
877
- `producer=${input.producer}`,
878
- `astBudget=${input.astBudget ?? "default"}`,
879
- `filename=${input.filename}`,
880
- `source=${inputSha256}`
881
- ].join("\n");
882
- return {
883
- key: node_crypto.createHash("sha256").update(keyMaterial).digest("hex").slice(0, 16),
884
- inputSha256
885
- };
1486
+ const VIRTUAL_MODULE_ID = "virtual:csszyx/mangle-map";
1487
+ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
1488
+ const VIRTUAL_CHECKSUM_ID = "virtual:csszyx/checksum";
1489
+ const RESOLVED_VIRTUAL_CHECKSUM_ID = `\0${VIRTUAL_CHECKSUM_ID}`;
1490
+ function createMangleMapModule(mangleMap, checksum, varMangleMap = {}, cssVarMetrics = null) {
1491
+ return `/**
1492
+ * Auto-generated mangle map for csszyx.
1493
+ * This module is generated at build time and contains the mapping
1494
+ * from original class names and CSS variable names to mangled names.
1495
+ *
1496
+ * @generated
1497
+ */
1498
+
1499
+ export const mangleMap = ${JSON.stringify(mangleMap, null, 2)};
1500
+
1501
+ export const varMangleMap = ${JSON.stringify(varMangleMap, null, 2)};
1502
+
1503
+ export const cssVarMetrics = ${JSON.stringify(cssVarMetrics, null, 2)};
1504
+
1505
+ export const checksum = ${JSON.stringify(checksum)};
1506
+
1507
+ export default {
1508
+ mangleMap,
1509
+ varMangleMap,
1510
+ cssVarMetrics,
1511
+ checksum,
1512
+ };
1513
+ `;
886
1514
  }
887
- function readTransformCache(cacheRoot, input, precomputedKey) {
888
- const { key, inputSha256 } = precomputedKey ?? createTransformCacheKey(input);
889
- const file = cacheEntryPath(cacheRoot, key);
890
- let entry;
891
- try {
892
- entry = JSON.parse(fs__namespace.readFileSync(file, "utf8"));
893
- } catch {
894
- return null;
1515
+ function createChecksumModule(checksum) {
1516
+ return `/**
1517
+ * Auto-generated checksum for csszyx mangle map.
1518
+ *
1519
+ * @generated
1520
+ */
1521
+
1522
+ export const checksum = ${JSON.stringify(checksum)};
1523
+
1524
+ export default checksum;
1525
+ `;
1526
+ }
1527
+ function isVirtualModule(id) {
1528
+ return id === VIRTUAL_MODULE_ID || id === VIRTUAL_CHECKSUM_ID;
1529
+ }
1530
+ function resolveVirtualModule(id) {
1531
+ if (id === VIRTUAL_MODULE_ID) {
1532
+ return RESOLVED_VIRTUAL_MODULE_ID;
895
1533
  }
896
- if (entry.version !== CACHE_SCHEMA_VERSION || entry.pluginVersion !== input.pluginVersion || entry.compilerVersion !== input.compilerVersion || entry.parserMode !== input.parserMode || entry.producer !== input.producer || entry.astBudget !== (input.astBudget ?? null) || entry.filename !== input.filename || entry.inputSha256 !== inputSha256) {
897
- return null;
1534
+ if (id === VIRTUAL_CHECKSUM_ID) {
1535
+ return RESOLVED_VIRTUAL_CHECKSUM_ID;
898
1536
  }
899
- return deserializeResult(entry.result);
1537
+ return void 0;
900
1538
  }
901
- function writeTransformCache(cacheRoot, input, result, precomputedKey) {
902
- const { key, inputSha256 } = precomputedKey ?? createTransformCacheKey(input);
903
- const file = cacheEntryPath(cacheRoot, key);
904
- const dir = path__namespace.dirname(file);
905
- const tmp = path__namespace.join(
906
- dir,
907
- `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
908
- );
909
- const entry = {
910
- version: CACHE_SCHEMA_VERSION,
911
- pluginVersion: input.pluginVersion,
912
- compilerVersion: input.compilerVersion,
913
- parserMode: input.parserMode,
914
- producer: input.producer,
915
- astBudget: input.astBudget ?? null,
916
- filename: input.filename,
917
- inputSha256,
918
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
919
- result: serializeResult(result)
920
- };
921
- try {
922
- fs__namespace.mkdirSync(dir, { recursive: true });
923
- fs__namespace.writeFileSync(tmp, JSON.stringify(entry), "utf8");
924
- fs__namespace.renameSync(tmp, file);
925
- } catch {
926
- try {
927
- fs__namespace.rmSync(tmp, { force: true });
928
- } catch {
1539
+
1540
+ const CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
1541
+ const MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
1542
+ const VAR_MANGLE_MAP_PLACEHOLDER = "___CSSZYX_VAR_MANGLE_MAP___";
1543
+ const UNKNOWN_PACKAGE_VERSION = "0.0.0";
1544
+ const TRANSFORM_CACHE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
1545
+ const TRANSFORM_CACHE_MAX_ENTRIES = 1e4;
1546
+ const TRANSFORM_MEMORY_CACHE_MAX_ENTRIES = 1e3;
1547
+ const DEFAULT_VAR_MANGLE_MAP_MAX_BYTES = 100 * 1024;
1548
+ const GLOBAL_VAR_ALIAS_MAP_OWNER = "\0csszyx:global-var-aliases";
1549
+ const DIRECTIVE_PROLOGUE_PREFIX_RE = /^((?:\s|\/\/[^\n]*\n|\/\*(?:[^*]|\*(?!\/))*\*\/)*)(['"]use (?:client|server)['"];?\s*)/;
1550
+ const RUNTIME_HELPER_IMPORT_RE = {
1551
+ _sz: /\{[^}]*\b_sz\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/,
1552
+ _szMerge: /\{[^}]*\b_szMerge\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/,
1553
+ __szColorVar: /\{[^}]*\b__szColorVar\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/
1554
+ };
1555
+ let _hasWarnedTsConfig = false;
1556
+ let _hasWarnedTransformCacheVersion = false;
1557
+ const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.CFp386gH.cjs', document.baseURI).href)));
1558
+ const PLUGIN_VERSION = findPackageVersionFromFile(
1559
+ node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.CFp386gH.cjs', document.baseURI).href))),
1560
+ UNKNOWN_PACKAGE_VERSION
1561
+ );
1562
+ const COMPILER_VERSION = findPackageVersionFromModule("@csszyx/compiler", UNKNOWN_PACKAGE_VERSION);
1563
+ const BENCH_TRACE_ENABLED = process.env.CSSZYX_BENCH_TRACE === "1";
1564
+ const BENCH_TRACE_FILE = process.env.CSSZYX_BENCH_TRACE_FILE;
1565
+ function cssVariableEntries(result) {
1566
+ const entries = [];
1567
+ for (const [original, value] of result.cssVariableMap ?? []) {
1568
+ if (Array.isArray(value)) {
1569
+ for (const mangled of value) {
1570
+ entries.push([original, mangled]);
1571
+ }
1572
+ } else {
1573
+ entries.push([original, value]);
929
1574
  }
930
1575
  }
1576
+ return entries;
1577
+ }
1578
+ function recordFileVarMangleEntries(state, filename, entries) {
1579
+ const normalizedFilename = normalizeSourceFilename(filename);
1580
+ if (entries.length === 0) {
1581
+ state.varMangleEntriesByFile.delete(normalizedFilename);
1582
+ } else {
1583
+ state.varMangleEntriesByFile.set(normalizedFilename, entries);
1584
+ }
1585
+ state.varMangleMap = buildVarMangleMap(state.varMangleEntriesByFile);
1586
+ }
1587
+ function recordGlobalVarSourceFile(state, filename, code) {
1588
+ const normalizedFilename = normalizeSourceFilename(filename);
1589
+ if (!/\.[tj]sx?(?:\?.*)?$/.test(normalizedFilename)) {
1590
+ return;
1591
+ }
1592
+ if (code === null) {
1593
+ state.globalVarSourceFilesByFile.delete(normalizedFilename);
1594
+ } else {
1595
+ state.globalVarSourceFilesByFile.set(normalizedFilename, code);
1596
+ }
1597
+ }
1598
+ function buildGlobalVarSourceFiles(state) {
1599
+ return [...state.globalVarSourceFilesByFile.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([filePath, code]) => ({ filePath, code }));
1600
+ }
1601
+ function collectRollupGlobalVarCssAssets(bundle) {
1602
+ return Object.values(bundle).filter(
1603
+ (chunk) => chunk.type === "asset" && typeof chunk.fileName === "string" && /\.css(?:$|\?)/.test(chunk.fileName) && (typeof chunk.source === "string" || chunk.source instanceof Uint8Array)
1604
+ ).sort((left, right) => left.fileName.localeCompare(right.fileName)).map((asset) => ({
1605
+ fileName: asset.fileName,
1606
+ source: asset.source
1607
+ }));
931
1608
  }
932
- function evictOldTransformCacheEntries(cacheRoot, options) {
933
- let deleted = 0;
934
- const now = options.now ?? Date.now();
935
- const survivors = [];
936
- for (const file of listJsonFiles(cacheRoot)) {
1609
+ function collectConfiguredGlobalVarCssSources(rootDir, scanCss) {
1610
+ if (!scanCss) {
1611
+ return [];
1612
+ }
1613
+ return expandFilePatterns(rootDir, scanCss).filter((file) => file.endsWith(".css")).sort((left, right) => left.localeCompare(right)).flatMap((file) => {
937
1614
  try {
938
- const entry = JSON.parse(fs__namespace.readFileSync(file, "utf8"));
939
- const timestamp = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : 0;
940
- if (!Number.isFinite(timestamp) || now - timestamp > options.maxAgeMs) {
941
- fs__namespace.rmSync(file, { force: true });
942
- deleted++;
943
- } else {
944
- survivors.push({ file, timestamp });
945
- }
1615
+ const snapshot = readStableTextFileSnapshotSync(file);
1616
+ return [
1617
+ {
1618
+ fileName: file,
1619
+ source: snapshot.source,
1620
+ mtimeMs: snapshot.mtimeMs
1621
+ }
1622
+ ];
946
1623
  } catch {
947
- fs__namespace.rmSync(file, { force: true });
948
- deleted++;
1624
+ return [];
949
1625
  }
1626
+ });
1627
+ }
1628
+ function collectWebpackGlobalVarCssAssets(assets) {
1629
+ return Object.entries(assets).flatMap(([fileName, asset]) => {
1630
+ if (!/\.css(?:$|\?)/.test(fileName)) {
1631
+ return [];
1632
+ }
1633
+ const source = asset.source();
1634
+ if (typeof source !== "string" && !(source instanceof Uint8Array)) {
1635
+ return [];
1636
+ }
1637
+ return [{ fileName, source }];
1638
+ }).sort((left, right) => left.fileName.localeCompare(right.fileName)).map(({ fileName, source }) => ({ fileName, source }));
1639
+ }
1640
+ function assertNoGlobalVarAliasValidationErrors(result) {
1641
+ const messages = [
1642
+ ...result.plan.diagnostics.map((diagnostic) => {
1643
+ const location = diagnostic.location ? ` (${diagnostic.location.filePath}:${diagnostic.location.line}:${diagnostic.location.column})` : "";
1644
+ return `[${diagnostic.code}] ${diagnostic.name}${location}: ${diagnostic.message}`;
1645
+ }),
1646
+ ...result.usageDiagnostics.map((diagnostic) => {
1647
+ const location = diagnostic.location;
1648
+ return `[${diagnostic.kind}] ${diagnostic.name} (${location.filePath}:${location.line}:${location.column}): ${diagnostic.message}`;
1649
+ })
1650
+ ];
1651
+ if (messages.length > 0) {
1652
+ throw new Error(
1653
+ `[csszyx] production.mangleGlobalVars validation failed:
1654
+ ${messages.join("\n")}`
1655
+ );
1656
+ }
1657
+ }
1658
+ function rewriteCssWithValidatedGlobalVarPlan(css, filePath, result) {
1659
+ if (result === null || result.plan.entries.length === 0) {
1660
+ return css;
1661
+ }
1662
+ const rewrite = rewriteGlobalVarCssAliases({
1663
+ css,
1664
+ plan: result.plan,
1665
+ filePath
1666
+ });
1667
+ assertNoGlobalVarAliasValidationErrors({
1668
+ scans: result.scans,
1669
+ plan: {
1670
+ ...result.plan,
1671
+ diagnostics: rewrite.diagnostics
1672
+ },
1673
+ usageDiagnostics: []
1674
+ });
1675
+ return rewrite.css;
1676
+ }
1677
+ function assertGlobalVarPlanMatchesEarlyAliases(result, expectedEntries) {
1678
+ const actualEntries = [...result.plan.aliases.entries()].sort(
1679
+ ([left], [right]) => left.localeCompare(right)
1680
+ );
1681
+ const expected = expectedEntries.map(([original, alias]) => [original, alias]).sort(([left], [right]) => left.localeCompare(right));
1682
+ const expectedJson = JSON.stringify(expected);
1683
+ const actualJson = JSON.stringify(actualEntries);
1684
+ if (expectedJson !== actualJson) {
1685
+ throw new Error(
1686
+ `[csszyx] production.mangleGlobalVars validation failed:
1687
+ CSS alias plan ${actualJson} does not match source-transform alias table ${expectedJson}.`
1688
+ );
950
1689
  }
951
- const overflow = survivors.length - options.maxEntries ;
952
- if (overflow > 0) {
953
- survivors.sort((a, b) => a.timestamp - b.timestamp);
954
- for (const survivor of survivors.slice(0, overflow)) {
955
- fs__namespace.rmSync(survivor.file, { force: true });
956
- deleted++;
1690
+ }
1691
+ function buildVarMangleMap(entriesByFile) {
1692
+ const next = {};
1693
+ const files = [...entriesByFile.keys()].sort();
1694
+ for (const file of files) {
1695
+ for (const [original, mangled] of entriesByFile.get(file) ?? []) {
1696
+ addVarMangleMapping(next, original, mangled);
957
1697
  }
958
1698
  }
959
- return deleted;
1699
+ return next;
960
1700
  }
961
- function cacheEntryPath(cacheRoot, key) {
962
- return path__namespace.join(cacheRoot, key.slice(0, 2), `${key.slice(2)}.json`);
1701
+ function extractGlobalVarAliasesForManifest(varMangleMap, aliasPrefix = types.CSSZYX_GLOBAL_ALIAS_PREFIX, validationResult = null) {
1702
+ const aliases = {};
1703
+ for (const [original, value] of Object.entries(varMangleMap).sort(
1704
+ ([left], [right]) => left.localeCompare(right)
1705
+ )) {
1706
+ const values = Array.isArray(value) ? value : [value];
1707
+ const alias = values.find((candidate) => candidate.startsWith(aliasPrefix));
1708
+ if (alias) {
1709
+ aliases[original] = alias;
1710
+ }
1711
+ }
1712
+ for (const entry of validationResult?.plan.entries ?? []) {
1713
+ if (entry.alias.startsWith(aliasPrefix)) {
1714
+ aliases[entry.original] = entry.alias;
1715
+ }
1716
+ }
1717
+ return Object.fromEntries(
1718
+ Object.entries(aliases).sort(([left], [right]) => left.localeCompare(right))
1719
+ );
963
1720
  }
964
- function serializeResult(result) {
965
- return {
966
- code: result.code,
967
- transformed: result.transformed,
968
- usesRuntime: result.usesRuntime,
969
- usesMerge: result.usesMerge,
970
- usesColorVar: result.usesColorVar,
971
- classes: [...result.classes],
972
- rawClassNames: [...result.rawClassNames],
973
- diagnostics: [...result.diagnostics],
974
- recoveryTokens: [...result.recoveryTokens]
975
- };
1721
+ function createGlobalVarMapAssetSource(varMangleMap, aliasPrefix = types.CSSZYX_GLOBAL_ALIAS_PREFIX, validationResult = null) {
1722
+ const aliases = extractGlobalVarAliasesForManifest(varMangleMap, aliasPrefix, validationResult);
1723
+ return Object.keys(aliases).length > 0 ? JSON.stringify(aliases) : null;
976
1724
  }
977
- function deserializeResult(result) {
1725
+ function normalizeGlobalVarAliasesForCache(aliases) {
1726
+ if (!aliases) {
1727
+ return [];
1728
+ }
1729
+ const entries = aliases instanceof Map ? aliases.entries() : Array.isArray(aliases) ? aliases : Object.entries(aliases);
1730
+ const normalized = /* @__PURE__ */ new Map();
1731
+ for (const [original, alias] of entries) {
1732
+ if (original.startsWith("--") && alias.startsWith("--")) {
1733
+ normalized.set(original, alias);
1734
+ }
1735
+ }
1736
+ return [...normalized].sort(([left], [right]) => left.localeCompare(right));
1737
+ }
1738
+ function createEarlyGlobalVarAliasEntries(config, aliasPrefix) {
1739
+ if (config?.enabled !== true || !config.tokens || config.tokens.length === 0) {
1740
+ return [];
1741
+ }
1742
+ const tokens = [...new Set(config.tokens)].sort();
1743
+ return tokens.map((original, index) => [original, `${aliasPrefix}${core.encode(index)}`]);
1744
+ }
1745
+ function shouldEmitGlobalVarMapAsset(config) {
1746
+ return config?.emitMap !== false;
1747
+ }
1748
+ function assertVarMangleMapSize(varMangleMap, maxBytes) {
1749
+ const size = Buffer.byteLength(JSON.stringify(varMangleMap), "utf8");
1750
+ if (size <= maxBytes) {
1751
+ return;
1752
+ }
1753
+ throw new Error(
1754
+ `[csszyx] CSS variable mangle map is ${size} bytes, which exceeds the ${maxBytes} byte safety cap. Reduce production.mangleVars usage, split the bundle, or raise CSSZYX_VAR_MANGLE_MAP_MAX_BYTES if this payload size is intentional.`
1755
+ );
1756
+ }
1757
+ function resolveVarMangleMapMaxBytes() {
1758
+ const raw = process.env.CSSZYX_VAR_MANGLE_MAP_MAX_BYTES;
1759
+ if (!raw) {
1760
+ return DEFAULT_VAR_MANGLE_MAP_MAX_BYTES;
1761
+ }
1762
+ const value = Number.parseInt(raw, 10);
1763
+ return Number.isFinite(value) && value > 0 ? value : DEFAULT_VAR_MANGLE_MAP_MAX_BYTES;
1764
+ }
1765
+ function addVarMangleMapping(map, original, mangled) {
1766
+ const existing = map[original];
1767
+ if (!existing) {
1768
+ map[original] = mangled;
1769
+ return;
1770
+ }
1771
+ const values = Array.isArray(existing) ? existing : [existing];
1772
+ if (!values.includes(mangled)) {
1773
+ map[original] = [...values, mangled];
1774
+ }
1775
+ }
1776
+ function emptyCSSVariableMetrics() {
978
1777
  return {
979
- code: result.code,
980
- transformed: result.transformed,
981
- usesRuntime: result.usesRuntime,
982
- usesMerge: result.usesMerge,
983
- usesColorVar: result.usesColorVar,
984
- classes: new Set(result.classes),
985
- rawClassNames: new Set(result.rawClassNames),
986
- diagnostics: [...result.diagnostics],
987
- recoveryTokens: new Map(result.recoveryTokens)
1778
+ componentClassUses: 0,
1779
+ componentStyleDeclarations: 0,
1780
+ estimatedHoistedDeclarationsSaved: 0,
1781
+ scopedClassUses: 0,
1782
+ scopedStyleDeclarations: 0
988
1783
  };
989
1784
  }
990
- function listJsonFiles(dir) {
991
- let entries;
992
- try {
993
- entries = fs__namespace.readdirSync(dir, { withFileTypes: true });
994
- } catch {
995
- return [];
1785
+ function recordFileCSSVariableMetrics(state, filename, code) {
1786
+ const normalizedFilename = normalizeSourceFilename(filename);
1787
+ if (!code) {
1788
+ state.cssVarMetricsByFile.delete(normalizedFilename);
1789
+ } else {
1790
+ const metrics = collectCSSVariableMetrics(code);
1791
+ if (hasCSSVariableMetrics(metrics)) {
1792
+ state.cssVarMetricsByFile.set(normalizedFilename, metrics);
1793
+ } else {
1794
+ state.cssVarMetricsByFile.delete(normalizedFilename);
1795
+ }
1796
+ }
1797
+ state.cssVarMetrics = buildCSSVariableMetrics(state.cssVarMetricsByFile);
1798
+ }
1799
+ function collectCSSVariableMetrics(code) {
1800
+ const componentUses = /* @__PURE__ */ new Map();
1801
+ const componentDeclarations = /* @__PURE__ */ new Map();
1802
+ const metrics = emptyCSSVariableMetrics();
1803
+ for (const match of code.matchAll(/\(--([cs][A-Za-z0-9]+)\)/g)) {
1804
+ const name = `--${match[1]}`;
1805
+ if (name.startsWith("--c")) {
1806
+ metrics.componentClassUses++;
1807
+ incrementCount(componentUses, name);
1808
+ } else {
1809
+ metrics.scopedClassUses++;
1810
+ }
996
1811
  }
997
- const files = [];
998
- for (const entry of entries) {
999
- const fullPath = path__namespace.join(dir, entry.name);
1000
- if (entry.isDirectory()) {
1001
- files.push(...listJsonFiles(fullPath));
1002
- } else if (entry.isFile() && entry.name.endsWith(".json")) {
1003
- files.push(fullPath);
1812
+ for (const match of code.matchAll(/["'](--([cs][A-Za-z0-9]+))["']\s*:/g)) {
1813
+ const name = match[1];
1814
+ if (name.startsWith("--c")) {
1815
+ metrics.componentStyleDeclarations++;
1816
+ incrementCount(componentDeclarations, name);
1817
+ } else {
1818
+ metrics.scopedStyleDeclarations++;
1004
1819
  }
1005
1820
  }
1006
- return files;
1007
- }
1008
-
1009
- const VIRTUAL_MODULE_ID = "virtual:csszyx/mangle-map";
1010
- const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
1011
- const VIRTUAL_CHECKSUM_ID = "virtual:csszyx/checksum";
1012
- const RESOLVED_VIRTUAL_CHECKSUM_ID = `\0${VIRTUAL_CHECKSUM_ID}`;
1013
- function createMangleMapModule(mangleMap, checksum) {
1014
- return `/**
1015
- * Auto-generated mangle map for csszyx.
1016
- * This module is generated at build time and contains the mapping
1017
- * from original class names to mangled class names.
1018
- *
1019
- * @generated
1020
- */
1021
-
1022
- export const mangleMap = ${JSON.stringify(mangleMap, null, 2)};
1023
-
1024
- export const checksum = ${JSON.stringify(checksum)};
1025
-
1026
- export default {
1027
- mangleMap,
1028
- checksum,
1029
- };
1030
- `;
1821
+ for (const [name, uses] of componentUses) {
1822
+ const declarations = componentDeclarations.get(name) ?? 0;
1823
+ metrics.estimatedHoistedDeclarationsSaved += Math.max(0, uses - declarations);
1824
+ }
1825
+ return metrics;
1031
1826
  }
1032
- function createChecksumModule(checksum) {
1033
- return `/**
1034
- * Auto-generated checksum for csszyx mangle map.
1035
- *
1036
- * @generated
1037
- */
1038
-
1039
- export const checksum = ${JSON.stringify(checksum)};
1040
-
1041
- export default checksum;
1042
- `;
1827
+ function buildCSSVariableMetrics(metricsByFile) {
1828
+ const total = emptyCSSVariableMetrics();
1829
+ for (const file of [...metricsByFile.keys()].sort()) {
1830
+ const metrics = metricsByFile.get(file);
1831
+ if (!metrics) {
1832
+ continue;
1833
+ }
1834
+ total.componentClassUses += metrics.componentClassUses;
1835
+ total.componentStyleDeclarations += metrics.componentStyleDeclarations;
1836
+ total.estimatedHoistedDeclarationsSaved += metrics.estimatedHoistedDeclarationsSaved;
1837
+ total.scopedClassUses += metrics.scopedClassUses;
1838
+ total.scopedStyleDeclarations += metrics.scopedStyleDeclarations;
1839
+ }
1840
+ return total;
1043
1841
  }
1044
- function isVirtualModule(id) {
1045
- return id === VIRTUAL_MODULE_ID || id === VIRTUAL_CHECKSUM_ID;
1842
+ function hasCSSVariableMetrics(metrics) {
1843
+ return Object.values(metrics).some((value) => value > 0);
1046
1844
  }
1047
- function resolveVirtualModule(id) {
1048
- if (id === VIRTUAL_MODULE_ID) {
1049
- return RESOLVED_VIRTUAL_MODULE_ID;
1050
- }
1051
- if (id === VIRTUAL_CHECKSUM_ID) {
1052
- return RESOLVED_VIRTUAL_CHECKSUM_ID;
1053
- }
1054
- return void 0;
1845
+ function incrementCount(map, key) {
1846
+ map.set(key, (map.get(key) ?? 0) + 1);
1055
1847
  }
1056
-
1057
- const CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
1058
- const MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
1059
- const UNKNOWN_PACKAGE_VERSION = "0.0.0";
1060
- const TRANSFORM_CACHE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
1061
- const TRANSFORM_CACHE_MAX_ENTRIES = 1e4;
1062
- const TRANSFORM_MEMORY_CACHE_MAX_ENTRIES = 1e3;
1063
- const DIRECTIVE_PROLOGUE_PREFIX_RE = /^((?:\s|\/\/[^\n]*\n|\/\*(?:[^*]|\*(?!\/))*\*\/)*)(['"]use (?:client|server)['"];?\s*)/;
1064
- const RUNTIME_HELPER_IMPORT_RE = {
1065
- _sz: /\{[^}]*\b_sz\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/,
1066
- _szMerge: /\{[^}]*\b_szMerge\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/,
1067
- __szColorVar: /\{[^}]*\b__szColorVar\b[^}]*\}\s*from\s*['"]@csszyx\/runtime['"]/
1068
- };
1069
- let _hasWarnedTsConfig = false;
1070
- let _hasWarnedTransformCacheVersion = false;
1071
- const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.CL0F6RZa.cjs', document.baseURI).href)));
1072
- const PLUGIN_VERSION = findPackageVersionFromFile(
1073
- node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.CL0F6RZa.cjs', document.baseURI).href))),
1074
- UNKNOWN_PACKAGE_VERSION
1075
- );
1076
- const COMPILER_VERSION = findPackageVersionFromModule("@csszyx/compiler", UNKNOWN_PACKAGE_VERSION);
1077
- const BENCH_TRACE_ENABLED = process.env.CSSZYX_BENCH_TRACE === "1";
1078
- const BENCH_TRACE_FILE = process.env.CSSZYX_BENCH_TRACE_FILE;
1079
1848
  function traceBenchTiming(label, filename, elapsedMs) {
1080
1849
  if (!BENCH_TRACE_ENABLED) {
1081
1850
  return;
@@ -1097,7 +1866,7 @@ function runThemeScan(rootDir, scanCss) {
1097
1866
  }
1098
1867
  const themes = sourceFiles.map((f) => {
1099
1868
  try {
1100
- return parseThemeBlocks(fs__namespace.readFileSync(f, "utf-8"));
1869
+ return parseThemeBlocks(readStableTextFileSnapshotSync(f).source);
1101
1870
  } catch {
1102
1871
  return null;
1103
1872
  }
@@ -1109,18 +1878,23 @@ function runThemeScan(rootDir, scanCss) {
1109
1878
  _hasWarnedTsConfig = true;
1110
1879
  try {
1111
1880
  const checkFile = (cfgPath) => {
1112
- if (fs__namespace.existsSync(cfgPath)) {
1113
- const content = fs__namespace.readFileSync(cfgPath, "utf-8");
1114
- if (!content.includes(".csszyx")) {
1115
- console.warn(
1116
- `
1881
+ let content;
1882
+ try {
1883
+ content = fs__namespace.readFileSync(cfgPath, "utf-8");
1884
+ } catch (err) {
1885
+ if (err?.code === "ENOENT") {
1886
+ return false;
1887
+ }
1888
+ throw err;
1889
+ }
1890
+ if (!content.includes(".csszyx")) {
1891
+ console.warn(
1892
+ `
1117
1893
  \x1B[33m\u26A0\uFE0F CSSzyx: Theme Auto-Scan enabled, but TypeScript isn't configured. Run "npx @csszyx/cli init" to fix.\x1B[0m
1118
1894
  `
1119
- );
1120
- }
1121
- return true;
1895
+ );
1122
1896
  }
1123
- return false;
1897
+ return true;
1124
1898
  };
1125
1899
  if (!checkFile(path__namespace.join(rootDir, "tsconfig.json"))) {
1126
1900
  checkFile(path__namespace.join(rootDir, "tsconfig.app.json"));
@@ -1337,12 +2111,43 @@ function mangleCodeClassesSync(code, mangleMap) {
1337
2111
  });
1338
2112
  return result;
1339
2113
  }
2114
+ function assertGlobalVarMangleConfig(options) {
2115
+ const config = options.production?.mangleGlobalVars;
2116
+ const errors = types.validateGlobalVarMangleConfig(config);
2117
+ if (errors.length > 0) {
2118
+ throw new Error(
2119
+ `[csszyx] Invalid production.mangleGlobalVars config:
2120
+ ${errors.join("\n")}`
2121
+ );
2122
+ }
2123
+ if (config?.enabled === true) {
2124
+ if (!config.tokens || config.tokens.length === 0) {
2125
+ throw new Error(
2126
+ "[csszyx] production.mangleGlobalVars.enabled requires explicit tokens in Phase H v1."
2127
+ );
2128
+ }
2129
+ if (config.autoPrefix !== void 0 && config.autoPrefix !== "") {
2130
+ throw new Error(
2131
+ "[csszyx] production.mangleGlobalVars.autoPrefix requires CSS pre-scan support and is not enabled in Phase H v1."
2132
+ );
2133
+ }
2134
+ }
2135
+ }
1340
2136
  function createCsszyxPlugins(options = {}) {
2137
+ assertGlobalVarMangleConfig(options);
1341
2138
  const manglingEnabled = options.production?.mangle !== false;
1342
2139
  const astBudgetOverride = options.build?.astBudgetLimit;
1343
2140
  const cacheRequested = (options.build?.cache ?? types.DEFAULT_BUILD_CONFIG.cache) !== false;
1344
2141
  const cacheVersionsKnown = PLUGIN_VERSION !== UNKNOWN_PACKAGE_VERSION && COMPILER_VERSION !== UNKNOWN_PACKAGE_VERSION;
1345
2142
  const cacheEnabled = cacheRequested && cacheVersionsKnown;
2143
+ const varMangleMapMaxBytes = resolveVarMangleMapMaxBytes();
2144
+ const globalVarMangleConfig = options.production?.mangleGlobalVars;
2145
+ const globalVarAliasPrefix = globalVarMangleConfig?.aliasPrefix ?? types.CSSZYX_GLOBAL_ALIAS_PREFIX;
2146
+ const encodedGlobalVarAliasPrefix = encodeURIComponent(globalVarAliasPrefix);
2147
+ const earlyGlobalVarAliasEntries = createEarlyGlobalVarAliasEntries(
2148
+ globalVarMangleConfig,
2149
+ globalVarAliasPrefix
2150
+ );
1346
2151
  if (cacheRequested && !cacheVersionsKnown && !_hasWarnedTransformCacheVersion) {
1347
2152
  _hasWarnedTransformCacheVersion = true;
1348
2153
  console.warn(
@@ -1357,12 +2162,21 @@ function createCsszyxPlugins(options = {}) {
1357
2162
  const state = {
1358
2163
  classes: /* @__PURE__ */ new Set(),
1359
2164
  mangleMap: {},
2165
+ varMangleEntriesByFile: /* @__PURE__ */ new Map(),
2166
+ varMangleMap: Object.fromEntries(earlyGlobalVarAliasEntries),
2167
+ cssVarMetricsByFile: /* @__PURE__ */ new Map(),
2168
+ cssVarMetrics: emptyCSSVariableMetrics(),
1360
2169
  checksum: "",
1361
2170
  finalized: false,
1362
2171
  rootDir: process.cwd(),
1363
2172
  recoveryTokens: /* @__PURE__ */ new Map(),
1364
- rscModules: /* @__PURE__ */ new Map()
2173
+ rscModules: /* @__PURE__ */ new Map(),
2174
+ globalVarSourceFilesByFile: /* @__PURE__ */ new Map(),
2175
+ globalVarValidationResult: null
1365
2176
  };
2177
+ if (earlyGlobalVarAliasEntries.length > 0) {
2178
+ state.varMangleEntriesByFile.set(GLOBAL_VAR_ALIAS_MAP_OWNER, earlyGlobalVarAliasEntries);
2179
+ }
1366
2180
  const SAFELIST_FILENAME = "csszyx-classes.html";
1367
2181
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
1368
2182
  const IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", ".turbo"]);
@@ -1372,6 +2186,40 @@ function createCsszyxPlugins(options = {}) {
1372
2186
  function isUserIncluded(id) {
1373
2187
  return !options.include || matchesAnyPattern(id, options.include, state.rootDir);
1374
2188
  }
2189
+ function resolveGlobalVarValidationCacheDir() {
2190
+ if (!cacheEnabled) {
2191
+ return void 0;
2192
+ }
2193
+ const cacheRoot = path__namespace.resolve(
2194
+ state.rootDir,
2195
+ options.build?.cacheDir ?? types.DEFAULT_BUILD_CONFIG.cacheDir ?? ".csszyx/cache"
2196
+ );
2197
+ return resolveGlobalVarScanCacheDir(cacheRoot);
2198
+ }
2199
+ function validateGlobalVarBundleInputs(cssAssets) {
2200
+ if (globalVarMangleConfig?.enabled !== true) {
2201
+ return null;
2202
+ }
2203
+ const configuredCssAssets = collectConfiguredGlobalVarCssSources(
2204
+ state.rootDir,
2205
+ options.build?.scanCss
2206
+ );
2207
+ const result = validateGlobalVarAliasInputs(
2208
+ createGlobalVarAliasValidationOptions({
2209
+ rootDir: state.rootDir,
2210
+ cssAssets: [...configuredCssAssets, ...cssAssets],
2211
+ sourceFiles: buildGlobalVarSourceFiles(state),
2212
+ tokens: globalVarMangleConfig.tokens,
2213
+ autoPrefix: globalVarMangleConfig.autoPrefix,
2214
+ aliasPrefix: globalVarAliasPrefix,
2215
+ reserved: globalVarMangleConfig.reserved,
2216
+ cacheDir: resolveGlobalVarValidationCacheDir()
2217
+ })
2218
+ );
2219
+ assertNoGlobalVarAliasValidationErrors(result);
2220
+ assertGlobalVarPlanMatchesEarlyAliases(result, earlyGlobalVarAliasEntries);
2221
+ return result;
2222
+ }
1375
2223
  function isHardIgnored(id) {
1376
2224
  return id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static");
1377
2225
  }
@@ -1382,25 +2230,21 @@ function createCsszyxPlugins(options = {}) {
1382
2230
  return !isHardIgnored(id) && !isUserExcluded(id) && /\.css(\?.*)?$/.test(id);
1383
2231
  }
1384
2232
  function transformConfiguredSource(source, filename) {
1385
- const compilerOptions = { astBudget: astBudgetOverride };
2233
+ const compilerOptions = createCompilerOptions();
1386
2234
  const effectiveFilename = normalizeSourceFilename(filename);
1387
- const cacheRoot = resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
2235
+ const cacheRoot = transformCache.resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
1388
2236
  if (cacheEnabled) {
1389
2237
  evictTransformCacheOnce();
1390
2238
  }
1391
- const cacheInput = {
1392
- pluginVersion: PLUGIN_VERSION,
1393
- compilerVersion: COMPILER_VERSION,
1394
- parserMode,
1395
- producer: parserMode,
1396
- astBudget: astBudgetOverride,
1397
- filename: effectiveFilename,
1398
- source
1399
- };
2239
+ const cacheInput = createConfiguredTransformCacheInput(
2240
+ source,
2241
+ effectiveFilename,
2242
+ compilerOptions
2243
+ );
1400
2244
  if (parserMode === "rust") {
1401
2245
  compiler.ensureRustTransformAvailable();
1402
2246
  }
1403
- const cacheKey = cacheEnabled ? createTransformCacheKey(cacheInput) : null;
2247
+ const cacheKey = cacheEnabled ? transformCache.createTransformCacheKey(cacheInput) : null;
1404
2248
  if (cacheEnabled && cacheKey) {
1405
2249
  const memoryCached = transformMemoryCache.get(cacheKey.key);
1406
2250
  if (memoryCached) {
@@ -1408,7 +2252,7 @@ function createCsszyxPlugins(options = {}) {
1408
2252
  transformMemoryCache.set(cacheKey.key, memoryCached);
1409
2253
  return memoryCached;
1410
2254
  }
1411
- const cached = readTransformCache(cacheRoot, cacheInput, cacheKey);
2255
+ const cached = transformCache.readTransformCache(cacheRoot, cacheInput, cacheKey);
1412
2256
  if (cached) {
1413
2257
  rememberTransformCacheEntry(cacheKey.key, cached);
1414
2258
  return cached;
@@ -1432,11 +2276,131 @@ function createCsszyxPlugins(options = {}) {
1432
2276
  }
1433
2277
  }
1434
2278
  if (cacheEnabled && cacheKey) {
1435
- writeTransformCache(cacheRoot, cacheInput, result, cacheKey);
2279
+ transformCache.writeTransformCache(cacheRoot, cacheInput, result, cacheKey);
1436
2280
  rememberTransformCacheEntry(cacheKey.key, result);
1437
2281
  }
1438
2282
  return result;
1439
2283
  }
2284
+ function createCompilerOptions() {
2285
+ return {
2286
+ astBudget: astBudgetOverride,
2287
+ mangleVars: options.production?.mangleVars === true,
2288
+ mangleVarHoistMaxDepth: options.production?.mangleVarHoistMaxDepth,
2289
+ globalVarAliases: earlyGlobalVarAliasEntries.length > 0 ? earlyGlobalVarAliasEntries : void 0
2290
+ };
2291
+ }
2292
+ function createConfiguredTransformCacheInput(source, effectiveFilename, compilerOptions) {
2293
+ return {
2294
+ pluginVersion: PLUGIN_VERSION,
2295
+ compilerVersion: COMPILER_VERSION,
2296
+ parserMode,
2297
+ producer: parserMode,
2298
+ astBudget: astBudgetOverride,
2299
+ mangleVars: compilerOptions.mangleVars,
2300
+ mangleVarHoistMaxDepth: compilerOptions.mangleVarHoistMaxDepth,
2301
+ globalVarAliases: normalizeGlobalVarAliasesForCache(compilerOptions.globalVarAliases),
2302
+ filename: effectiveFilename,
2303
+ source
2304
+ };
2305
+ }
2306
+ function transformPrescanSources(files) {
2307
+ if (parserMode !== "rust" || files.length <= 1) {
2308
+ return transformPrescanSourcesIndividually(files);
2309
+ }
2310
+ const compilerOptions = createCompilerOptions();
2311
+ const cacheRoot = transformCache.resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
2312
+ const results = /* @__PURE__ */ new Map();
2313
+ const misses = [];
2314
+ if (cacheEnabled) {
2315
+ evictTransformCacheOnce();
2316
+ }
2317
+ compiler.ensureRustTransformAvailable();
2318
+ for (const file of files) {
2319
+ const effectiveFilename = normalizeSourceFilename(file.filePath);
2320
+ const cacheInput = createConfiguredTransformCacheInput(
2321
+ file.content,
2322
+ effectiveFilename,
2323
+ compilerOptions
2324
+ );
2325
+ const cacheKey = cacheEnabled ? transformCache.createTransformCacheKey(cacheInput) : null;
2326
+ if (cacheEnabled && cacheKey) {
2327
+ const memoryCached = transformMemoryCache.get(cacheKey.key);
2328
+ if (memoryCached) {
2329
+ transformMemoryCache.delete(cacheKey.key);
2330
+ transformMemoryCache.set(cacheKey.key, memoryCached);
2331
+ results.set(file.filePath, memoryCached);
2332
+ continue;
2333
+ }
2334
+ const cached = transformCache.readTransformCache(cacheRoot, cacheInput, cacheKey);
2335
+ if (cached) {
2336
+ rememberTransformCacheEntry(cacheKey.key, cached);
2337
+ results.set(file.filePath, cached);
2338
+ continue;
2339
+ }
2340
+ }
2341
+ misses.push({
2342
+ filePath: file.filePath,
2343
+ effectiveFilename,
2344
+ content: file.content,
2345
+ cacheInput,
2346
+ cacheKey
2347
+ });
2348
+ }
2349
+ if (misses.length === 0) {
2350
+ return files.map((file) => {
2351
+ const result = results.get(file.filePath);
2352
+ return result ? { filePath: file.filePath, result } : null;
2353
+ }).filter((entry) => entry !== null);
2354
+ }
2355
+ try {
2356
+ const batchResults = compiler.transformRustBatch(
2357
+ misses.map((file) => ({
2358
+ filename: file.effectiveFilename,
2359
+ source: file.content
2360
+ })),
2361
+ compilerOptions
2362
+ );
2363
+ for (let index = 0; index < misses.length; index++) {
2364
+ const miss = misses[index];
2365
+ const result = batchResults[index];
2366
+ if (!miss || !result) {
2367
+ continue;
2368
+ }
2369
+ if (cacheEnabled && miss.cacheKey) {
2370
+ transformCache.writeTransformCache(cacheRoot, miss.cacheInput, result, miss.cacheKey);
2371
+ rememberTransformCacheEntry(miss.cacheKey.key, result);
2372
+ }
2373
+ results.set(miss.filePath, result);
2374
+ }
2375
+ } catch {
2376
+ for (const miss of misses) {
2377
+ try {
2378
+ results.set(
2379
+ miss.filePath,
2380
+ transformConfiguredSource(miss.content, miss.effectiveFilename)
2381
+ );
2382
+ } catch {
2383
+ }
2384
+ }
2385
+ }
2386
+ return files.map((file) => {
2387
+ const result = results.get(file.filePath);
2388
+ return result ? { filePath: file.filePath, result } : null;
2389
+ }).filter((entry) => entry !== null);
2390
+ }
2391
+ function transformPrescanSourcesIndividually(files) {
2392
+ const results = [];
2393
+ for (const file of files) {
2394
+ try {
2395
+ results.push({
2396
+ filePath: file.filePath,
2397
+ result: transformConfiguredSource(file.content, file.filePath)
2398
+ });
2399
+ } catch {
2400
+ }
2401
+ }
2402
+ return results;
2403
+ }
1440
2404
  function rememberTransformCacheEntry(key, result) {
1441
2405
  transformMemoryCache.delete(key);
1442
2406
  transformMemoryCache.set(key, result);
@@ -1452,12 +2416,12 @@ function createCsszyxPlugins(options = {}) {
1452
2416
  if (!cacheEnabled) {
1453
2417
  return;
1454
2418
  }
1455
- const cacheRoot = resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
2419
+ const cacheRoot = transformCache.resolveTransformCacheDir(state.rootDir, options.build?.cacheDir);
1456
2420
  if (evictedCacheRoot === cacheRoot) {
1457
2421
  return;
1458
2422
  }
1459
2423
  evictedCacheRoot = cacheRoot;
1460
- evictOldTransformCacheEntries(cacheRoot, {
2424
+ transformCache.evictOldTransformCacheEntries(cacheRoot, {
1461
2425
  maxAgeMs: TRANSFORM_CACHE_MAX_AGE_MS,
1462
2426
  maxEntries: TRANSFORM_CACHE_MAX_ENTRIES
1463
2427
  });
@@ -1473,7 +2437,14 @@ function createCsszyxPlugins(options = {}) {
1473
2437
  <div class="${classList}"><div class="${classList}">x</div><div class="${classList}">x</div></div>
1474
2438
  `;
1475
2439
  try {
1476
- const existing = fs__namespace.existsSync(safelistPath) ? fs__namespace.readFileSync(safelistPath, "utf-8") : "";
2440
+ let existing = "";
2441
+ try {
2442
+ existing = fs__namespace.readFileSync(safelistPath, "utf-8");
2443
+ } catch (err) {
2444
+ if (err?.code !== "ENOENT") {
2445
+ throw err;
2446
+ }
2447
+ }
1477
2448
  if (existing !== content) {
1478
2449
  fs__namespace.writeFileSync(safelistPath, content);
1479
2450
  }
@@ -1481,8 +2452,10 @@ function createCsszyxPlugins(options = {}) {
1481
2452
  }
1482
2453
  }
1483
2454
  function prescanAndWriteClasses() {
2455
+ const prescanStarted = node_perf_hooks.performance.now();
1484
2456
  const discoveredClasses = /* @__PURE__ */ new Set();
1485
2457
  const rawDiscoveredClasses = /* @__PURE__ */ new Set();
2458
+ const prescanSources = [];
1486
2459
  function scanDir(dir) {
1487
2460
  let entries;
1488
2461
  try {
@@ -1500,85 +2473,107 @@ function createCsszyxPlugins(options = {}) {
1500
2473
  if (!shouldProcessSource(filePath)) {
1501
2474
  continue;
1502
2475
  }
2476
+ let content;
1503
2477
  try {
1504
- const content = fs__namespace.readFileSync(filePath, "utf-8");
1505
- if (!content.includes("sz=") && !content.includes("sz:")) {
1506
- continue;
1507
- }
1508
- const result = transformConfiguredSource(content, filePath);
1509
- if (!result.transformed) {
1510
- continue;
1511
- }
1512
- for (const cls of result.classes) {
1513
- discoveredClasses.add(cls);
1514
- }
1515
- for (const cls of result.rawClassNames) {
1516
- rawDiscoveredClasses.add(cls);
1517
- }
1518
- for (const [token, data] of result.recoveryTokens) {
1519
- state.recoveryTokens.set(token, data);
1520
- }
1521
- if (result.usesRuntime) {
1522
- const szCallRe = /_sz\(\s*\{/g;
1523
- for (const szMatch of result.code.matchAll(szCallRe)) {
1524
- let depth = 1;
1525
- let idx = (szMatch.index ?? 0) + szMatch[0].length;
1526
- while (idx < result.code.length && depth > 0) {
1527
- if (result.code[idx] === "{") {
1528
- depth++;
1529
- } else if (result.code[idx] === "}") {
1530
- depth--;
1531
- }
1532
- idx++;
1533
- }
1534
- const objStr = result.code.slice(
1535
- (szMatch.index ?? 0) + szMatch[0].length,
1536
- idx - 1
1537
- );
1538
- const strKv = /(\w+)\s*:\s*(?:"([^"]*)"|'([^']*)')/g;
1539
- for (const kv of objStr.matchAll(strKv)) {
1540
- try {
1541
- const val = kv[2] ?? kv[3];
1542
- const r = compiler.transform({ [kv[1]]: val });
1543
- for (const c of r.className.split(/\s+/).filter(Boolean)) {
1544
- discoveredClasses.add(c);
1545
- }
1546
- } catch {
1547
- }
1548
- }
1549
- const numKv = /(\w+)\s*:\s*(-?\d+(?:\.\d+)?)\s*(?=[,}\n])/g;
1550
- for (const kv of objStr.matchAll(numKv)) {
1551
- try {
1552
- const r = compiler.transform({ [kv[1]]: parseFloat(kv[2]) });
1553
- for (const c of r.className.split(/\s+/).filter(Boolean)) {
1554
- discoveredClasses.add(c);
1555
- }
1556
- } catch {
1557
- }
1558
- }
1559
- const boolKv = /(\w+)\s*:\s*(true|false)\s*(?=[,}\n])/g;
1560
- for (const kv of objStr.matchAll(boolKv)) {
1561
- try {
1562
- const r = compiler.transform({ [kv[1]]: kv[2] === "true" });
1563
- for (const c of r.className.split(/\s+/).filter(Boolean)) {
1564
- discoveredClasses.add(c);
1565
- }
1566
- } catch {
1567
- }
1568
- }
1569
- }
1570
- }
2478
+ content = fs__namespace.readFileSync(filePath, "utf-8");
1571
2479
  } catch {
2480
+ continue;
2481
+ }
2482
+ if (!content.includes("sz=") && !content.includes("sz:")) {
2483
+ continue;
1572
2484
  }
2485
+ prescanSources.push({ filePath, content });
1573
2486
  }
1574
2487
  }
1575
2488
  }
1576
2489
  scanDir(state.rootDir);
2490
+ for (const { filePath, result } of transformPrescanSources(prescanSources)) {
2491
+ if (!result.transformed) {
2492
+ continue;
2493
+ }
2494
+ collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses);
2495
+ }
1577
2496
  for (const cls of discoveredClasses) {
1578
2497
  state.classes.add(cls);
1579
2498
  }
1580
2499
  const safelistClasses = /* @__PURE__ */ new Set([...discoveredClasses, ...rawDiscoveredClasses]);
1581
2500
  writeSafelistFile(safelistClasses);
2501
+ traceBenchTiming("prescan", state.rootDir, node_perf_hooks.performance.now() - prescanStarted);
2502
+ }
2503
+ function collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses) {
2504
+ for (const cls of result.classes) {
2505
+ discoveredClasses.add(cls);
2506
+ }
2507
+ for (const cls of result.rawClassNames) {
2508
+ rawDiscoveredClasses.add(cls);
2509
+ }
2510
+ for (const [token, data] of result.recoveryTokens) {
2511
+ state.recoveryTokens.set(token, data);
2512
+ }
2513
+ recordFileVarMangleEntries(state, filePath, cssVariableEntries(result));
2514
+ recordFileCSSVariableMetrics(state, filePath, result.code);
2515
+ collectRuntimeStaticClasses(result, discoveredClasses);
2516
+ }
2517
+ function collectRuntimeStaticClasses(result, discoveredClasses) {
2518
+ if (!result.usesRuntime) {
2519
+ return;
2520
+ }
2521
+ const szCallRe = /_sz\(\s*\{/g;
2522
+ for (const szMatch of result.code.matchAll(szCallRe)) {
2523
+ let depth = 1;
2524
+ let idx = (szMatch.index ?? 0) + szMatch[0].length;
2525
+ while (idx < result.code.length && depth > 0) {
2526
+ if (result.code[idx] === "{") {
2527
+ depth++;
2528
+ } else if (result.code[idx] === "}") {
2529
+ depth--;
2530
+ }
2531
+ idx++;
2532
+ }
2533
+ const objStr = result.code.slice((szMatch.index ?? 0) + szMatch[0].length, idx - 1);
2534
+ collectRuntimeStringClasses(objStr, discoveredClasses);
2535
+ collectRuntimeNumberClasses(objStr, discoveredClasses);
2536
+ collectRuntimeBooleanClasses(objStr, discoveredClasses);
2537
+ }
2538
+ }
2539
+ function collectRuntimeStringClasses(objStr, discoveredClasses) {
2540
+ const strKv = /(\w+)\s*:\s*(?:"([^"]*)"|'([^']*)')/g;
2541
+ for (const kv of objStr.matchAll(strKv)) {
2542
+ try {
2543
+ const val = kv[2] ?? kv[3];
2544
+ collectTransformClasses(compiler.transform({ [kv[1]]: val }), discoveredClasses);
2545
+ } catch {
2546
+ }
2547
+ }
2548
+ }
2549
+ function collectRuntimeNumberClasses(objStr, discoveredClasses) {
2550
+ const numKv = /(\w+)\s*:\s*(-?\d+(?:\.\d+)?)\s*(?=[,}\n])/g;
2551
+ for (const kv of objStr.matchAll(numKv)) {
2552
+ try {
2553
+ collectTransformClasses(
2554
+ compiler.transform({ [kv[1]]: parseFloat(kv[2]) }),
2555
+ discoveredClasses
2556
+ );
2557
+ } catch {
2558
+ }
2559
+ }
2560
+ }
2561
+ function collectRuntimeBooleanClasses(objStr, discoveredClasses) {
2562
+ const boolKv = /(\w+)\s*:\s*(true|false)\s*(?=[,}\n])/g;
2563
+ for (const kv of objStr.matchAll(boolKv)) {
2564
+ try {
2565
+ collectTransformClasses(
2566
+ compiler.transform({ [kv[1]]: kv[2] === "true" }),
2567
+ discoveredClasses
2568
+ );
2569
+ } catch {
2570
+ }
2571
+ }
2572
+ }
2573
+ function collectTransformClasses(result, discoveredClasses) {
2574
+ for (const cls of result.className.split(/\s+/).filter(Boolean)) {
2575
+ discoveredClasses.add(cls);
2576
+ }
1582
2577
  }
1583
2578
  function extractClasses(code) {
1584
2579
  const dqPattern = /(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g;
@@ -1621,7 +2616,10 @@ function createCsszyxPlugins(options = {}) {
1621
2616
  newMap[sortedClasses[i]] = core.encode(i);
1622
2617
  }
1623
2618
  state.mangleMap = newMap;
1624
- state.checksum = core.compute_mangle_checksum(state.mangleMap);
2619
+ assertVarMangleMapSize(state.varMangleMap, varMangleMapMaxBytes);
2620
+ state.checksum = core.compute_mangle_checksum(
2621
+ createHydrationMangleMap(state.mangleMap, state.varMangleMap)
2622
+ );
1625
2623
  state.finalized = true;
1626
2624
  }
1627
2625
  function mangleCodeClasses(code) {
@@ -1637,6 +2635,11 @@ function createCsszyxPlugins(options = {}) {
1637
2635
  const escapedMap = result.includes("eval(") ? jsonMap.replace(/"/g, '\\"') : jsonMap;
1638
2636
  result = result.split(MANGLE_MAP_PLACEHOLDER).join(escapedMap);
1639
2637
  }
2638
+ if (result.includes(VAR_MANGLE_MAP_PLACEHOLDER)) {
2639
+ const jsonMap = JSON.stringify(state.varMangleMap);
2640
+ const escapedMap = result.includes("eval(") ? jsonMap.replace(/"/g, '\\"') : jsonMap;
2641
+ result = result.split(VAR_MANGLE_MAP_PLACEHOLDER).join(escapedMap);
2642
+ }
1640
2643
  return result;
1641
2644
  }
1642
2645
  const prePlugin = unplugin$1.createUnplugin(
@@ -1662,7 +2665,12 @@ function createCsszyxPlugins(options = {}) {
1662
2665
  load(id) {
1663
2666
  if (id === RESOLVED_VIRTUAL_MODULE_ID) {
1664
2667
  finalizeMangleMap();
1665
- return createMangleMapModule(state.mangleMap, state.checksum);
2668
+ return createMangleMapModule(
2669
+ state.mangleMap,
2670
+ state.checksum,
2671
+ state.varMangleMap,
2672
+ state.cssVarMetrics
2673
+ );
1666
2674
  }
1667
2675
  if (id === RESOLVED_VIRTUAL_CHECKSUM_ID) {
1668
2676
  finalizeMangleMap();
@@ -1693,6 +2701,9 @@ function createCsszyxPlugins(options = {}) {
1693
2701
  if (!shouldProcessCss(id) && !shouldProcessSource(id)) {
1694
2702
  return null;
1695
2703
  }
2704
+ if (shouldProcessSource(id)) {
2705
+ recordGlobalVarSourceFile(state, id, code);
2706
+ }
1696
2707
  if (/\.[tj]sx?(\?.*)?$/.test(id)) {
1697
2708
  assertNoRSCBoundaryViolation(code, id);
1698
2709
  }
@@ -1755,6 +2766,8 @@ ${sourceDirective}`
1755
2766
  usesColorVar = result.usesColorVar;
1756
2767
  transformed = result.transformed;
1757
2768
  szClasses = result.classes;
2769
+ recordFileVarMangleEntries(state, id, cssVariableEntries(result));
2770
+ recordFileCSSVariableMetrics(state, id, result.code);
1758
2771
  if (result.diagnostics.length > 0 && process.env.NODE_ENV !== "production") {
1759
2772
  for (const msg of result.diagnostics) {
1760
2773
  this.warn(`[csszyx] ${id}
@@ -1765,14 +2778,17 @@ ${sourceDirective}`
1765
2778
  state.recoveryTokens.set(token, data);
1766
2779
  }
1767
2780
  }
2781
+ } else if (shouldProcessSource(id)) {
2782
+ recordFileVarMangleEntries(state, id, []);
2783
+ recordFileCSSVariableMetrics(state, id, null);
1768
2784
  }
1769
- if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
2785
+ if (transformedCode.includes("<html") && /(?:layout|Root|Document|app)\.tsx?$/i.test(id)) {
1770
2786
  const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
1771
2787
  transformedCode = transformedCode.replace(
1772
2788
  /<html([^>]*)>/i,
1773
2789
  `<html$1 ${attrName}="${CHECKSUM_PLACEHOLDER}">`
1774
2790
  );
1775
- const debugScript = `<script dangerouslySetInnerHTML={{__html: \`(function(){var m=${MANGLE_MAP_PLACEHOLDER};var r={};for(var k in m)r[m[k]]=k;window.__csszyx={mangleMap:m,checksum:"${CHECKSUM_PLACEHOLDER}",decode:function(c){return r[c]},encode:function(c){return m[c]},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()\`}} />`;
2791
+ const debugScript = `<script dangerouslySetInnerHTML={{__html: \`(function(){var m=${MANGLE_MAP_PLACEHOLDER};var vm=${VAR_MANGLE_MAP_PLACEHOLDER};var gp=decodeURIComponent(${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})}}})()\`}} />`;
1776
2792
  if (transformedCode.includes("<body")) {
1777
2793
  transformedCode = transformedCode.replace(
1778
2794
  /(<body[^>]*>)/i,
@@ -1841,6 +2857,9 @@ ${sourceDirective}`
1841
2857
  watchChange(id, change) {
1842
2858
  if (change.event === "delete") {
1843
2859
  deleteRSCModuleRecord(state.rscModules, id);
2860
+ recordGlobalVarSourceFile(state, id, null);
2861
+ recordFileVarMangleEntries(state, id, []);
2862
+ recordFileCSSVariableMetrics(state, id, null);
1844
2863
  }
1845
2864
  },
1846
2865
  /**
@@ -1902,6 +2921,9 @@ ${sourceDirective}`
1902
2921
  return;
1903
2922
  }
1904
2923
  if (!fileContent.includes("sz=") && !/\bsz\s*:\s*["'{]/.test(fileContent)) {
2924
+ recordGlobalVarSourceFile(state, ctx.file, fileContent);
2925
+ recordFileVarMangleEntries(state, ctx.file, []);
2926
+ recordFileCSSVariableMetrics(state, ctx.file, null);
1905
2927
  return;
1906
2928
  }
1907
2929
  try {
@@ -1913,15 +2935,24 @@ ${sourceDirective}`
1913
2935
  node_perf_hooks.performance.now() - hmrTransformStarted
1914
2936
  );
1915
2937
  } catch {
2938
+ recordGlobalVarSourceFile(state, ctx.file, fileContent);
2939
+ recordFileVarMangleEntries(state, ctx.file, []);
2940
+ recordFileCSSVariableMetrics(state, ctx.file, null);
1916
2941
  return;
1917
2942
  }
1918
2943
  if (!result.transformed) {
2944
+ recordGlobalVarSourceFile(state, ctx.file, fileContent);
2945
+ recordFileVarMangleEntries(state, ctx.file, []);
2946
+ recordFileCSSVariableMetrics(state, ctx.file, null);
1919
2947
  return;
1920
2948
  }
1921
2949
  const sizeBefore = state.classes.size;
2950
+ recordGlobalVarSourceFile(state, ctx.file, fileContent);
1922
2951
  for (const cls of result.classes) {
1923
2952
  state.classes.add(cls);
1924
2953
  }
2954
+ recordFileVarMangleEntries(state, ctx.file, cssVariableEntries(result));
2955
+ recordFileCSSVariableMetrics(state, ctx.file, result.code);
1925
2956
  for (const [token, data] of result.recoveryTokens) {
1926
2957
  state.recoveryTokens.set(token, data);
1927
2958
  }
@@ -1943,7 +2974,9 @@ ${sourceDirective}`
1943
2974
  finalizeMangleMap();
1944
2975
  let result = transformIndexHtml(html, state.mangleMap, state.checksum, {
1945
2976
  mode: options.production?.injectChecksum === false ? "script" : "script",
1946
- minify: process.env.NODE_ENV === "production"
2977
+ minify: process.env.NODE_ENV === "production",
2978
+ varMangleMap: state.varMangleMap,
2979
+ globalVarAliasPrefix
1947
2980
  });
1948
2981
  if (state.recoveryTokens.size > 0) {
1949
2982
  const isProduction = process.env.NODE_ENV === "production";
@@ -1987,6 +3020,9 @@ ${sourceDirective}`
1987
3020
  },
1988
3021
  (assets) => {
1989
3022
  finalizeMangleMap();
3023
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
3024
+ collectWebpackGlobalVarCssAssets(assets)
3025
+ );
1990
3026
  const isWebpackDevMode = compiler.options.mode === "development";
1991
3027
  const manifestData = {
1992
3028
  version: "0.4.0",
@@ -1996,33 +3032,71 @@ ${sourceDirective}`
1996
3032
  if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
1997
3033
  manifestData.mangleMap = state.mangleMap;
1998
3034
  }
3035
+ if (Object.keys(state.varMangleMap).length > 0) {
3036
+ manifestData.varMangleMap = state.varMangleMap;
3037
+ }
3038
+ const globalVarAliases = extractGlobalVarAliasesForManifest(
3039
+ state.varMangleMap,
3040
+ globalVarAliasPrefix,
3041
+ state.globalVarValidationResult
3042
+ );
3043
+ if (Object.keys(globalVarAliases).length > 0) {
3044
+ manifestData.globalVarAliases = globalVarAliases;
3045
+ }
3046
+ if (hasCSSVariableMetrics(state.cssVarMetrics)) {
3047
+ manifestData.cssVarMetrics = state.cssVarMetrics;
3048
+ }
1999
3049
  compilation.emitAsset(
2000
3050
  "csszyx-manifest.json",
2001
3051
  new compiler.webpack.sources.RawSource(JSON.stringify(manifestData))
2002
3052
  );
3053
+ if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
3054
+ const globalVarMapAsset = createGlobalVarMapAssetSource(
3055
+ state.varMangleMap,
3056
+ globalVarAliasPrefix,
3057
+ state.globalVarValidationResult
3058
+ );
3059
+ if (globalVarMapAsset) {
3060
+ compilation.emitAsset(
3061
+ ".csszyx/global-var-map.json",
3062
+ new compiler.webpack.sources.RawSource(globalVarMapAsset)
3063
+ );
3064
+ }
3065
+ }
2003
3066
  for (const file in assets) {
2004
3067
  const asset = assets[file];
2005
3068
  const source = asset.source().toString();
2006
- if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
2007
- if (file.endsWith(".css")) {
3069
+ if (file.endsWith(".css")) {
3070
+ let css = rewriteCssWithValidatedGlobalVarPlan(
3071
+ source,
3072
+ file,
3073
+ state.globalVarValidationResult
3074
+ );
3075
+ if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
2008
3076
  try {
2009
- const result = cssMangler.mangleCSSSync(source, state.mangleMap, {
3077
+ const result = cssMangler.mangleCSSSync(css, state.mangleMap, {
2010
3078
  debug: options.development?.debug,
2011
3079
  from: file
2012
3080
  });
2013
3081
  if (result.transformedCount > 0) {
2014
- compilation.updateAsset(
2015
- file,
2016
- new compiler.webpack.sources.RawSource(result.css)
2017
- );
2018
- continue;
3082
+ css = result.css;
2019
3083
  }
2020
3084
  } catch (e) {
2021
3085
  if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") ; else {
2022
3086
  throw e;
2023
3087
  }
2024
3088
  }
2025
- } else if (file.endsWith(".html")) {
3089
+ }
3090
+ if (css !== source) {
3091
+ compilation.updateAsset(
3092
+ file,
3093
+ new compiler.webpack.sources.RawSource(css)
3094
+ );
3095
+ }
3096
+ continue;
3097
+ }
3098
+ if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
3099
+ if (file.endsWith(".html")) {
2026
3100
  const mangledHtml = source.replace(
2027
3101
  /\bclass="([^"]*)"/g,
2028
3102
  (_m, cls) => {
@@ -2077,6 +3151,9 @@ ${sourceDirective}`
2077
3151
  */
2078
3152
  generateBundle(_options, bundle) {
2079
3153
  finalizeMangleMap();
3154
+ state.globalVarValidationResult = validateGlobalVarBundleInputs(
3155
+ collectRollupGlobalVarCssAssets(bundle)
3156
+ );
2080
3157
  const manifestData = {
2081
3158
  version: "0.4.0",
2082
3159
  buildId: state.checksum,
@@ -2085,31 +3162,70 @@ ${sourceDirective}`
2085
3162
  if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
2086
3163
  manifestData.mangleMap = state.mangleMap;
2087
3164
  }
3165
+ if (Object.keys(state.varMangleMap).length > 0) {
3166
+ manifestData.varMangleMap = state.varMangleMap;
3167
+ }
3168
+ const globalVarAliases = extractGlobalVarAliasesForManifest(
3169
+ state.varMangleMap,
3170
+ globalVarAliasPrefix,
3171
+ state.globalVarValidationResult
3172
+ );
3173
+ if (Object.keys(globalVarAliases).length > 0) {
3174
+ manifestData.globalVarAliases = globalVarAliases;
3175
+ }
3176
+ if (hasCSSVariableMetrics(state.cssVarMetrics)) {
3177
+ manifestData.cssVarMetrics = state.cssVarMetrics;
3178
+ }
2088
3179
  this.emitFile({
2089
3180
  type: "asset",
2090
3181
  fileName: "csszyx-manifest.json",
2091
3182
  source: JSON.stringify(manifestData)
2092
3183
  });
3184
+ if (shouldEmitGlobalVarMapAsset(globalVarMangleConfig)) {
3185
+ const globalVarMapAsset = createGlobalVarMapAssetSource(
3186
+ state.varMangleMap,
3187
+ globalVarAliasPrefix,
3188
+ state.globalVarValidationResult
3189
+ );
3190
+ if (globalVarMapAsset) {
3191
+ this.emitFile({
3192
+ type: "asset",
3193
+ fileName: ".csszyx/global-var-map.json",
3194
+ source: globalVarMapAsset
3195
+ });
3196
+ }
3197
+ }
2093
3198
  for (const file in bundle) {
2094
3199
  const chunk = bundle[file];
2095
- if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
2096
- if (chunk.type === "asset" && chunk.fileName.endsWith(".css")) {
2097
- const css = chunk.source.toString();
3200
+ if (chunk.type === "asset" && chunk.fileName.endsWith(".css")) {
3201
+ const originalCss = chunk.source.toString();
3202
+ let css = rewriteCssWithValidatedGlobalVarPlan(
3203
+ originalCss,
3204
+ file,
3205
+ state.globalVarValidationResult
3206
+ );
3207
+ if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
2098
3208
  try {
2099
3209
  const result = cssMangler.mangleCSSSync(css, state.mangleMap, {
2100
3210
  debug: options.development?.debug,
2101
3211
  from: file
2102
3212
  });
2103
3213
  if (result.transformedCount > 0) {
2104
- chunk.source = result.css;
3214
+ css = result.css;
2105
3215
  }
2106
3216
  } catch (e) {
2107
3217
  if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") ; else {
2108
3218
  throw e;
2109
3219
  }
2110
3220
  }
2111
- continue;
2112
- } else if (chunk.type === "chunk") {
3221
+ }
3222
+ if (css !== originalCss) {
3223
+ chunk.source = css;
3224
+ }
3225
+ continue;
3226
+ }
3227
+ if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
3228
+ if (chunk.type === "chunk") {
2113
3229
  let mangledCode = mangleCodeClasses(chunk.code);
2114
3230
  mangledCode = replacePlaceholders(mangledCode);
2115
3231
  if (mangledCode !== chunk.code) {
@@ -2174,19 +3290,32 @@ const esbuildPlugin = (options = {}) => {
2174
3290
 
2175
3291
  exports.assertNoRSCBoundaryViolation = assertNoRSCBoundaryViolation;
2176
3292
  exports.assertNoRSCGraphViolation = assertNoRSCGraphViolation;
3293
+ exports.createGlobalVarAliasValidationOptions = createGlobalVarAliasValidationOptions;
3294
+ exports.createGlobalVarMapAssetSource = createGlobalVarMapAssetSource;
3295
+ exports.createGlobalVarScanCacheKey = createGlobalVarScanCacheKey;
2177
3296
  exports.createRSCModuleRecord = createRSCModuleRecord;
2178
3297
  exports.deleteRSCModuleRecord = deleteRSCModuleRecord;
2179
3298
  exports.esbuildPlugin = esbuildPlugin;
3299
+ exports.extractGlobalVarAliasesForManifest = extractGlobalVarAliasesForManifest;
2180
3300
  exports.findRSCBoundaryViolation = findRSCBoundaryViolation;
2181
3301
  exports.findRSCGraphViolation = findRSCGraphViolation;
2182
3302
  exports.hasTokens = hasTokens;
2183
3303
  exports.hasUseClientDirective = hasUseClientDirective;
2184
3304
  exports.hasUseServerDirective = hasUseServerDirective;
2185
3305
  exports.isRSCServerModule = isRSCServerModule;
3306
+ exports.isTailwindReservedGlobalVar = isTailwindReservedGlobalVar;
2186
3307
  exports.mangleCodeClassesSync = mangleCodeClassesSync;
2187
3308
  exports.mergeThemes = mergeThemes;
3309
+ exports.normalizeGlobalVarAliasesForCache = normalizeGlobalVarAliasesForCache;
2188
3310
  exports.parseThemeBlocks = parseThemeBlocks;
3311
+ exports.planGlobalVarAliases = planGlobalVarAliases;
3312
+ exports.readGlobalVarScanCache = readGlobalVarScanCache;
3313
+ exports.resolveGlobalVarScanCacheDir = resolveGlobalVarScanCacheDir;
3314
+ exports.rewriteGlobalVarCssAliases = rewriteGlobalVarCssAliases;
2189
3315
  exports.rollupPlugin = rollupPlugin;
3316
+ exports.scanGlobalVarCss = scanGlobalVarCss;
2190
3317
  exports.unplugin = unplugin;
3318
+ exports.validateGlobalVarAliasInputs = validateGlobalVarAliasInputs;
2191
3319
  exports.vitePlugin = vitePlugin;
2192
3320
  exports.webpackPlugin = webpackPlugin;
3321
+ exports.writeGlobalVarScanCache = writeGlobalVarScanCache;