@csszyx/unplugin 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/index.cjs +8 -7
  2. package/dist/index.d.cts +4 -4
  3. package/dist/index.d.mts +4 -4
  4. package/dist/index.mjs +3 -3
  5. package/dist/next-config.cjs +3 -0
  6. package/dist/next-config.d.cts +10 -0
  7. package/dist/next-config.d.mts +10 -0
  8. package/dist/next-config.mjs +3 -0
  9. package/dist/next-prebuild.cjs +12 -5
  10. package/dist/next-prebuild.d.cts +7 -0
  11. package/dist/next-prebuild.d.mts +7 -0
  12. package/dist/next-prebuild.mjs +12 -5
  13. package/dist/next-turbo-loader.cjs +29 -11
  14. package/dist/next-turbo-loader.d.cts +10 -0
  15. package/dist/next-turbo-loader.d.mts +10 -0
  16. package/dist/next-turbo-loader.mjs +28 -10
  17. package/dist/next-watcher.cjs +1 -1
  18. package/dist/next-watcher.mjs +1 -1
  19. package/dist/shared/unplugin.4du3qMst.cjs +529 -0
  20. package/dist/shared/unplugin.5l4RHMQh.mjs +578 -0
  21. package/dist/shared/unplugin.BB0iWSds.mjs +495 -0
  22. package/dist/shared/{unplugin.DMcbmP01.mjs → unplugin.BU0O4IkX.mjs} +4 -1
  23. package/dist/shared/{unplugin.BK3XVHe8.cjs → unplugin.Bf4fNbp7.cjs} +318 -532
  24. package/dist/shared/{unplugin.Bb5TeU9B.cjs → unplugin.CUTa6bY9.cjs} +89 -1
  25. package/dist/shared/{unplugin.DblMogcN.cjs → unplugin.Cji6O5jv.cjs} +4 -1
  26. package/dist/shared/{unplugin.DXgxFHzO.mjs → unplugin.CogPHmDs.mjs} +73 -3
  27. package/dist/shared/{unplugin.CtnKJhAi.d.cts → unplugin.DCT7DDG6.d.cts} +75 -30
  28. package/dist/shared/{unplugin.CtnKJhAi.d.mts → unplugin.DCT7DDG6.d.mts} +75 -30
  29. package/dist/shared/unplugin.X9a9SL_s.cjs +612 -0
  30. package/dist/shared/{unplugin.B9vpjOhD.mjs → unplugin.ymMe428s.mjs} +288 -499
  31. package/dist/vite.cjs +3 -3
  32. package/dist/vite.d.cts +2 -2
  33. package/dist/vite.d.mts +1 -1
  34. package/dist/vite.mjs +3 -3
  35. package/dist/webpack.cjs +3 -3
  36. package/dist/webpack.d.cts +2 -2
  37. package/dist/webpack.d.mts +1 -1
  38. package/dist/webpack.mjs +3 -3
  39. package/package.json +9 -9
  40. package/dist/shared/unplugin.C2lHQFii.cjs +0 -114
  41. package/dist/shared/unplugin.CBMJufQ8.mjs +0 -108
  42. package/dist/shared/unplugin.CDqY7kmk.mjs +0 -224
  43. package/dist/shared/unplugin.DbZ7tCfN.cjs +0 -248
@@ -0,0 +1,612 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const htmlEscape = require('./unplugin.BkRah5Ot.cjs');
6
+
7
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
8
+
9
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
10
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
11
+
12
+ const EMPTY_THEME = {
13
+ colors: [],
14
+ spacings: [],
15
+ fonts: [],
16
+ textSizes: [],
17
+ fontWeights: [],
18
+ radii: [],
19
+ shadows: [],
20
+ breakpoints: []
21
+ };
22
+ function findMatchingBrace(source, openBrace) {
23
+ let depth = 0;
24
+ for (let index = openBrace; index < source.length; index++) {
25
+ if (source[index] === "{") {
26
+ depth++;
27
+ } else if (source[index] === "}") {
28
+ depth--;
29
+ if (depth === 0) {
30
+ return index;
31
+ }
32
+ }
33
+ }
34
+ return -1;
35
+ }
36
+ function stripLayerWrappers(css) {
37
+ let result = "";
38
+ let i = 0;
39
+ while (i < css.length) {
40
+ const layerIdx = css.indexOf("@layer", i);
41
+ if (layerIdx === -1) {
42
+ result += css.slice(i);
43
+ break;
44
+ }
45
+ result += css.slice(i, layerIdx);
46
+ const openBrace = css.indexOf("{", layerIdx);
47
+ if (openBrace === -1) {
48
+ result += css.slice(layerIdx);
49
+ break;
50
+ }
51
+ const closeBrace = findMatchingBrace(css, openBrace);
52
+ if (closeBrace === -1) {
53
+ result += css.slice(openBrace);
54
+ break;
55
+ }
56
+ result += css.slice(openBrace + 1, closeBrace);
57
+ i = closeBrace + 1;
58
+ }
59
+ return result;
60
+ }
61
+ function themePreludeStart(css, at) {
62
+ const cursor = at + "@theme".length;
63
+ const next = css[cursor];
64
+ const validBoundary = next === "{" || next === " " || next === " " || next === "\n" || next === "\r";
65
+ return validBoundary ? cursor : null;
66
+ }
67
+ function readThemeBlock(css, start) {
68
+ for (let cursor = start; cursor < css.length; cursor++) {
69
+ const character = css[cursor];
70
+ if (character === "{") {
71
+ const close = findMatchingBrace(css, cursor);
72
+ return {
73
+ body: close === -1 ? null : css.slice(cursor + 1, close),
74
+ end: close === -1 ? cursor : close
75
+ };
76
+ }
77
+ if (character === ";" || character === "}" || character === "@") {
78
+ return { body: null, end: cursor };
79
+ }
80
+ }
81
+ return { body: null, end: css.length };
82
+ }
83
+ function extractThemeBlocks(css) {
84
+ const blocks = [];
85
+ let searchFrom = 0;
86
+ for (; ; ) {
87
+ const at = css.indexOf("@theme", searchFrom);
88
+ if (at === -1) {
89
+ break;
90
+ }
91
+ const preludeStart = themePreludeStart(css, at);
92
+ if (preludeStart === null) {
93
+ searchFrom = at + "@theme".length;
94
+ continue;
95
+ }
96
+ const match = readThemeBlock(css, preludeStart);
97
+ if (match.body !== null) blocks.push(match.body);
98
+ searchFrom = Math.max(match.end, at + "@theme".length);
99
+ }
100
+ return blocks;
101
+ }
102
+ function categorizeProperty(prop) {
103
+ const categoryMap = [
104
+ ["color-", "colors"],
105
+ ["spacing-", "spacings"],
106
+ // `font-weight-` MUST precede `font-`: startsWith would otherwise route
107
+ // `font-weight-chunky` into font FAMILIES as token "weight-chunky".
108
+ ["font-weight-", "fontWeights"],
109
+ ["font-", "fonts"],
110
+ // `--text-*` defines font-size utilities (text-huge) in Tailwind v4.
111
+ ["text-", "textSizes"],
112
+ ["radius-", "radii"],
113
+ ["shadow-", "shadows"],
114
+ ["breakpoint-", "breakpoints"]
115
+ ];
116
+ for (const [prefix, category] of categoryMap) {
117
+ if (prop.startsWith(prefix)) {
118
+ let token = prop.slice(prefix.length);
119
+ if (category !== "breakpoints") {
120
+ token = token.replace(/-\d+$/, "");
121
+ }
122
+ if (token) {
123
+ return { category, token };
124
+ }
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ function parseThemeBlocks(cssContent) {
130
+ const result = {
131
+ colors: /* @__PURE__ */ new Set(),
132
+ spacings: /* @__PURE__ */ new Set(),
133
+ fonts: /* @__PURE__ */ new Set(),
134
+ textSizes: /* @__PURE__ */ new Set(),
135
+ fontWeights: /* @__PURE__ */ new Set(),
136
+ radii: /* @__PURE__ */ new Set(),
137
+ shadows: /* @__PURE__ */ new Set(),
138
+ breakpoints: /* @__PURE__ */ new Set()
139
+ };
140
+ const stripped = stripLayerWrappers(cssContent);
141
+ const blocks = extractThemeBlocks(stripped);
142
+ for (const block of blocks) {
143
+ for (const name of scanCustomPropertyNames(block)) {
144
+ const categorized = categorizeProperty(name);
145
+ if (categorized) {
146
+ result[categorized.category].add(categorized.token);
147
+ }
148
+ }
149
+ }
150
+ return {
151
+ colors: htmlEscape.sortStrings(result.colors),
152
+ spacings: htmlEscape.sortStrings(result.spacings),
153
+ fonts: htmlEscape.sortStrings(result.fonts),
154
+ textSizes: htmlEscape.sortStrings(result.textSizes),
155
+ fontWeights: htmlEscape.sortStrings(result.fontWeights),
156
+ radii: htmlEscape.sortStrings(result.radii),
157
+ shadows: htmlEscape.sortStrings(result.shadows),
158
+ breakpoints: htmlEscape.sortStrings(result.breakpoints)
159
+ };
160
+ }
161
+ function mergeThemes(themes) {
162
+ if (themes.length === 0) {
163
+ return { ...EMPTY_THEME };
164
+ }
165
+ const merged = {
166
+ colors: /* @__PURE__ */ new Set(),
167
+ spacings: /* @__PURE__ */ new Set(),
168
+ fonts: /* @__PURE__ */ new Set(),
169
+ textSizes: /* @__PURE__ */ new Set(),
170
+ fontWeights: /* @__PURE__ */ new Set(),
171
+ radii: /* @__PURE__ */ new Set(),
172
+ shadows: /* @__PURE__ */ new Set(),
173
+ breakpoints: /* @__PURE__ */ new Set()
174
+ };
175
+ for (const theme of themes) {
176
+ for (const cat of Object.keys(merged)) {
177
+ for (const token of theme[cat]) {
178
+ merged[cat].add(token);
179
+ }
180
+ }
181
+ }
182
+ return {
183
+ colors: htmlEscape.sortStrings(merged.colors),
184
+ spacings: htmlEscape.sortStrings(merged.spacings),
185
+ fonts: htmlEscape.sortStrings(merged.fonts),
186
+ textSizes: htmlEscape.sortStrings(merged.textSizes),
187
+ fontWeights: htmlEscape.sortStrings(merged.fontWeights),
188
+ radii: htmlEscape.sortStrings(merged.radii),
189
+ shadows: htmlEscape.sortStrings(merged.shadows),
190
+ breakpoints: htmlEscape.sortStrings(merged.breakpoints)
191
+ };
192
+ }
193
+ function hasTokens(theme) {
194
+ return Object.values(theme).some((arr) => arr.length > 0);
195
+ }
196
+ function readCustomPropertyName(block, dashes) {
197
+ let end = dashes + 2;
198
+ if (end >= block.length || !/[a-z]/.test(block[end])) {
199
+ return null;
200
+ }
201
+ end++;
202
+ while (end < block.length && /[a-z0-9-]/.test(block[end])) {
203
+ end++;
204
+ }
205
+ return { name: block.slice(dashes + 2, end), end };
206
+ }
207
+ function findCustomPropertyDeclarationEnd(block, nameEnd) {
208
+ let cursor = nameEnd;
209
+ while (cursor < block.length && /\s/.test(block[cursor])) {
210
+ cursor++;
211
+ }
212
+ if (block[cursor] === ":") {
213
+ const valueStart = cursor + 1;
214
+ const semicolon = block.indexOf(";", valueStart);
215
+ return semicolon > valueStart ? semicolon + 1 : -1;
216
+ }
217
+ return block[nameEnd] === ";" ? nameEnd + 1 : -1;
218
+ }
219
+ function scanCustomPropertyNames(block) {
220
+ const names = [];
221
+ let i = 0;
222
+ while (i < block.length) {
223
+ const dashes = block.indexOf("--", i);
224
+ if (dashes === -1) {
225
+ break;
226
+ }
227
+ const property = readCustomPropertyName(block, dashes);
228
+ if (!property) {
229
+ i = dashes + 1;
230
+ continue;
231
+ }
232
+ const matchEnd = findCustomPropertyDeclarationEnd(block, property.end);
233
+ if (matchEnd === -1) {
234
+ i = dashes + 1;
235
+ continue;
236
+ }
237
+ names.push(property.name);
238
+ i = matchEnd;
239
+ }
240
+ return names;
241
+ }
242
+
243
+ const LEADING_WHITESPACE_RE = /^\s+/;
244
+ const LINE_COMMENT_RE = /^\/\/[^\n]*(?:\n|$)/;
245
+ const BLOCK_COMMENT_RE = /^\/\*[\s\S]*?\*\//;
246
+ const USE_DIRECTIVE_RE = /^['"]use (?:client|server)['"];?\s*/;
247
+ function insertAfterUseDirective(code, insertion) {
248
+ let offset = 0;
249
+ while (offset < code.length) {
250
+ const triviaLength = leadingTriviaLength(code.slice(offset));
251
+ if (triviaLength === 0) break;
252
+ offset += triviaLength;
253
+ }
254
+ const directive = USE_DIRECTIVE_RE.exec(code.slice(offset));
255
+ if (!directive) return `${insertion}${code}`;
256
+ const insertionOffset = offset + directive[0].length;
257
+ return `${code.slice(0, insertionOffset)}${insertion}${code.slice(insertionOffset)}`;
258
+ }
259
+ function leadingTriviaLength(source) {
260
+ return LEADING_WHITESPACE_RE.exec(source)?.[0].length ?? LINE_COMMENT_RE.exec(source)?.[0].length ?? BLOCK_COMMENT_RE.exec(source)?.[0].length ?? 0;
261
+ }
262
+
263
+ const RUNTIME_IMPORT_CLAUSE_RE = /(?:import|export)\s+\{([^{}]*)\}\s*from\s*['"]@csszyx\/runtime['"]/g;
264
+ function clauseNames(clauseBody) {
265
+ const names = [];
266
+ for (const part of clauseBody.split(",")) {
267
+ const trimmed = part.trim();
268
+ if (!trimmed) {
269
+ continue;
270
+ }
271
+ const spaceAt = trimmed.search(/\s/);
272
+ names.push(spaceAt === -1 ? trimmed : trimmed.slice(0, spaceAt));
273
+ }
274
+ return names;
275
+ }
276
+ function importsRuntimeHelper(code, helper) {
277
+ RUNTIME_IMPORT_CLAUSE_RE.lastIndex = 0;
278
+ for (let match = RUNTIME_IMPORT_CLAUSE_RE.exec(code); match; match = RUNTIME_IMPORT_CLAUSE_RE.exec(code)) {
279
+ if (clauseNames(match[1]).includes(helper)) {
280
+ return true;
281
+ }
282
+ }
283
+ return false;
284
+ }
285
+ const RUNTIME_IMPORT_APPEND_RE = /(import\s+\{[^{}]*)\}\s*from\s*['"]@csszyx\/runtime['"]/;
286
+ function findRuntimeImportClause(code) {
287
+ const match = RUNTIME_IMPORT_APPEND_RE.exec(code);
288
+ return match ? { statement: match[0], prefixWithBody: match[1] } : null;
289
+ }
290
+
291
+ function runtimeHelperGroupsFromUsage(usage) {
292
+ const slim = usage.usesSzPart === true && usage.szPartArgsProvable === true && usage.usesRuntime !== true && usage.usesMerge !== true;
293
+ const groups = { all: [], barrel: [], merge: [] };
294
+ const append = (helper, toMerge = false) => {
295
+ groups.all.push(helper);
296
+ (toMerge ? groups.merge : groups.barrel).push(helper);
297
+ };
298
+ if (usage.usesRuntime) append("_sz");
299
+ if (usage.usesMerge) append("_szMerge");
300
+ if (usage.usesSzcn) append("_szcn", slim);
301
+ if (usage.usesSzPart) append("_szPart", slim);
302
+ if (usage.usesSzvPick) append("__szvPick");
303
+ if (usage.usesSzvPick1) append("__szvPick1");
304
+ if (usage.usesColorVar) append("__szColorVar");
305
+ if (usage.usesSpacingVar) append("__szSpacingVar");
306
+ if (usage.usesUnitVar) append("__szUnitVar");
307
+ return groups;
308
+ }
309
+ function injectNextRuntimeImports(code, usage) {
310
+ const groups = runtimeHelperGroupsFromUsage(usage);
311
+ const helpers = groups.all;
312
+ if (helpers.length === 0) {
313
+ return { code, injected: [] };
314
+ }
315
+ const hasRuntimeImport = code.includes("@csszyx/runtime");
316
+ const missing = hasRuntimeImport ? helpers.filter((helper) => !importsRuntimeHelper(code, helper)) : helpers;
317
+ if (missing.length === 0) {
318
+ return { code, injected: [] };
319
+ }
320
+ if (groups.merge.length > 0) {
321
+ const mergeHelpers = missing.filter((helper) => groups.merge.includes(helper));
322
+ const barrelHelpers = missing.filter((helper) => groups.barrel.includes(helper));
323
+ let next = insertRuntimeImport(
324
+ code,
325
+ `import { ${mergeHelpers.join(", ")} } from '@csszyx/runtime/merge';
326
+ `
327
+ );
328
+ if (barrelHelpers.length > 0) {
329
+ next = insertRuntimeImport(
330
+ next,
331
+ `import { ${barrelHelpers.join(", ")} } from '@csszyx/runtime';
332
+ `
333
+ );
334
+ }
335
+ return { code: next, injected: missing };
336
+ }
337
+ return {
338
+ code: insertRuntimeImport(
339
+ code,
340
+ `import { ${missing.join(", ")} } from '@csszyx/runtime';
341
+ `
342
+ ),
343
+ injected: missing
344
+ };
345
+ }
346
+ function insertRuntimeImport(code, importStmt) {
347
+ return insertAfterUseDirective(code, importStmt);
348
+ }
349
+
350
+ const THEME_SCAN_IGNORE_DIRS = /* @__PURE__ */ new Set([
351
+ "node_modules",
352
+ ".next",
353
+ ".git",
354
+ "dist",
355
+ "build",
356
+ ".turbo"
357
+ ]);
358
+ function normalize(value) {
359
+ const posix = value.replaceAll("\\", "/");
360
+ return posix.endsWith("/") ? posix.slice(0, -1) : posix;
361
+ }
362
+ function walkCss(dir, out) {
363
+ let entries;
364
+ try {
365
+ entries = fs__default.readdirSync(dir, { withFileTypes: true });
366
+ } catch {
367
+ return;
368
+ }
369
+ for (const entry of entries) {
370
+ if (entry.isDirectory()) {
371
+ if (!THEME_SCAN_IGNORE_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
372
+ walkCss(path__default.join(dir, entry.name), out);
373
+ }
374
+ continue;
375
+ }
376
+ if (entry.name.endsWith(".css")) {
377
+ out.push(path__default.join(dir, entry.name));
378
+ }
379
+ }
380
+ }
381
+ function discoverProjectTheme(rootDir, extraDirs = []) {
382
+ const cssFiles = [];
383
+ walkCss(rootDir, cssFiles);
384
+ const normalizedRoot = normalize(rootDir);
385
+ for (const dir of extraDirs) {
386
+ const normalized = normalize(dir);
387
+ if (normalized === normalizedRoot || normalized.startsWith(`${normalizedRoot}/`)) continue;
388
+ walkCss(dir, cssFiles);
389
+ }
390
+ const themes = [];
391
+ const files = [];
392
+ for (const file of cssFiles) {
393
+ let content;
394
+ try {
395
+ content = fs__default.readFileSync(file, "utf-8");
396
+ } catch {
397
+ continue;
398
+ }
399
+ if (!content.includes("@theme")) continue;
400
+ themes.push(parseThemeBlocks(content));
401
+ files.push(file);
402
+ }
403
+ return {
404
+ theme: themes.length > 0 ? mergeThemes(themes) : null,
405
+ files,
406
+ scanned: cssFiles
407
+ };
408
+ }
409
+
410
+ const VIRTUAL_MODULE_ID = "virtual:csszyx/mangle-map";
411
+ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
412
+ const THEME_GROUPS_VIRTUAL_ID = "virtual:csszyx/theme-groups";
413
+ const RESOLVED_THEME_GROUPS_VIRTUAL_ID = `\0${THEME_GROUPS_VIRTUAL_ID}`;
414
+ const VIRTUAL_CHECKSUM_ID = "virtual:csszyx/checksum";
415
+ const RESOLVED_VIRTUAL_CHECKSUM_ID = `\0${VIRTUAL_CHECKSUM_ID}`;
416
+ function createMangleMapModule(mangleMap, checksum, varMangleMap = {}, cssVarMetrics = null) {
417
+ return `/**
418
+ * Auto-generated mangle map for csszyx.
419
+ * This module is generated at build time and contains the mapping
420
+ * from original class names and CSS variable names to mangled names.
421
+ *
422
+ * @generated
423
+ */
424
+
425
+ export const mangleMap = ${JSON.stringify(mangleMap, null, 2)};
426
+
427
+ export const varMangleMap = ${JSON.stringify(varMangleMap, null, 2)};
428
+
429
+ export const cssVarMetrics = ${JSON.stringify(cssVarMetrics, null, 2)};
430
+
431
+ export const checksum = ${JSON.stringify(checksum)};
432
+
433
+ export default {
434
+ mangleMap,
435
+ varMangleMap,
436
+ cssVarMetrics,
437
+ checksum,
438
+ };
439
+ `;
440
+ }
441
+ function createChecksumModule(checksum) {
442
+ return `/**
443
+ * Auto-generated checksum for csszyx mangle map.
444
+ *
445
+ * @generated
446
+ */
447
+
448
+ export const checksum = ${JSON.stringify(checksum)};
449
+
450
+ export default checksum;
451
+ `;
452
+ }
453
+ function isVirtualModule(id) {
454
+ return id === VIRTUAL_MODULE_ID || id === VIRTUAL_CHECKSUM_ID || id === THEME_GROUPS_VIRTUAL_ID || id === MANGLE_RUNTIME_VIRTUAL_ID;
455
+ }
456
+ function resolveVirtualModule(id) {
457
+ if (id === VIRTUAL_MODULE_ID) {
458
+ return RESOLVED_VIRTUAL_MODULE_ID;
459
+ }
460
+ if (id === VIRTUAL_CHECKSUM_ID) {
461
+ return RESOLVED_VIRTUAL_CHECKSUM_ID;
462
+ }
463
+ if (id === THEME_GROUPS_VIRTUAL_ID) {
464
+ return RESOLVED_THEME_GROUPS_VIRTUAL_ID;
465
+ }
466
+ if (id === MANGLE_RUNTIME_VIRTUAL_ID) {
467
+ return RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID;
468
+ }
469
+ return void 0;
470
+ }
471
+ const MANGLE_RUNTIME_VIRTUAL_ID = "virtual:csszyx/mangle-runtime";
472
+ const RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID = `\0${MANGLE_RUNTIME_VIRTUAL_ID}`;
473
+ const MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
474
+ const VAR_MANGLE_MAP_PLACEHOLDER = "___CSSZYX_VAR_MANGLE_MAP___";
475
+ const CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
476
+ function createMangleRuntimeModule(globalVarAliasPrefix) {
477
+ return `/**
478
+ * Auto-generated by csszyx: installs the runtime mangle map from the bundle.
479
+ *
480
+ * @generated
481
+ */
482
+
483
+ const m = ${MANGLE_MAP_PLACEHOLDER};
484
+ const vm = ${VAR_MANGLE_MAP_PLACEHOLDER};
485
+ const gp = ${JSON.stringify(globalVarAliasPrefix)};
486
+ const checksum = "${CHECKSUM_PLACEHOLDER}";
487
+
488
+ if (typeof window !== 'undefined' && !window.__csszyx) {
489
+ const r = {};
490
+ const vr = {};
491
+ for (const k in m) r[m[k]] = k;
492
+ for (const vk in vm) {
493
+ const vv = vm[vk];
494
+ const vs = Array.isArray(vv) ? vv : [vv];
495
+ for (const v of vs) (vr[v] || (vr[v] = [])).push(vk);
496
+ }
497
+ window.__csszyx = {
498
+ mangleMap: m,
499
+ varMangleMap: vm,
500
+ checksum,
501
+ decode: (c) => r[c],
502
+ encode: (c) => m[c],
503
+ decodeVar: (v) => vr[v] || [],
504
+ encodeVar: (v) => vm[v],
505
+ decodeGlobalVar: (v) => {
506
+ const a = vr[v] || [];
507
+ return v.indexOf(gp) === 0 ? a[0] : undefined;
508
+ },
509
+ decodeAll: (el) => (el.className || '').split(' ').map((c) => r[c] || c),
510
+ };
511
+ }
512
+
513
+ export {};
514
+ `;
515
+ }
516
+ function createThemeGroupsModule(tokens) {
517
+ const payload = JSON.stringify({
518
+ colors: tokens.colors,
519
+ textSizes: tokens.textSizes,
520
+ fontFamilies: tokens.fontFamilies,
521
+ fontWeights: tokens.fontWeights
522
+ });
523
+ return [
524
+ "// Auto-generated by csszyx from the @theme blocks in scanned CSS.",
525
+ "import { setSzcnGroups } from '@csszyx/runtime';",
526
+ // `set`, not `register`: this payload is the COMPLETE scanned set, so
527
+ // re-running it after a `@theme` edit has to drop the tokens the
528
+ // stylesheet lost. The source name scopes the replace, leaving an app's
529
+ // own hand-written registration untouched.
530
+ `setSzcnGroups(${payload}, 'build');`,
531
+ "export {};"
532
+ ].join("\n");
533
+ }
534
+
535
+ const THEME_GROUPS_FILE = "theme-groups.mjs";
536
+ const THEME_GROUPS_FILE_MARKER = `.csszyx/${THEME_GROUPS_FILE}`;
537
+ const cacheByRoot = /* @__PURE__ */ new Map();
538
+ function signatureOf(files) {
539
+ return files.map((file) => {
540
+ try {
541
+ const stat = fs__default.statSync(file);
542
+ return `${file}:${stat.size}:${stat.mtimeMs}`;
543
+ } catch {
544
+ return `${file}:gone`;
545
+ }
546
+ }).join("|");
547
+ }
548
+ function isCacheUsable(cached) {
549
+ if (cached === void 0) return false;
550
+ return signatureOf(cached.watch) === cached.signature;
551
+ }
552
+ function ensureThemeGroupsFile(root, outputDir) {
553
+ const cached = cacheByRoot.get(root);
554
+ if (isCacheUsable(cached)) {
555
+ return { file: cached.file, watch: cached.watch };
556
+ }
557
+ const { theme, scanned } = discoverProjectTheme(root);
558
+ const tokens = {
559
+ colors: theme?.colors ?? [],
560
+ textSizes: theme?.textSizes ?? [],
561
+ fontFamilies: theme?.fonts ?? [],
562
+ fontWeights: theme?.fontWeights ?? []
563
+ };
564
+ const hasTokens = Object.values(tokens).some((names) => names.length > 0);
565
+ let file = null;
566
+ if (hasTokens) {
567
+ const target = path__default.join(outputDir, THEME_GROUPS_FILE);
568
+ try {
569
+ fs__default.mkdirSync(outputDir, { recursive: true });
570
+ fs__default.writeFileSync(target, createThemeGroupsModule(tokens), "utf8");
571
+ file = target;
572
+ } catch {
573
+ file = null;
574
+ }
575
+ }
576
+ const result = { file, watch: scanned, signature: signatureOf(scanned) };
577
+ cacheByRoot.set(root, result);
578
+ return { file, watch: scanned };
579
+ }
580
+ function themeGroupsSpecifier(fromFile, themeGroupsFile) {
581
+ const relative = path__default.relative(path__default.dirname(fromFile), themeGroupsFile).replaceAll("\\", "/");
582
+ return relative.startsWith("./") || relative.startsWith("../") ? relative : `./${relative}`;
583
+ }
584
+
585
+ exports.CHECKSUM_PLACEHOLDER = CHECKSUM_PLACEHOLDER;
586
+ exports.MANGLE_MAP_PLACEHOLDER = MANGLE_MAP_PLACEHOLDER;
587
+ exports.MANGLE_RUNTIME_VIRTUAL_ID = MANGLE_RUNTIME_VIRTUAL_ID;
588
+ exports.RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID = RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID;
589
+ exports.RESOLVED_THEME_GROUPS_VIRTUAL_ID = RESOLVED_THEME_GROUPS_VIRTUAL_ID;
590
+ exports.RESOLVED_VIRTUAL_CHECKSUM_ID = RESOLVED_VIRTUAL_CHECKSUM_ID;
591
+ exports.RESOLVED_VIRTUAL_MODULE_ID = RESOLVED_VIRTUAL_MODULE_ID;
592
+ exports.THEME_GROUPS_FILE_MARKER = THEME_GROUPS_FILE_MARKER;
593
+ exports.THEME_GROUPS_VIRTUAL_ID = THEME_GROUPS_VIRTUAL_ID;
594
+ exports.VAR_MANGLE_MAP_PLACEHOLDER = VAR_MANGLE_MAP_PLACEHOLDER;
595
+ exports.createChecksumModule = createChecksumModule;
596
+ exports.createMangleMapModule = createMangleMapModule;
597
+ exports.createMangleRuntimeModule = createMangleRuntimeModule;
598
+ exports.createThemeGroupsModule = createThemeGroupsModule;
599
+ exports.discoverProjectTheme = discoverProjectTheme;
600
+ exports.ensureThemeGroupsFile = ensureThemeGroupsFile;
601
+ exports.findRuntimeImportClause = findRuntimeImportClause;
602
+ exports.hasTokens = hasTokens;
603
+ exports.importsRuntimeHelper = importsRuntimeHelper;
604
+ exports.injectNextRuntimeImports = injectNextRuntimeImports;
605
+ exports.insertAfterUseDirective = insertAfterUseDirective;
606
+ exports.isVirtualModule = isVirtualModule;
607
+ exports.mergeThemes = mergeThemes;
608
+ exports.parseThemeBlocks = parseThemeBlocks;
609
+ exports.resolveVirtualModule = resolveVirtualModule;
610
+ exports.runtimeHelperGroupsFromUsage = runtimeHelperGroupsFromUsage;
611
+ exports.scanCustomPropertyNames = scanCustomPropertyNames;
612
+ exports.themeGroupsSpecifier = themeGroupsSpecifier;