@csszyx/unplugin 0.9.10 → 0.10.1
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 +16 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +2 -1
- package/dist/next-prebuild.cjs +2 -1
- package/dist/next-prebuild.mjs +2 -1
- package/dist/next-turbo-loader.cjs +2 -1
- package/dist/next-turbo-loader.mjs +2 -1
- package/dist/next-watcher.cjs +2 -1
- package/dist/next-watcher.mjs +2 -1
- package/dist/shared/unplugin.3UumZ5gn.mjs +5 -0
- package/dist/shared/{unplugin.CMNZChGZ.d.cts → unplugin.BqLCtc84.d.cts} +164 -2
- package/dist/shared/{unplugin.CMNZChGZ.d.mts → unplugin.BqLCtc84.d.mts} +164 -2
- package/dist/shared/{unplugin.jEasXLFM.mjs → unplugin.CLXpKBe4.mjs} +280 -54
- package/dist/shared/{unplugin.VAel6lI0.mjs → unplugin.CLjhn81z.mjs} +1 -3
- package/dist/shared/{unplugin.Bo6Kx-T6.cjs → unplugin.Cwe-dz1f.cjs} +2 -4
- package/dist/shared/{unplugin.BT-U5kd1.cjs → unplugin.Dk6ddrZX.cjs} +295 -55
- package/dist/shared/unplugin.DoBHTRra.cjs +7 -0
- package/dist/vite.cjs +2 -1
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +2 -1
- package/dist/webpack.cjs +2 -1
- package/dist/webpack.d.cts +1 -1
- package/dist/webpack.d.mts +1 -1
- package/dist/webpack.mjs +2 -1
- package/package.json +7 -7
|
@@ -13,6 +13,7 @@ import { isTailwindReservedCustomProperty, CSSZYX_GLOBAL_ALIAS_PREFIX, isCsszyxG
|
|
|
13
13
|
import { preprocess } from '@csszyx/vue-adapter';
|
|
14
14
|
import { createUnplugin } from 'unplugin';
|
|
15
15
|
import { mangleCSSSync } from '../css-mangler.mjs';
|
|
16
|
+
import { e as escapeHtmlAttribute } from './unplugin.3UumZ5gn.mjs';
|
|
16
17
|
import { createHash } from 'node:crypto';
|
|
17
18
|
import { r as resolveTransformCacheDir, c as createTransformCacheKey, a as readTransformCache, w as writeTransformCache, e as evictOldTransformCacheEntries } from './unplugin.BpWUtI9U.mjs';
|
|
18
19
|
import postcss from 'postcss';
|
|
@@ -454,15 +455,7 @@ const CLIENT_RUNTIME_MODULES = /* @__PURE__ */ new Set(["csszyx/browser"]);
|
|
|
454
455
|
const CLIENT_RUNTIME_MODULE_ROOTS = ["@csszyx/dynamic", "csszyx/dynamic"];
|
|
455
456
|
const normalizedModuleIdCache = /* @__PURE__ */ new Map();
|
|
456
457
|
const resolvedLocalModuleCache = /* @__PURE__ */ new Map();
|
|
457
|
-
const FORBIDDEN_SYMBOLS = /* @__PURE__ */ new Set([
|
|
458
|
-
"_sz",
|
|
459
|
-
"_sz2",
|
|
460
|
-
"_sz3",
|
|
461
|
-
"_szIf",
|
|
462
|
-
"_szMerge",
|
|
463
|
-
"_szSwitch",
|
|
464
|
-
"__csszyx_runtime__"
|
|
465
|
-
]);
|
|
458
|
+
const FORBIDDEN_SYMBOLS = /* @__PURE__ */ new Set(["_sz", "_sz2", "_sz3", "_szMerge", "__csszyx_runtime__"]);
|
|
466
459
|
function hasUseServerDirective(code) {
|
|
467
460
|
for (const statement of readDirectivePrologue(code)) {
|
|
468
461
|
if (SERVER_DIRECTIVE_RE.test(statement)) {
|
|
@@ -841,7 +834,10 @@ function resolveLocalModule(importer, source) {
|
|
|
841
834
|
const cacheKey = `${importer}\0${source}`;
|
|
842
835
|
const cached = resolvedLocalModuleCache.get(cacheKey);
|
|
843
836
|
if (cached) {
|
|
844
|
-
|
|
837
|
+
if (fs.existsSync(cached)) {
|
|
838
|
+
return cached;
|
|
839
|
+
}
|
|
840
|
+
resolvedLocalModuleCache.delete(cacheKey);
|
|
845
841
|
}
|
|
846
842
|
const base = source.startsWith("/") ? source : path.resolve(path.dirname(importer), source);
|
|
847
843
|
const candidates = [
|
|
@@ -1006,7 +1002,14 @@ function stripCommentsForImportScan(code) {
|
|
|
1006
1002
|
return out;
|
|
1007
1003
|
}
|
|
1008
1004
|
|
|
1009
|
-
const EMPTY_THEME = {
|
|
1005
|
+
const EMPTY_THEME = {
|
|
1006
|
+
colors: [],
|
|
1007
|
+
spacings: [],
|
|
1008
|
+
fonts: [],
|
|
1009
|
+
radii: [],
|
|
1010
|
+
shadows: [],
|
|
1011
|
+
breakpoints: []
|
|
1012
|
+
};
|
|
1010
1013
|
function stripLayerWrappers(css) {
|
|
1011
1014
|
let result = "";
|
|
1012
1015
|
let i = 0;
|
|
@@ -1074,12 +1077,15 @@ function categorizeProperty(prop) {
|
|
|
1074
1077
|
["spacing-", "spacings"],
|
|
1075
1078
|
["font-", "fonts"],
|
|
1076
1079
|
["radius-", "radii"],
|
|
1077
|
-
["shadow-", "shadows"]
|
|
1080
|
+
["shadow-", "shadows"],
|
|
1081
|
+
["breakpoint-", "breakpoints"]
|
|
1078
1082
|
];
|
|
1079
1083
|
for (const [prefix, category] of categoryMap) {
|
|
1080
1084
|
if (prop.startsWith(prefix)) {
|
|
1081
1085
|
let token = prop.slice(prefix.length);
|
|
1082
|
-
|
|
1086
|
+
if (category !== "breakpoints") {
|
|
1087
|
+
token = token.replace(/-\d+$/, "");
|
|
1088
|
+
}
|
|
1083
1089
|
if (token) {
|
|
1084
1090
|
return { category, token };
|
|
1085
1091
|
}
|
|
@@ -1093,7 +1099,8 @@ function parseThemeBlocks(cssContent) {
|
|
|
1093
1099
|
spacings: /* @__PURE__ */ new Set(),
|
|
1094
1100
|
fonts: /* @__PURE__ */ new Set(),
|
|
1095
1101
|
radii: /* @__PURE__ */ new Set(),
|
|
1096
|
-
shadows: /* @__PURE__ */ new Set()
|
|
1102
|
+
shadows: /* @__PURE__ */ new Set(),
|
|
1103
|
+
breakpoints: /* @__PURE__ */ new Set()
|
|
1097
1104
|
};
|
|
1098
1105
|
const stripped = stripLayerWrappers(cssContent);
|
|
1099
1106
|
const blocks = extractThemeBlocks(stripped);
|
|
@@ -1111,7 +1118,8 @@ function parseThemeBlocks(cssContent) {
|
|
|
1111
1118
|
spacings: [...result.spacings].sort(),
|
|
1112
1119
|
fonts: [...result.fonts].sort(),
|
|
1113
1120
|
radii: [...result.radii].sort(),
|
|
1114
|
-
shadows: [...result.shadows].sort()
|
|
1121
|
+
shadows: [...result.shadows].sort(),
|
|
1122
|
+
breakpoints: [...result.breakpoints].sort()
|
|
1115
1123
|
};
|
|
1116
1124
|
}
|
|
1117
1125
|
function mergeThemes(themes) {
|
|
@@ -1123,7 +1131,8 @@ function mergeThemes(themes) {
|
|
|
1123
1131
|
spacings: /* @__PURE__ */ new Set(),
|
|
1124
1132
|
fonts: /* @__PURE__ */ new Set(),
|
|
1125
1133
|
radii: /* @__PURE__ */ new Set(),
|
|
1126
|
-
shadows: /* @__PURE__ */ new Set()
|
|
1134
|
+
shadows: /* @__PURE__ */ new Set(),
|
|
1135
|
+
breakpoints: /* @__PURE__ */ new Set()
|
|
1127
1136
|
};
|
|
1128
1137
|
for (const theme of themes) {
|
|
1129
1138
|
for (const cat of Object.keys(merged)) {
|
|
@@ -1137,7 +1146,8 @@ function mergeThemes(themes) {
|
|
|
1137
1146
|
spacings: [...merged.spacings].sort(),
|
|
1138
1147
|
fonts: [...merged.fonts].sort(),
|
|
1139
1148
|
radii: [...merged.radii].sort(),
|
|
1140
|
-
shadows: [...merged.shadows].sort()
|
|
1149
|
+
shadows: [...merged.shadows].sort(),
|
|
1150
|
+
breakpoints: [...merged.breakpoints].sort()
|
|
1141
1151
|
};
|
|
1142
1152
|
}
|
|
1143
1153
|
function hasTokens(theme) {
|
|
@@ -1425,11 +1435,15 @@ function isSameFileVersion(before, after) {
|
|
|
1425
1435
|
return before.dev === after.dev && before.ino === after.ino && before.size === after.size && before.mtimeNs === after.mtimeNs && before.ctimeNs === after.ctimeNs;
|
|
1426
1436
|
}
|
|
1427
1437
|
|
|
1438
|
+
function escapeTsString(value) {
|
|
1439
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
1440
|
+
}
|
|
1428
1441
|
function generateThemeDts(opts) {
|
|
1429
1442
|
const { theme, sourceFiles } = opts;
|
|
1430
1443
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1431
|
-
const sources = sourceFiles.join(", ");
|
|
1432
|
-
const toUnion = (tokens) => tokens.map((t) => `'${t}'`).join(" | ");
|
|
1444
|
+
const sources = sourceFiles.join(", ").replace(/[\r\n]/g, " ");
|
|
1445
|
+
const toUnion = (tokens) => tokens.map((t) => `'${escapeTsString(t)}'`).join(" | ");
|
|
1446
|
+
const quoteKey = (key) => /^[a-z_$][\w$]*$/i.test(key) ? key : `'${escapeTsString(key)}'`;
|
|
1433
1447
|
const entries = [];
|
|
1434
1448
|
if (theme.colors.length > 0) {
|
|
1435
1449
|
entries.push(` colors: ${toUnion(theme.colors)};`);
|
|
@@ -1446,19 +1460,36 @@ function generateThemeDts(opts) {
|
|
|
1446
1460
|
if (theme.shadows.length > 0) {
|
|
1447
1461
|
entries.push(` shadows: ${toUnion(theme.shadows)};`);
|
|
1448
1462
|
}
|
|
1449
|
-
|
|
1450
|
-
"// Auto-generated by csszyx theme-scanner \u2014 DO NOT EDIT",
|
|
1451
|
-
`// Source: ${sources}`,
|
|
1452
|
-
`// Updated: ${timestamp}`,
|
|
1453
|
-
"",
|
|
1454
|
-
"declare module '@csszyx/compiler' {",
|
|
1463
|
+
const moduleBody = [
|
|
1455
1464
|
" /**",
|
|
1456
1465
|
" * Custom design tokens extracted from @theme blocks.",
|
|
1457
1466
|
" * These tokens are surfaced in sz prop IntelliSense.",
|
|
1458
1467
|
" */",
|
|
1459
1468
|
" interface CustomTheme {",
|
|
1460
1469
|
...entries,
|
|
1461
|
-
" }"
|
|
1470
|
+
" }"
|
|
1471
|
+
];
|
|
1472
|
+
if (theme.breakpoints.length > 0) {
|
|
1473
|
+
const variantEntries = theme.breakpoints.map(
|
|
1474
|
+
(bp) => ` ${quoteKey(bp)}?: SzPropsBase;`
|
|
1475
|
+
);
|
|
1476
|
+
moduleBody.push(
|
|
1477
|
+
" /**",
|
|
1478
|
+
" * Custom responsive breakpoints from @theme (--breakpoint-*),",
|
|
1479
|
+
" * surfaced as typed sz variant keys.",
|
|
1480
|
+
" */",
|
|
1481
|
+
" interface VariantModifiers {",
|
|
1482
|
+
...variantEntries,
|
|
1483
|
+
" }"
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
return [
|
|
1487
|
+
"// Auto-generated by csszyx theme-scanner \u2014 DO NOT EDIT",
|
|
1488
|
+
`// Source: ${sources}`,
|
|
1489
|
+
`// Updated: ${timestamp}`,
|
|
1490
|
+
"",
|
|
1491
|
+
"declare module '@csszyx/compiler' {",
|
|
1492
|
+
...moduleBody,
|
|
1462
1493
|
"}",
|
|
1463
1494
|
"",
|
|
1464
1495
|
"export {};",
|
|
@@ -1532,6 +1563,7 @@ const UNKNOWN_PACKAGE_VERSION = "0.0.0";
|
|
|
1532
1563
|
const TRANSFORM_CACHE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1533
1564
|
const TRANSFORM_CACHE_MAX_ENTRIES = 1e4;
|
|
1534
1565
|
const TRANSFORM_MEMORY_CACHE_MAX_ENTRIES = 1e3;
|
|
1566
|
+
const MAX_SAFELIST_CLASSES = 1e5;
|
|
1535
1567
|
const DEFAULT_VAR_MANGLE_MAP_MAX_BYTES = 100 * 1024;
|
|
1536
1568
|
const GLOBAL_VAR_ALIAS_MAP_OWNER = "\0csszyx:global-var-aliases";
|
|
1537
1569
|
const DIRECTIVE_PROLOGUE_PREFIX_RE = /^((?:\s|\/\/[^\n]*\n|\/\*(?:[^*]|\*(?!\/))*\*\/)*)(['"]use (?:client|server)['"];?\s*)/;
|
|
@@ -1572,6 +1604,133 @@ function resolveNativeCacheIdentity() {
|
|
|
1572
1604
|
}
|
|
1573
1605
|
const BENCH_TRACE_ENABLED = process.env.CSSZYX_BENCH_TRACE === "1";
|
|
1574
1606
|
const BENCH_TRACE_FILE = process.env.CSSZYX_BENCH_TRACE_FILE;
|
|
1607
|
+
function appendTailwindSourceDirective(code, relPath) {
|
|
1608
|
+
const directive = `@source "${relPath}";`;
|
|
1609
|
+
if (code.includes(directive)) {
|
|
1610
|
+
return null;
|
|
1611
|
+
}
|
|
1612
|
+
const separator = code.length === 0 || code.endsWith("\n") ? "" : "\n";
|
|
1613
|
+
return `${code}${separator}${directive}
|
|
1614
|
+
`;
|
|
1615
|
+
}
|
|
1616
|
+
function stripCssBlockComments(code) {
|
|
1617
|
+
const SLASH = 47;
|
|
1618
|
+
const STAR = 42;
|
|
1619
|
+
let out = "";
|
|
1620
|
+
let last = 0;
|
|
1621
|
+
let i = 0;
|
|
1622
|
+
const n = code.length;
|
|
1623
|
+
while (i < n) {
|
|
1624
|
+
if (code.charCodeAt(i) === SLASH && code.charCodeAt(i + 1) === STAR) {
|
|
1625
|
+
out += code.slice(last, i);
|
|
1626
|
+
i += 2;
|
|
1627
|
+
while (i < n && !(code.charCodeAt(i) === STAR && code.charCodeAt(i + 1) === SLASH)) {
|
|
1628
|
+
i++;
|
|
1629
|
+
}
|
|
1630
|
+
i += 2;
|
|
1631
|
+
last = i;
|
|
1632
|
+
} else {
|
|
1633
|
+
i++;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
return out + code.slice(last);
|
|
1637
|
+
}
|
|
1638
|
+
function cssImportsTailwind(code) {
|
|
1639
|
+
const withoutBlockComments = stripCssBlockComments(code);
|
|
1640
|
+
return /@import\s+["']tailwindcss(?:\/[^"']*)?["']/.test(withoutBlockComments);
|
|
1641
|
+
}
|
|
1642
|
+
function hasInjectableTailwindCandidate(classes) {
|
|
1643
|
+
for (const c of classes) {
|
|
1644
|
+
if (c.length >= 2 && /^[a-z]/.test(c)) {
|
|
1645
|
+
return true;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
return false;
|
|
1649
|
+
}
|
|
1650
|
+
function shouldWarnMissingTailwindEntry(ownedClassCount, sawTailwindEntry) {
|
|
1651
|
+
return ownedClassCount > 0 && !sawTailwindEntry;
|
|
1652
|
+
}
|
|
1653
|
+
function missingTailwindEntryMessage(ownedClassCount) {
|
|
1654
|
+
return `[csszyx] generated ${ownedClassCount} sz class(es) but found no CSS entry importing "tailwindcss" \u2014 those classes will produce no CSS. Import "tailwindcss" in a CSS file (csszyx auto-injects @source for the generated classes) so Tailwind emits their styles.`;
|
|
1655
|
+
}
|
|
1656
|
+
function cssHasContentScope(code) {
|
|
1657
|
+
const s = stripCssBlockComments(code);
|
|
1658
|
+
return /@import\s+["']tailwindcss(?:\/[^"']*)?["']\s+source\(/.test(s) || /@source\s+not\b/.test(s);
|
|
1659
|
+
}
|
|
1660
|
+
function isMonorepoPackage(root) {
|
|
1661
|
+
let dir = path.dirname(path.resolve(root));
|
|
1662
|
+
const { root: fsRoot } = path.parse(dir);
|
|
1663
|
+
while (dir !== fsRoot) {
|
|
1664
|
+
if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml")) || fs.existsSync(path.join(dir, "nx.json")) || fs.existsSync(path.join(dir, "lerna.json"))) {
|
|
1665
|
+
return true;
|
|
1666
|
+
}
|
|
1667
|
+
const pkgPath = path.join(dir, "package.json");
|
|
1668
|
+
if (fs.existsSync(pkgPath)) {
|
|
1669
|
+
try {
|
|
1670
|
+
if ("workspaces" in JSON.parse(fs.readFileSync(pkgPath, "utf8"))) {
|
|
1671
|
+
return true;
|
|
1672
|
+
}
|
|
1673
|
+
} catch {
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
dir = path.dirname(dir);
|
|
1677
|
+
}
|
|
1678
|
+
return false;
|
|
1679
|
+
}
|
|
1680
|
+
function shouldWarnUnscopedMonorepo(sawTailwindEntry, tailwindEntryScoped, inMonorepo) {
|
|
1681
|
+
return sawTailwindEntry && !tailwindEntryScoped && inMonorepo;
|
|
1682
|
+
}
|
|
1683
|
+
function unscopedMonorepoMessage() {
|
|
1684
|
+
return '[csszyx] Tailwind content detection is UNSCOPED in a monorepo. Tailwind v4 climbs to the workspace root and scans sibling packages + docs (.md/.mdx/.txt are not ignored), which can generate phantom or broken url() classes and fail the build. Scope it in your Tailwind CSS entry:\n @import "tailwindcss" source(none);\n @source "."; /* this package, relative to the CSS file */\ncsszyx auto-injects @source for its generated classes, so only your own templates need listing. Guide: https://csszyx.com/docs/monorepo-content-scope/\nSilence (if a broad scan is intentional): csszyx({ contentScopeCheck: false }).';
|
|
1685
|
+
}
|
|
1686
|
+
function isCompilePackageOptedIn(id, compilePackages) {
|
|
1687
|
+
const path2 = id.replace(/\\/g, "/");
|
|
1688
|
+
if (path2.includes("node_modules")) {
|
|
1689
|
+
return false;
|
|
1690
|
+
}
|
|
1691
|
+
return compilePackages.some((name) => path2.includes(`/packages/${name}/`));
|
|
1692
|
+
}
|
|
1693
|
+
function isHardIgnoredPath(id, compilePackages = []) {
|
|
1694
|
+
const path2 = id.replace(/\\/g, "/");
|
|
1695
|
+
if (path2.includes("node_modules")) {
|
|
1696
|
+
return true;
|
|
1697
|
+
}
|
|
1698
|
+
if (path2.includes(".next") && !path2.includes("static")) {
|
|
1699
|
+
return true;
|
|
1700
|
+
}
|
|
1701
|
+
if (path2.includes("/packages/")) {
|
|
1702
|
+
return !isCompilePackageOptedIn(path2, compilePackages);
|
|
1703
|
+
}
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
function isPackagesSkippedSource(id, compilePackages = []) {
|
|
1707
|
+
const path2 = id.replace(/\\/g, "/");
|
|
1708
|
+
if (path2.includes("node_modules")) {
|
|
1709
|
+
return false;
|
|
1710
|
+
}
|
|
1711
|
+
if (path2.includes(".next") && !path2.includes("static")) {
|
|
1712
|
+
return false;
|
|
1713
|
+
}
|
|
1714
|
+
if (!path2.includes("/packages/")) {
|
|
1715
|
+
return false;
|
|
1716
|
+
}
|
|
1717
|
+
return !isCompilePackageOptedIn(path2, compilePackages);
|
|
1718
|
+
}
|
|
1719
|
+
function skippedSzFilesMessage(files) {
|
|
1720
|
+
const list = files.map((file) => ` - ${file}`).join("\n");
|
|
1721
|
+
return `[csszyx] ${files.length} file(s) under packages/ contain \`sz\` but were skipped by ignore rules:
|
|
1722
|
+
${list}
|
|
1723
|
+
Add the package to \`compilePackages\` (or move the file out of packages/) \u2014 otherwise their \`sz\` produces no CSS.`;
|
|
1724
|
+
}
|
|
1725
|
+
function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
|
|
1726
|
+
const safelistPath = path.join(rootDir, safelistFilename).replace(/\\/g, "/");
|
|
1727
|
+
const cssDir = path.dirname(cssId).replace(/\\/g, "/");
|
|
1728
|
+
let relPath = path.posix.relative(cssDir, safelistPath);
|
|
1729
|
+
if (!relPath.startsWith(".")) {
|
|
1730
|
+
relPath = `./${relPath}`;
|
|
1731
|
+
}
|
|
1732
|
+
return relPath;
|
|
1733
|
+
}
|
|
1575
1734
|
function cssVariableEntries(result) {
|
|
1576
1735
|
const entries = [];
|
|
1577
1736
|
for (const [original, value] of result.cssVariableMap ?? []) {
|
|
@@ -2195,6 +2354,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2195
2354
|
"[csszyx] Transform cache disabled because package versions could not be resolved."
|
|
2196
2355
|
);
|
|
2197
2356
|
}
|
|
2357
|
+
const compilePackages = options.compilePackages ?? [];
|
|
2198
2358
|
const parserOverride = process.env.CSSZYX_PARSER;
|
|
2199
2359
|
const defaultParser = DEFAULT_BUILD_CONFIG.parser ?? "rust";
|
|
2200
2360
|
const parserMode = parserOverride === "babel" || parserOverride === "oxc" || parserOverride === "rust" ? parserOverride : options.build?.parser ?? defaultParser;
|
|
@@ -2202,6 +2362,15 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2202
2362
|
const transformMemoryCache = /* @__PURE__ */ new Map();
|
|
2203
2363
|
const state = {
|
|
2204
2364
|
classes: /* @__PURE__ */ new Set(),
|
|
2365
|
+
sawTailwindEntry: false,
|
|
2366
|
+
tailwindWarningEmitted: false,
|
|
2367
|
+
tailwindEntryScoped: false,
|
|
2368
|
+
contentScopeWarningEmitted: false,
|
|
2369
|
+
spreadWarnings: /* @__PURE__ */ new Set(),
|
|
2370
|
+
skippedSzFiles: /* @__PURE__ */ new Set(),
|
|
2371
|
+
skipWarningEmitted: false,
|
|
2372
|
+
classesCapped: false,
|
|
2373
|
+
ownedClasses: /* @__PURE__ */ new Set(),
|
|
2205
2374
|
mangleMap: {},
|
|
2206
2375
|
varMangleEntriesByFile: /* @__PURE__ */ new Map(),
|
|
2207
2376
|
varMangleMap: Object.fromEntries(earlyGlobalVarAliasEntries),
|
|
@@ -2262,7 +2431,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2262
2431
|
return result;
|
|
2263
2432
|
}
|
|
2264
2433
|
function isHardIgnored(id) {
|
|
2265
|
-
return
|
|
2434
|
+
return isHardIgnoredPath(id, compilePackages);
|
|
2266
2435
|
}
|
|
2267
2436
|
function shouldProcessSource(id) {
|
|
2268
2437
|
return !isHardIgnored(id) && !isUserExcluded(id) && isUserIncluded(id) && (/\.[tj]sx?(\?.*)?$/.test(id) || id.endsWith(".vue") || id.endsWith(".svelte"));
|
|
@@ -2468,12 +2637,19 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2468
2637
|
maxEntries: TRANSFORM_CACHE_MAX_ENTRIES
|
|
2469
2638
|
});
|
|
2470
2639
|
}
|
|
2640
|
+
function addSafelistClass(cls) {
|
|
2641
|
+
if (state.classes.size >= MAX_SAFELIST_CLASSES) {
|
|
2642
|
+
state.classesCapped = true;
|
|
2643
|
+
return;
|
|
2644
|
+
}
|
|
2645
|
+
state.classes.add(cls);
|
|
2646
|
+
}
|
|
2471
2647
|
function writeSafelistFile(classes) {
|
|
2472
2648
|
if (classes.size === 0) {
|
|
2473
2649
|
return;
|
|
2474
2650
|
}
|
|
2475
2651
|
const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
|
|
2476
|
-
const classList = Array.from(classes).join(" ");
|
|
2652
|
+
const classList = escapeHtmlAttribute(Array.from(classes).join(" "));
|
|
2477
2653
|
const content = `<!-- Auto-generated by csszyx \u2014 DO NOT EDIT -->
|
|
2478
2654
|
<!-- Tailwind CSS scans this file for class name detection -->
|
|
2479
2655
|
<div class="${classList}"><div class="${classList}">x</div><div class="${classList}">x</div></div>
|
|
@@ -2493,6 +2669,20 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2493
2669
|
} catch {
|
|
2494
2670
|
}
|
|
2495
2671
|
}
|
|
2672
|
+
function recordPackagesSkipIfSz(filePath) {
|
|
2673
|
+
if (!isPackagesSkippedSource(filePath, compilePackages)) {
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
let content;
|
|
2677
|
+
try {
|
|
2678
|
+
content = fs.readFileSync(filePath, "utf-8");
|
|
2679
|
+
} catch {
|
|
2680
|
+
return;
|
|
2681
|
+
}
|
|
2682
|
+
if (content.includes("sz=") || content.includes("sz:")) {
|
|
2683
|
+
state.skippedSzFiles.add(filePath);
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2496
2686
|
function prescanAndWriteClasses() {
|
|
2497
2687
|
const prescanStarted = performance.now();
|
|
2498
2688
|
const discoveredClasses = /* @__PURE__ */ new Set();
|
|
@@ -2513,6 +2703,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2513
2703
|
} else if (SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
|
|
2514
2704
|
const filePath = path.join(dir, entry.name);
|
|
2515
2705
|
if (!shouldProcessSource(filePath)) {
|
|
2706
|
+
recordPackagesSkipIfSz(filePath);
|
|
2516
2707
|
continue;
|
|
2517
2708
|
}
|
|
2518
2709
|
let content;
|
|
@@ -2536,7 +2727,8 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2536
2727
|
collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses);
|
|
2537
2728
|
}
|
|
2538
2729
|
for (const cls of discoveredClasses) {
|
|
2539
|
-
|
|
2730
|
+
addSafelistClass(cls);
|
|
2731
|
+
state.ownedClasses.add(cls);
|
|
2540
2732
|
}
|
|
2541
2733
|
const safelistClasses = /* @__PURE__ */ new Set([...discoveredClasses, ...rawDiscoveredClasses]);
|
|
2542
2734
|
writeSafelistFile(safelistClasses);
|
|
@@ -2624,7 +2816,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2624
2816
|
for (const match of code.matchAll(classPattern)) {
|
|
2625
2817
|
const classes = match[1].split(/\s+/).filter(Boolean);
|
|
2626
2818
|
for (const cls of classes) {
|
|
2627
|
-
|
|
2819
|
+
addSafelistClass(cls);
|
|
2628
2820
|
}
|
|
2629
2821
|
}
|
|
2630
2822
|
}
|
|
@@ -2646,13 +2838,13 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2646
2838
|
const str = strMatch[1] || strMatch[2];
|
|
2647
2839
|
const classes = str.split(/\s+/).filter(Boolean);
|
|
2648
2840
|
for (const cls of classes) {
|
|
2649
|
-
|
|
2841
|
+
addSafelistClass(cls);
|
|
2650
2842
|
}
|
|
2651
2843
|
}
|
|
2652
2844
|
}
|
|
2653
2845
|
}
|
|
2654
2846
|
function finalizeMangleMap() {
|
|
2655
|
-
const sortedClasses = Array.from(state.
|
|
2847
|
+
const sortedClasses = Array.from(state.ownedClasses);
|
|
2656
2848
|
const newMap = {};
|
|
2657
2849
|
for (let i = 0; i < sortedClasses.length; i++) {
|
|
2658
2850
|
newMap[sortedClasses[i]] = encode(i);
|
|
@@ -2737,7 +2929,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2737
2929
|
},
|
|
2738
2930
|
/**
|
|
2739
2931
|
* Filters files for the pre-transform phase — source files plus CSS files.
|
|
2740
|
-
* CSS files need special handling to
|
|
2932
|
+
* CSS files need special handling to append an @source directive for Tailwind class discovery.
|
|
2741
2933
|
* @param id - the file path to check for inclusion
|
|
2742
2934
|
* @returns true if the file should be transformed, false otherwise
|
|
2743
2935
|
*/
|
|
@@ -2749,7 +2941,7 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2749
2941
|
},
|
|
2750
2942
|
/**
|
|
2751
2943
|
* Core transform: detects sz prop, compiles to className, injects runtime, collects classes.
|
|
2752
|
-
* For CSS files:
|
|
2944
|
+
* For CSS files: appends an @source directive so Tailwind generates CSS for sz-derived classes.
|
|
2753
2945
|
* @param code - the source code to transform
|
|
2754
2946
|
* @param id - the file path of the module being transformed
|
|
2755
2947
|
* @returns transformed code with source map, or null if no changes were made
|
|
@@ -2765,24 +2957,19 @@ function createCsszyxPlugins(options = {}) {
|
|
|
2765
2957
|
assertNoRSCBoundaryViolation(code, id);
|
|
2766
2958
|
}
|
|
2767
2959
|
if (/\.css(\?.*)?$/.test(id)) {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
const sourceDirective = `@source "${relPath}";
|
|
2779
|
-
`;
|
|
2780
|
-
const transformed2 = code.replace(
|
|
2781
|
-
/(@import\s+["']tailwindcss[^"']*["'];)/,
|
|
2782
|
-
`$1
|
|
2783
|
-
${sourceDirective}`
|
|
2960
|
+
if (cssImportsTailwind(code)) {
|
|
2961
|
+
state.sawTailwindEntry = true;
|
|
2962
|
+
if (cssHasContentScope(code)) {
|
|
2963
|
+
state.tailwindEntryScoped = true;
|
|
2964
|
+
}
|
|
2965
|
+
if (hasInjectableTailwindCandidate(state.classes)) {
|
|
2966
|
+
const relPath = computeSafelistRelPath(
|
|
2967
|
+
state.rootDir,
|
|
2968
|
+
SAFELIST_FILENAME,
|
|
2969
|
+
id
|
|
2784
2970
|
);
|
|
2785
|
-
|
|
2971
|
+
const transformed2 = appendTailwindSourceDirective(code, relPath);
|
|
2972
|
+
if (transformed2 !== null) {
|
|
2786
2973
|
return { code: transformed2, map: null };
|
|
2787
2974
|
}
|
|
2788
2975
|
}
|
|
@@ -2825,8 +3012,15 @@ ${sourceDirective}`
|
|
|
2825
3012
|
szClasses = result.classes;
|
|
2826
3013
|
recordFileVarMangleEntries(state, id, cssVariableEntries(result));
|
|
2827
3014
|
recordFileCSSVariableMetrics(state, id, result.code);
|
|
3015
|
+
for (const msg of result.diagnostics) {
|
|
3016
|
+
if (msg.includes("unresolvable sz spread")) {
|
|
3017
|
+
state.spreadWarnings.add(`${id}
|
|
3018
|
+
${msg}`);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
2828
3021
|
if (result.diagnostics.length > 0 && process.env.NODE_ENV !== "production") {
|
|
2829
3022
|
for (const msg of result.diagnostics) {
|
|
3023
|
+
if (msg.includes("unresolvable sz spread")) continue;
|
|
2830
3024
|
this.warn(`[csszyx] ${id}
|
|
2831
3025
|
${msg}`);
|
|
2832
3026
|
}
|
|
@@ -2894,7 +3088,8 @@ ${sourceDirective}`
|
|
|
2894
3088
|
if (transformed || transformedCode.includes("class=") || transformedCode.includes("className=")) {
|
|
2895
3089
|
if (szClasses !== void 0) {
|
|
2896
3090
|
for (const cls of szClasses) {
|
|
2897
|
-
|
|
3091
|
+
addSafelistClass(cls);
|
|
3092
|
+
state.ownedClasses.add(cls);
|
|
2898
3093
|
}
|
|
2899
3094
|
} else {
|
|
2900
3095
|
extractClasses(transformedCode);
|
|
@@ -2907,6 +3102,36 @@ ${sourceDirective}`
|
|
|
2907
3102
|
buildEnd() {
|
|
2908
3103
|
finalizeMangleMap();
|
|
2909
3104
|
assertNoRSCGraphViolation(state.rscModules);
|
|
3105
|
+
if (!state.tailwindWarningEmitted && shouldWarnMissingTailwindEntry(state.ownedClasses.size, state.sawTailwindEntry)) {
|
|
3106
|
+
state.tailwindWarningEmitted = true;
|
|
3107
|
+
console.warn(missingTailwindEntryMessage(state.ownedClasses.size));
|
|
3108
|
+
}
|
|
3109
|
+
if (!state.contentScopeWarningEmitted && options.contentScopeCheck !== false && state.sawTailwindEntry && !state.tailwindEntryScoped) {
|
|
3110
|
+
if (state.inMonorepo === void 0) {
|
|
3111
|
+
state.inMonorepo = isMonorepoPackage(state.rootDir);
|
|
3112
|
+
}
|
|
3113
|
+
if (shouldWarnUnscopedMonorepo(
|
|
3114
|
+
state.sawTailwindEntry,
|
|
3115
|
+
state.tailwindEntryScoped,
|
|
3116
|
+
state.inMonorepo
|
|
3117
|
+
)) {
|
|
3118
|
+
state.contentScopeWarningEmitted = true;
|
|
3119
|
+
console.warn(unscopedMonorepoMessage());
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
if (!state.skipWarningEmitted && state.skippedSzFiles.size > 0) {
|
|
3123
|
+
state.skipWarningEmitted = true;
|
|
3124
|
+
console.warn(skippedSzFilesMessage([...state.skippedSzFiles].sort()));
|
|
3125
|
+
}
|
|
3126
|
+
if (state.classesCapped) {
|
|
3127
|
+
console.warn(
|
|
3128
|
+
`[csszyx] safelist exceeded ${MAX_SAFELIST_CLASSES} classes; additional classes were dropped. This usually means an unbounded set of arbitrary values reached an sz prop.`
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
for (const warning of state.spreadWarnings) {
|
|
3132
|
+
console.warn(`[csszyx] ${warning}`);
|
|
3133
|
+
}
|
|
3134
|
+
state.spreadWarnings.clear();
|
|
2910
3135
|
if (manglingEnabled && Object.keys(state.mangleMap).length > 0) {
|
|
2911
3136
|
globalThis.__csszyx_ssr_mangle_map = state.mangleMap;
|
|
2912
3137
|
}
|
|
@@ -3006,7 +3231,8 @@ ${sourceDirective}`
|
|
|
3006
3231
|
const sizeBefore = state.classes.size;
|
|
3007
3232
|
recordGlobalVarSourceFile(state, ctx.file, fileContent);
|
|
3008
3233
|
for (const cls of result.classes) {
|
|
3009
|
-
|
|
3234
|
+
addSafelistClass(cls);
|
|
3235
|
+
state.ownedClasses.add(cls);
|
|
3010
3236
|
}
|
|
3011
3237
|
recordFileVarMangleEntries(state, ctx.file, cssVariableEntries(result));
|
|
3012
3238
|
recordFileCSSVariableMetrics(state, ctx.file, result.code);
|
|
@@ -3345,4 +3571,4 @@ const esbuildPlugin = (options = {}) => {
|
|
|
3345
3571
|
};
|
|
3346
3572
|
};
|
|
3347
3573
|
|
|
3348
|
-
export {
|
|
3574
|
+
export { mangleCodeClassesSync as A, mergeThemes as B, missingTailwindEntryMessage as C, normalizeGlobalVarAliasesForCache as D, parseThemeBlocks as E, planGlobalVarAliases as F, readGlobalVarScanCache as G, resolveGlobalVarScanCacheDir as H, resolveNativeCacheIdentity as I, rewriteGlobalVarCssAliases as J, rollupPlugin as K, scanGlobalVarCss as L, shouldWarnMissingTailwindEntry as M, shouldWarnUnscopedMonorepo as N, skippedSzFilesMessage as O, unscopedMonorepoMessage as P, validateGlobalVarAliasInputs as Q, vitePlugin as R, webpackPlugin as S, writeGlobalVarScanCache as T, appendTailwindSourceDirective as a, assertNoRSCBoundaryViolation as b, assertNoRSCGraphViolation as c, computeSafelistRelPath as d, createGlobalVarAliasValidationOptions as e, createGlobalVarMapAssetSource as f, createGlobalVarScanCacheKey as g, createRSCModuleRecord as h, cssHasContentScope as i, cssImportsTailwind as j, deleteRSCModuleRecord as k, esbuildPlugin as l, extractGlobalVarAliasesForManifest as m, findRSCBoundaryViolation as n, findRSCGraphViolation as o, hasInjectableTailwindCandidate as p, hasTokens as q, hasUseClientDirective as r, hasUseServerDirective as s, isCompilePackageOptedIn as t, unplugin as u, isHardIgnoredPath as v, isMonorepoPackage as w, isPackagesSkippedSource as x, isRSCServerModule as y, isTailwindReservedGlobalVar as z };
|
|
@@ -3,6 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { hostname } from 'node:os';
|
|
5
5
|
import lockfile from 'proper-lockfile';
|
|
6
|
+
import { e as escapeHtmlAttribute } from './unplugin.3UumZ5gn.mjs';
|
|
6
7
|
|
|
7
8
|
const DEFAULT_RENAME_RETRIES = 5;
|
|
8
9
|
const DEFAULT_RENAME_RETRY_DELAY_MS = 10;
|
|
@@ -235,9 +236,6 @@ function renderTailwindSourceHtml(classNames) {
|
|
|
235
236
|
return `${classNames.map((className) => `<div class="${escapeHtmlAttribute(className)}"></div>`).join("\n")}
|
|
236
237
|
`;
|
|
237
238
|
}
|
|
238
|
-
function escapeHtmlAttribute(value) {
|
|
239
|
-
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
240
|
-
}
|
|
241
239
|
function createLockMetadata(options) {
|
|
242
240
|
const now = new Date(options.now ?? Date.now()).toISOString();
|
|
243
241
|
const pid = options.pid ?? process.pid;
|
|
@@ -5,6 +5,7 @@ const fs = require('node:fs');
|
|
|
5
5
|
const node_crypto = require('node:crypto');
|
|
6
6
|
const node_os = require('node:os');
|
|
7
7
|
const lockfile = require('proper-lockfile');
|
|
8
|
+
const htmlEscape = require('./unplugin.DoBHTRra.cjs');
|
|
8
9
|
|
|
9
10
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
10
11
|
|
|
@@ -252,12 +253,9 @@ function renderTailwindSourceHtml(classNames) {
|
|
|
252
253
|
if (classNames.length === 0) {
|
|
253
254
|
return "<!-- csszyx Next safelist: empty -->\n";
|
|
254
255
|
}
|
|
255
|
-
return `${classNames.map((className) => `<div class="${escapeHtmlAttribute(className)}"></div>`).join("\n")}
|
|
256
|
+
return `${classNames.map((className) => `<div class="${htmlEscape.escapeHtmlAttribute(className)}"></div>`).join("\n")}
|
|
256
257
|
`;
|
|
257
258
|
}
|
|
258
|
-
function escapeHtmlAttribute(value) {
|
|
259
|
-
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
260
|
-
}
|
|
261
259
|
function createLockMetadata(options) {
|
|
262
260
|
const now = new Date(options.now ?? Date.now()).toISOString();
|
|
263
261
|
const pid = options.pid ?? process.pid;
|