@csszyx/unplugin 0.11.6 → 0.11.7
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/css-mangler.cjs +41 -41
- package/dist/css-mangler.mjs +41 -41
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/next-prebuild.cjs +3 -3
- package/dist/next-prebuild.mjs +3 -3
- package/dist/next-turbo-loader.cjs +9 -3
- package/dist/next-turbo-loader.mjs +9 -3
- package/dist/next-watcher.cjs +1 -1
- package/dist/next-watcher.mjs +1 -1
- package/dist/shared/{unplugin.CP2cz9bA.cjs → unplugin.ByAzFdqO.cjs} +246 -211
- package/dist/shared/{unplugin.CBKZoxQ1.cjs → unplugin.CZKUWN1J.cjs} +1 -1
- package/dist/shared/{unplugin.BS60onPk.mjs → unplugin.CtHwCYxE.mjs} +244 -209
- package/dist/shared/{unplugin.ByzV6iZE.mjs → unplugin.CwcOd1q3.mjs} +7 -6
- package/dist/shared/{unplugin.BFN_Ueyx.cjs → unplugin.D6hes1O8.cjs} +2 -2
- package/dist/shared/{unplugin.D0N9bprz.cjs → unplugin.D8vSG36M.cjs} +6 -5
- package/dist/shared/{unplugin.ChwZMl_w.mjs → unplugin.Dqt1aLCX.mjs} +3 -3
- package/dist/shared/{unplugin.B3cvNxnk.mjs → unplugin.VSslRpfN.mjs} +1 -1
- package/dist/vite.cjs +2 -2
- package/dist/vite.mjs +2 -2
- package/dist/webpack.cjs +2 -2
- package/dist/webpack.mjs +2 -2
- package/package.json +7 -7
|
@@ -16,7 +16,7 @@ import { createUnplugin } from 'unplugin';
|
|
|
16
16
|
import { mangleCSSSync } from '../css-mangler.mjs';
|
|
17
17
|
import { s as sortStrings, e as escapeHtmlAttribute } from './unplugin.B1mblcm-.mjs';
|
|
18
18
|
import { i as importsRuntimeHelper, f as findRuntimeImportClause } from './unplugin.B3RHYokB.mjs';
|
|
19
|
-
import { r as resolveTransformCacheDir, c as createTransformCacheKey, a as readTransformCache, w as writeTransformCache, e as evictOldTransformCacheEntries, b as evictMemoryCacheToBudget } from './unplugin.
|
|
19
|
+
import { r as resolveTransformCacheDir, c as createTransformCacheKey, a as readTransformCache, w as writeTransformCache, e as evictOldTransformCacheEntries, b as evictMemoryCacheToBudget } from './unplugin.CwcOd1q3.mjs';
|
|
20
20
|
import postcss from 'postcss';
|
|
21
21
|
import valueParser from 'postcss-value-parser';
|
|
22
22
|
|
|
@@ -615,6 +615,27 @@ function walkRSCGraph(current, records, chain, seen) {
|
|
|
615
615
|
}
|
|
616
616
|
return null;
|
|
617
617
|
}
|
|
618
|
+
function findDirectiveQuoteEnd(code, start, quote) {
|
|
619
|
+
let escaped = false;
|
|
620
|
+
for (let index = start + 1; index < code.length; index++) {
|
|
621
|
+
const char = code[index];
|
|
622
|
+
if (escaped) {
|
|
623
|
+
escaped = false;
|
|
624
|
+
} else if (char === "\\") {
|
|
625
|
+
escaped = true;
|
|
626
|
+
} else if (char === quote) {
|
|
627
|
+
return index;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return -1;
|
|
631
|
+
}
|
|
632
|
+
function findDirectiveStatementEnd(code, start) {
|
|
633
|
+
let end = start;
|
|
634
|
+
while (end < code.length && /[ \t\r\n]/.test(code[end])) {
|
|
635
|
+
end++;
|
|
636
|
+
}
|
|
637
|
+
return code[end] === ";" ? end + 1 : end;
|
|
638
|
+
}
|
|
618
639
|
function readDirectivePrologue(code) {
|
|
619
640
|
const out = [];
|
|
620
641
|
let i = code.charCodeAt(0) === 65279 ? 1 : 0;
|
|
@@ -624,29 +645,11 @@ function readDirectivePrologue(code) {
|
|
|
624
645
|
if (quote !== '"' && quote !== "'") {
|
|
625
646
|
break;
|
|
626
647
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
while (j < code.length) {
|
|
630
|
-
const ch = code[j];
|
|
631
|
-
if (escaped) {
|
|
632
|
-
escaped = false;
|
|
633
|
-
} else if (ch === "\\") {
|
|
634
|
-
escaped = true;
|
|
635
|
-
} else if (ch === quote) {
|
|
636
|
-
break;
|
|
637
|
-
}
|
|
638
|
-
j++;
|
|
639
|
-
}
|
|
640
|
-
if (j >= code.length) {
|
|
648
|
+
const quoteEnd = findDirectiveQuoteEnd(code, i, quote);
|
|
649
|
+
if (quoteEnd === -1) {
|
|
641
650
|
break;
|
|
642
651
|
}
|
|
643
|
-
|
|
644
|
-
while (end < code.length && /[ \t\r\n]/.test(code[end])) {
|
|
645
|
-
end++;
|
|
646
|
-
}
|
|
647
|
-
if (code[end] === ";") {
|
|
648
|
-
end++;
|
|
649
|
-
}
|
|
652
|
+
const end = findDirectiveStatementEnd(code, quoteEnd + 1);
|
|
650
653
|
out.push(code.slice(i, end).trim());
|
|
651
654
|
i = end;
|
|
652
655
|
}
|
|
@@ -982,33 +985,34 @@ function pruneRSCModulePathCaches(moduleIds) {
|
|
|
982
985
|
}
|
|
983
986
|
}
|
|
984
987
|
}
|
|
985
|
-
function
|
|
986
|
-
const symbols = [];
|
|
988
|
+
function readNamedImportedSymbols(clause) {
|
|
987
989
|
const openBrace = clause.indexOf("{");
|
|
988
990
|
const closeBrace = openBrace === -1 ? -1 : clause.indexOf("}", openBrace);
|
|
989
|
-
if (openBrace
|
|
990
|
-
|
|
991
|
-
for (const part of namedPart.split(",")) {
|
|
992
|
-
const trimmed = part.trim();
|
|
993
|
-
if (!trimmed || trimmed.startsWith("type ")) {
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
const sourceName = trimmed.replace(/^type[ \t]+/, "").split(/(?<![ \t])[ \t]+as[ \t]+/)[0]?.trim();
|
|
997
|
-
if (sourceName) {
|
|
998
|
-
symbols.push(sourceName);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
const namespaceParts = splitAsciiWhitespace(clause);
|
|
1003
|
-
if (namespaceParts.length >= 3 && namespaceParts[0] === "*" && namespaceParts[1] === "as" && isIdentifier(namespaceParts[2] ?? "")) {
|
|
1004
|
-
symbols.push(...FORBIDDEN_SYMBOLS);
|
|
991
|
+
if (openBrace === -1 || closeBrace === -1) {
|
|
992
|
+
return [];
|
|
1005
993
|
}
|
|
994
|
+
return clause.slice(openBrace + 1, closeBrace).split(",").map((part) => part.trim()).filter((part) => part !== "" && !part.startsWith("type ")).map(
|
|
995
|
+
(part) => part.replace(/^type[ \t]+/, "").split(/(?<![ \t])[ \t]+as[ \t]+/)[0]?.trim()
|
|
996
|
+
).filter((symbol) => Boolean(symbol));
|
|
997
|
+
}
|
|
998
|
+
function readForbiddenDefaultSymbol(clause) {
|
|
1006
999
|
const braceStart = clause.indexOf("{");
|
|
1007
1000
|
const braceEnd = clause.indexOf("}", braceStart);
|
|
1008
1001
|
const stripped = braceStart !== -1 && braceEnd !== -1 ? clause.slice(0, braceStart) + clause.slice(braceEnd + 1) : clause;
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
|
|
1002
|
+
const candidate = stripped.trimStart().split(",", 1)[0]?.trim() ?? "";
|
|
1003
|
+
return isIdentifier(candidate) && FORBIDDEN_SYMBOLS.has(candidate) ? candidate : null;
|
|
1004
|
+
}
|
|
1005
|
+
function hasNamespaceImport(clause) {
|
|
1006
|
+
const parts = splitAsciiWhitespace(clause);
|
|
1007
|
+
return parts.length >= 3 && parts[0] === "*" && parts[1] === "as" && isIdentifier(parts[2] ?? "");
|
|
1008
|
+
}
|
|
1009
|
+
function readImportedSymbols(clause) {
|
|
1010
|
+
const symbols = readNamedImportedSymbols(clause);
|
|
1011
|
+
if (hasNamespaceImport(clause)) {
|
|
1012
|
+
symbols.push(...FORBIDDEN_SYMBOLS);
|
|
1013
|
+
}
|
|
1014
|
+
const defaultSymbol = readForbiddenDefaultSymbol(clause);
|
|
1015
|
+
if (defaultSymbol) {
|
|
1012
1016
|
symbols.push(defaultSymbol);
|
|
1013
1017
|
}
|
|
1014
1018
|
return symbols;
|
|
@@ -1112,6 +1116,20 @@ const EMPTY_THEME = {
|
|
|
1112
1116
|
shadows: [],
|
|
1113
1117
|
breakpoints: []
|
|
1114
1118
|
};
|
|
1119
|
+
function findMatchingBrace(source, openBrace) {
|
|
1120
|
+
let depth = 0;
|
|
1121
|
+
for (let index = openBrace; index < source.length; index++) {
|
|
1122
|
+
if (source[index] === "{") {
|
|
1123
|
+
depth++;
|
|
1124
|
+
} else if (source[index] === "}") {
|
|
1125
|
+
depth--;
|
|
1126
|
+
if (depth === 0) {
|
|
1127
|
+
return index;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return -1;
|
|
1132
|
+
}
|
|
1115
1133
|
function stripLayerWrappers(css) {
|
|
1116
1134
|
let result = "";
|
|
1117
1135
|
let i = 0;
|
|
@@ -1127,26 +1145,13 @@ function stripLayerWrappers(css) {
|
|
|
1127
1145
|
result += css.slice(layerIdx);
|
|
1128
1146
|
break;
|
|
1129
1147
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
while (j < css.length) {
|
|
1133
|
-
if (css[j] === "{") {
|
|
1134
|
-
depth++;
|
|
1135
|
-
}
|
|
1136
|
-
if (css[j] === "}") {
|
|
1137
|
-
depth--;
|
|
1138
|
-
if (depth === 0) {
|
|
1139
|
-
result += css.slice(openBrace + 1, j);
|
|
1140
|
-
i = j + 1;
|
|
1141
|
-
break;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
j++;
|
|
1145
|
-
}
|
|
1146
|
-
if (depth !== 0) {
|
|
1148
|
+
const closeBrace = findMatchingBrace(css, openBrace);
|
|
1149
|
+
if (closeBrace === -1) {
|
|
1147
1150
|
result += css.slice(openBrace);
|
|
1148
1151
|
break;
|
|
1149
1152
|
}
|
|
1153
|
+
result += css.slice(openBrace + 1, closeBrace);
|
|
1154
|
+
i = closeBrace + 1;
|
|
1150
1155
|
}
|
|
1151
1156
|
return result;
|
|
1152
1157
|
}
|
|
@@ -1155,20 +1160,9 @@ function extractThemeBlocks(css) {
|
|
|
1155
1160
|
const themeStart = /@theme\s+(?:inline\s+)?\{|@theme\{/g;
|
|
1156
1161
|
for (const match of css.matchAll(themeStart)) {
|
|
1157
1162
|
const openPos = css.indexOf("{", match.index);
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
if (css[j] === "{") {
|
|
1162
|
-
depth++;
|
|
1163
|
-
}
|
|
1164
|
-
if (css[j] === "}") {
|
|
1165
|
-
depth--;
|
|
1166
|
-
if (depth === 0) {
|
|
1167
|
-
blocks.push(css.slice(openPos + 1, j));
|
|
1168
|
-
break;
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
j++;
|
|
1163
|
+
const closePos = findMatchingBrace(css, openPos);
|
|
1164
|
+
if (closePos !== -1) {
|
|
1165
|
+
blocks.push(css.slice(openPos + 1, closePos));
|
|
1172
1166
|
}
|
|
1173
1167
|
}
|
|
1174
1168
|
return blocks;
|
|
@@ -1267,6 +1261,29 @@ function mergeThemes(themes) {
|
|
|
1267
1261
|
function hasTokens(theme) {
|
|
1268
1262
|
return Object.values(theme).some((arr) => arr.length > 0);
|
|
1269
1263
|
}
|
|
1264
|
+
function readCustomPropertyName(block, dashes) {
|
|
1265
|
+
let end = dashes + 2;
|
|
1266
|
+
if (end >= block.length || !/[a-z]/.test(block[end])) {
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
end++;
|
|
1270
|
+
while (end < block.length && /[a-z0-9-]/.test(block[end])) {
|
|
1271
|
+
end++;
|
|
1272
|
+
}
|
|
1273
|
+
return { name: block.slice(dashes + 2, end), end };
|
|
1274
|
+
}
|
|
1275
|
+
function findCustomPropertyDeclarationEnd(block, nameEnd) {
|
|
1276
|
+
let cursor = nameEnd;
|
|
1277
|
+
while (cursor < block.length && /\s/.test(block[cursor])) {
|
|
1278
|
+
cursor++;
|
|
1279
|
+
}
|
|
1280
|
+
if (block[cursor] === ":") {
|
|
1281
|
+
const valueStart = cursor + 1;
|
|
1282
|
+
const semicolon = block.indexOf(";", valueStart);
|
|
1283
|
+
return semicolon > valueStart ? semicolon + 1 : -1;
|
|
1284
|
+
}
|
|
1285
|
+
return block[nameEnd] === ";" ? nameEnd + 1 : -1;
|
|
1286
|
+
}
|
|
1270
1287
|
function scanCustomPropertyNames(block) {
|
|
1271
1288
|
const names = [];
|
|
1272
1289
|
let i = 0;
|
|
@@ -1275,36 +1292,17 @@ function scanCustomPropertyNames(block) {
|
|
|
1275
1292
|
if (dashes === -1) {
|
|
1276
1293
|
break;
|
|
1277
1294
|
}
|
|
1278
|
-
|
|
1279
|
-
if (
|
|
1295
|
+
const property = readCustomPropertyName(block, dashes);
|
|
1296
|
+
if (!property) {
|
|
1280
1297
|
i = dashes + 1;
|
|
1281
1298
|
continue;
|
|
1282
1299
|
}
|
|
1283
|
-
end
|
|
1284
|
-
while (end < block.length && /[a-z0-9-]/.test(block[end])) {
|
|
1285
|
-
end++;
|
|
1286
|
-
}
|
|
1287
|
-
const name = block.slice(dashes + 2, end);
|
|
1288
|
-
let matchEnd = -1;
|
|
1289
|
-
let cursor = end;
|
|
1290
|
-
while (cursor < block.length && /\s/.test(block[cursor])) {
|
|
1291
|
-
cursor++;
|
|
1292
|
-
}
|
|
1293
|
-
if (block[cursor] === ":") {
|
|
1294
|
-
const valueStart = cursor + 1;
|
|
1295
|
-
const semi = block.indexOf(";", valueStart);
|
|
1296
|
-
if (semi > valueStart) {
|
|
1297
|
-
matchEnd = semi + 1;
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
if (matchEnd === -1 && block[end] === ";") {
|
|
1301
|
-
matchEnd = end + 1;
|
|
1302
|
-
}
|
|
1300
|
+
const matchEnd = findCustomPropertyDeclarationEnd(block, property.end);
|
|
1303
1301
|
if (matchEnd === -1) {
|
|
1304
1302
|
i = dashes + 1;
|
|
1305
1303
|
continue;
|
|
1306
1304
|
}
|
|
1307
|
-
names.push(name);
|
|
1305
|
+
names.push(property.name);
|
|
1308
1306
|
i = matchEnd;
|
|
1309
1307
|
}
|
|
1310
1308
|
return names;
|
|
@@ -1372,27 +1370,36 @@ function matchesAnyPattern(id, patterns, rootDir) {
|
|
|
1372
1370
|
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
1373
1371
|
return list.some((pattern) => matchesPattern(id, pattern, rootDir));
|
|
1374
1372
|
}
|
|
1373
|
+
function collectDirectoryFiles(dir, files) {
|
|
1374
|
+
let entries;
|
|
1375
|
+
try {
|
|
1376
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1377
|
+
} catch {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
for (const entry of entries) {
|
|
1381
|
+
const full = path.join(dir, entry.name);
|
|
1382
|
+
if (entry.isDirectory()) {
|
|
1383
|
+
if (!DEFAULT_IGNORED_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
1384
|
+
collectDirectoryFiles(full, files);
|
|
1385
|
+
}
|
|
1386
|
+
} else {
|
|
1387
|
+
files.add(path.resolve(full));
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
function isExpandedPatternMatch(file, patterns, rootDir) {
|
|
1392
|
+
return patterns.some((pattern) => {
|
|
1393
|
+
if (hasGlobMagic(pattern)) {
|
|
1394
|
+
return matchesPattern(file, pattern, rootDir);
|
|
1395
|
+
}
|
|
1396
|
+
const resolved = path.isAbsolute(pattern) ? pattern : path.join(rootDir, pattern);
|
|
1397
|
+
return normalizeFileId(path.resolve(resolved)) === normalizeFileId(file);
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1375
1400
|
function expandFilePatterns(rootDir, patterns) {
|
|
1376
1401
|
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
1377
1402
|
const files = /* @__PURE__ */ new Set();
|
|
1378
|
-
const walk = (dir) => {
|
|
1379
|
-
let entries;
|
|
1380
|
-
try {
|
|
1381
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1382
|
-
} catch {
|
|
1383
|
-
return;
|
|
1384
|
-
}
|
|
1385
|
-
for (const entry of entries) {
|
|
1386
|
-
const full = path.join(dir, entry.name);
|
|
1387
|
-
if (entry.isDirectory()) {
|
|
1388
|
-
if (!DEFAULT_IGNORED_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
1389
|
-
walk(full);
|
|
1390
|
-
}
|
|
1391
|
-
} else {
|
|
1392
|
-
files.add(path.resolve(full));
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
};
|
|
1396
1403
|
let needsWalk = false;
|
|
1397
1404
|
for (const pattern of list) {
|
|
1398
1405
|
const resolved = path.isAbsolute(pattern) ? pattern : path.join(rootDir, pattern);
|
|
@@ -1405,21 +1412,10 @@ function expandFilePatterns(rootDir, patterns) {
|
|
|
1405
1412
|
}
|
|
1406
1413
|
}
|
|
1407
1414
|
if (needsWalk) {
|
|
1408
|
-
|
|
1415
|
+
collectDirectoryFiles(rootDir, files);
|
|
1409
1416
|
for (const file of Array.from(files)) {
|
|
1410
|
-
if (!list
|
|
1411
|
-
(
|
|
1412
|
-
)) {
|
|
1413
|
-
const isLiteralMatch = list.some((pattern) => {
|
|
1414
|
-
if (hasGlobMagic(pattern)) {
|
|
1415
|
-
return false;
|
|
1416
|
-
}
|
|
1417
|
-
const resolved = path.isAbsolute(pattern) ? pattern : path.join(rootDir, pattern);
|
|
1418
|
-
return normalizeFileId(path.resolve(resolved)) === normalizeFileId(file);
|
|
1419
|
-
});
|
|
1420
|
-
if (!isLiteralMatch) {
|
|
1421
|
-
files.delete(file);
|
|
1422
|
-
}
|
|
1417
|
+
if (!isExpandedPatternMatch(file, list, rootDir)) {
|
|
1418
|
+
files.delete(file);
|
|
1423
1419
|
}
|
|
1424
1420
|
}
|
|
1425
1421
|
}
|
|
@@ -3139,12 +3135,55 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3139
3135
|
state.skippedSzFiles.add(filePath);
|
|
3140
3136
|
}
|
|
3141
3137
|
}
|
|
3138
|
+
function processPrescanTransform(filePath, content, result, discoveredClasses, rawDiscoveredClasses) {
|
|
3139
|
+
const budgetExceeded = result.diagnostics.some(
|
|
3140
|
+
(diagnostic) => diagnostic.includes("AST budget exceeded")
|
|
3141
|
+
);
|
|
3142
|
+
if (cacheEnabled && !budgetExceeded && content !== void 0) {
|
|
3143
|
+
prescanResultHandoff.set(normalizeSourceFilename(filePath), {
|
|
3144
|
+
inputSha256: createHash("sha256").update(content).digest("hex"),
|
|
3145
|
+
result
|
|
3146
|
+
});
|
|
3147
|
+
}
|
|
3148
|
+
if (budgetExceeded) {
|
|
3149
|
+
warnPrescanBudgetSkip(filePath);
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
const parseFailed = result.diagnostics.some(
|
|
3153
|
+
(diagnostic) => diagnostic.includes("[csszyx] parse error in ")
|
|
3154
|
+
);
|
|
3155
|
+
if (result.classes.size === 0 && result.rawClassNames.size === 0 && parseFailed) {
|
|
3156
|
+
console.warn(
|
|
3157
|
+
`[csszyx] prescan skipped ${filePath}: the file failed to parse, so none of its classes reached the safelist. Fix the syntax error (or check the file extension matches its contents).`
|
|
3158
|
+
);
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
if (!result.transformed && result.classes.size === 0) {
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses);
|
|
3165
|
+
}
|
|
3142
3166
|
function prescanAndWriteClasses() {
|
|
3143
3167
|
refreshCompileSourceDirs();
|
|
3144
3168
|
const prescanStarted = performance.now();
|
|
3145
3169
|
const discoveredClasses = /* @__PURE__ */ new Set();
|
|
3146
3170
|
const rawDiscoveredClasses = /* @__PURE__ */ new Set();
|
|
3147
3171
|
const prescanSources = [];
|
|
3172
|
+
function collectPrescanSource(filePath) {
|
|
3173
|
+
if (!shouldProcessSource(filePath)) {
|
|
3174
|
+
recordPackagesSkipIfSz(filePath);
|
|
3175
|
+
return;
|
|
3176
|
+
}
|
|
3177
|
+
let content;
|
|
3178
|
+
try {
|
|
3179
|
+
content = fs.readFileSync(filePath, "utf-8");
|
|
3180
|
+
} catch {
|
|
3181
|
+
return;
|
|
3182
|
+
}
|
|
3183
|
+
if (fileMayContainSafelistableSz(content)) {
|
|
3184
|
+
prescanSources.push({ filePath, content });
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3148
3187
|
function scanDir(dir) {
|
|
3149
3188
|
let entries;
|
|
3150
3189
|
try {
|
|
@@ -3157,22 +3196,10 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3157
3196
|
if (!IGNORE_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
3158
3197
|
scanDir(path.join(dir, entry.name));
|
|
3159
3198
|
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
continue;
|
|
3165
|
-
}
|
|
3166
|
-
let content;
|
|
3167
|
-
try {
|
|
3168
|
-
content = fs.readFileSync(filePath, "utf-8");
|
|
3169
|
-
} catch {
|
|
3170
|
-
continue;
|
|
3171
|
-
}
|
|
3172
|
-
if (!fileMayContainSafelistableSz(content)) {
|
|
3173
|
-
continue;
|
|
3174
|
-
}
|
|
3175
|
-
prescanSources.push({ filePath, content });
|
|
3199
|
+
continue;
|
|
3200
|
+
}
|
|
3201
|
+
if (SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
|
|
3202
|
+
collectPrescanSource(path.join(dir, entry.name));
|
|
3176
3203
|
}
|
|
3177
3204
|
}
|
|
3178
3205
|
}
|
|
@@ -3188,29 +3215,13 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3188
3215
|
prescanSources.map((file) => [file.filePath, file.content])
|
|
3189
3216
|
);
|
|
3190
3217
|
for (const { filePath, result } of transformPrescanSources(prescanSources)) {
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
if (result.diagnostics.some((d) => d.includes("AST budget exceeded"))) {
|
|
3201
|
-
warnPrescanBudgetSkip(filePath);
|
|
3202
|
-
continue;
|
|
3203
|
-
}
|
|
3204
|
-
if (result.classes.size === 0 && result.rawClassNames.size === 0 && result.diagnostics.some((d) => d.includes("[csszyx] parse error in "))) {
|
|
3205
|
-
console.warn(
|
|
3206
|
-
`[csszyx] prescan skipped ${filePath}: the file failed to parse, so none of its classes reached the safelist. Fix the syntax error (or check the file extension matches its contents).`
|
|
3207
|
-
);
|
|
3208
|
-
continue;
|
|
3209
|
-
}
|
|
3210
|
-
if (!result.transformed && result.classes.size === 0) {
|
|
3211
|
-
continue;
|
|
3212
|
-
}
|
|
3213
|
-
collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses);
|
|
3218
|
+
processPrescanTransform(
|
|
3219
|
+
filePath,
|
|
3220
|
+
prescanContentByPath.get(filePath),
|
|
3221
|
+
result,
|
|
3222
|
+
discoveredClasses,
|
|
3223
|
+
rawDiscoveredClasses
|
|
3224
|
+
);
|
|
3214
3225
|
}
|
|
3215
3226
|
for (const cls of discoveredClasses) {
|
|
3216
3227
|
addSafelistClass(cls);
|
|
@@ -3295,40 +3306,48 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3295
3306
|
discoveredClasses.add(cls);
|
|
3296
3307
|
}
|
|
3297
3308
|
}
|
|
3298
|
-
function
|
|
3299
|
-
const
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3309
|
+
function addSafelistClasses(value) {
|
|
3310
|
+
for (const className of value.split(/\s+/).filter(Boolean)) {
|
|
3311
|
+
addSafelistClass(className);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
function collectQuotedAttributeClasses(code) {
|
|
3315
|
+
const patterns = [
|
|
3316
|
+
/(?:class(?:Name)?|sz)[:=]\s*"([^"]*)"/g,
|
|
3317
|
+
/(?:class(?:Name)?|sz)[:=]\s*'([^']*)'/g
|
|
3318
|
+
];
|
|
3319
|
+
for (const pattern of patterns) {
|
|
3320
|
+
for (const match of code.matchAll(pattern)) {
|
|
3321
|
+
addSafelistClasses(match[1] ?? "");
|
|
3307
3322
|
}
|
|
3308
3323
|
}
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
}
|
|
3319
|
-
i++;
|
|
3324
|
+
}
|
|
3325
|
+
function findJsxExpressionEnd(code, bodyStart) {
|
|
3326
|
+
let depth = 1;
|
|
3327
|
+
let index = bodyStart;
|
|
3328
|
+
while (index < code.length && depth > 0) {
|
|
3329
|
+
if (code[index] === "{") {
|
|
3330
|
+
depth++;
|
|
3331
|
+
} else if (code[index] === "}") {
|
|
3332
|
+
depth--;
|
|
3320
3333
|
}
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3334
|
+
index++;
|
|
3335
|
+
}
|
|
3336
|
+
return index - 1;
|
|
3337
|
+
}
|
|
3338
|
+
function collectExpressionClasses(code) {
|
|
3339
|
+
for (const match of code.matchAll(/className=\{/g)) {
|
|
3340
|
+
const bodyStart = (match.index ?? 0) + match[0].length;
|
|
3341
|
+
const expression = code.slice(bodyStart, findJsxExpressionEnd(code, bodyStart));
|
|
3342
|
+
for (const stringMatch of expression.matchAll(/"([^"]+)"|'([^']+)'/g)) {
|
|
3343
|
+
addSafelistClasses(stringMatch[1] ?? stringMatch[2] ?? "");
|
|
3329
3344
|
}
|
|
3330
3345
|
}
|
|
3331
3346
|
}
|
|
3347
|
+
function extractClasses(code) {
|
|
3348
|
+
collectQuotedAttributeClasses(code);
|
|
3349
|
+
collectExpressionClasses(code);
|
|
3350
|
+
}
|
|
3332
3351
|
function finalizeMangleMap() {
|
|
3333
3352
|
const sortedClasses = Array.from(state.ownedClasses);
|
|
3334
3353
|
const newMap = {};
|
|
@@ -3352,6 +3371,24 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3352
3371
|
function mangleCodeClasses(code) {
|
|
3353
3372
|
return mangleCodeClassesSync(code, state.mangleMap);
|
|
3354
3373
|
}
|
|
3374
|
+
function mangleHtmlClassList(classes) {
|
|
3375
|
+
const output = [];
|
|
3376
|
+
for (const className of classes.split(/\s+/)) {
|
|
3377
|
+
if (className) output.push(state.mangleMap[className] || className);
|
|
3378
|
+
}
|
|
3379
|
+
return output.join(" ");
|
|
3380
|
+
}
|
|
3381
|
+
function replaceDoubleQuotedHtmlClass(match, classes) {
|
|
3382
|
+
const output = mangleHtmlClassList(classes);
|
|
3383
|
+
return output !== classes ? `class="${output}"` : match;
|
|
3384
|
+
}
|
|
3385
|
+
function replaceSingleQuotedHtmlClass(match, classes) {
|
|
3386
|
+
const output = mangleHtmlClassList(classes);
|
|
3387
|
+
return output !== classes ? `class='${output}'` : match;
|
|
3388
|
+
}
|
|
3389
|
+
function mangleHtmlClasses(source) {
|
|
3390
|
+
return source.replace(/\bclass="([^"]*)"/g, replaceDoubleQuotedHtmlClass).replace(/\bclass='([^']*)'/g, replaceSingleQuotedHtmlClass);
|
|
3391
|
+
}
|
|
3355
3392
|
function replacePlaceholders(code) {
|
|
3356
3393
|
let result = code;
|
|
3357
3394
|
if (result.includes(CHECKSUM_PLACEHOLDER)) {
|
|
@@ -3486,6 +3523,8 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3486
3523
|
let usesSzcn = false;
|
|
3487
3524
|
let usesSzPart = false;
|
|
3488
3525
|
let usesColorVar = false;
|
|
3526
|
+
let usesSpacingVar = false;
|
|
3527
|
+
let usesUnitVar = false;
|
|
3489
3528
|
let transformed = false;
|
|
3490
3529
|
let szClasses;
|
|
3491
3530
|
const hasSzProp = code.includes("sz=") || code.includes("szs=") || /\bsz\s*:\s*["'{]/.test(code) || code.includes('sz: "');
|
|
@@ -3516,6 +3555,8 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3516
3555
|
usesSzcn = result.usesSzcn;
|
|
3517
3556
|
usesSzPart = result.usesSzPart;
|
|
3518
3557
|
usesColorVar = result.usesColorVar;
|
|
3558
|
+
usesSpacingVar = result.usesSpacingVar;
|
|
3559
|
+
usesUnitVar = result.usesUnitVar;
|
|
3519
3560
|
transformed = result.transformed;
|
|
3520
3561
|
szClasses = result.classes;
|
|
3521
3562
|
recordFileVarMangleEntries(state, id, cssVariableEntries(result));
|
|
@@ -3576,6 +3617,12 @@ function createCsszyxPlugins(options = {}) {
|
|
|
3576
3617
|
if (usesColorVar) {
|
|
3577
3618
|
imports.push("__szColorVar");
|
|
3578
3619
|
}
|
|
3620
|
+
if (usesSpacingVar) {
|
|
3621
|
+
imports.push("__szSpacingVar");
|
|
3622
|
+
}
|
|
3623
|
+
if (usesUnitVar) {
|
|
3624
|
+
imports.push("__szUnitVar");
|
|
3625
|
+
}
|
|
3579
3626
|
const hasRuntimeImport = imports.length > 0 && transformedCode.includes("@csszyx/runtime");
|
|
3580
3627
|
const needed = hasRuntimeImport ? imports.filter((name) => !importsRuntimeHelper(transformedCode, name)) : imports;
|
|
3581
3628
|
if (needed.length > 0) {
|
|
@@ -3928,19 +3975,7 @@ ${transformedCode}`;
|
|
|
3928
3975
|
}
|
|
3929
3976
|
if (manglingEnabled && !isWebpackDevMode && Object.keys(state.mangleMap).length > 0) {
|
|
3930
3977
|
if (file.endsWith(".html")) {
|
|
3931
|
-
const mangledHtml = source
|
|
3932
|
-
/\bclass="([^"]*)"/g,
|
|
3933
|
-
(_m, cls) => {
|
|
3934
|
-
const out = cls.split(/\s+/).filter(Boolean).map((c) => state.mangleMap[c] || c).join(" ");
|
|
3935
|
-
return out !== cls ? `class="${out}"` : _m;
|
|
3936
|
-
}
|
|
3937
|
-
).replace(
|
|
3938
|
-
/\bclass='([^']*)'/g,
|
|
3939
|
-
(_m, cls) => {
|
|
3940
|
-
const out = cls.split(/\s+/).filter(Boolean).map((c) => state.mangleMap[c] || c).join(" ");
|
|
3941
|
-
return out !== cls ? `class='${out}'` : _m;
|
|
3942
|
-
}
|
|
3943
|
-
);
|
|
3978
|
+
const mangledHtml = mangleHtmlClasses(source);
|
|
3944
3979
|
if (mangledHtml !== source) {
|
|
3945
3980
|
compilation.updateAsset(
|
|
3946
3981
|
file,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
|
|
5
|
-
const CACHE_SCHEMA_VERSION =
|
|
5
|
+
const CACHE_SCHEMA_VERSION = 10;
|
|
6
6
|
function resolveTransformCacheDir(rootDir, cacheDir) {
|
|
7
7
|
return path.resolve(rootDir, cacheDir ?? ".csszyx/cache", "transform");
|
|
8
8
|
}
|
|
@@ -48,10 +48,7 @@ function writeTransformCache(cacheRoot, input, result, precomputedKey) {
|
|
|
48
48
|
const globalVarAliases = normalizeGlobalVarAliasEntries(input.globalVarAliases);
|
|
49
49
|
const file = cacheEntryPath(cacheRoot, key);
|
|
50
50
|
const dir = path.dirname(file);
|
|
51
|
-
const tmp = path.join(
|
|
52
|
-
dir,
|
|
53
|
-
`.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
54
|
-
);
|
|
51
|
+
const tmp = path.join(dir, `.tmp-${process.pid}-${Date.now()}-${randomUUID()}.json`);
|
|
55
52
|
const entry = {
|
|
56
53
|
version: CACHE_SCHEMA_VERSION,
|
|
57
54
|
pluginVersion: input.pluginVersion,
|
|
@@ -120,6 +117,8 @@ function serializeResult(result) {
|
|
|
120
117
|
usesSzcn: result.usesSzcn,
|
|
121
118
|
usesSzPart: result.usesSzPart,
|
|
122
119
|
usesColorVar: result.usesColorVar,
|
|
120
|
+
usesSpacingVar: result.usesSpacingVar,
|
|
121
|
+
usesUnitVar: result.usesUnitVar,
|
|
123
122
|
classes: [...result.classes],
|
|
124
123
|
rawClassNames: [...result.rawClassNames],
|
|
125
124
|
diagnostics: [...result.diagnostics],
|
|
@@ -136,6 +135,8 @@ function deserializeResult(result) {
|
|
|
136
135
|
usesSzcn: result.usesSzcn,
|
|
137
136
|
usesSzPart: result.usesSzPart,
|
|
138
137
|
usesColorVar: result.usesColorVar,
|
|
138
|
+
usesSpacingVar: result.usesSpacingVar,
|
|
139
|
+
usesUnitVar: result.usesUnitVar,
|
|
139
140
|
classes: new Set(result.classes),
|
|
140
141
|
rawClassNames: new Set(result.rawClassNames),
|
|
141
142
|
diagnostics: [...result.diagnostics],
|
|
@@ -152,7 +152,7 @@ function atomicWriteFileSync(file, content, options = {}) {
|
|
|
152
152
|
const dir = path__namespace.dirname(file);
|
|
153
153
|
const tmp = path__namespace.join(
|
|
154
154
|
dir,
|
|
155
|
-
`.tmp-${path__namespace.basename(file)}-${process.pid}-${Date.now()}-${
|
|
155
|
+
`.tmp-${path__namespace.basename(file)}-${process.pid}-${Date.now()}-${node_crypto.randomUUID()}`
|
|
156
156
|
);
|
|
157
157
|
fs__namespace.mkdirSync(dir, { recursive: true });
|
|
158
158
|
fs__namespace.writeFileSync(tmp, content, "utf8");
|
|
@@ -262,7 +262,7 @@ function createLockMetadata(options) {
|
|
|
262
262
|
return {
|
|
263
263
|
version: 1,
|
|
264
264
|
pid,
|
|
265
|
-
token: options.token ?? node_crypto.
|
|
265
|
+
token: options.token ?? node_crypto.randomUUID(),
|
|
266
266
|
hostname: node_os.hostname(),
|
|
267
267
|
root: path__namespace.resolve(options.root ?? process.cwd()),
|
|
268
268
|
mode: options.mode ?? "development",
|