@csszyx/unplugin 0.14.5 → 0.15.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/README.md +4 -3
- package/dist/index.cjs +8 -7
- package/dist/index.d.cts +70 -3
- package/dist/index.d.mts +70 -3
- package/dist/index.mjs +4 -4
- package/dist/next-config.d.cts +1 -2
- package/dist/next-config.d.mts +1 -2
- package/dist/next-prebuild.cjs +9 -5
- package/dist/next-prebuild.d.cts +4 -2
- package/dist/next-prebuild.d.mts +4 -2
- package/dist/next-prebuild.mjs +8 -4
- package/dist/next-turbo-loader.cjs +20 -14
- package/dist/next-turbo-loader.d.cts +1 -1
- package/dist/next-turbo-loader.d.mts +1 -1
- package/dist/next-turbo-loader.mjs +19 -13
- package/dist/next-watcher.cjs +2 -2
- package/dist/next-watcher.d.cts +2 -2
- package/dist/next-watcher.d.mts +2 -2
- package/dist/next-watcher.mjs +2 -2
- package/dist/postcss.cjs +124 -0
- package/dist/postcss.d.cts +42 -0
- package/dist/postcss.d.mts +42 -0
- package/dist/postcss.mjs +107 -0
- package/dist/shared/{unplugin.RGzhYt-D.cjs → unplugin.8KYddE6x.cjs} +394 -226
- package/dist/shared/{unplugin.CPEWNSA0.d.cts → unplugin.BGog1Bib.d.cts} +9 -6
- package/dist/shared/{unplugin.CPEWNSA0.d.mts → unplugin.BGog1Bib.d.mts} +9 -6
- package/dist/shared/{unplugin.BU0O4IkX.mjs → unplugin.BLptVbUe.mjs} +22 -61
- package/dist/shared/{unplugin.BXYakiXt.d.cts → unplugin.BT7PqYuK.d.cts} +53 -55
- package/dist/shared/{unplugin.BXYakiXt.d.mts → unplugin.BT7PqYuK.d.mts} +53 -55
- package/dist/shared/{unplugin.Cji6O5jv.cjs → unplugin.BWnmKv07.cjs} +32 -69
- package/dist/shared/{unplugin.NlPvn5P4.mjs → unplugin.Bk9o8_RZ.mjs} +2 -6
- package/dist/shared/{unplugin.VtXstzEh.cjs → unplugin.BzF0V2kw.cjs} +6 -11
- package/dist/shared/{unplugin.CdZxp0x-.d.mts → unplugin.COlI0dJs.d.mts} +1 -1
- package/dist/shared/{unplugin.BnRf0Tvd.mjs → unplugin.D68hyqgb.mjs} +347 -178
- package/dist/shared/{unplugin.DN95k991.mjs → unplugin.DAzgbtuZ.mjs} +2 -2
- package/dist/shared/unplugin.DDSWQJYX.cjs +289 -0
- package/dist/shared/unplugin.DH_ij6cf.mjs +258 -0
- package/dist/shared/{unplugin.BZPdvVcj.mjs → unplugin.DK0b4fr7.mjs} +105 -127
- package/dist/shared/{unplugin.D8BxOOkA.cjs → unplugin.J6ue_lRJ.cjs} +121 -142
- package/dist/shared/{unplugin.DVbPNK3W.cjs → unplugin.gksolKh2.cjs} +6 -6
- package/dist/shared/{unplugin.xeED_qwh.d.cts → unplugin.rWOMecQs.d.cts} +1 -1
- package/dist/vite.cjs +4 -4
- package/dist/vite.d.cts +2 -2
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +4 -4
- package/dist/webpack.cjs +4 -4
- package/dist/webpack.d.cts +2 -1
- package/dist/webpack.d.mts +1 -1
- package/dist/webpack.mjs +4 -4
- package/package.json +19 -9
- package/dist/shared/unplugin.B3XoSRB8.mjs +0 -40
- package/dist/shared/unplugin.BkRah5Ot.cjs +0 -48
|
@@ -2,9 +2,9 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { extractCrossModuleForwards, extractCrossModuleRegistryEntries, ensureRustTransformAvailable, transformRust, transformWasm, transform } from '@csszyx/compiler';
|
|
4
4
|
import { DEFAULT_IMPORTED_STATIC_SZ } from '@csszyx/types';
|
|
5
|
-
import { c as collectSpecifierAliases, i as importedSpecifiersIn, s as specifierBases, a as resolveProviderPathWith,
|
|
5
|
+
import { c as collectSpecifierAliases, i as importedSpecifiersIn, s as specifierBases, a as resolveProviderPathWith, b as recordResolvedEntry, f as forwardVisitKey, M as MAX_FORWARD_HOPS, d as isReadableProviderFile, e as createTransformCacheKey, g as readTransformCache, w as writeTransformCache } from './unplugin.Bk9o8_RZ.mjs';
|
|
6
|
+
import { n as normalizePathSeparators, s as sortStrings } from './unplugin.DH_ij6cf.mjs';
|
|
6
7
|
import { createHash } from 'node:crypto';
|
|
7
|
-
import { s as sortStrings } from './unplugin.B3XoSRB8.mjs';
|
|
8
8
|
|
|
9
9
|
function resolveImportedStaticSz(value) {
|
|
10
10
|
return value ?? DEFAULT_IMPORTED_STATIC_SZ;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const node_crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
function _interopNamespaceCompat(e) {
|
|
8
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
9
|
+
const n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
for (const k in e) {
|
|
12
|
+
n[k] = e[k];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
n.default = e;
|
|
16
|
+
return n;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
20
|
+
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
21
|
+
|
|
22
|
+
function sortStrings(values) {
|
|
23
|
+
return [...values].sort((a, b) => {
|
|
24
|
+
if (a < b) return -1;
|
|
25
|
+
if (a > b) return 1;
|
|
26
|
+
return 0;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const WINDOWS_PATH_SEPARATOR = String.fromCodePoint(92);
|
|
31
|
+
function normalizePathSeparators(value) {
|
|
32
|
+
return value.split(WINDOWS_PATH_SEPARATOR).join("/");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const DEFAULT_RENAME_RETRIES = 5;
|
|
36
|
+
const DEFAULT_RENAME_RETRY_DELAY_MS = 10;
|
|
37
|
+
function isRetryableRenameError(error) {
|
|
38
|
+
return typeof error === "object" && error !== null && "code" in error && (error.code === "EBUSY" || error.code === "EPERM" || error.code === "EACCES");
|
|
39
|
+
}
|
|
40
|
+
function sleepSync(ms) {
|
|
41
|
+
if (ms <= 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
45
|
+
}
|
|
46
|
+
function atomicRenameWithRetry(from, to, options = {}) {
|
|
47
|
+
const maxRetries = options.maxRetries ?? DEFAULT_RENAME_RETRIES;
|
|
48
|
+
const retryDelayMs = options.retryDelayMs ?? DEFAULT_RENAME_RETRY_DELAY_MS;
|
|
49
|
+
const renameSync = options.renameSync ?? fs__namespace.renameSync;
|
|
50
|
+
for (let attempt = 0; ; attempt++) {
|
|
51
|
+
try {
|
|
52
|
+
renameSync(from, to);
|
|
53
|
+
return;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (!isRetryableRenameError(error) || attempt >= maxRetries) {
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
sleepSync(retryDelayMs);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function atomicWriteFileSync(file, content, options = {}) {
|
|
63
|
+
const dir = path__namespace.dirname(file);
|
|
64
|
+
const tmp = path__namespace.join(
|
|
65
|
+
dir,
|
|
66
|
+
`.tmp-${path__namespace.basename(file)}-${process.pid}-${Date.now()}-${node_crypto.randomUUID()}`
|
|
67
|
+
);
|
|
68
|
+
fs__namespace.mkdirSync(dir, { recursive: true });
|
|
69
|
+
fs__namespace.writeFileSync(tmp, content, "utf8");
|
|
70
|
+
try {
|
|
71
|
+
atomicRenameWithRetry(tmp, file, options);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
try {
|
|
74
|
+
fs__namespace.rmSync(tmp, { force: true });
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const SAFELIST_HEADER = "# Auto-generated by csszyx \u2014 DO NOT EDIT\n# Tailwind scans this file for class names, one per line.\n";
|
|
82
|
+
function renderSafelistFile(classNames) {
|
|
83
|
+
if (classNames.length === 0) {
|
|
84
|
+
return SAFELIST_HEADER;
|
|
85
|
+
}
|
|
86
|
+
return `${SAFELIST_HEADER}${classNames.join("\n")}
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const SAFELIST_FILE = ".csszyx/csszyx-classes.txt";
|
|
91
|
+
const LEGACY_SAFELIST_FILES = [
|
|
92
|
+
"csszyx-classes.html",
|
|
93
|
+
".csszyx/next-loader-classes.html"
|
|
94
|
+
];
|
|
95
|
+
const LEGACY_HTML_MARKERS = [
|
|
96
|
+
"<!-- Auto-generated by csszyx",
|
|
97
|
+
"<!-- csszyx Next safelist",
|
|
98
|
+
"<!-- csszyx exact scanner candidates -->"
|
|
99
|
+
];
|
|
100
|
+
function removeLegacySafelists(rootDir, warn) {
|
|
101
|
+
for (const legacy of LEGACY_SAFELIST_FILES) {
|
|
102
|
+
const file = path__namespace.join(rootDir, legacy);
|
|
103
|
+
let content;
|
|
104
|
+
try {
|
|
105
|
+
content = fs__namespace.readFileSync(file, "utf8");
|
|
106
|
+
} catch {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (!LEGACY_HTML_MARKERS.some((marker) => content.includes(marker))) continue;
|
|
110
|
+
try {
|
|
111
|
+
fs__namespace.rmSync(file, { force: true });
|
|
112
|
+
} catch (error) {
|
|
113
|
+
const { message } = error;
|
|
114
|
+
warn(`[csszyx] could not remove ${legacy}: ${message}. Delete it by hand.`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
warn(
|
|
118
|
+
`[csszyx] removed ${legacy}: the safelist now lives at ${SAFELIST_FILE}. Update any hand-written @source that named the old file, or drop it and list '@csszyx/unplugin/postcss' before '@tailwindcss/postcss' in postcss.config.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const LEGACY_SAFELIST_BASENAMES = new Set(
|
|
123
|
+
LEGACY_SAFELIST_FILES.map((file) => path__namespace.posix.basename(file))
|
|
124
|
+
);
|
|
125
|
+
function isDanglingLegacySource(target, cssFile) {
|
|
126
|
+
if (!LEGACY_SAFELIST_BASENAMES.has(path__namespace.posix.basename(target))) return false;
|
|
127
|
+
return !fs__namespace.existsSync(path__namespace.resolve(path__namespace.dirname(cssFile), target));
|
|
128
|
+
}
|
|
129
|
+
function findLegacySourceDirective(code, cssFile) {
|
|
130
|
+
const withoutComments = stripCssBlockComments(code);
|
|
131
|
+
for (const match of withoutComments.matchAll(/@source\s+(["'])([^"']+)\1/g)) {
|
|
132
|
+
const target = match[2];
|
|
133
|
+
if (isDanglingLegacySource(target, cssFile)) {
|
|
134
|
+
return { directive: match[0], target };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const SKIPPED_DIRS = /* @__PURE__ */ new Set([
|
|
140
|
+
"node_modules",
|
|
141
|
+
".git",
|
|
142
|
+
".csszyx",
|
|
143
|
+
"dist",
|
|
144
|
+
"build",
|
|
145
|
+
"out",
|
|
146
|
+
"coverage",
|
|
147
|
+
".turbo",
|
|
148
|
+
".vercel"
|
|
149
|
+
]);
|
|
150
|
+
const STYLESHEET_EXTENSIONS = /* @__PURE__ */ new Set([".css", ".pcss", ".postcss"]);
|
|
151
|
+
function findLegacySourceStylesheet(rootDir) {
|
|
152
|
+
const pending = [rootDir];
|
|
153
|
+
while (pending.length > 0) {
|
|
154
|
+
const dir = pending.pop();
|
|
155
|
+
for (const entry of readDirectory(dir)) {
|
|
156
|
+
if (entry.isDirectory()) {
|
|
157
|
+
if (!isSkippedDirectory(entry.name)) pending.push(path__namespace.join(dir, entry.name));
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const found = readLegacySourceDirective(dir, entry);
|
|
161
|
+
if (found !== null) return found;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
function readDirectory(dir) {
|
|
167
|
+
try {
|
|
168
|
+
return fs__namespace.readdirSync(dir, { withFileTypes: true });
|
|
169
|
+
} catch {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function isSkippedDirectory(name) {
|
|
174
|
+
return SKIPPED_DIRS.has(name) || name.startsWith(".next");
|
|
175
|
+
}
|
|
176
|
+
function readLegacySourceDirective(dir, entry) {
|
|
177
|
+
if (!entry.isFile() || !STYLESHEET_EXTENSIONS.has(path__namespace.extname(entry.name))) return null;
|
|
178
|
+
const file = path__namespace.join(dir, entry.name);
|
|
179
|
+
const code = fs__namespace.readFileSync(file, "utf8");
|
|
180
|
+
if (!code.includes("@source")) return null;
|
|
181
|
+
const found = findLegacySourceDirective(code, file);
|
|
182
|
+
return found === null ? null : { file, ...found };
|
|
183
|
+
}
|
|
184
|
+
const ROOTS_WITHOUT_LEGACY_SOURCE = /* @__PURE__ */ new Set();
|
|
185
|
+
function assertNoLegacySourceStylesheet(rootDir) {
|
|
186
|
+
if (ROOTS_WITHOUT_LEGACY_SOURCE.has(rootDir)) return;
|
|
187
|
+
const found = findLegacySourceStylesheet(rootDir);
|
|
188
|
+
if (found !== null) throw new Error(legacySourceMessage(found.file, found.target));
|
|
189
|
+
ROOTS_WITHOUT_LEGACY_SOURCE.add(rootDir);
|
|
190
|
+
}
|
|
191
|
+
const CSSZYX_POSTCSS_PLUGIN = "@csszyx/unplugin/postcss";
|
|
192
|
+
const POSTCSS_CONFIG_FILES = [
|
|
193
|
+
".postcssrc.json",
|
|
194
|
+
"postcss.config.json",
|
|
195
|
+
".postcssrc.js",
|
|
196
|
+
"postcss.config.js",
|
|
197
|
+
"postcss.config.mjs",
|
|
198
|
+
"postcss.config.cjs"
|
|
199
|
+
];
|
|
200
|
+
function findPostcssConfigWithoutCsszyx(rootDir) {
|
|
201
|
+
const packageJson = path__namespace.join(rootDir, "package.json");
|
|
202
|
+
let postcssKey;
|
|
203
|
+
try {
|
|
204
|
+
postcssKey = JSON.parse(fs__namespace.readFileSync(packageJson, "utf8")).postcss;
|
|
205
|
+
} catch {
|
|
206
|
+
postcssKey = void 0;
|
|
207
|
+
}
|
|
208
|
+
if (postcssKey !== void 0) {
|
|
209
|
+
return JSON.stringify(postcssKey).includes(CSSZYX_POSTCSS_PLUGIN) ? null : packageJson;
|
|
210
|
+
}
|
|
211
|
+
for (const name of POSTCSS_CONFIG_FILES) {
|
|
212
|
+
const file = path__namespace.join(rootDir, name);
|
|
213
|
+
let text;
|
|
214
|
+
try {
|
|
215
|
+
text = fs__namespace.readFileSync(file, "utf8");
|
|
216
|
+
} catch {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
return text.includes(CSSZYX_POSTCSS_PLUGIN) ? null : file;
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
function missingPostcssPluginMessage(configFile) {
|
|
224
|
+
return `[csszyx] ${configFile} does not list '@csszyx/unplugin/postcss'. Next.js reads the safelist only through that plugin: list it before '@tailwindcss/postcss', or no sz class gets CSS.`;
|
|
225
|
+
}
|
|
226
|
+
function legacySourceMessage(cssFile, target) {
|
|
227
|
+
return `[csszyx] ${cssFile}: @source "${target}" names the old safelist, which csszyx no longer writes. The safelist is now ${SAFELIST_FILE}, and csszyx adds the directive itself: remove this line. Vite, Rollup and webpack inject it; on Next.js list '@csszyx/unplugin/postcss' before '@tailwindcss/postcss' in postcss.config.`;
|
|
228
|
+
}
|
|
229
|
+
const TAILWIND_SPECIFIER = String.raw`["']tailwindcss(?:\/[^"']*)?["']`;
|
|
230
|
+
const TAILWIND_IMPORT = new RegExp(String.raw`@import\s+${TAILWIND_SPECIFIER}`);
|
|
231
|
+
function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
|
|
232
|
+
const safelistPath = normalizePathSeparators(path__namespace.join(rootDir, safelistFilename));
|
|
233
|
+
const cssDir = normalizePathSeparators(path__namespace.dirname(cssId));
|
|
234
|
+
let relPath = path__namespace.posix.relative(cssDir, safelistPath);
|
|
235
|
+
if (!relPath.startsWith("./") && !relPath.startsWith("../")) {
|
|
236
|
+
relPath = `./${relPath}`;
|
|
237
|
+
}
|
|
238
|
+
return relPath;
|
|
239
|
+
}
|
|
240
|
+
function appendTailwindSourceDirective(code, relPath) {
|
|
241
|
+
const directive = `@source "${relPath}";`;
|
|
242
|
+
if (code.includes(directive)) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const separator = code.length === 0 || code.endsWith("\n") ? "" : "\n";
|
|
246
|
+
return `${code}${separator}${directive}
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
function stripCssBlockComments(code) {
|
|
250
|
+
const SLASH = 47;
|
|
251
|
+
const STAR = 42;
|
|
252
|
+
let out = "";
|
|
253
|
+
let last = 0;
|
|
254
|
+
let i = 0;
|
|
255
|
+
const n = code.length;
|
|
256
|
+
while (i < n) {
|
|
257
|
+
if (code.codePointAt(i) === SLASH && code.codePointAt(i + 1) === STAR) {
|
|
258
|
+
out += code.slice(last, i);
|
|
259
|
+
i += 2;
|
|
260
|
+
while (i < n && !(code.codePointAt(i) === STAR && code.codePointAt(i + 1) === SLASH)) {
|
|
261
|
+
i++;
|
|
262
|
+
}
|
|
263
|
+
i += 2;
|
|
264
|
+
last = i;
|
|
265
|
+
} else {
|
|
266
|
+
i++;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return out + code.slice(last);
|
|
270
|
+
}
|
|
271
|
+
function cssImportsTailwind(code) {
|
|
272
|
+
return TAILWIND_IMPORT.test(stripCssBlockComments(code));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
exports.SAFELIST_FILE = SAFELIST_FILE;
|
|
276
|
+
exports.appendTailwindSourceDirective = appendTailwindSourceDirective;
|
|
277
|
+
exports.assertNoLegacySourceStylesheet = assertNoLegacySourceStylesheet;
|
|
278
|
+
exports.atomicWriteFileSync = atomicWriteFileSync;
|
|
279
|
+
exports.computeSafelistRelPath = computeSafelistRelPath;
|
|
280
|
+
exports.cssImportsTailwind = cssImportsTailwind;
|
|
281
|
+
exports.findLegacySourceDirective = findLegacySourceDirective;
|
|
282
|
+
exports.findPostcssConfigWithoutCsszyx = findPostcssConfigWithoutCsszyx;
|
|
283
|
+
exports.legacySourceMessage = legacySourceMessage;
|
|
284
|
+
exports.missingPostcssPluginMessage = missingPostcssPluginMessage;
|
|
285
|
+
exports.normalizePathSeparators = normalizePathSeparators;
|
|
286
|
+
exports.removeLegacySafelists = removeLegacySafelists;
|
|
287
|
+
exports.renderSafelistFile = renderSafelistFile;
|
|
288
|
+
exports.sortStrings = sortStrings;
|
|
289
|
+
exports.stripCssBlockComments = stripCssBlockComments;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
|
|
5
|
+
function sortStrings(values) {
|
|
6
|
+
return [...values].sort((a, b) => {
|
|
7
|
+
if (a < b) return -1;
|
|
8
|
+
if (a > b) return 1;
|
|
9
|
+
return 0;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const WINDOWS_PATH_SEPARATOR = String.fromCodePoint(92);
|
|
14
|
+
function normalizePathSeparators(value) {
|
|
15
|
+
return value.split(WINDOWS_PATH_SEPARATOR).join("/");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DEFAULT_RENAME_RETRIES = 5;
|
|
19
|
+
const DEFAULT_RENAME_RETRY_DELAY_MS = 10;
|
|
20
|
+
function isRetryableRenameError(error) {
|
|
21
|
+
return typeof error === "object" && error !== null && "code" in error && (error.code === "EBUSY" || error.code === "EPERM" || error.code === "EACCES");
|
|
22
|
+
}
|
|
23
|
+
function sleepSync(ms) {
|
|
24
|
+
if (ms <= 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
28
|
+
}
|
|
29
|
+
function atomicRenameWithRetry(from, to, options = {}) {
|
|
30
|
+
const maxRetries = options.maxRetries ?? DEFAULT_RENAME_RETRIES;
|
|
31
|
+
const retryDelayMs = options.retryDelayMs ?? DEFAULT_RENAME_RETRY_DELAY_MS;
|
|
32
|
+
const renameSync = options.renameSync ?? fs.renameSync;
|
|
33
|
+
for (let attempt = 0; ; attempt++) {
|
|
34
|
+
try {
|
|
35
|
+
renameSync(from, to);
|
|
36
|
+
return;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (!isRetryableRenameError(error) || attempt >= maxRetries) {
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
sleepSync(retryDelayMs);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function atomicWriteFileSync(file, content, options = {}) {
|
|
46
|
+
const dir = path.dirname(file);
|
|
47
|
+
const tmp = path.join(
|
|
48
|
+
dir,
|
|
49
|
+
`.tmp-${path.basename(file)}-${process.pid}-${Date.now()}-${randomUUID()}`
|
|
50
|
+
);
|
|
51
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
52
|
+
fs.writeFileSync(tmp, content, "utf8");
|
|
53
|
+
try {
|
|
54
|
+
atomicRenameWithRetry(tmp, file, options);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
try {
|
|
57
|
+
fs.rmSync(tmp, { force: true });
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const SAFELIST_HEADER = "# Auto-generated by csszyx \u2014 DO NOT EDIT\n# Tailwind scans this file for class names, one per line.\n";
|
|
65
|
+
function renderSafelistFile(classNames) {
|
|
66
|
+
if (classNames.length === 0) {
|
|
67
|
+
return SAFELIST_HEADER;
|
|
68
|
+
}
|
|
69
|
+
return `${SAFELIST_HEADER}${classNames.join("\n")}
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const SAFELIST_FILE = ".csszyx/csszyx-classes.txt";
|
|
74
|
+
const LEGACY_SAFELIST_FILES = [
|
|
75
|
+
"csszyx-classes.html",
|
|
76
|
+
".csszyx/next-loader-classes.html"
|
|
77
|
+
];
|
|
78
|
+
const LEGACY_HTML_MARKERS = [
|
|
79
|
+
"<!-- Auto-generated by csszyx",
|
|
80
|
+
"<!-- csszyx Next safelist",
|
|
81
|
+
"<!-- csszyx exact scanner candidates -->"
|
|
82
|
+
];
|
|
83
|
+
function removeLegacySafelists(rootDir, warn) {
|
|
84
|
+
for (const legacy of LEGACY_SAFELIST_FILES) {
|
|
85
|
+
const file = path.join(rootDir, legacy);
|
|
86
|
+
let content;
|
|
87
|
+
try {
|
|
88
|
+
content = fs.readFileSync(file, "utf8");
|
|
89
|
+
} catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!LEGACY_HTML_MARKERS.some((marker) => content.includes(marker))) continue;
|
|
93
|
+
try {
|
|
94
|
+
fs.rmSync(file, { force: true });
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const { message } = error;
|
|
97
|
+
warn(`[csszyx] could not remove ${legacy}: ${message}. Delete it by hand.`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
warn(
|
|
101
|
+
`[csszyx] removed ${legacy}: the safelist now lives at ${SAFELIST_FILE}. Update any hand-written @source that named the old file, or drop it and list '@csszyx/unplugin/postcss' before '@tailwindcss/postcss' in postcss.config.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const LEGACY_SAFELIST_BASENAMES = new Set(
|
|
106
|
+
LEGACY_SAFELIST_FILES.map((file) => path.posix.basename(file))
|
|
107
|
+
);
|
|
108
|
+
function isDanglingLegacySource(target, cssFile) {
|
|
109
|
+
if (!LEGACY_SAFELIST_BASENAMES.has(path.posix.basename(target))) return false;
|
|
110
|
+
return !fs.existsSync(path.resolve(path.dirname(cssFile), target));
|
|
111
|
+
}
|
|
112
|
+
function findLegacySourceDirective(code, cssFile) {
|
|
113
|
+
const withoutComments = stripCssBlockComments(code);
|
|
114
|
+
for (const match of withoutComments.matchAll(/@source\s+(["'])([^"']+)\1/g)) {
|
|
115
|
+
const target = match[2];
|
|
116
|
+
if (isDanglingLegacySource(target, cssFile)) {
|
|
117
|
+
return { directive: match[0], target };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const SKIPPED_DIRS = /* @__PURE__ */ new Set([
|
|
123
|
+
"node_modules",
|
|
124
|
+
".git",
|
|
125
|
+
".csszyx",
|
|
126
|
+
"dist",
|
|
127
|
+
"build",
|
|
128
|
+
"out",
|
|
129
|
+
"coverage",
|
|
130
|
+
".turbo",
|
|
131
|
+
".vercel"
|
|
132
|
+
]);
|
|
133
|
+
const STYLESHEET_EXTENSIONS = /* @__PURE__ */ new Set([".css", ".pcss", ".postcss"]);
|
|
134
|
+
function findLegacySourceStylesheet(rootDir) {
|
|
135
|
+
const pending = [rootDir];
|
|
136
|
+
while (pending.length > 0) {
|
|
137
|
+
const dir = pending.pop();
|
|
138
|
+
for (const entry of readDirectory(dir)) {
|
|
139
|
+
if (entry.isDirectory()) {
|
|
140
|
+
if (!isSkippedDirectory(entry.name)) pending.push(path.join(dir, entry.name));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const found = readLegacySourceDirective(dir, entry);
|
|
144
|
+
if (found !== null) return found;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
function readDirectory(dir) {
|
|
150
|
+
try {
|
|
151
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
152
|
+
} catch {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function isSkippedDirectory(name) {
|
|
157
|
+
return SKIPPED_DIRS.has(name) || name.startsWith(".next");
|
|
158
|
+
}
|
|
159
|
+
function readLegacySourceDirective(dir, entry) {
|
|
160
|
+
if (!entry.isFile() || !STYLESHEET_EXTENSIONS.has(path.extname(entry.name))) return null;
|
|
161
|
+
const file = path.join(dir, entry.name);
|
|
162
|
+
const code = fs.readFileSync(file, "utf8");
|
|
163
|
+
if (!code.includes("@source")) return null;
|
|
164
|
+
const found = findLegacySourceDirective(code, file);
|
|
165
|
+
return found === null ? null : { file, ...found };
|
|
166
|
+
}
|
|
167
|
+
const ROOTS_WITHOUT_LEGACY_SOURCE = /* @__PURE__ */ new Set();
|
|
168
|
+
function assertNoLegacySourceStylesheet(rootDir) {
|
|
169
|
+
if (ROOTS_WITHOUT_LEGACY_SOURCE.has(rootDir)) return;
|
|
170
|
+
const found = findLegacySourceStylesheet(rootDir);
|
|
171
|
+
if (found !== null) throw new Error(legacySourceMessage(found.file, found.target));
|
|
172
|
+
ROOTS_WITHOUT_LEGACY_SOURCE.add(rootDir);
|
|
173
|
+
}
|
|
174
|
+
const CSSZYX_POSTCSS_PLUGIN = "@csszyx/unplugin/postcss";
|
|
175
|
+
const POSTCSS_CONFIG_FILES = [
|
|
176
|
+
".postcssrc.json",
|
|
177
|
+
"postcss.config.json",
|
|
178
|
+
".postcssrc.js",
|
|
179
|
+
"postcss.config.js",
|
|
180
|
+
"postcss.config.mjs",
|
|
181
|
+
"postcss.config.cjs"
|
|
182
|
+
];
|
|
183
|
+
function findPostcssConfigWithoutCsszyx(rootDir) {
|
|
184
|
+
const packageJson = path.join(rootDir, "package.json");
|
|
185
|
+
let postcssKey;
|
|
186
|
+
try {
|
|
187
|
+
postcssKey = JSON.parse(fs.readFileSync(packageJson, "utf8")).postcss;
|
|
188
|
+
} catch {
|
|
189
|
+
postcssKey = void 0;
|
|
190
|
+
}
|
|
191
|
+
if (postcssKey !== void 0) {
|
|
192
|
+
return JSON.stringify(postcssKey).includes(CSSZYX_POSTCSS_PLUGIN) ? null : packageJson;
|
|
193
|
+
}
|
|
194
|
+
for (const name of POSTCSS_CONFIG_FILES) {
|
|
195
|
+
const file = path.join(rootDir, name);
|
|
196
|
+
let text;
|
|
197
|
+
try {
|
|
198
|
+
text = fs.readFileSync(file, "utf8");
|
|
199
|
+
} catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
return text.includes(CSSZYX_POSTCSS_PLUGIN) ? null : file;
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
function missingPostcssPluginMessage(configFile) {
|
|
207
|
+
return `[csszyx] ${configFile} does not list '@csszyx/unplugin/postcss'. Next.js reads the safelist only through that plugin: list it before '@tailwindcss/postcss', or no sz class gets CSS.`;
|
|
208
|
+
}
|
|
209
|
+
function legacySourceMessage(cssFile, target) {
|
|
210
|
+
return `[csszyx] ${cssFile}: @source "${target}" names the old safelist, which csszyx no longer writes. The safelist is now ${SAFELIST_FILE}, and csszyx adds the directive itself: remove this line. Vite, Rollup and webpack inject it; on Next.js list '@csszyx/unplugin/postcss' before '@tailwindcss/postcss' in postcss.config.`;
|
|
211
|
+
}
|
|
212
|
+
const TAILWIND_SPECIFIER = String.raw`["']tailwindcss(?:\/[^"']*)?["']`;
|
|
213
|
+
const TAILWIND_IMPORT = new RegExp(String.raw`@import\s+${TAILWIND_SPECIFIER}`);
|
|
214
|
+
function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
|
|
215
|
+
const safelistPath = normalizePathSeparators(path.join(rootDir, safelistFilename));
|
|
216
|
+
const cssDir = normalizePathSeparators(path.dirname(cssId));
|
|
217
|
+
let relPath = path.posix.relative(cssDir, safelistPath);
|
|
218
|
+
if (!relPath.startsWith("./") && !relPath.startsWith("../")) {
|
|
219
|
+
relPath = `./${relPath}`;
|
|
220
|
+
}
|
|
221
|
+
return relPath;
|
|
222
|
+
}
|
|
223
|
+
function appendTailwindSourceDirective(code, relPath) {
|
|
224
|
+
const directive = `@source "${relPath}";`;
|
|
225
|
+
if (code.includes(directive)) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
const separator = code.length === 0 || code.endsWith("\n") ? "" : "\n";
|
|
229
|
+
return `${code}${separator}${directive}
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
function stripCssBlockComments(code) {
|
|
233
|
+
const SLASH = 47;
|
|
234
|
+
const STAR = 42;
|
|
235
|
+
let out = "";
|
|
236
|
+
let last = 0;
|
|
237
|
+
let i = 0;
|
|
238
|
+
const n = code.length;
|
|
239
|
+
while (i < n) {
|
|
240
|
+
if (code.codePointAt(i) === SLASH && code.codePointAt(i + 1) === STAR) {
|
|
241
|
+
out += code.slice(last, i);
|
|
242
|
+
i += 2;
|
|
243
|
+
while (i < n && !(code.codePointAt(i) === STAR && code.codePointAt(i + 1) === SLASH)) {
|
|
244
|
+
i++;
|
|
245
|
+
}
|
|
246
|
+
i += 2;
|
|
247
|
+
last = i;
|
|
248
|
+
} else {
|
|
249
|
+
i++;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return out + code.slice(last);
|
|
253
|
+
}
|
|
254
|
+
function cssImportsTailwind(code) {
|
|
255
|
+
return TAILWIND_IMPORT.test(stripCssBlockComments(code));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { SAFELIST_FILE as S, appendTailwindSourceDirective as a, cssImportsTailwind as b, computeSafelistRelPath as c, atomicWriteFileSync as d, removeLegacySafelists as e, findPostcssConfigWithoutCsszyx as f, assertNoLegacySourceStylesheet as g, stripCssBlockComments as h, findLegacySourceDirective as i, legacySourceMessage as l, missingPostcssPluginMessage as m, normalizePathSeparators as n, renderSafelistFile as r, sortStrings as s };
|