@csszyx/unplugin 0.1.3 → 0.3.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @csszyx/unplugin
2
2
 
3
- > Vite, Webpack, and esbuild integration for csszyx.
3
+ > Vite, Webpack, and esbuild integration for CSSzyx.
4
4
 
5
5
  Build-time plugin that transforms `sz` props into Tailwind classes, generates static CSS, mangles class names in production, and injects hydration scripts for SSR.
6
6
 
@@ -160,34 +160,8 @@ function createCsszyxPlugins(options = {}) {
160
160
  if (!result.transformed) {
161
161
  continue;
162
162
  }
163
- const classPattern = /class(?:Name)?=["']([^"']*)["']/g;
164
- let match;
165
- while ((match = classPattern.exec(result.code)) !== null) {
166
- for (const cls of match[1].split(/\s+/).filter(Boolean)) {
167
- discoveredClasses.add(cls);
168
- }
169
- }
170
- const exprPattern = /className=\{/g;
171
- while ((match = exprPattern.exec(result.code)) !== null) {
172
- let depth = 1;
173
- let i = match.index + match[0].length;
174
- while (i < result.code.length && depth > 0) {
175
- if (result.code[i] === "{") {
176
- depth++;
177
- } else if (result.code[i] === "}") {
178
- depth--;
179
- }
180
- i++;
181
- }
182
- const expr = result.code.slice(match.index + match[0].length, i - 1);
183
- const strPattern = /"([^"]+)"|'([^']+)'/g;
184
- let strMatch;
185
- while ((strMatch = strPattern.exec(expr)) !== null) {
186
- const str = strMatch[1] || strMatch[2];
187
- for (const cls of str.split(/\s+/).filter(Boolean)) {
188
- discoveredClasses.add(cls);
189
- }
190
- }
163
+ for (const cls of result.classes) {
164
+ discoveredClasses.add(cls);
191
165
  }
192
166
  if (result.usesRuntime) {
193
167
  const szCallRe = /_sz\(\s*\{/g;
@@ -260,12 +234,15 @@ function createCsszyxPlugins(options = {}) {
260
234
  }
261
235
  }
262
236
  function extractClasses(code) {
263
- const classPattern = /(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g;
237
+ const dqPattern = /(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g;
238
+ const sqPattern = /(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g;
264
239
  let match;
265
- while ((match = classPattern.exec(code)) !== null) {
266
- const classes = match[1].split(/\s+/).filter(Boolean);
267
- for (const cls of classes) {
268
- state.classes.add(cls);
240
+ for (const classPattern of [dqPattern, sqPattern]) {
241
+ while ((match = classPattern.exec(code)) !== null) {
242
+ const classes = match[1].split(/\s+/).filter(Boolean);
243
+ for (const cls of classes) {
244
+ state.classes.add(cls);
245
+ }
269
246
  }
270
247
  }
271
248
  const exprStart = /className=\{/g;
@@ -306,14 +283,24 @@ function createCsszyxPlugins(options = {}) {
306
283
  return classString.split(/\s+/).map((cls) => state.mangleMap[cls] || cls).join(" ");
307
284
  }
308
285
  function mangleCodeClasses(code) {
309
- let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g, (match, classes) => {
286
+ let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g, (match, classes) => {
287
+ const mangled = mangleClassString(classes);
288
+ if (mangled === classes) {
289
+ return match;
290
+ }
291
+ return match.replace(classes, mangled);
292
+ }).replace(/(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g, (match, classes) => {
310
293
  const mangled = mangleClassString(classes);
311
294
  if (mangled === classes) {
312
295
  return match;
313
296
  }
314
297
  return match.replace(classes, mangled);
315
298
  });
316
- result = result.replace(/className:([^,;}\])\n]+)/g, (fullMatch, expr) => {
299
+ result = result.replace(/className:(?!["'])([^,;}\])\n]+)/g, (fullMatch, expr) => {
300
+ const qIdx = expr.indexOf("?");
301
+ if (qIdx === -1 || !expr.slice(qIdx).includes(":")) {
302
+ return fullMatch;
303
+ }
317
304
  let changed = false;
318
305
  const mangled = expr.replace(/"([^"]*)"/g, (qm, inner) => {
319
306
  const parts = inner.split(/\s+/).filter(Boolean);
@@ -375,7 +362,8 @@ function createCsszyxPlugins(options = {}) {
375
362
  return null;
376
363
  },
377
364
  /**
378
- * Filters files for the pre-transform phase — only source files outside node_modules.
365
+ * Filters files for the pre-transform phase — source files plus CSS files.
366
+ * CSS files need special handling to inject @source inline() for Tailwind class discovery.
379
367
  * @param id - the file path to check for inclusion
380
368
  * @returns true if the file should be transformed, false otherwise
381
369
  */
@@ -383,19 +371,43 @@ function createCsszyxPlugins(options = {}) {
383
371
  if (id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static")) {
384
372
  return false;
385
373
  }
374
+ if (/\.css(\?.*)?$/.test(id)) {
375
+ return true;
376
+ }
386
377
  return /\.[tj]sx?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte");
387
378
  },
388
379
  /**
389
380
  * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
381
+ * For CSS files: injects @source inline() so Tailwind generates CSS for sz-derived classes.
390
382
  * @param code - the source code to transform
391
383
  * @param id - the file path of the module being transformed
392
384
  * @returns transformed code with source map, or null if no changes were made
393
385
  */
394
386
  transform(code, id) {
387
+ if (/\.css(\?.*)?$/.test(id)) {
388
+ const hasTailwindImport = code.includes('@import "tailwindcss') || code.includes("@import 'tailwindcss");
389
+ if (hasTailwindImport && state.classes.size > 0) {
390
+ const candidates = Array.from(state.classes).filter((c) => c.length >= 2 && /^[a-z]/.test(c)).join(" ");
391
+ if (candidates) {
392
+ const inlineDirective = `@source inline("${candidates}");
393
+ `;
394
+ const transformed2 = code.replace(
395
+ /(@import\s+["']tailwindcss[^"']*["'];)/,
396
+ `$1
397
+ ${inlineDirective}`
398
+ );
399
+ if (transformed2 !== code) {
400
+ return { code: transformed2, map: null };
401
+ }
402
+ }
403
+ }
404
+ return null;
405
+ }
395
406
  let transformedCode = code;
396
407
  let usesRuntime = false;
397
408
  let usesColorVar = false;
398
409
  let transformed = false;
410
+ let szClasses;
399
411
  const hasSzProp = code.includes("sz=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
400
412
  if (hasSzProp) {
401
413
  if (id.endsWith(".vue")) {
@@ -416,6 +428,7 @@ function createCsszyxPlugins(options = {}) {
416
428
  usesRuntime = result.usesRuntime;
417
429
  usesColorVar = result.usesColorVar;
418
430
  transformed = result.transformed;
431
+ szClasses = result.classes;
419
432
  }
420
433
  }
421
434
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -452,7 +465,13 @@ function createCsszyxPlugins(options = {}) {
452
465
  }
453
466
  }
454
467
  if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
455
- extractClasses(transformedCode);
468
+ if (szClasses !== void 0) {
469
+ for (const cls of szClasses) {
470
+ state.classes.add(cls);
471
+ }
472
+ } else {
473
+ extractClasses(transformedCode);
474
+ }
456
475
  return { code: transformedCode, map: null };
457
476
  }
458
477
  return null;
package/dist/index.cjs CHANGED
@@ -397,34 +397,8 @@ function createCsszyxPlugins(options = {}) {
397
397
  if (!result.transformed) {
398
398
  continue;
399
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
- }
400
+ for (const cls of result.classes) {
401
+ discoveredClasses.add(cls);
428
402
  }
429
403
  if (result.usesRuntime) {
430
404
  const szCallRe = /_sz\(\s*\{/g;
@@ -497,12 +471,15 @@ function createCsszyxPlugins(options = {}) {
497
471
  }
498
472
  }
499
473
  function extractClasses(code) {
500
- const classPattern = /(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g;
474
+ const dqPattern = /(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g;
475
+ const sqPattern = /(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g;
501
476
  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);
477
+ for (const classPattern of [dqPattern, sqPattern]) {
478
+ while ((match = classPattern.exec(code)) !== null) {
479
+ const classes = match[1].split(/\s+/).filter(Boolean);
480
+ for (const cls of classes) {
481
+ state.classes.add(cls);
482
+ }
506
483
  }
507
484
  }
508
485
  const exprStart = /className=\{/g;
@@ -543,14 +520,24 @@ function createCsszyxPlugins(options = {}) {
543
520
  return classString.split(/\s+/).map((cls) => state.mangleMap[cls] || cls).join(" ");
544
521
  }
545
522
  function mangleCodeClasses(code) {
546
- let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g, (match, classes) => {
523
+ let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g, (match, classes) => {
524
+ const mangled = mangleClassString(classes);
525
+ if (mangled === classes) {
526
+ return match;
527
+ }
528
+ return match.replace(classes, mangled);
529
+ }).replace(/(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g, (match, classes) => {
547
530
  const mangled = mangleClassString(classes);
548
531
  if (mangled === classes) {
549
532
  return match;
550
533
  }
551
534
  return match.replace(classes, mangled);
552
535
  });
553
- result = result.replace(/className:([^,;}\])\n]+)/g, (fullMatch, expr) => {
536
+ result = result.replace(/className:(?!["'])([^,;}\])\n]+)/g, (fullMatch, expr) => {
537
+ const qIdx = expr.indexOf("?");
538
+ if (qIdx === -1 || !expr.slice(qIdx).includes(":")) {
539
+ return fullMatch;
540
+ }
554
541
  let changed = false;
555
542
  const mangled = expr.replace(/"([^"]*)"/g, (qm, inner) => {
556
543
  const parts = inner.split(/\s+/).filter(Boolean);
@@ -612,7 +599,8 @@ function createCsszyxPlugins(options = {}) {
612
599
  return null;
613
600
  },
614
601
  /**
615
- * Filters files for the pre-transform phase — only source files outside node_modules.
602
+ * Filters files for the pre-transform phase — source files plus CSS files.
603
+ * CSS files need special handling to inject @source inline() for Tailwind class discovery.
616
604
  * @param id - the file path to check for inclusion
617
605
  * @returns true if the file should be transformed, false otherwise
618
606
  */
@@ -620,19 +608,43 @@ function createCsszyxPlugins(options = {}) {
620
608
  if (id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static")) {
621
609
  return false;
622
610
  }
611
+ if (/\.css(\?.*)?$/.test(id)) {
612
+ return true;
613
+ }
623
614
  return /\.[tj]sx?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte");
624
615
  },
625
616
  /**
626
617
  * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
618
+ * For CSS files: injects @source inline() so Tailwind generates CSS for sz-derived classes.
627
619
  * @param code - the source code to transform
628
620
  * @param id - the file path of the module being transformed
629
621
  * @returns transformed code with source map, or null if no changes were made
630
622
  */
631
623
  transform(code, id) {
624
+ if (/\.css(\?.*)?$/.test(id)) {
625
+ const hasTailwindImport = code.includes('@import "tailwindcss') || code.includes("@import 'tailwindcss");
626
+ if (hasTailwindImport && state.classes.size > 0) {
627
+ const candidates = Array.from(state.classes).filter((c) => c.length >= 2 && /^[a-z]/.test(c)).join(" ");
628
+ if (candidates) {
629
+ const inlineDirective = `@source inline("${candidates}");
630
+ `;
631
+ const transformed2 = code.replace(
632
+ /(@import\s+["']tailwindcss[^"']*["'];)/,
633
+ `$1
634
+ ${inlineDirective}`
635
+ );
636
+ if (transformed2 !== code) {
637
+ return { code: transformed2, map: null };
638
+ }
639
+ }
640
+ }
641
+ return null;
642
+ }
632
643
  let transformedCode = code;
633
644
  let usesRuntime = false;
634
645
  let usesColorVar = false;
635
646
  let transformed = false;
647
+ let szClasses;
636
648
  const hasSzProp = code.includes("sz=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
637
649
  if (hasSzProp) {
638
650
  if (id.endsWith(".vue")) {
@@ -653,6 +665,7 @@ function createCsszyxPlugins(options = {}) {
653
665
  usesRuntime = result.usesRuntime;
654
666
  usesColorVar = result.usesColorVar;
655
667
  transformed = result.transformed;
668
+ szClasses = result.classes;
656
669
  }
657
670
  }
658
671
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -689,7 +702,13 @@ function createCsszyxPlugins(options = {}) {
689
702
  }
690
703
  }
691
704
  if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
692
- extractClasses(transformedCode);
705
+ if (szClasses !== void 0) {
706
+ for (const cls of szClasses) {
707
+ state.classes.add(cls);
708
+ }
709
+ } else {
710
+ extractClasses(transformedCode);
711
+ }
693
712
  return { code: transformedCode, map: null };
694
713
  }
695
714
  return null;
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  unplugin,
5
5
  vitePlugin,
6
6
  webpackPlugin
7
- } from "./chunk-JKM7IRGZ.js";
7
+ } from "./chunk-3J4XUYF5.js";
8
8
  import {
9
9
  createPostCSSPlugin,
10
10
  escapeCSSClassName,
package/dist/vite.cjs CHANGED
@@ -288,34 +288,8 @@ function createCsszyxPlugins(options = {}) {
288
288
  if (!result.transformed) {
289
289
  continue;
290
290
  }
291
- const classPattern = /class(?:Name)?=["']([^"']*)["']/g;
292
- let match;
293
- while ((match = classPattern.exec(result.code)) !== null) {
294
- for (const cls of match[1].split(/\s+/).filter(Boolean)) {
295
- discoveredClasses.add(cls);
296
- }
297
- }
298
- const exprPattern = /className=\{/g;
299
- while ((match = exprPattern.exec(result.code)) !== null) {
300
- let depth = 1;
301
- let i = match.index + match[0].length;
302
- while (i < result.code.length && depth > 0) {
303
- if (result.code[i] === "{") {
304
- depth++;
305
- } else if (result.code[i] === "}") {
306
- depth--;
307
- }
308
- i++;
309
- }
310
- const expr = result.code.slice(match.index + match[0].length, i - 1);
311
- const strPattern = /"([^"]+)"|'([^']+)'/g;
312
- let strMatch;
313
- while ((strMatch = strPattern.exec(expr)) !== null) {
314
- const str = strMatch[1] || strMatch[2];
315
- for (const cls of str.split(/\s+/).filter(Boolean)) {
316
- discoveredClasses.add(cls);
317
- }
318
- }
291
+ for (const cls of result.classes) {
292
+ discoveredClasses.add(cls);
319
293
  }
320
294
  if (result.usesRuntime) {
321
295
  const szCallRe = /_sz\(\s*\{/g;
@@ -388,12 +362,15 @@ function createCsszyxPlugins(options = {}) {
388
362
  }
389
363
  }
390
364
  function extractClasses(code) {
391
- const classPattern = /(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g;
365
+ const dqPattern = /(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g;
366
+ const sqPattern = /(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g;
392
367
  let match;
393
- while ((match = classPattern.exec(code)) !== null) {
394
- const classes = match[1].split(/\s+/).filter(Boolean);
395
- for (const cls of classes) {
396
- state.classes.add(cls);
368
+ for (const classPattern of [dqPattern, sqPattern]) {
369
+ while ((match = classPattern.exec(code)) !== null) {
370
+ const classes = match[1].split(/\s+/).filter(Boolean);
371
+ for (const cls of classes) {
372
+ state.classes.add(cls);
373
+ }
397
374
  }
398
375
  }
399
376
  const exprStart = /className=\{/g;
@@ -434,14 +411,24 @@ function createCsszyxPlugins(options = {}) {
434
411
  return classString.split(/\s+/).map((cls) => state.mangleMap[cls] || cls).join(" ");
435
412
  }
436
413
  function mangleCodeClasses(code) {
437
- let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g, (match, classes) => {
414
+ let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g, (match, classes) => {
415
+ const mangled = mangleClassString(classes);
416
+ if (mangled === classes) {
417
+ return match;
418
+ }
419
+ return match.replace(classes, mangled);
420
+ }).replace(/(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g, (match, classes) => {
438
421
  const mangled = mangleClassString(classes);
439
422
  if (mangled === classes) {
440
423
  return match;
441
424
  }
442
425
  return match.replace(classes, mangled);
443
426
  });
444
- result = result.replace(/className:([^,;}\])\n]+)/g, (fullMatch, expr) => {
427
+ result = result.replace(/className:(?!["'])([^,;}\])\n]+)/g, (fullMatch, expr) => {
428
+ const qIdx = expr.indexOf("?");
429
+ if (qIdx === -1 || !expr.slice(qIdx).includes(":")) {
430
+ return fullMatch;
431
+ }
445
432
  let changed = false;
446
433
  const mangled = expr.replace(/"([^"]*)"/g, (qm, inner) => {
447
434
  const parts = inner.split(/\s+/).filter(Boolean);
@@ -503,7 +490,8 @@ function createCsszyxPlugins(options = {}) {
503
490
  return null;
504
491
  },
505
492
  /**
506
- * Filters files for the pre-transform phase — only source files outside node_modules.
493
+ * Filters files for the pre-transform phase — source files plus CSS files.
494
+ * CSS files need special handling to inject @source inline() for Tailwind class discovery.
507
495
  * @param id - the file path to check for inclusion
508
496
  * @returns true if the file should be transformed, false otherwise
509
497
  */
@@ -511,19 +499,43 @@ function createCsszyxPlugins(options = {}) {
511
499
  if (id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static")) {
512
500
  return false;
513
501
  }
502
+ if (/\.css(\?.*)?$/.test(id)) {
503
+ return true;
504
+ }
514
505
  return /\.[tj]sx?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte");
515
506
  },
516
507
  /**
517
508
  * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
509
+ * For CSS files: injects @source inline() so Tailwind generates CSS for sz-derived classes.
518
510
  * @param code - the source code to transform
519
511
  * @param id - the file path of the module being transformed
520
512
  * @returns transformed code with source map, or null if no changes were made
521
513
  */
522
514
  transform(code, id) {
515
+ if (/\.css(\?.*)?$/.test(id)) {
516
+ const hasTailwindImport = code.includes('@import "tailwindcss') || code.includes("@import 'tailwindcss");
517
+ if (hasTailwindImport && state.classes.size > 0) {
518
+ const candidates = Array.from(state.classes).filter((c) => c.length >= 2 && /^[a-z]/.test(c)).join(" ");
519
+ if (candidates) {
520
+ const inlineDirective = `@source inline("${candidates}");
521
+ `;
522
+ const transformed2 = code.replace(
523
+ /(@import\s+["']tailwindcss[^"']*["'];)/,
524
+ `$1
525
+ ${inlineDirective}`
526
+ );
527
+ if (transformed2 !== code) {
528
+ return { code: transformed2, map: null };
529
+ }
530
+ }
531
+ }
532
+ return null;
533
+ }
523
534
  let transformedCode = code;
524
535
  let usesRuntime = false;
525
536
  let usesColorVar = false;
526
537
  let transformed = false;
538
+ let szClasses;
527
539
  const hasSzProp = code.includes("sz=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
528
540
  if (hasSzProp) {
529
541
  if (id.endsWith(".vue")) {
@@ -544,6 +556,7 @@ function createCsszyxPlugins(options = {}) {
544
556
  usesRuntime = result.usesRuntime;
545
557
  usesColorVar = result.usesColorVar;
546
558
  transformed = result.transformed;
559
+ szClasses = result.classes;
547
560
  }
548
561
  }
549
562
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -580,7 +593,13 @@ function createCsszyxPlugins(options = {}) {
580
593
  }
581
594
  }
582
595
  if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
583
- extractClasses(transformedCode);
596
+ if (szClasses !== void 0) {
597
+ for (const cls of szClasses) {
598
+ state.classes.add(cls);
599
+ }
600
+ } else {
601
+ extractClasses(transformedCode);
602
+ }
584
603
  return { code: transformedCode, map: null };
585
604
  }
586
605
  return null;
package/dist/vite.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  vitePlugin
3
- } from "./chunk-JKM7IRGZ.js";
3
+ } from "./chunk-3J4XUYF5.js";
4
4
  import "./chunk-4M7CPGP7.js";
5
5
 
6
6
  // src/vite.ts
package/dist/webpack.cjs CHANGED
@@ -288,34 +288,8 @@ function createCsszyxPlugins(options = {}) {
288
288
  if (!result.transformed) {
289
289
  continue;
290
290
  }
291
- const classPattern = /class(?:Name)?=["']([^"']*)["']/g;
292
- let match;
293
- while ((match = classPattern.exec(result.code)) !== null) {
294
- for (const cls of match[1].split(/\s+/).filter(Boolean)) {
295
- discoveredClasses.add(cls);
296
- }
297
- }
298
- const exprPattern = /className=\{/g;
299
- while ((match = exprPattern.exec(result.code)) !== null) {
300
- let depth = 1;
301
- let i = match.index + match[0].length;
302
- while (i < result.code.length && depth > 0) {
303
- if (result.code[i] === "{") {
304
- depth++;
305
- } else if (result.code[i] === "}") {
306
- depth--;
307
- }
308
- i++;
309
- }
310
- const expr = result.code.slice(match.index + match[0].length, i - 1);
311
- const strPattern = /"([^"]+)"|'([^']+)'/g;
312
- let strMatch;
313
- while ((strMatch = strPattern.exec(expr)) !== null) {
314
- const str = strMatch[1] || strMatch[2];
315
- for (const cls of str.split(/\s+/).filter(Boolean)) {
316
- discoveredClasses.add(cls);
317
- }
318
- }
291
+ for (const cls of result.classes) {
292
+ discoveredClasses.add(cls);
319
293
  }
320
294
  if (result.usesRuntime) {
321
295
  const szCallRe = /_sz\(\s*\{/g;
@@ -388,12 +362,15 @@ function createCsszyxPlugins(options = {}) {
388
362
  }
389
363
  }
390
364
  function extractClasses(code) {
391
- const classPattern = /(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g;
365
+ const dqPattern = /(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g;
366
+ const sqPattern = /(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g;
392
367
  let match;
393
- while ((match = classPattern.exec(code)) !== null) {
394
- const classes = match[1].split(/\s+/).filter(Boolean);
395
- for (const cls of classes) {
396
- state.classes.add(cls);
368
+ for (const classPattern of [dqPattern, sqPattern]) {
369
+ while ((match = classPattern.exec(code)) !== null) {
370
+ const classes = match[1].split(/\s+/).filter(Boolean);
371
+ for (const cls of classes) {
372
+ state.classes.add(cls);
373
+ }
397
374
  }
398
375
  }
399
376
  const exprStart = /className=\{/g;
@@ -434,14 +411,24 @@ function createCsszyxPlugins(options = {}) {
434
411
  return classString.split(/\s+/).map((cls) => state.mangleMap[cls] || cls).join(" ");
435
412
  }
436
413
  function mangleCodeClasses(code) {
437
- let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*["']([^"']*)["']/g, (match, classes) => {
414
+ let result = code.replace(/(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g, (match, classes) => {
415
+ const mangled = mangleClassString(classes);
416
+ if (mangled === classes) {
417
+ return match;
418
+ }
419
+ return match.replace(classes, mangled);
420
+ }).replace(/(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g, (match, classes) => {
438
421
  const mangled = mangleClassString(classes);
439
422
  if (mangled === classes) {
440
423
  return match;
441
424
  }
442
425
  return match.replace(classes, mangled);
443
426
  });
444
- result = result.replace(/className:([^,;}\])\n]+)/g, (fullMatch, expr) => {
427
+ result = result.replace(/className:(?!["'])([^,;}\])\n]+)/g, (fullMatch, expr) => {
428
+ const qIdx = expr.indexOf("?");
429
+ if (qIdx === -1 || !expr.slice(qIdx).includes(":")) {
430
+ return fullMatch;
431
+ }
445
432
  let changed = false;
446
433
  const mangled = expr.replace(/"([^"]*)"/g, (qm, inner) => {
447
434
  const parts = inner.split(/\s+/).filter(Boolean);
@@ -503,7 +490,8 @@ function createCsszyxPlugins(options = {}) {
503
490
  return null;
504
491
  },
505
492
  /**
506
- * Filters files for the pre-transform phase — only source files outside node_modules.
493
+ * Filters files for the pre-transform phase — source files plus CSS files.
494
+ * CSS files need special handling to inject @source inline() for Tailwind class discovery.
507
495
  * @param id - the file path to check for inclusion
508
496
  * @returns true if the file should be transformed, false otherwise
509
497
  */
@@ -511,19 +499,43 @@ function createCsszyxPlugins(options = {}) {
511
499
  if (id.includes("node_modules") || id.includes("/packages/") || id.includes(".next") && !id.includes("static")) {
512
500
  return false;
513
501
  }
502
+ if (/\.css(\?.*)?$/.test(id)) {
503
+ return true;
504
+ }
514
505
  return /\.[tj]sx?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte");
515
506
  },
516
507
  /**
517
508
  * Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
509
+ * For CSS files: injects @source inline() so Tailwind generates CSS for sz-derived classes.
518
510
  * @param code - the source code to transform
519
511
  * @param id - the file path of the module being transformed
520
512
  * @returns transformed code with source map, or null if no changes were made
521
513
  */
522
514
  transform(code, id) {
515
+ if (/\.css(\?.*)?$/.test(id)) {
516
+ const hasTailwindImport = code.includes('@import "tailwindcss') || code.includes("@import 'tailwindcss");
517
+ if (hasTailwindImport && state.classes.size > 0) {
518
+ const candidates = Array.from(state.classes).filter((c) => c.length >= 2 && /^[a-z]/.test(c)).join(" ");
519
+ if (candidates) {
520
+ const inlineDirective = `@source inline("${candidates}");
521
+ `;
522
+ const transformed2 = code.replace(
523
+ /(@import\s+["']tailwindcss[^"']*["'];)/,
524
+ `$1
525
+ ${inlineDirective}`
526
+ );
527
+ if (transformed2 !== code) {
528
+ return { code: transformed2, map: null };
529
+ }
530
+ }
531
+ }
532
+ return null;
533
+ }
523
534
  let transformedCode = code;
524
535
  let usesRuntime = false;
525
536
  let usesColorVar = false;
526
537
  let transformed = false;
538
+ let szClasses;
527
539
  const hasSzProp = code.includes("sz=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
528
540
  if (hasSzProp) {
529
541
  if (id.endsWith(".vue")) {
@@ -544,6 +556,7 @@ function createCsszyxPlugins(options = {}) {
544
556
  usesRuntime = result.usesRuntime;
545
557
  usesColorVar = result.usesColorVar;
546
558
  transformed = result.transformed;
559
+ szClasses = result.classes;
547
560
  }
548
561
  }
549
562
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -580,7 +593,13 @@ function createCsszyxPlugins(options = {}) {
580
593
  }
581
594
  }
582
595
  if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
583
- extractClasses(transformedCode);
596
+ if (szClasses !== void 0) {
597
+ for (const cls of szClasses) {
598
+ state.classes.add(cls);
599
+ }
600
+ } else {
601
+ extractClasses(transformedCode);
602
+ }
584
603
  return { code: transformedCode, map: null };
585
604
  }
586
605
  return null;
package/dist/webpack.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  webpackPlugin
3
- } from "./chunk-JKM7IRGZ.js";
3
+ } from "./chunk-3J4XUYF5.js";
4
4
  import "./chunk-4M7CPGP7.js";
5
5
 
6
6
  // src/webpack.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csszyx/unplugin",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "Vite and Webpack integration for csszyx",
5
5
  "keywords": [
6
6
  "csszyx",
@@ -55,11 +55,11 @@
55
55
  "postcss": "^8.4.35",
56
56
  "postcss-selector-parser": "^6.0.15",
57
57
  "unplugin": "^1.10.1",
58
- "@csszyx/compiler": "0.1.3",
59
- "@csszyx/core": "0.1.3",
60
- "@csszyx/svelte-adapter": "0.0.0",
61
- "@csszyx/types": "0.1.3",
62
- "@csszyx/vue-adapter": "0.0.0"
58
+ "@csszyx/compiler": "0.3.0",
59
+ "@csszyx/core": "0.3.0",
60
+ "@csszyx/svelte-adapter": "0.0.1",
61
+ "@csszyx/types": "0.3.0",
62
+ "@csszyx/vue-adapter": "0.0.1"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/node": "^20.11.0",