@csszyx/unplugin 0.1.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,905 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createPostCSSPlugin: () => createPostCSSPlugin,
34
+ default: () => unplugin,
35
+ esbuildPlugin: () => esbuildPlugin,
36
+ escapeCSSClassName: () => escapeCSSClassName,
37
+ mangleCSS: () => mangleCSS,
38
+ mangleCSSSync: () => mangleCSSSync,
39
+ rollupPlugin: () => rollupPlugin,
40
+ unescapeTailwindClass: () => unescapeTailwindClass,
41
+ unplugin: () => unplugin,
42
+ vitePlugin: () => vitePlugin,
43
+ webpackPlugin: () => webpackPlugin
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/css-mangler.ts
48
+ var import_postcss = __toESM(require("postcss"), 1);
49
+ var import_postcss_selector_parser = __toESM(require("postcss-selector-parser"), 1);
50
+ function unescapeTailwindClass(escapedName) {
51
+ let result = "";
52
+ let i = 0;
53
+ while (i < escapedName.length) {
54
+ if (escapedName[i] === "\\") {
55
+ i++;
56
+ if (i >= escapedName.length) {
57
+ break;
58
+ }
59
+ const char = escapedName[i];
60
+ if (/[0-9a-fA-F]/.test(char)) {
61
+ let hexStr = "";
62
+ while (i < escapedName.length && /[0-9a-fA-F]/.test(escapedName[i]) && hexStr.length < 6) {
63
+ hexStr += escapedName[i];
64
+ i++;
65
+ }
66
+ if (i < escapedName.length && escapedName[i] === " ") {
67
+ i++;
68
+ }
69
+ const codePoint = parseInt(hexStr, 16);
70
+ if (codePoint > 0) {
71
+ result += String.fromCodePoint(codePoint);
72
+ }
73
+ continue;
74
+ }
75
+ result += char;
76
+ i++;
77
+ } else {
78
+ result += escapedName[i];
79
+ i++;
80
+ }
81
+ }
82
+ return result;
83
+ }
84
+ function escapeCSSClassName(className) {
85
+ let result = "";
86
+ for (let i = 0; i < className.length; i++) {
87
+ const char = className[i];
88
+ const code = char.charCodeAt(0);
89
+ if (i === 0) {
90
+ if (/[0-9]/.test(char)) {
91
+ result += "\\3" + char + " ";
92
+ continue;
93
+ }
94
+ if (char === "-" && i + 1 < className.length) {
95
+ const next = className[i + 1];
96
+ if (/[0-9]/.test(next) || next === "-") {
97
+ result += "\\-";
98
+ continue;
99
+ }
100
+ }
101
+ }
102
+ if (/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/.test(char)) {
103
+ result += "\\" + char;
104
+ } else if (code >= 128) {
105
+ result += char;
106
+ } else {
107
+ result += char;
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ function createSelectorProcessor(mangleMap, mangledClasses, unmangledClasses) {
113
+ return (0, import_postcss_selector_parser.default)((selectors) => {
114
+ selectors.walkClasses((classNode) => {
115
+ const originalValue = classNode.value;
116
+ const unescapedValue = unescapeTailwindClass(originalValue);
117
+ let mangledValue, matchedKey;
118
+ if (mangleMap[unescapedValue]) {
119
+ mangledValue = mangleMap[unescapedValue];
120
+ matchedKey = unescapedValue;
121
+ } else if (mangleMap[originalValue]) {
122
+ mangledValue = mangleMap[originalValue];
123
+ matchedKey = originalValue;
124
+ }
125
+ if (mangledValue && matchedKey) {
126
+ classNode.value = mangledValue;
127
+ mangledClasses.add(matchedKey);
128
+ } else {
129
+ unmangledClasses.add(originalValue);
130
+ }
131
+ });
132
+ });
133
+ }
134
+ async function mangleCSS(css, mangleMap, options = {}) {
135
+ const mangledClasses = /* @__PURE__ */ new Set();
136
+ const unmangledClasses = /* @__PURE__ */ new Set();
137
+ let transformedCount = 0;
138
+ const selectorProcessor = createSelectorProcessor(
139
+ mangleMap,
140
+ mangledClasses,
141
+ unmangledClasses
142
+ );
143
+ const csszyxManglerPlugin = {
144
+ postcssPlugin: "csszyx-css-mangler",
145
+ Rule(rule) {
146
+ try {
147
+ const originalSelector = rule.selector;
148
+ const newSelector = selectorProcessor.processSync(originalSelector);
149
+ if (newSelector !== originalSelector) {
150
+ rule.selector = newSelector;
151
+ transformedCount++;
152
+ }
153
+ } catch (error) {
154
+ if (options.debug) {
155
+ console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
156
+ }
157
+ }
158
+ }
159
+ };
160
+ const result = await (0, import_postcss.default)([csszyxManglerPlugin]).process(css, {
161
+ from: options.from
162
+ });
163
+ if (options.debug) {
164
+ console.log(`[csszyx] CSS Mangler: ${transformedCount} selectors transformed`);
165
+ console.log(`[csszyx] Mangled classes: ${mangledClasses.size}`);
166
+ console.log(`[csszyx] Unmangled classes: ${unmangledClasses.size}`);
167
+ }
168
+ return {
169
+ css: result.css,
170
+ transformedCount,
171
+ mangledClasses: Array.from(mangledClasses),
172
+ unmangledClasses: Array.from(unmangledClasses)
173
+ };
174
+ }
175
+ function mangleCSSSync(css, mangleMap, options = {}) {
176
+ const mangledClasses = /* @__PURE__ */ new Set();
177
+ const unmangledClasses = /* @__PURE__ */ new Set();
178
+ let transformedCount = 0;
179
+ const selectorProcessor = createSelectorProcessor(
180
+ mangleMap,
181
+ mangledClasses,
182
+ unmangledClasses
183
+ );
184
+ const root = import_postcss.default.parse(css, { from: options.from });
185
+ root.walkRules((rule) => {
186
+ try {
187
+ const originalSelector = rule.selector;
188
+ const newSelector = selectorProcessor.processSync(originalSelector);
189
+ if (newSelector !== originalSelector) {
190
+ rule.selector = newSelector;
191
+ transformedCount++;
192
+ }
193
+ } catch (error) {
194
+ if (options.debug) {
195
+ console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
196
+ }
197
+ }
198
+ });
199
+ if (options.debug) {
200
+ console.log(`[csszyx] CSS Mangler: ${transformedCount} selectors transformed`);
201
+ console.log(`[csszyx] Mangled classes: ${mangledClasses.size}`);
202
+ console.log(`[csszyx] Unmangled classes: ${unmangledClasses.size}`);
203
+ }
204
+ return {
205
+ css: root.toString(),
206
+ transformedCount,
207
+ mangledClasses: Array.from(mangledClasses),
208
+ unmangledClasses: Array.from(unmangledClasses)
209
+ };
210
+ }
211
+ function createPostCSSPlugin(mangleMap, options = {}) {
212
+ const mangledClasses = /* @__PURE__ */ new Set();
213
+ const unmangledClasses = /* @__PURE__ */ new Set();
214
+ const selectorProcessor = createSelectorProcessor(
215
+ mangleMap,
216
+ mangledClasses,
217
+ unmangledClasses
218
+ );
219
+ return {
220
+ postcssPlugin: "csszyx-css-mangler",
221
+ Rule(rule) {
222
+ try {
223
+ const originalSelector = rule.selector;
224
+ const newSelector = selectorProcessor.processSync(originalSelector);
225
+ if (newSelector !== originalSelector) {
226
+ rule.selector = newSelector;
227
+ }
228
+ } catch (error) {
229
+ if (options.debug) {
230
+ console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
231
+ }
232
+ }
233
+ },
234
+ OnceExit() {
235
+ if (options.debug) {
236
+ console.log(`[csszyx] Mangled ${mangledClasses.size} unique classes`);
237
+ }
238
+ }
239
+ };
240
+ }
241
+
242
+ // src/unplugin.ts
243
+ var fs = __toESM(require("fs"), 1);
244
+ var path = __toESM(require("path"), 1);
245
+ var import_compiler = require("@csszyx/compiler");
246
+ var import_core = require("@csszyx/core");
247
+ var import_svelte_adapter = require("@csszyx/svelte-adapter");
248
+ var import_vue_adapter = require("@csszyx/vue-adapter");
249
+ var import_unplugin = require("unplugin");
250
+
251
+ // src/html-transformer.ts
252
+ function injectChecksum(html, checksum, minify = false) {
253
+ const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
254
+ const htmlTagPattern = /<html([^>]*)>/i;
255
+ const match = html.match(htmlTagPattern);
256
+ if (!match) {
257
+ return html;
258
+ }
259
+ const existingAttrs = match[1];
260
+ const checksumAttr = ` ${attrName}="${checksum}"`;
261
+ return html.replace(
262
+ htmlTagPattern,
263
+ `<html${checksumAttr}${existingAttrs}>`
264
+ );
265
+ }
266
+ function injectMangleMapScript(html, mangleMap, options = {}) {
267
+ const { prettyPrint = false } = options;
268
+ const jsonContent = prettyPrint ? JSON.stringify(mangleMap, null, 2) : JSON.stringify(mangleMap);
269
+ const scriptTag = `<script id="__CSSZYX_MANGLE_MAP__" type="application/json">${jsonContent}</script>`;
270
+ 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>`;
271
+ const combined = `${scriptTag}
272
+ ${debugScript}`;
273
+ if (html.includes("</head>")) {
274
+ return html.replace("</head>", `${combined}
275
+ </head>`);
276
+ } else if (html.includes("</html>")) {
277
+ return html.replace("</html>", `${combined}
278
+ </html>`);
279
+ }
280
+ return html + combined;
281
+ }
282
+ function injectMangleMapAttribute(html, mangleMap, minify = false) {
283
+ const attrName = minify ? "data-sz-m" : "data-sz-map";
284
+ const jsonContent = JSON.stringify(mangleMap);
285
+ const htmlTagPattern = /<html([^>]*)>/i;
286
+ const match = html.match(htmlTagPattern);
287
+ if (!match) {
288
+ return html;
289
+ }
290
+ const existingAttrs = match[1];
291
+ const mapAttr = ` ${attrName}='${jsonContent}'`;
292
+ return html.replace(htmlTagPattern, `<html${mapAttr}${existingAttrs}>`);
293
+ }
294
+ function injectHydrationData(html, mangleMap, checksum, options = {}) {
295
+ const { mode = "script", minify = false } = options;
296
+ let result = html;
297
+ result = injectChecksum(result, checksum, minify);
298
+ if (mode === "inline") {
299
+ result = injectMangleMapAttribute(result, mangleMap, minify);
300
+ } else if (mode === "script") {
301
+ result = injectMangleMapScript(result, mangleMap, options);
302
+ } else if (mode === "both") {
303
+ result = injectMangleMapAttribute(result, mangleMap, minify);
304
+ result = injectMangleMapScript(result, mangleMap, options);
305
+ }
306
+ return result;
307
+ }
308
+ function transformIndexHtml(html, mangleMap, checksum, options = {}) {
309
+ return injectHydrationData(html, mangleMap, checksum, options);
310
+ }
311
+
312
+ // src/virtual-modules.ts
313
+ var VIRTUAL_MODULE_ID = "virtual:csszyx/mangle-map";
314
+ var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
315
+ var VIRTUAL_CHECKSUM_ID = "virtual:csszyx/checksum";
316
+ var RESOLVED_VIRTUAL_CHECKSUM_ID = "\0" + VIRTUAL_CHECKSUM_ID;
317
+ function createMangleMapModule(mangleMap, checksum) {
318
+ return `/**
319
+ * Auto-generated mangle map for csszyx.
320
+ * This module is generated at build time and contains the mapping
321
+ * from original class names to mangled class names.
322
+ *
323
+ * @generated
324
+ */
325
+
326
+ export const mangleMap = ${JSON.stringify(mangleMap, null, 2)};
327
+
328
+ export const checksum = ${JSON.stringify(checksum)};
329
+
330
+ export default {
331
+ mangleMap,
332
+ checksum,
333
+ };
334
+ `;
335
+ }
336
+ function createChecksumModule(checksum) {
337
+ return `/**
338
+ * Auto-generated checksum for csszyx mangle map.
339
+ *
340
+ * @generated
341
+ */
342
+
343
+ export const checksum = ${JSON.stringify(checksum)};
344
+
345
+ export default checksum;
346
+ `;
347
+ }
348
+ function isVirtualModule(id) {
349
+ return id === VIRTUAL_MODULE_ID || id === VIRTUAL_CHECKSUM_ID;
350
+ }
351
+ function resolveVirtualModule(id) {
352
+ if (id === VIRTUAL_MODULE_ID) {
353
+ return RESOLVED_VIRTUAL_MODULE_ID;
354
+ }
355
+ if (id === VIRTUAL_CHECKSUM_ID) {
356
+ return RESOLVED_VIRTUAL_CHECKSUM_ID;
357
+ }
358
+ return void 0;
359
+ }
360
+
361
+ // src/unplugin.ts
362
+ var CHECKSUM_PLACEHOLDER = "___CSSZYX_CHECKSUM___";
363
+ var MANGLE_MAP_PLACEHOLDER = "___CSSZYX_MANGLE_MAP___";
364
+ function createCsszyxPlugins(options = {}) {
365
+ const manglingEnabled = options.production?.mangle !== false;
366
+ const state = {
367
+ classes: /* @__PURE__ */ new Set(),
368
+ mangleMap: {},
369
+ checksum: "",
370
+ finalized: false
371
+ };
372
+ const SAFELIST_FILENAME = "csszyx-classes.js";
373
+ const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
374
+ const IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".next", ".git", "dist", "build", ".turbo"]);
375
+ function prescanAndWriteClasses(rootDir) {
376
+ const discoveredClasses = /* @__PURE__ */ new Set();
377
+ function scanDir(dir) {
378
+ let entries;
379
+ try {
380
+ entries = fs.readdirSync(dir, { withFileTypes: true });
381
+ } catch {
382
+ return;
383
+ }
384
+ for (const entry of entries) {
385
+ if (entry.isDirectory()) {
386
+ if (!IGNORE_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
387
+ scanDir(path.join(dir, entry.name));
388
+ }
389
+ } else if (SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
390
+ const filePath = path.join(dir, entry.name);
391
+ try {
392
+ const content = fs.readFileSync(filePath, "utf-8");
393
+ if (!content.includes("sz=") && !content.includes("sz:")) {
394
+ continue;
395
+ }
396
+ const result = (0, import_compiler.transformSourceCode)(content);
397
+ if (!result.transformed) {
398
+ continue;
399
+ }
400
+ const classPattern = /class(?:Name)?=["']([^"']*)["']/g;
401
+ let match;
402
+ while ((match = classPattern.exec(result.code)) !== null) {
403
+ for (const cls of match[1].split(/\s+/).filter(Boolean)) {
404
+ discoveredClasses.add(cls);
405
+ }
406
+ }
407
+ const exprPattern = /className=\{/g;
408
+ while ((match = exprPattern.exec(result.code)) !== null) {
409
+ let depth = 1;
410
+ let i = match.index + match[0].length;
411
+ while (i < result.code.length && depth > 0) {
412
+ if (result.code[i] === "{") {
413
+ depth++;
414
+ } else if (result.code[i] === "}") {
415
+ depth--;
416
+ }
417
+ i++;
418
+ }
419
+ const expr = result.code.slice(match.index + match[0].length, i - 1);
420
+ const strPattern = /"([^"]+)"|'([^']+)'/g;
421
+ let strMatch;
422
+ while ((strMatch = strPattern.exec(expr)) !== null) {
423
+ const str = strMatch[1] || strMatch[2];
424
+ for (const cls of str.split(/\s+/).filter(Boolean)) {
425
+ discoveredClasses.add(cls);
426
+ }
427
+ }
428
+ }
429
+ if (result.usesRuntime) {
430
+ const szCallRe = /_sz\(\s*\{/g;
431
+ let szMatch;
432
+ while ((szMatch = szCallRe.exec(result.code)) !== null) {
433
+ let depth = 1;
434
+ let idx = szMatch.index + szMatch[0].length;
435
+ while (idx < result.code.length && depth > 0) {
436
+ if (result.code[idx] === "{") {
437
+ depth++;
438
+ } else if (result.code[idx] === "}") {
439
+ depth--;
440
+ }
441
+ idx++;
442
+ }
443
+ const objStr = result.code.slice(szMatch.index + szMatch[0].length, idx - 1);
444
+ const strKv = /(\w+)\s*:\s*(?:"([^"]*)"|'([^']*)')/g;
445
+ let kv;
446
+ while ((kv = strKv.exec(objStr)) !== null) {
447
+ try {
448
+ const val = kv[2] ?? kv[3];
449
+ const r = (0, import_compiler.transform)({ [kv[1]]: val });
450
+ for (const c of r.className.split(/\s+/).filter(Boolean)) {
451
+ discoveredClasses.add(c);
452
+ }
453
+ } catch {
454
+ }
455
+ }
456
+ const numKv = /(\w+)\s*:\s*(-?\d+(?:\.\d+)?)\s*(?=[,}\n])/g;
457
+ while ((kv = numKv.exec(objStr)) !== null) {
458
+ try {
459
+ const r = (0, import_compiler.transform)({ [kv[1]]: parseFloat(kv[2]) });
460
+ for (const c of r.className.split(/\s+/).filter(Boolean)) {
461
+ discoveredClasses.add(c);
462
+ }
463
+ } catch {
464
+ }
465
+ }
466
+ const boolKv = /(\w+)\s*:\s*(true|false)\s*(?=[,}\n])/g;
467
+ while ((kv = boolKv.exec(objStr)) !== null) {
468
+ try {
469
+ const r = (0, import_compiler.transform)({ [kv[1]]: kv[2] === "true" });
470
+ for (const c of r.className.split(/\s+/).filter(Boolean)) {
471
+ discoveredClasses.add(c);
472
+ }
473
+ } catch {
474
+ }
475
+ }
476
+ }
477
+ }
478
+ } catch {
479
+ }
480
+ }
481
+ }
482
+ }
483
+ scanDir(rootDir);
484
+ for (const cls of discoveredClasses) {
485
+ state.classes.add(cls);
486
+ }
487
+ if (discoveredClasses.size > 0) {
488
+ const safelistPath = path.join(rootDir, SAFELIST_FILENAME);
489
+ const content = '// Auto-generated by csszyx \u2014 DO NOT EDIT\n// Tailwind CSS scans this file for class name detection\nexport default "' + Array.from(discoveredClasses).join(" ") + '";\n';
490
+ try {
491
+ const existing = fs.existsSync(safelistPath) ? fs.readFileSync(safelistPath, "utf-8") : "";
492
+ if (existing !== content) {
493
+ fs.writeFileSync(safelistPath, content);
494
+ }
495
+ } catch {
496
+ }
497
+ }
498
+ }
499
+ function extractClasses(code) {
500
+ const classPattern = /(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g;
501
+ let match;
502
+ while ((match = classPattern.exec(code)) !== null) {
503
+ const classes = match[1].split(/\s+/).filter(Boolean);
504
+ for (const cls of classes) {
505
+ state.classes.add(cls);
506
+ }
507
+ }
508
+ const exprStart = /className=\{/g;
509
+ while ((match = exprStart.exec(code)) !== null) {
510
+ let depth = 1;
511
+ let i = match.index + match[0].length;
512
+ while (i < code.length && depth > 0) {
513
+ if (code[i] === "{") {
514
+ depth++;
515
+ } else if (code[i] === "}") {
516
+ depth--;
517
+ }
518
+ i++;
519
+ }
520
+ const expr = code.slice(match.index + match[0].length, i - 1);
521
+ const strPattern = /"([^"]+)"|'([^']+)'/g;
522
+ let strMatch;
523
+ while ((strMatch = strPattern.exec(expr)) !== null) {
524
+ const str = strMatch[1] || strMatch[2];
525
+ const classes = str.split(/\s+/).filter(Boolean);
526
+ for (const cls of classes) {
527
+ state.classes.add(cls);
528
+ }
529
+ }
530
+ }
531
+ }
532
+ function finalizeMangleMap() {
533
+ const sortedClasses = Array.from(state.classes);
534
+ const newMap = {};
535
+ for (let i = 0; i < sortedClasses.length; i++) {
536
+ newMap[sortedClasses[i]] = (0, import_core.encode)(i);
537
+ }
538
+ state.mangleMap = newMap;
539
+ state.checksum = (0, import_core.compute_mangle_checksum)(state.mangleMap);
540
+ state.finalized = true;
541
+ }
542
+ function mangleClassString(classString) {
543
+ return classString.split(/\s+/).map((cls) => state.mangleMap[cls] || cls).join(" ");
544
+ }
545
+ function mangleCodeClasses(code) {
546
+ let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g, (match, classes) => {
547
+ const mangled = mangleClassString(classes);
548
+ if (mangled === classes) {
549
+ return match;
550
+ }
551
+ return match.replace(classes, mangled);
552
+ });
553
+ result = result.replace(/className:([^,;}\])\n]+)/g, (fullMatch, expr) => {
554
+ let changed = false;
555
+ const mangled = expr.replace(/"([^"]*)"/g, (qm, inner) => {
556
+ const parts = inner.split(/\s+/).filter(Boolean);
557
+ if (parts.length === 0) {
558
+ return qm;
559
+ }
560
+ const mangledStr = parts.map((p) => state.mangleMap[p] || p).join(" ");
561
+ if (mangledStr !== inner) {
562
+ changed = true;
563
+ return '"' + mangledStr + '"';
564
+ }
565
+ return qm;
566
+ });
567
+ if (changed) {
568
+ return "className:" + mangled;
569
+ }
570
+ return fullMatch;
571
+ });
572
+ return result;
573
+ }
574
+ function replacePlaceholders(code) {
575
+ let result = code;
576
+ if (result.includes(CHECKSUM_PLACEHOLDER)) {
577
+ result = result.split(CHECKSUM_PLACEHOLDER).join(state.checksum);
578
+ }
579
+ if (result.includes(MANGLE_MAP_PLACEHOLDER)) {
580
+ result = result.split(MANGLE_MAP_PLACEHOLDER).join(JSON.stringify(state.mangleMap));
581
+ }
582
+ return result;
583
+ }
584
+ const prePlugin = (0, import_unplugin.createUnplugin)((_pluginOptions) => ({
585
+ name: "csszyx:pre",
586
+ enforce: "pre",
587
+ /**
588
+ * Resolves virtual module IDs for csszyx mangle-map and checksum modules.
589
+ * @param id - the module ID to resolve
590
+ * @returns resolved ID if virtual, null otherwise
591
+ */
592
+ resolveId(id) {
593
+ if (isVirtualModule(id)) {
594
+ return resolveVirtualModule(id);
595
+ }
596
+ return null;
597
+ },
598
+ /**
599
+ * Loads virtual module content — generates mangle map or checksum module code.
600
+ * @param id - the resolved module ID to load
601
+ * @returns generated module source if virtual, null otherwise
602
+ */
603
+ load(id) {
604
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
605
+ finalizeMangleMap();
606
+ return createMangleMapModule(state.mangleMap, state.checksum);
607
+ }
608
+ if (id === RESOLVED_VIRTUAL_CHECKSUM_ID) {
609
+ finalizeMangleMap();
610
+ return createChecksumModule(state.checksum);
611
+ }
612
+ return null;
613
+ },
614
+ /**
615
+ * Filters files for the pre-transform phase — only source files outside node_modules.
616
+ * @param id - the file path to check for inclusion
617
+ * @returns true if the file should be transformed, false otherwise
618
+ */
619
+ transformInclude(id) {
620
+ if (id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static")) {
621
+ return false;
622
+ }
623
+ return /\.[tj]sx?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte");
624
+ },
625
+ /**
626
+ * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
627
+ * @param code - the source code to transform
628
+ * @param id - the file path of the module being transformed
629
+ * @returns transformed code with source map, or null if no changes were made
630
+ */
631
+ transform(code, id) {
632
+ let transformedCode = code;
633
+ let usesRuntime = false;
634
+ let usesColorVar = false;
635
+ let transformed = false;
636
+ const hasSzProp = code.includes("sz=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
637
+ if (hasSzProp) {
638
+ if (id.endsWith(".vue")) {
639
+ const result = (0, import_vue_adapter.preprocess)(code, options);
640
+ if (result.transformed) {
641
+ transformedCode = result.code;
642
+ transformed = true;
643
+ }
644
+ } else if (id.endsWith(".svelte")) {
645
+ const result = (0, import_svelte_adapter.preprocess)(code, options);
646
+ if (result) {
647
+ transformedCode = result.code;
648
+ transformed = true;
649
+ }
650
+ } else {
651
+ const result = (0, import_compiler.transformSourceCode)(code);
652
+ transformedCode = result.code;
653
+ usesRuntime = result.usesRuntime;
654
+ usesColorVar = result.usesColorVar;
655
+ transformed = result.transformed;
656
+ }
657
+ }
658
+ if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
659
+ const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
660
+ transformedCode = transformedCode.replace(/<html([^>]*)>/i, `<html$1 ${attrName}="${CHECKSUM_PLACEHOLDER}">`);
661
+ 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})}}})()\`}} />`;
662
+ if (transformedCode.includes("<body")) {
663
+ transformedCode = transformedCode.replace(
664
+ /(<body[^>]*>)/i,
665
+ `$1${debugScript}`
666
+ );
667
+ }
668
+ transformed = true;
669
+ }
670
+ {
671
+ const imports = [];
672
+ if (usesRuntime) {
673
+ imports.push("_sz");
674
+ }
675
+ if (usesColorVar) {
676
+ imports.push("__szColorVar");
677
+ }
678
+ if (imports.length > 0 && !transformedCode.includes("from 'csszyx/lite'")) {
679
+ const importStmt = `import { ${imports.join(", ")} } from 'csszyx/lite';
680
+ `;
681
+ const directiveMatch = transformedCode.match(/^['"]use (client|server)['"];?\s*/);
682
+ if (directiveMatch) {
683
+ const directive = directiveMatch[0];
684
+ transformedCode = transformedCode.replace(directive, `${directive}${importStmt}`);
685
+ } else {
686
+ transformedCode = `${importStmt}${transformedCode}`;
687
+ }
688
+ transformed = true;
689
+ }
690
+ }
691
+ if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
692
+ extractClasses(transformedCode);
693
+ return { code: transformedCode, map: null };
694
+ }
695
+ return null;
696
+ },
697
+ /** Finalizes the mangle map after all source modules have been processed. */
698
+ buildEnd() {
699
+ finalizeMangleMap();
700
+ },
701
+ /**
702
+ * Webpack hook: pre-scans source files before compilation for Tailwind class discovery.
703
+ * @param compiler - the Webpack compiler instance
704
+ */
705
+ webpack(compiler) {
706
+ compiler.hooks.beforeCompile.tap("csszyx:prescan", () => {
707
+ if (state.classes.size === 0) {
708
+ prescanAndWriteClasses(compiler.context || process.cwd());
709
+ }
710
+ });
711
+ },
712
+ vite: {
713
+ /**
714
+ * Vite hook: pre-scans source files when config is resolved.
715
+ * @param config - the resolved Vite configuration object
716
+ */
717
+ configResolved(config) {
718
+ prescanAndWriteClasses(config.root || process.cwd());
719
+ },
720
+ transformIndexHtml: {
721
+ order: "pre",
722
+ /**
723
+ * Injects hydration data (mangle map + checksum) into the HTML document.
724
+ * @param html - the raw HTML string to transform
725
+ * @returns transformed HTML with injected hydration data
726
+ */
727
+ handler(html) {
728
+ finalizeMangleMap();
729
+ return transformIndexHtml(html, state.mangleMap, state.checksum, {
730
+ mode: options.production?.injectChecksum === false ? "script" : "script",
731
+ minify: process.env.NODE_ENV === "production"
732
+ });
733
+ }
734
+ }
735
+ }
736
+ }));
737
+ const postPlugin = (0, import_unplugin.createUnplugin)(() => ({
738
+ name: "csszyx:post",
739
+ enforce: "post",
740
+ // No transform hook — all mangling is deferred to asset processing
741
+ // where the complete mangle map is available.
742
+ /**
743
+ * Webpack hook: mangles CSS/JS class names in processAssets after compilation.
744
+ * @param compiler - the Webpack compiler instance
745
+ */
746
+ webpack(compiler) {
747
+ compiler.hooks.compilation.tap("csszyx:post", (compilation) => {
748
+ const stage = compiler.webpack?.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE || // eslint-disable-next-line @typescript-eslint/no-explicit-any
749
+ compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE;
750
+ compilation.hooks.processAssets.tap(
751
+ {
752
+ name: "csszyx:post",
753
+ stage: stage || 400
754
+ // Fallback integer
755
+ },
756
+ (assets) => {
757
+ finalizeMangleMap();
758
+ for (const file in assets) {
759
+ const asset = assets[file];
760
+ const source = asset.source().toString();
761
+ if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
762
+ if (file.endsWith(".css")) {
763
+ try {
764
+ const result = mangleCSSSync(source, state.mangleMap, {
765
+ debug: options.development?.debug,
766
+ from: file
767
+ });
768
+ if (result.transformedCount > 0) {
769
+ compilation.updateAsset(
770
+ file,
771
+ new compiler.webpack.sources.RawSource(result.css)
772
+ );
773
+ continue;
774
+ }
775
+ } catch (e) {
776
+ if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") {
777
+ } else {
778
+ throw e;
779
+ }
780
+ }
781
+ } else if (file.endsWith(".js")) {
782
+ let mangled = mangleCodeClasses(source);
783
+ mangled = replacePlaceholders(mangled);
784
+ if (mangled !== source) {
785
+ compilation.updateAsset(
786
+ file,
787
+ new compiler.webpack.sources.RawSource(mangled)
788
+ );
789
+ continue;
790
+ }
791
+ }
792
+ }
793
+ if (file.endsWith(".js") && (source.includes(CHECKSUM_PLACEHOLDER) || source.includes(MANGLE_MAP_PLACEHOLDER))) {
794
+ const replaced = replacePlaceholders(source);
795
+ if (replaced !== source) {
796
+ compilation.updateAsset(
797
+ file,
798
+ new compiler.webpack.sources.RawSource(replaced)
799
+ );
800
+ }
801
+ }
802
+ }
803
+ }
804
+ );
805
+ });
806
+ },
807
+ vite: {
808
+ /**
809
+ * Vite hook: mangles CSS selectors and JS class strings in the final bundle.
810
+ * @param _options - the output options (unused)
811
+ * @param bundle - the output bundle containing chunks and assets to process
812
+ */
813
+ generateBundle(_options, bundle) {
814
+ finalizeMangleMap();
815
+ for (const file in bundle) {
816
+ const chunk = bundle[file];
817
+ if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
818
+ if (chunk.type === "asset" && chunk.fileName.endsWith(".css")) {
819
+ const css = chunk.source.toString();
820
+ try {
821
+ const result = mangleCSSSync(css, state.mangleMap, {
822
+ debug: options.development?.debug,
823
+ from: file
824
+ });
825
+ if (result.transformedCount > 0) {
826
+ chunk.source = result.css;
827
+ }
828
+ } catch (e) {
829
+ if (e && typeof e === "object" && "name" in e && e.name === "CssSyntaxError") {
830
+ } else {
831
+ throw e;
832
+ }
833
+ }
834
+ continue;
835
+ } else if (chunk.type === "chunk") {
836
+ let mangledCode = mangleCodeClasses(chunk.code);
837
+ mangledCode = replacePlaceholders(mangledCode);
838
+ if (mangledCode !== chunk.code) {
839
+ chunk.code = mangledCode;
840
+ }
841
+ continue;
842
+ }
843
+ }
844
+ if (chunk.type === "chunk" && (chunk.code.includes(CHECKSUM_PLACEHOLDER) || chunk.code.includes(MANGLE_MAP_PLACEHOLDER))) {
845
+ const replaced = replacePlaceholders(chunk.code);
846
+ if (replaced !== chunk.code) {
847
+ chunk.code = replaced;
848
+ }
849
+ }
850
+ }
851
+ }
852
+ }
853
+ }));
854
+ return { prePlugin, postPlugin };
855
+ }
856
+ var defaultInstance = createCsszyxPlugins();
857
+ var unplugin = defaultInstance.prePlugin;
858
+ var vitePlugin = (options = {}) => {
859
+ const { prePlugin, postPlugin } = createCsszyxPlugins(options);
860
+ return [prePlugin.vite(options), postPlugin.vite(options)];
861
+ };
862
+ var webpackPlugin = (options = {}) => {
863
+ const { prePlugin, postPlugin } = createCsszyxPlugins(options);
864
+ return {
865
+ /**
866
+ * Applies both pre and post plugins to the Webpack compiler.
867
+ * @param compiler - the Webpack compiler instance to apply plugins to
868
+ */
869
+ apply(compiler) {
870
+ prePlugin.webpack(options).apply(compiler);
871
+ postPlugin.webpack(options).apply(compiler);
872
+ }
873
+ };
874
+ };
875
+ var rollupPlugin = (options = {}) => {
876
+ const { prePlugin, postPlugin } = createCsszyxPlugins(options);
877
+ return [prePlugin.rollup(options), postPlugin.rollup(options)];
878
+ };
879
+ var esbuildPlugin = (options = {}) => {
880
+ const { prePlugin, postPlugin } = createCsszyxPlugins(options);
881
+ return {
882
+ name: "csszyx",
883
+ /**
884
+ * Registers both pre and post plugin setup hooks with the esbuild build.
885
+ * @param build - the esbuild plugin build context
886
+ */
887
+ setup(build) {
888
+ prePlugin.esbuild(options).setup(build);
889
+ postPlugin.esbuild(options).setup(build);
890
+ }
891
+ };
892
+ };
893
+ // Annotate the CommonJS export names for ESM import in node:
894
+ 0 && (module.exports = {
895
+ createPostCSSPlugin,
896
+ esbuildPlugin,
897
+ escapeCSSClassName,
898
+ mangleCSS,
899
+ mangleCSSSync,
900
+ rollupPlugin,
901
+ unescapeTailwindClass,
902
+ unplugin,
903
+ vitePlugin,
904
+ webpackPlugin
905
+ });