@csszyx/unplugin 0.11.6 → 0.11.8

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.
Files changed (41) hide show
  1. package/README.md +6 -1
  2. package/dist/css-mangler.cjs +44 -41
  3. package/dist/css-mangler.mjs +44 -41
  4. package/dist/index.cjs +5 -4
  5. package/dist/index.d.cts +2 -2
  6. package/dist/index.d.mts +2 -2
  7. package/dist/index.mjs +4 -4
  8. package/dist/next-config.cjs +1 -1
  9. package/dist/next-config.mjs +1 -1
  10. package/dist/next-prebuild.cjs +5 -5
  11. package/dist/next-prebuild.mjs +5 -5
  12. package/dist/next-turbo-loader.cjs +13 -12
  13. package/dist/next-turbo-loader.mjs +13 -12
  14. package/dist/next-watcher.cjs +2 -2
  15. package/dist/next-watcher.mjs +2 -2
  16. package/dist/shared/{unplugin.BFN_Ueyx.cjs → unplugin.C9dMG7ye.cjs} +7 -5
  17. package/dist/shared/{unplugin.PhOFTQpB.d.cts → unplugin.CNwV3RrQ.d.cts} +18 -5
  18. package/dist/shared/{unplugin.PhOFTQpB.d.mts → unplugin.CNwV3RrQ.d.mts} +18 -5
  19. package/dist/shared/unplugin.CcA7jP1r.cjs +48 -0
  20. package/dist/shared/{unplugin.ByzV6iZE.mjs → unplugin.D-K57LNR.mjs} +13 -7
  21. package/dist/shared/{unplugin.D0N9bprz.cjs → unplugin.DVCQC5wq.cjs} +12 -5
  22. package/dist/shared/{unplugin.CBKZoxQ1.cjs → unplugin.DdtOZANG.cjs} +51 -50
  23. package/dist/shared/{unplugin.ChwZMl_w.mjs → unplugin.Dg1tGPSd.mjs} +8 -6
  24. package/dist/shared/{unplugin.Rov-j_Wm.cjs → unplugin.DmuOKVS4.cjs} +21 -0
  25. package/dist/shared/{unplugin.CP2cz9bA.cjs → unplugin.DtPQz8Kg.cjs} +1291 -938
  26. package/dist/shared/{unplugin.BS60onPk.mjs → unplugin.DtYxS8M8.mjs} +1290 -938
  27. package/dist/shared/{unplugin.B3cvNxnk.mjs → unplugin.Rl8sIkHi.mjs} +51 -50
  28. package/dist/shared/unplugin.TtmP77BS.mjs +40 -0
  29. package/dist/shared/unplugin.nnsa7OVW.mjs +49 -0
  30. package/dist/vite.cjs +4 -4
  31. package/dist/vite.d.cts +2 -25
  32. package/dist/vite.d.mts +1 -25
  33. package/dist/vite.mjs +4 -8
  34. package/dist/webpack.cjs +4 -4
  35. package/dist/webpack.d.cts +2 -5
  36. package/dist/webpack.d.mts +1 -5
  37. package/dist/webpack.mjs +4 -8
  38. package/package.json +7 -7
  39. package/dist/shared/unplugin.B1mblcm-.mjs +0 -9
  40. package/dist/shared/unplugin.B3RHYokB.mjs +0 -29
  41. package/dist/shared/unplugin.BCwRIUs_.cjs +0 -12
@@ -430,12 +430,17 @@ interface PluginState {
430
430
  /** Memoized `isMonorepoPackage(rootDir)` result; `undefined` until computed. */
431
431
  inMonorepo?: boolean;
432
432
  /**
433
- * Classes csszyx generated by lowering `sz` props the ONLY classes the
434
- * mangle map may rename. Author-written `className` values are deliberately
435
- * excluded: renaming them would break selectors an external stylesheet (or
436
- * JS that references classes by name) owns.
433
+ * Classes csszyx generated by lowering `sz` props. Final map eligibility
434
+ * subtracts authoredClasses because a class can be both generated and used
435
+ * by a raw selector consumer.
437
436
  */
438
437
  ownedClasses: Set<string>;
438
+ /**
439
+ * Classes written through author-facing class/className attributes. Any
440
+ * overlap with ownedClasses must keep its original name because bundled
441
+ * helper calls may not preserve enough context for safe string rewriting.
442
+ */
443
+ authoredClasses: Set<string>;
439
444
  /** Unresolvable-spread warnings surfaced to the build log in every mode. */
440
445
  spreadWarnings: Set<string>;
441
446
  /**
@@ -706,6 +711,14 @@ declare function isHardIgnoredPath(id: string, sourceDirs?: readonly string[]):
706
711
  * @returns true when the file should be prescanned for safelist extraction.
707
712
  */
708
713
  declare function fileMayContainSafelistableSz(content: string): boolean;
714
+ /**
715
+ * Return csszyx-owned classes that are safe to rename.
716
+ *
717
+ * @param ownedClasses Classes emitted from sz transforms.
718
+ * @param authoredClasses Classes also written in class/className source positions.
719
+ * @returns Owned classes with hybrid raw consumers removed.
720
+ */
721
+ declare function mangleEligibleClasses(ownedClasses: ReadonlySet<string>, authoredClasses: ReadonlySet<string>): string[];
709
722
  /**
710
723
  * Whether a file is workspace-package source that csszyx skipped only because it
711
724
  * lives under `/packages/` and is not under any opted-in `compileSources`
@@ -836,5 +849,5 @@ declare const rollupPlugin: (options?: PartialCsszyxConfig) => InputPluginOption
836
849
  */
837
850
  declare const esbuildPlugin: (options?: PartialCsszyxConfig) => Plugin;
838
851
 
839
- export { missingTailwindEntryMessage as $, unplugin as A, deleteRSCModuleRecord as B, esbuildPlugin as D, extractGlobalVarAliasesForManifest as E, fileMayContainSafelistableSz as F, findLocalImportSources as H, findRSCBoundaryViolation as I, findRSCGraphViolation as J, hasInjectableTailwindCandidate as K, hasTokens as L, hasUseClientDirective as N, hasUseServerDirective as O, isCompileSourceOptedIn as Q, isHardIgnoredPath as T, isMonorepoPackage as U, isPackagesSkippedSource as W, isRSCServerModule as X, mangleCodeClassesSync as Y, mangleHybridHazardMessage as Z, mergeThemes as _, normalizeGlobalVarAliasesForCache as a0, parseThemeBlocks as a1, recordGlobalVarSourceFile as a2, resolveCompileSourceDirs as a3, resolveNativeCacheIdentity as a4, rollupPlugin as a5, scanCustomPropertyNames as a6, shouldEmitWarning as a7, shouldTrackGlobalVarSources as a8, shouldWarnMissingTailwindEntry as a9, shouldWarnUnscopedMonorepo as aa, skippedSzFilesMessage as ab, unscopedMonorepoMessage as ac, vitePlugin as ad, webpackPlugin as ae, appendTailwindSourceDirective as r, assertNoRSCBoundaryViolation as s, assertNoRSCGraphViolation as t, collectMangleHybridHazards as u, computeSafelistRelPath as v, createGlobalVarMapAssetSource as w, createRSCModuleRecord as x, cssHasContentScope as y, cssImportsTailwind as z };
852
+ export { mergeThemes as $, unplugin as A, deleteRSCModuleRecord as B, esbuildPlugin as D, extractGlobalVarAliasesForManifest as E, fileMayContainSafelistableSz as F, findLocalImportSources as H, findRSCBoundaryViolation as I, findRSCGraphViolation as J, hasInjectableTailwindCandidate as K, hasTokens as L, hasUseClientDirective as N, hasUseServerDirective as O, isCompileSourceOptedIn as Q, isHardIgnoredPath as T, isMonorepoPackage as U, isPackagesSkippedSource as W, isRSCServerModule as X, mangleCodeClassesSync as Y, mangleEligibleClasses as Z, mangleHybridHazardMessage as _, missingTailwindEntryMessage as a0, normalizeGlobalVarAliasesForCache as a1, parseThemeBlocks as a2, recordGlobalVarSourceFile as a3, resolveCompileSourceDirs as a4, resolveNativeCacheIdentity as a5, rollupPlugin as a6, scanCustomPropertyNames as a7, shouldEmitWarning as a8, shouldTrackGlobalVarSources as a9, shouldWarnMissingTailwindEntry as aa, shouldWarnUnscopedMonorepo as ab, skippedSzFilesMessage as ac, unscopedMonorepoMessage as ad, vitePlugin as ae, webpackPlugin as af, appendTailwindSourceDirective as r, assertNoRSCBoundaryViolation as s, assertNoRSCGraphViolation as t, collectMangleHybridHazards as u, computeSafelistRelPath as v, createGlobalVarMapAssetSource as w, createRSCModuleRecord as x, cssHasContentScope as y, cssImportsTailwind as z };
840
853
  export type { CssVarScanResult as C, GlobalVarScanCacheKeyInput as G, MangleHybridHazards as M, PlanGlobalVarAliasesInput as P, RewriteGlobalVarCssAliasesOptions as R, ScanGlobalVarCssOptions as S, ValidateGlobalVarAliasInputsOptions as V, GlobalVarAliasPlan as a, GlobalVarCssAliasRewriteResult as b, CreateGlobalVarAliasValidationOptionsInput as c, GlobalVarAliasValidationResult as d, CssVarDefinition as e, CssVarLocation as f, CssVarReference as g, GlobalVarAliasDiagnostic as h, GlobalVarAliasDiagnosticSeverity as i, GlobalVarAliasEntry as j, GlobalVarCodeSource as k, GlobalVarCssAssetSource as l, GlobalVarCssSource as m, GlobalVarScanCacheEntry as n, ParsedTheme as o, RSCBoundaryViolation as p, RSCModuleRecord as q };
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ function sortStrings(values) {
4
+ return [...values].sort((a, b) => {
5
+ if (a < b) return -1;
6
+ if (a > b) return 1;
7
+ return 0;
8
+ });
9
+ }
10
+
11
+ const BACKSLASH = String.fromCodePoint(92);
12
+ function unicodeEscape(hexadecimal) {
13
+ return `${BACKSLASH}u${hexadecimal}`;
14
+ }
15
+ function replaceEveryLiteral(value, search, replacement) {
16
+ return value.split(search).join(replacement);
17
+ }
18
+ function escapeSingleQuotedString(value) {
19
+ let escaped = replaceEveryLiteral(value, BACKSLASH, BACKSLASH.repeat(2));
20
+ escaped = replaceEveryLiteral(escaped, "'", `${BACKSLASH}'`);
21
+ escaped = replaceEveryLiteral(escaped, "\r", `${BACKSLASH}r`);
22
+ return replaceEveryLiteral(escaped, "\n", `${BACKSLASH}n`);
23
+ }
24
+ function escapeDoubleQuotedString(value) {
25
+ const escaped = replaceEveryLiteral(value, BACKSLASH, BACKSLASH.repeat(2));
26
+ return replaceEveryLiteral(escaped, '"', `${BACKSLASH}"`);
27
+ }
28
+
29
+ function escapeHtmlAttribute(value) {
30
+ let escaped = replaceEveryLiteral(value, "&", "&amp;");
31
+ escaped = replaceEveryLiteral(escaped, '"', "&quot;");
32
+ escaped = replaceEveryLiteral(escaped, "<", "&lt;");
33
+ return replaceEveryLiteral(escaped, ">", "&gt;");
34
+ }
35
+ const RAW_SAFELIST_MARKER = "<!-- csszyx exact scanner candidates -->";
36
+ function renderTailwindScannerCandidates(classNames) {
37
+ return `${RAW_SAFELIST_MARKER}
38
+ ${classNames.join("\n")}
39
+ `;
40
+ }
41
+
42
+ exports.escapeDoubleQuotedString = escapeDoubleQuotedString;
43
+ exports.escapeHtmlAttribute = escapeHtmlAttribute;
44
+ exports.escapeSingleQuotedString = escapeSingleQuotedString;
45
+ exports.renderTailwindScannerCandidates = renderTailwindScannerCandidates;
46
+ exports.replaceEveryLiteral = replaceEveryLiteral;
47
+ exports.sortStrings = sortStrings;
48
+ exports.unicodeEscape = unicodeEscape;
@@ -1,8 +1,13 @@
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 = 9;
5
+ const WINDOWS_PATH_SEPARATOR = String.fromCodePoint(92);
6
+ function normalizePathSeparators(value) {
7
+ return value.split(WINDOWS_PATH_SEPARATOR).join("/");
8
+ }
9
+
10
+ const CACHE_SCHEMA_VERSION = 10;
6
11
  function resolveTransformCacheDir(rootDir, cacheDir) {
7
12
  return path.resolve(rootDir, cacheDir ?? ".csszyx/cache", "transform");
8
13
  }
@@ -48,10 +53,7 @@ function writeTransformCache(cacheRoot, input, result, precomputedKey) {
48
53
  const globalVarAliases = normalizeGlobalVarAliasEntries(input.globalVarAliases);
49
54
  const file = cacheEntryPath(cacheRoot, key);
50
55
  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
- );
56
+ const tmp = path.join(dir, `.tmp-${process.pid}-${Date.now()}-${randomUUID()}.json`);
55
57
  const entry = {
56
58
  version: CACHE_SCHEMA_VERSION,
57
59
  pluginVersion: input.pluginVersion,
@@ -120,6 +122,8 @@ function serializeResult(result) {
120
122
  usesSzcn: result.usesSzcn,
121
123
  usesSzPart: result.usesSzPart,
122
124
  usesColorVar: result.usesColorVar,
125
+ usesSpacingVar: result.usesSpacingVar,
126
+ usesUnitVar: result.usesUnitVar,
123
127
  classes: [...result.classes],
124
128
  rawClassNames: [...result.rawClassNames],
125
129
  diagnostics: [...result.diagnostics],
@@ -136,6 +140,8 @@ function deserializeResult(result) {
136
140
  usesSzcn: result.usesSzcn,
137
141
  usesSzPart: result.usesSzPart,
138
142
  usesColorVar: result.usesColorVar,
143
+ usesSpacingVar: result.usesSpacingVar,
144
+ usesUnitVar: result.usesUnitVar,
139
145
  classes: new Set(result.classes),
140
146
  rawClassNames: new Set(result.rawClassNames),
141
147
  diagnostics: [...result.diagnostics],
@@ -200,4 +206,4 @@ function evictMemoryCacheToBudget(cache, totalCodeChars, maxEntries, maxCodeChar
200
206
  return total;
201
207
  }
202
208
 
203
- export { readTransformCache as a, evictMemoryCacheToBudget as b, createTransformCacheKey as c, evictOldTransformCacheEntries as e, resolveTransformCacheDir as r, writeTransformCache as w };
209
+ export { readTransformCache as a, evictMemoryCacheToBudget as b, createTransformCacheKey as c, evictOldTransformCacheEntries as e, normalizePathSeparators as n, resolveTransformCacheDir as r, writeTransformCache as w };
@@ -19,7 +19,12 @@ function _interopNamespaceCompat(e) {
19
19
  const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
20
20
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
21
21
 
22
- const CACHE_SCHEMA_VERSION = 9;
22
+ const WINDOWS_PATH_SEPARATOR = String.fromCodePoint(92);
23
+ function normalizePathSeparators(value) {
24
+ return value.split(WINDOWS_PATH_SEPARATOR).join("/");
25
+ }
26
+
27
+ const CACHE_SCHEMA_VERSION = 10;
23
28
  function resolveTransformCacheDir(rootDir, cacheDir) {
24
29
  return path__namespace.resolve(rootDir, cacheDir ?? ".csszyx/cache", "transform");
25
30
  }
@@ -65,10 +70,7 @@ function writeTransformCache(cacheRoot, input, result, precomputedKey) {
65
70
  const globalVarAliases = normalizeGlobalVarAliasEntries(input.globalVarAliases);
66
71
  const file = cacheEntryPath(cacheRoot, key);
67
72
  const dir = path__namespace.dirname(file);
68
- const tmp = path__namespace.join(
69
- dir,
70
- `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
71
- );
73
+ const tmp = path__namespace.join(dir, `.tmp-${process.pid}-${Date.now()}-${node_crypto.randomUUID()}.json`);
72
74
  const entry = {
73
75
  version: CACHE_SCHEMA_VERSION,
74
76
  pluginVersion: input.pluginVersion,
@@ -137,6 +139,8 @@ function serializeResult(result) {
137
139
  usesSzcn: result.usesSzcn,
138
140
  usesSzPart: result.usesSzPart,
139
141
  usesColorVar: result.usesColorVar,
142
+ usesSpacingVar: result.usesSpacingVar,
143
+ usesUnitVar: result.usesUnitVar,
140
144
  classes: [...result.classes],
141
145
  rawClassNames: [...result.rawClassNames],
142
146
  diagnostics: [...result.diagnostics],
@@ -153,6 +157,8 @@ function deserializeResult(result) {
153
157
  usesSzcn: result.usesSzcn,
154
158
  usesSzPart: result.usesSzPart,
155
159
  usesColorVar: result.usesColorVar,
160
+ usesSpacingVar: result.usesSpacingVar,
161
+ usesUnitVar: result.usesUnitVar,
156
162
  classes: new Set(result.classes),
157
163
  rawClassNames: new Set(result.rawClassNames),
158
164
  diagnostics: [...result.diagnostics],
@@ -220,6 +226,7 @@ function evictMemoryCacheToBudget(cache, totalCodeChars, maxEntries, maxCodeChar
220
226
  exports.createTransformCacheKey = createTransformCacheKey;
221
227
  exports.evictMemoryCacheToBudget = evictMemoryCacheToBudget;
222
228
  exports.evictOldTransformCacheEntries = evictOldTransformCacheEntries;
229
+ exports.normalizePathSeparators = normalizePathSeparators;
223
230
  exports.readTransformCache = readTransformCache;
224
231
  exports.resolveTransformCacheDir = resolveTransformCacheDir;
225
232
  exports.writeTransformCache = writeTransformCache;
@@ -2,9 +2,9 @@
2
2
 
3
3
  const fs = require('node:fs');
4
4
  const compiler = require('@csszyx/compiler');
5
- const transformCache = require('./unplugin.D0N9bprz.cjs');
5
+ const transformCache = require('./unplugin.DVCQC5wq.cjs');
6
6
  const node_crypto = require('node:crypto');
7
- const htmlEscape = require('./unplugin.BCwRIUs_.cjs');
7
+ const htmlEscape = require('./unplugin.CcA7jP1r.cjs');
8
8
 
9
9
  function readPackageVersion(relativePackageJson, fromUrl) {
10
10
  try {
@@ -61,61 +61,19 @@ function stripJsCommentsAndStrings(source) {
61
61
  const char = source[index];
62
62
  const peek = index + 1 < length ? source[index + 1] : "";
63
63
  if (char === "/" && peek === "/") {
64
- index += 2;
65
- while (index < length && source[index] !== "\n") {
66
- index++;
67
- }
64
+ index = skipLineComment(source, index);
68
65
  continue;
69
66
  }
70
67
  if (char === "/" && peek === "*") {
71
- index += 2;
72
- while (index + 1 < length && !(source[index] === "*" && source[index + 1] === "/")) {
73
- index++;
74
- }
75
- index = Math.min(length, index + 2);
68
+ index = skipBlockComment(source, index);
76
69
  continue;
77
70
  }
78
71
  if (char === "/" && isRegexLiteralStart(out)) {
79
- index++;
80
- let inCharClass = false;
81
- while (index < length) {
82
- const current = source[index];
83
- if (current === "\\" && index + 1 < length) {
84
- index += 2;
85
- continue;
86
- }
87
- if (current === "[") {
88
- inCharClass = true;
89
- index++;
90
- continue;
91
- }
92
- if (current === "]") {
93
- inCharClass = false;
94
- index++;
95
- continue;
96
- }
97
- if (current === "/" && !inCharClass) {
98
- index++;
99
- while (/[a-z]/i.test(source[index] ?? "")) {
100
- index++;
101
- }
102
- break;
103
- }
104
- index++;
105
- }
72
+ index = skipRegexLiteral(source, index);
106
73
  continue;
107
74
  }
108
75
  if (char === '"' || char === "'" || char === "`") {
109
- const quote = char;
110
- index++;
111
- while (index < length && source[index] !== quote) {
112
- if (source[index] === "\\" && index + 1 < length) {
113
- index += 2;
114
- } else {
115
- index++;
116
- }
117
- }
118
- index++;
76
+ index = skipQuotedSource(source, index, char);
119
77
  continue;
120
78
  }
121
79
  out += char;
@@ -123,6 +81,46 @@ function stripJsCommentsAndStrings(source) {
123
81
  }
124
82
  return out;
125
83
  }
84
+ function skipLineComment(source, start) {
85
+ const newline = source.indexOf("\n", start + 2);
86
+ return newline === -1 ? source.length : newline;
87
+ }
88
+ function skipBlockComment(source, start) {
89
+ const close = source.indexOf("*/", start + 2);
90
+ return close === -1 ? source.length : close + 2;
91
+ }
92
+ function skipRegexLiteral(source, start) {
93
+ let index = start + 1;
94
+ let inCharClass = false;
95
+ while (index < source.length) {
96
+ const current = source[index];
97
+ if (current === "\\" && index + 1 < source.length) {
98
+ index += 2;
99
+ continue;
100
+ }
101
+ if (current === "[") {
102
+ inCharClass = true;
103
+ } else if (current === "]") {
104
+ inCharClass = false;
105
+ } else if (current === "/" && !inCharClass) {
106
+ return skipRegexFlags(source, index + 1);
107
+ }
108
+ index++;
109
+ }
110
+ return index;
111
+ }
112
+ function skipRegexFlags(source, start) {
113
+ let index = start;
114
+ while (/[a-z]/i.test(source[index] ?? "")) index++;
115
+ return index;
116
+ }
117
+ function skipQuotedSource(source, start, quote) {
118
+ let index = start + 1;
119
+ while (index < source.length && source[index] !== quote) {
120
+ index += source[index] === "\\" && index + 1 < source.length ? 2 : 1;
121
+ }
122
+ return index + 1;
123
+ }
126
124
  function isRegexLiteralStart(emitted) {
127
125
  const trimmed = emitted.trimEnd();
128
126
  const previous = trimmed.length > 0 ? trimmed.charAt(trimmed.length - 1) : void 0;
@@ -176,13 +174,16 @@ function createNextSourceTransformCacheInput(input, filename, producer) {
176
174
  };
177
175
  }
178
176
  function normalizeSourceFilename(filename) {
179
- return filename.replace(/\\/g, "/");
177
+ return transformCache.normalizePathSeparators(filename);
180
178
  }
181
179
  function normalizeGlobalVarAliasesForCache(aliases) {
182
180
  if (!aliases) {
183
181
  return [];
184
182
  }
185
- const entries = aliases instanceof Map ? aliases.entries() : Array.isArray(aliases) ? aliases : Object.entries(aliases);
183
+ let entries;
184
+ if (aliases instanceof Map) entries = aliases.entries();
185
+ else if (Array.isArray(aliases)) entries = aliases;
186
+ else entries = Object.entries(aliases);
186
187
  const normalized = /* @__PURE__ */ new Map();
187
188
  for (const [original, alias] of entries) {
188
189
  if (original.startsWith("--") && alias.startsWith("--")) {
@@ -1,9 +1,9 @@
1
1
  import * as path from 'node:path';
2
2
  import * as fs from 'node:fs';
3
- import { createHash } from 'node:crypto';
3
+ import { createHash, randomUUID } from 'node:crypto';
4
4
  import { hostname } from 'node:os';
5
5
  import lockfile from 'proper-lockfile';
6
- import { s as sortStrings, e as escapeHtmlAttribute } from './unplugin.B1mblcm-.mjs';
6
+ import { s as sortStrings, e as escapeHtmlAttribute, r as renderTailwindScannerCandidates } from './unplugin.TtmP77BS.mjs';
7
7
 
8
8
  const DEFAULT_RENAME_RETRIES = 5;
9
9
  const DEFAULT_RENAME_RETRY_DELAY_MS = 10;
@@ -132,7 +132,7 @@ function atomicWriteFileSync(file, content, options = {}) {
132
132
  const dir = path.dirname(file);
133
133
  const tmp = path.join(
134
134
  dir,
135
- `.tmp-${path.basename(file)}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`
135
+ `.tmp-${path.basename(file)}-${process.pid}-${Date.now()}-${randomUUID()}`
136
136
  );
137
137
  fs.mkdirSync(dir, { recursive: true });
138
138
  fs.writeFileSync(tmp, content, "utf8");
@@ -233,8 +233,10 @@ function renderTailwindSourceHtml(classNames) {
233
233
  if (classNames.length === 0) {
234
234
  return "<!-- csszyx Next safelist: empty -->\n";
235
235
  }
236
- return `${classNames.map((className) => `<div class="${escapeHtmlAttribute(className)}"></div>`).join("\n")}
237
- `;
236
+ const structuralHtml = classNames.map((className) => `<div class="${escapeHtmlAttribute(className)}"></div>`).join("\n");
237
+ const scannerCandidates = renderTailwindScannerCandidates(classNames);
238
+ return `${structuralHtml}
239
+ ${scannerCandidates}`;
238
240
  }
239
241
  function createLockMetadata(options) {
240
242
  const now = new Date(options.now ?? Date.now()).toISOString();
@@ -242,7 +244,7 @@ function createLockMetadata(options) {
242
244
  return {
243
245
  version: 1,
244
246
  pid,
245
- token: options.token ?? createHash("sha256").update(`${pid}\0${now}\0${Math.random().toString(36)}`).digest("hex"),
247
+ token: options.token ?? randomUUID(),
246
248
  hostname: hostname(),
247
249
  root: path.resolve(options.root ?? process.cwd()),
248
250
  mode: options.mode ?? "development",
@@ -1,5 +1,25 @@
1
1
  'use strict';
2
2
 
3
+ const LEADING_WHITESPACE_RE = /^\s+/;
4
+ const LINE_COMMENT_RE = /^\/\/[^\n]*(?:\n|$)/;
5
+ const BLOCK_COMMENT_RE = /^\/\*[\s\S]*?\*\//;
6
+ const USE_DIRECTIVE_RE = /^['"]use (?:client|server)['"];?\s*/;
7
+ function insertAfterUseDirective(code, insertion) {
8
+ let offset = 0;
9
+ while (offset < code.length) {
10
+ const triviaLength = leadingTriviaLength(code.slice(offset));
11
+ if (triviaLength === 0) break;
12
+ offset += triviaLength;
13
+ }
14
+ const directive = code.slice(offset).match(USE_DIRECTIVE_RE);
15
+ if (!directive) return `${insertion}${code}`;
16
+ const insertionOffset = offset + directive[0].length;
17
+ return `${code.slice(0, insertionOffset)}${insertion}${code.slice(insertionOffset)}`;
18
+ }
19
+ function leadingTriviaLength(source) {
20
+ return source.match(LEADING_WHITESPACE_RE)?.[0].length ?? source.match(LINE_COMMENT_RE)?.[0].length ?? source.match(BLOCK_COMMENT_RE)?.[0].length ?? 0;
21
+ }
22
+
3
23
  const RUNTIME_IMPORT_CLAUSE_RE = /(?:import|export)\s+\{([^{}]*)\}\s*from\s*['"]@csszyx\/runtime['"]/g;
4
24
  function clauseNames(clauseBody) {
5
25
  const names = [];
@@ -30,3 +50,4 @@ function findRuntimeImportClause(code) {
30
50
 
31
51
  exports.findRuntimeImportClause = findRuntimeImportClause;
32
52
  exports.importsRuntimeHelper = importsRuntimeHelper;
53
+ exports.insertAfterUseDirective = insertAfterUseDirective;