@csszyx/cli 0.8.0 → 0.9.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 +3 -0
- package/dist/index.mjs +672 -116
- package/package.json +17 -16
package/README.md
CHANGED
|
@@ -61,6 +61,9 @@ npx csszyx generate-types --output ./src/csszyx.d.ts
|
|
|
61
61
|
### `migrate`
|
|
62
62
|
|
|
63
63
|
Convert Tailwind `className="..."` to CSSzyx `sz={...}` props. Phase 1 supports static string classNames.
|
|
64
|
+
Display utilities migrate to canonical `display` props (`flex` →
|
|
65
|
+
`{ display: 'flex' }`) instead of boolean sugar, and conflicting display
|
|
66
|
+
utilities in the same variant scope stay unresolved for manual review.
|
|
64
67
|
|
|
65
68
|
```bash
|
|
66
69
|
npx csszyx migrate src/
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from 'cac';
|
|
3
|
-
import
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import path__default, { resolve, dirname } from 'node:path';
|
|
4
5
|
import fs from 'fs-extra';
|
|
5
6
|
import ora from 'ora';
|
|
6
7
|
import pc from 'picocolors';
|
|
@@ -13,8 +14,11 @@ import prompts from 'prompts';
|
|
|
13
14
|
import readline from 'node:readline';
|
|
14
15
|
import fg from 'fast-glob';
|
|
15
16
|
import { parse } from '@babel/parser';
|
|
16
|
-
import _traverse from '@babel/traverse';
|
|
17
17
|
import * as t from '@babel/types';
|
|
18
|
+
import { runNextPrebuild } from '@csszyx/unplugin/next-prebuild';
|
|
19
|
+
import { NextSafelistWatcher } from '@csszyx/unplugin/next-watcher';
|
|
20
|
+
import { watch } from 'chokidar';
|
|
21
|
+
import { Minimatch } from 'minimatch';
|
|
18
22
|
|
|
19
23
|
const colors = {
|
|
20
24
|
success: pc.green,
|
|
@@ -141,19 +145,19 @@ async function collectStats(cwd) {
|
|
|
141
145
|
mangledCSS: 0
|
|
142
146
|
}
|
|
143
147
|
};
|
|
144
|
-
const distDir =
|
|
148
|
+
const distDir = path__default.join(cwd, "dist");
|
|
145
149
|
if (!fs.existsSync(distDir)) {
|
|
146
150
|
return stats;
|
|
147
151
|
}
|
|
148
152
|
const htmlFiles = fs.readdirSync(distDir, { recursive: true }).filter((f) => String(f).endsWith(".html"));
|
|
149
153
|
const cssFiles = fs.readdirSync(distDir, { recursive: true }).filter((f) => String(f).endsWith(".css"));
|
|
150
154
|
if (htmlFiles.length > 0) {
|
|
151
|
-
const htmlContent = fs.readFileSync(
|
|
155
|
+
const htmlContent = fs.readFileSync(path__default.join(distDir, String(htmlFiles[0])), "utf-8");
|
|
152
156
|
stats.bundleSavings.mangledHTML = Buffer.byteLength(htmlContent);
|
|
153
157
|
stats.bundleSavings.originalHTML = Math.round(stats.bundleSavings.mangledHTML * 1.67);
|
|
154
158
|
}
|
|
155
159
|
if (cssFiles.length > 0) {
|
|
156
|
-
const cssContent = fs.readFileSync(
|
|
160
|
+
const cssContent = fs.readFileSync(path__default.join(distDir, String(cssFiles[0])), "utf-8");
|
|
157
161
|
stats.bundleSavings.mangledCSS = Buffer.byteLength(cssContent);
|
|
158
162
|
stats.bundleSavings.originalCSS = Math.round(stats.bundleSavings.mangledCSS * 1.71);
|
|
159
163
|
}
|
|
@@ -174,14 +178,14 @@ function formatBytes(bytes) {
|
|
|
174
178
|
|
|
175
179
|
function detectFramework(cwd) {
|
|
176
180
|
try {
|
|
177
|
-
const pkgPath =
|
|
181
|
+
const pkgPath = path__default.join(cwd, "package.json");
|
|
178
182
|
if (!fs.existsSync(pkgPath)) {
|
|
179
183
|
return "unknown";
|
|
180
184
|
}
|
|
181
185
|
const pkg = fs.readJSONSync(pkgPath);
|
|
182
186
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
183
187
|
if (deps.next) {
|
|
184
|
-
const hasAppDir = fs.existsSync(
|
|
188
|
+
const hasAppDir = fs.existsSync(path__default.join(cwd, "app"));
|
|
185
189
|
return hasAppDir ? "nextjs-app" : "nextjs-pages";
|
|
186
190
|
}
|
|
187
191
|
if (deps.nuxt) {
|
|
@@ -210,20 +214,20 @@ function detectFramework(cwd) {
|
|
|
210
214
|
}
|
|
211
215
|
}
|
|
212
216
|
function detectPackageManager(cwd) {
|
|
213
|
-
if (fs.existsSync(
|
|
217
|
+
if (fs.existsSync(path__default.join(cwd, "pnpm-lock.yaml"))) {
|
|
214
218
|
return "pnpm";
|
|
215
219
|
}
|
|
216
|
-
if (fs.existsSync(
|
|
220
|
+
if (fs.existsSync(path__default.join(cwd, "yarn.lock"))) {
|
|
217
221
|
return "yarn";
|
|
218
222
|
}
|
|
219
|
-
if (fs.existsSync(
|
|
223
|
+
if (fs.existsSync(path__default.join(cwd, "bun.lockb"))) {
|
|
220
224
|
return "bun";
|
|
221
225
|
}
|
|
222
226
|
return "npm";
|
|
223
227
|
}
|
|
224
228
|
function hasTailwindInstalled(cwd) {
|
|
225
229
|
try {
|
|
226
|
-
const pkgPath =
|
|
230
|
+
const pkgPath = path__default.join(cwd, "package.json");
|
|
227
231
|
if (!fs.existsSync(pkgPath)) {
|
|
228
232
|
return false;
|
|
229
233
|
}
|
|
@@ -235,7 +239,7 @@ function hasTailwindInstalled(cwd) {
|
|
|
235
239
|
}
|
|
236
240
|
}
|
|
237
241
|
function hasTypeScript(cwd) {
|
|
238
|
-
return fs.existsSync(
|
|
242
|
+
return fs.existsSync(path__default.join(cwd, "tsconfig.json")) || fs.existsSync(path__default.join(cwd, "jsconfig.json"));
|
|
239
243
|
}
|
|
240
244
|
function getProjectInfo(cwd = process.cwd()) {
|
|
241
245
|
return {
|
|
@@ -267,7 +271,7 @@ async function doctor(options = {}) {
|
|
|
267
271
|
printHeader("csszyx Doctor");
|
|
268
272
|
let issueCount = 0;
|
|
269
273
|
printSection("\u{1F4CB} Configuration Health");
|
|
270
|
-
const hasConfig = fs.existsSync(
|
|
274
|
+
const hasConfig = fs.existsSync(path__default.join(cwd, "csszyx.config.ts")) || fs.existsSync(path__default.join(cwd, "csszyx.config.js"));
|
|
271
275
|
if (hasConfig) {
|
|
272
276
|
printSuccess("csszyx configuration found");
|
|
273
277
|
} else {
|
|
@@ -284,7 +288,7 @@ async function doctor(options = {}) {
|
|
|
284
288
|
}
|
|
285
289
|
printSection("\u{1F4E6} Package Versions");
|
|
286
290
|
try {
|
|
287
|
-
const pkgPath =
|
|
291
|
+
const pkgPath = path__default.join(cwd, "package.json");
|
|
288
292
|
const pkg = fs.readJSONSync(pkgPath);
|
|
289
293
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
290
294
|
if (deps.csszyx) {
|
|
@@ -298,12 +302,12 @@ async function doctor(options = {}) {
|
|
|
298
302
|
issueCount++;
|
|
299
303
|
}
|
|
300
304
|
printSection("\u{1F528} Build Output");
|
|
301
|
-
const distDir =
|
|
305
|
+
const distDir = path__default.join(cwd, "dist");
|
|
302
306
|
if (fs.existsSync(distDir)) {
|
|
303
307
|
const htmlFiles = fs.readdirSync(distDir, { recursive: true }).filter((f) => String(f).endsWith(".html"));
|
|
304
308
|
if (htmlFiles.length > 0) {
|
|
305
309
|
printSuccess(`Found ${htmlFiles.length} HTML file(s)`);
|
|
306
|
-
const htmlContent = fs.readFileSync(
|
|
310
|
+
const htmlContent = fs.readFileSync(path__default.join(distDir, String(htmlFiles[0])), "utf-8");
|
|
307
311
|
if (htmlContent.includes("data-sz-checksum")) {
|
|
308
312
|
printSuccess("Checksum injection working");
|
|
309
313
|
} else {
|
|
@@ -1196,6 +1200,16 @@ async function generateTypes(options = {}) {
|
|
|
1196
1200
|
}
|
|
1197
1201
|
|
|
1198
1202
|
const VITE_FRAMEWORKS = /* @__PURE__ */ new Set(["vite-react", "vite-vue", "vite-svelte"]);
|
|
1203
|
+
async function readFileOrNull(filePath) {
|
|
1204
|
+
try {
|
|
1205
|
+
return await fs.readFile(filePath, "utf8");
|
|
1206
|
+
} catch (err) {
|
|
1207
|
+
if (err?.code === "ENOENT") {
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
throw err;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1199
1213
|
const NEXTJS_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs-app", "nextjs-pages"]);
|
|
1200
1214
|
const CSS_ENTRY_CANDIDATES = [
|
|
1201
1215
|
"src/index.css",
|
|
@@ -1273,7 +1287,7 @@ async function init(options = {}) {
|
|
|
1273
1287
|
const spin2 = spinner.start("Creating config files...");
|
|
1274
1288
|
try {
|
|
1275
1289
|
const configContent = generateConfigFile(config);
|
|
1276
|
-
const configPath =
|
|
1290
|
+
const configPath = path__default.join(
|
|
1277
1291
|
cwd,
|
|
1278
1292
|
projectInfo.hasTypeScript ? "csszyx.config.ts" : "csszyx.config.js"
|
|
1279
1293
|
);
|
|
@@ -1283,11 +1297,11 @@ async function init(options = {}) {
|
|
|
1283
1297
|
}
|
|
1284
1298
|
await injectPlugin(cwd, projectInfo.framework);
|
|
1285
1299
|
if (config.setupGitignore) {
|
|
1286
|
-
const gitignorePath =
|
|
1300
|
+
const gitignorePath = path__default.join(cwd, ".gitignore");
|
|
1287
1301
|
const ignoreEntry = "\n# csszyx generated theme types\n.csszyx\n";
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (!
|
|
1302
|
+
const existing = await readFileOrNull(gitignorePath);
|
|
1303
|
+
if (existing !== null) {
|
|
1304
|
+
if (!existing.includes(".csszyx")) {
|
|
1291
1305
|
await fs.appendFile(gitignorePath, ignoreEntry);
|
|
1292
1306
|
}
|
|
1293
1307
|
} else {
|
|
@@ -1312,32 +1326,35 @@ async function init(options = {}) {
|
|
|
1312
1326
|
}
|
|
1313
1327
|
async function setupTailwindCss(cwd, framework) {
|
|
1314
1328
|
let cssPath;
|
|
1329
|
+
let content = null;
|
|
1315
1330
|
for (const candidate of CSS_ENTRY_CANDIDATES) {
|
|
1316
|
-
const full =
|
|
1317
|
-
|
|
1331
|
+
const full = path__default.join(cwd, candidate);
|
|
1332
|
+
const existing = await readFileOrNull(full);
|
|
1333
|
+
if (existing !== null) {
|
|
1318
1334
|
cssPath = full;
|
|
1335
|
+
content = existing;
|
|
1319
1336
|
break;
|
|
1320
1337
|
}
|
|
1321
1338
|
}
|
|
1322
|
-
if (!cssPath) {
|
|
1323
|
-
cssPath =
|
|
1324
|
-
await fs.ensureDir(
|
|
1339
|
+
if (!cssPath || content === null) {
|
|
1340
|
+
cssPath = path__default.join(cwd, "src/index.css");
|
|
1341
|
+
await fs.ensureDir(path__default.dirname(cssPath));
|
|
1325
1342
|
await fs.writeFile(cssPath, '@import "tailwindcss";\n');
|
|
1326
|
-
printInfo(`Created ${
|
|
1343
|
+
printInfo(`Created ${path__default.relative(cwd, cssPath)} with Tailwind v4 import`);
|
|
1327
1344
|
return;
|
|
1328
1345
|
}
|
|
1329
|
-
const content = await fs.readFile(cssPath, "utf8");
|
|
1330
1346
|
if (!content.includes('@import "tailwindcss"') && !content.includes("@import 'tailwindcss'")) {
|
|
1331
1347
|
await fs.writeFile(cssPath, `@import "tailwindcss";
|
|
1332
1348
|
|
|
1333
1349
|
${content}`);
|
|
1334
|
-
printInfo(`Added Tailwind v4 import to ${
|
|
1350
|
+
printInfo(`Added Tailwind v4 import to ${path__default.relative(cwd, cssPath)}`);
|
|
1335
1351
|
}
|
|
1336
1352
|
if (NEXTJS_FRAMEWORKS.has(framework)) {
|
|
1337
|
-
const postcssMjs =
|
|
1338
|
-
const postcssJs =
|
|
1339
|
-
const postcssTs =
|
|
1340
|
-
|
|
1353
|
+
const postcssMjs = path__default.join(cwd, "postcss.config.mjs");
|
|
1354
|
+
const postcssJs = path__default.join(cwd, "postcss.config.js");
|
|
1355
|
+
const postcssTs = path__default.join(cwd, "postcss.config.ts");
|
|
1356
|
+
const hasExisting = await readFileOrNull(postcssMjs) !== null || await readFileOrNull(postcssJs) !== null || await readFileOrNull(postcssTs) !== null;
|
|
1357
|
+
if (!hasExisting) {
|
|
1341
1358
|
await fs.writeFile(postcssMjs, generatePostcssConfig());
|
|
1342
1359
|
printInfo("Created postcss.config.mjs for Tailwind v4");
|
|
1343
1360
|
}
|
|
@@ -1363,22 +1380,24 @@ async function injectPlugin(cwd, framework) {
|
|
|
1363
1380
|
}
|
|
1364
1381
|
async function injectVitePlugin(cwd) {
|
|
1365
1382
|
const candidates = [
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1383
|
+
path__default.join(cwd, "vite.config.ts"),
|
|
1384
|
+
path__default.join(cwd, "vite.config.js"),
|
|
1385
|
+
path__default.join(cwd, "vite.config.mts"),
|
|
1386
|
+
path__default.join(cwd, "vite.config.mjs")
|
|
1370
1387
|
];
|
|
1371
1388
|
let configPath;
|
|
1389
|
+
let content = null;
|
|
1372
1390
|
for (const c of candidates) {
|
|
1373
|
-
|
|
1391
|
+
const existing = await readFileOrNull(c);
|
|
1392
|
+
if (existing !== null) {
|
|
1374
1393
|
configPath = c;
|
|
1394
|
+
content = existing;
|
|
1375
1395
|
break;
|
|
1376
1396
|
}
|
|
1377
1397
|
}
|
|
1378
|
-
if (!configPath) {
|
|
1398
|
+
if (!configPath || content === null) {
|
|
1379
1399
|
return false;
|
|
1380
1400
|
}
|
|
1381
|
-
let content = await fs.readFile(configPath, "utf8");
|
|
1382
1401
|
if (content.includes("csszyx")) {
|
|
1383
1402
|
return true;
|
|
1384
1403
|
}
|
|
@@ -1402,46 +1421,48 @@ ${importBlock}${content.slice(insertAt)}`;
|
|
|
1402
1421
|
content = content.slice(0, pluginsInsertAt) + `
|
|
1403
1422
|
...csszyx(), // csszyx MUST come before tailwindcss${twEntry}` + content.slice(pluginsInsertAt);
|
|
1404
1423
|
await fs.writeFile(configPath, content);
|
|
1405
|
-
printInfo(`Injected csszyx plugin into ${
|
|
1424
|
+
printInfo(`Injected csszyx plugin into ${path__default.basename(configPath)}`);
|
|
1406
1425
|
return true;
|
|
1407
1426
|
}
|
|
1408
1427
|
async function injectNextPlugin(cwd) {
|
|
1409
1428
|
const candidates = [
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1429
|
+
path__default.join(cwd, "next.config.ts"),
|
|
1430
|
+
path__default.join(cwd, "next.config.mjs"),
|
|
1431
|
+
path__default.join(cwd, "next.config.js")
|
|
1413
1432
|
];
|
|
1414
1433
|
let configPath;
|
|
1434
|
+
let content = null;
|
|
1415
1435
|
for (const c of candidates) {
|
|
1416
|
-
|
|
1436
|
+
const existing = await readFileOrNull(c);
|
|
1437
|
+
if (existing !== null) {
|
|
1417
1438
|
configPath = c;
|
|
1439
|
+
content = existing;
|
|
1418
1440
|
break;
|
|
1419
1441
|
}
|
|
1420
1442
|
}
|
|
1421
1443
|
if (!configPath) {
|
|
1422
|
-
configPath =
|
|
1444
|
+
configPath = path__default.join(cwd, "next.config.js");
|
|
1423
1445
|
await fs.writeFile(configPath, generateNextConfig());
|
|
1424
1446
|
printInfo("Created next.config.js with csszyx plugin");
|
|
1425
1447
|
return true;
|
|
1426
1448
|
}
|
|
1427
|
-
|
|
1428
|
-
if (content.includes("csszyx")) {
|
|
1449
|
+
if (content?.includes("csszyx")) {
|
|
1429
1450
|
return true;
|
|
1430
1451
|
}
|
|
1431
1452
|
return false;
|
|
1432
1453
|
}
|
|
1433
1454
|
async function setupTsconfig(cwd) {
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1455
|
+
const primary = path__default.join(cwd, "tsconfig.json");
|
|
1456
|
+
const viteTsConfig = path__default.join(cwd, "tsconfig.app.json");
|
|
1457
|
+
let tsconfigPath = primary;
|
|
1458
|
+
let content = await readFileOrNull(tsconfigPath);
|
|
1459
|
+
if (content === null) {
|
|
1460
|
+
tsconfigPath = viteTsConfig;
|
|
1461
|
+
content = await readFileOrNull(tsconfigPath);
|
|
1462
|
+
}
|
|
1463
|
+
if (content === null) {
|
|
1442
1464
|
return;
|
|
1443
1465
|
}
|
|
1444
|
-
let content = await fs.readFile(tsconfigPath, "utf8");
|
|
1445
1466
|
if (content.includes(".csszyx")) {
|
|
1446
1467
|
return;
|
|
1447
1468
|
}
|
|
@@ -1565,7 +1586,7 @@ function isGradientObj(v) {
|
|
|
1565
1586
|
return typeof v === "object" && v !== null && "gradient" in v;
|
|
1566
1587
|
}
|
|
1567
1588
|
function formatKey(key) {
|
|
1568
|
-
if (/^[a-
|
|
1589
|
+
if (/^[a-z_$][\w$]*$/i.test(key)) {
|
|
1569
1590
|
return key;
|
|
1570
1591
|
}
|
|
1571
1592
|
return `'${key}'`;
|
|
@@ -1590,7 +1611,7 @@ function formatValue(value, indent) {
|
|
|
1590
1611
|
const items = value.map((v) => formatValue(v, indent));
|
|
1591
1612
|
return `[${items.join(", ")}]`;
|
|
1592
1613
|
}
|
|
1593
|
-
if (typeof value === "object"
|
|
1614
|
+
if (typeof value === "object") {
|
|
1594
1615
|
if (isColorOpacityObj(value)) {
|
|
1595
1616
|
const parts = [`color: '${escapeString(String(value.color))}'`];
|
|
1596
1617
|
if (typeof value.op === "number") {
|
|
@@ -2351,7 +2372,7 @@ const KNOWN_SIMPLE_VARIANTS = /* @__PURE__ */ new Set([
|
|
|
2351
2372
|
"pointer-none"
|
|
2352
2373
|
]);
|
|
2353
2374
|
|
|
2354
|
-
function parseClass(cls) {
|
|
2375
|
+
function parseClass(cls, options = {}) {
|
|
2355
2376
|
let important = false;
|
|
2356
2377
|
let input = cls;
|
|
2357
2378
|
if (input.endsWith("!")) {
|
|
@@ -2364,7 +2385,7 @@ function parseClass(cls) {
|
|
|
2364
2385
|
negative = true;
|
|
2365
2386
|
negInput = input.slice(1);
|
|
2366
2387
|
}
|
|
2367
|
-
const boolResult = tryBooleanMatch(input);
|
|
2388
|
+
const boolResult = tryBooleanMatch(input, options);
|
|
2368
2389
|
if (boolResult) {
|
|
2369
2390
|
return applyImportant(boolResult, important);
|
|
2370
2391
|
}
|
|
@@ -2380,10 +2401,7 @@ function parseClass(cls) {
|
|
|
2380
2401
|
continue;
|
|
2381
2402
|
}
|
|
2382
2403
|
if (REVERSE_BOOLEAN_MAP[source]) {
|
|
2383
|
-
return applyImportant(
|
|
2384
|
-
{ prop: REVERSE_BOOLEAN_MAP[source], value: true },
|
|
2385
|
-
important
|
|
2386
|
-
);
|
|
2404
|
+
return applyImportant(booleanClassToParsed(source, options), important);
|
|
2387
2405
|
}
|
|
2388
2406
|
if (prefix === "divide-x" || prefix === "divide-y") {
|
|
2389
2407
|
return applyImportant({ prop, value: true }, important);
|
|
@@ -2422,7 +2440,7 @@ function parseClass(cls) {
|
|
|
2422
2440
|
}
|
|
2423
2441
|
}
|
|
2424
2442
|
}
|
|
2425
|
-
const displayResult = tryDisplay(input);
|
|
2443
|
+
const displayResult = tryDisplay(input, options);
|
|
2426
2444
|
if (displayResult) {
|
|
2427
2445
|
return applyImportant(displayResult, important);
|
|
2428
2446
|
}
|
|
@@ -2456,17 +2474,17 @@ function applyImportant(result, important) {
|
|
|
2456
2474
|
}
|
|
2457
2475
|
return result;
|
|
2458
2476
|
}
|
|
2459
|
-
function tryBooleanMatch(cls) {
|
|
2477
|
+
function tryBooleanMatch(cls, options) {
|
|
2460
2478
|
if (BOOLEAN_VALUE_MAP[cls]) {
|
|
2461
2479
|
const { prop, value } = BOOLEAN_VALUE_MAP[cls];
|
|
2462
2480
|
return { prop, value };
|
|
2463
2481
|
}
|
|
2464
2482
|
if (REVERSE_BOOLEAN_MAP[cls]) {
|
|
2465
|
-
return
|
|
2483
|
+
return booleanClassToParsed(cls, options);
|
|
2466
2484
|
}
|
|
2467
2485
|
return null;
|
|
2468
2486
|
}
|
|
2469
|
-
function tryDisplay(cls) {
|
|
2487
|
+
function tryDisplay(cls, options) {
|
|
2470
2488
|
const displayValues = /* @__PURE__ */ new Set([
|
|
2471
2489
|
"block",
|
|
2472
2490
|
"inline",
|
|
@@ -2484,10 +2502,33 @@ function tryDisplay(cls) {
|
|
|
2484
2502
|
"list-item"
|
|
2485
2503
|
]);
|
|
2486
2504
|
if (displayValues.has(cls)) {
|
|
2487
|
-
return REVERSE_BOOLEAN_MAP[cls] ?
|
|
2505
|
+
return REVERSE_BOOLEAN_MAP[cls] ? booleanClassToParsed(cls, options) : null;
|
|
2488
2506
|
}
|
|
2489
2507
|
return null;
|
|
2490
2508
|
}
|
|
2509
|
+
function booleanClassToParsed(cls, options) {
|
|
2510
|
+
const displayValue = DISPLAY_CLASS_VALUES[cls];
|
|
2511
|
+
if (options.display === "canonical" && displayValue) {
|
|
2512
|
+
return { prop: "display", value: displayValue, cssProperty: "display" };
|
|
2513
|
+
}
|
|
2514
|
+
return { prop: REVERSE_BOOLEAN_MAP[cls], value: true };
|
|
2515
|
+
}
|
|
2516
|
+
const DISPLAY_CLASS_VALUES = {
|
|
2517
|
+
block: "block",
|
|
2518
|
+
inline: "inline",
|
|
2519
|
+
"inline-block": "inline-block",
|
|
2520
|
+
flex: "flex",
|
|
2521
|
+
"inline-flex": "inline-flex",
|
|
2522
|
+
grid: "grid",
|
|
2523
|
+
"inline-grid": "inline-grid",
|
|
2524
|
+
hidden: "none",
|
|
2525
|
+
contents: "contents",
|
|
2526
|
+
table: "table",
|
|
2527
|
+
"table-row": "table-row",
|
|
2528
|
+
"table-cell": "table-cell",
|
|
2529
|
+
"flow-root": "flow-root",
|
|
2530
|
+
"list-item": "list-item"
|
|
2531
|
+
};
|
|
2491
2532
|
function tryGradient(cls, negative) {
|
|
2492
2533
|
let input = cls;
|
|
2493
2534
|
let type = null;
|
|
@@ -3133,6 +3174,8 @@ function normalizeVariantKey(variant) {
|
|
|
3133
3174
|
const TODO_KEEP = "sz:keep";
|
|
3134
3175
|
const TODO_REMOVE = "sz:remove";
|
|
3135
3176
|
const TODO_PENDING = "sz:todo";
|
|
3177
|
+
const MAX_TOKEN_CACHE_SIZE = 4096;
|
|
3178
|
+
const parsedTokenCache = /* @__PURE__ */ new Map();
|
|
3136
3179
|
function resolveCustomMapEntry(token, customMap, resolveString) {
|
|
3137
3180
|
if (!(token in customMap)) {
|
|
3138
3181
|
return null;
|
|
@@ -3164,6 +3207,8 @@ function classNameToSzObject(className, customMap) {
|
|
|
3164
3207
|
const szObject = {};
|
|
3165
3208
|
const unrecognized = [];
|
|
3166
3209
|
const keepInClassName = [];
|
|
3210
|
+
const seenCssPropertiesByPath = /* @__PURE__ */ new Map();
|
|
3211
|
+
const conflictedCssPropertiesByPath = /* @__PURE__ */ new Map();
|
|
3167
3212
|
for (const token of tokens) {
|
|
3168
3213
|
if (customMap && token in customMap) {
|
|
3169
3214
|
const entry = resolveCustomMapEntry(
|
|
@@ -3201,21 +3246,79 @@ function classNameToSzObject(className, customMap) {
|
|
|
3201
3246
|
}
|
|
3202
3247
|
}
|
|
3203
3248
|
}
|
|
3204
|
-
const
|
|
3205
|
-
|
|
3206
|
-
|
|
3249
|
+
const parsedToken = parseClassTokenCached(token);
|
|
3250
|
+
if (!parsedToken) {
|
|
3251
|
+
unrecognized.push(token);
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
3254
|
+
if (isCssPropertyConflicted(conflictedCssPropertiesByPath, parsedToken)) {
|
|
3207
3255
|
unrecognized.push(token);
|
|
3208
3256
|
continue;
|
|
3209
3257
|
}
|
|
3210
|
-
const
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3258
|
+
const conflict = findCssPropertyConflict(seenCssPropertiesByPath, parsedToken, token);
|
|
3259
|
+
if (conflict) {
|
|
3260
|
+
rememberCssPropertyConflict(conflictedCssPropertiesByPath, parsedToken);
|
|
3261
|
+
unrecognized.push(conflict, token);
|
|
3262
|
+
removeNestedValue(szObject, parsedToken.keyPath, parsedToken.prop);
|
|
3263
|
+
continue;
|
|
3214
3264
|
}
|
|
3215
|
-
|
|
3265
|
+
rememberCssProperty(seenCssPropertiesByPath, parsedToken, token);
|
|
3266
|
+
setNestedValue(
|
|
3267
|
+
szObject,
|
|
3268
|
+
parsedToken.keyPath,
|
|
3269
|
+
parsedToken.prop,
|
|
3270
|
+
cloneParsedValue(parsedToken.value)
|
|
3271
|
+
);
|
|
3216
3272
|
}
|
|
3217
3273
|
return { szObject, unrecognized, keepInClassName };
|
|
3218
3274
|
}
|
|
3275
|
+
function parseClassTokenCached(token) {
|
|
3276
|
+
if (parsedTokenCache.has(token)) {
|
|
3277
|
+
return parsedTokenCache.get(token) ?? null;
|
|
3278
|
+
}
|
|
3279
|
+
const parsed = parseClassToken(token);
|
|
3280
|
+
rememberParsedToken(token, parsed);
|
|
3281
|
+
return parsed;
|
|
3282
|
+
}
|
|
3283
|
+
function parseClassToken(token) {
|
|
3284
|
+
const { variantParts, baseClass } = extractVariants(token);
|
|
3285
|
+
const parsed = parseClass(baseClass, { display: "canonical" });
|
|
3286
|
+
if (!parsed) {
|
|
3287
|
+
return null;
|
|
3288
|
+
}
|
|
3289
|
+
const keyPath = [];
|
|
3290
|
+
for (const variant of variantParts) {
|
|
3291
|
+
keyPath.push(...mapVariant(variant));
|
|
3292
|
+
}
|
|
3293
|
+
return {
|
|
3294
|
+
keyPath,
|
|
3295
|
+
prop: parsed.prop,
|
|
3296
|
+
value: parsed.value,
|
|
3297
|
+
cssProperty: parsed.cssProperty
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
function rememberParsedToken(token, parsed) {
|
|
3301
|
+
if (parsedTokenCache.size >= MAX_TOKEN_CACHE_SIZE) {
|
|
3302
|
+
const oldest = parsedTokenCache.keys().next().value;
|
|
3303
|
+
if (oldest !== void 0) {
|
|
3304
|
+
parsedTokenCache.delete(oldest);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
parsedTokenCache.set(token, parsed);
|
|
3308
|
+
}
|
|
3309
|
+
function cloneParsedValue(value) {
|
|
3310
|
+
if (Array.isArray(value)) {
|
|
3311
|
+
return value.map(cloneParsedValue);
|
|
3312
|
+
}
|
|
3313
|
+
if (value && typeof value === "object") {
|
|
3314
|
+
const clone = {};
|
|
3315
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
3316
|
+
clone[key] = cloneParsedValue(nested);
|
|
3317
|
+
}
|
|
3318
|
+
return clone;
|
|
3319
|
+
}
|
|
3320
|
+
return value;
|
|
3321
|
+
}
|
|
3219
3322
|
function setNestedValue(obj, keyPath, prop, value) {
|
|
3220
3323
|
let current = obj;
|
|
3221
3324
|
for (const key of keyPath) {
|
|
@@ -3226,6 +3329,64 @@ function setNestedValue(obj, keyPath, prop, value) {
|
|
|
3226
3329
|
}
|
|
3227
3330
|
current[prop] = value;
|
|
3228
3331
|
}
|
|
3332
|
+
function findCssPropertyConflict(seen, parsed, token) {
|
|
3333
|
+
if (!parsed.cssProperty) {
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
const scope = parsed.keyPath.join("\0");
|
|
3337
|
+
const previous = seen.get(scope)?.get(parsed.cssProperty);
|
|
3338
|
+
return previous && previous !== token ? previous : null;
|
|
3339
|
+
}
|
|
3340
|
+
function isCssPropertyConflicted(conflicted, parsed) {
|
|
3341
|
+
if (!parsed.cssProperty) {
|
|
3342
|
+
return false;
|
|
3343
|
+
}
|
|
3344
|
+
return conflicted.get(parsed.keyPath.join("\0"))?.has(parsed.cssProperty) === true;
|
|
3345
|
+
}
|
|
3346
|
+
function rememberCssPropertyConflict(conflicted, parsed) {
|
|
3347
|
+
if (!parsed.cssProperty) {
|
|
3348
|
+
return;
|
|
3349
|
+
}
|
|
3350
|
+
const scope = parsed.keyPath.join("\0");
|
|
3351
|
+
let properties = conflicted.get(scope);
|
|
3352
|
+
if (!properties) {
|
|
3353
|
+
properties = /* @__PURE__ */ new Set();
|
|
3354
|
+
conflicted.set(scope, properties);
|
|
3355
|
+
}
|
|
3356
|
+
properties.add(parsed.cssProperty);
|
|
3357
|
+
}
|
|
3358
|
+
function rememberCssProperty(seen, parsed, token) {
|
|
3359
|
+
if (!parsed.cssProperty) {
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
const scope = parsed.keyPath.join("\0");
|
|
3363
|
+
let properties = seen.get(scope);
|
|
3364
|
+
if (!properties) {
|
|
3365
|
+
properties = /* @__PURE__ */ new Map();
|
|
3366
|
+
seen.set(scope, properties);
|
|
3367
|
+
}
|
|
3368
|
+
properties.set(parsed.cssProperty, token);
|
|
3369
|
+
}
|
|
3370
|
+
function removeNestedValue(obj, keyPath, prop) {
|
|
3371
|
+
let current = obj;
|
|
3372
|
+
const parents = [];
|
|
3373
|
+
for (const key of keyPath) {
|
|
3374
|
+
const next = current[key];
|
|
3375
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
|
3376
|
+
return;
|
|
3377
|
+
}
|
|
3378
|
+
parents.push([current, key]);
|
|
3379
|
+
current = next;
|
|
3380
|
+
}
|
|
3381
|
+
delete current[prop];
|
|
3382
|
+
for (let index = parents.length - 1; index >= 0; index--) {
|
|
3383
|
+
const [parent, key] = parents[index];
|
|
3384
|
+
const child = parent[key];
|
|
3385
|
+
if (child && typeof child === "object" && Object.keys(child).length === 0) {
|
|
3386
|
+
delete parent[key];
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3229
3390
|
|
|
3230
3391
|
const CLSX_LIKE_NAMES = /* @__PURE__ */ new Set(["clsx", "cn", "cx", "twMerge", "classNames", "classnames"]);
|
|
3231
3392
|
function isClsxLikeName(name) {
|
|
@@ -3532,7 +3693,7 @@ function isExpression(node, t) {
|
|
|
3532
3693
|
return t.isExpression(node);
|
|
3533
3694
|
}
|
|
3534
3695
|
|
|
3535
|
-
const
|
|
3696
|
+
const VISITOR_KEYS = t.VISITOR_KEYS;
|
|
3536
3697
|
function injectTodoComment(unrecognized, parent, options, replacements) {
|
|
3537
3698
|
if (!options.injectTodos || unrecognized.length === 0) {
|
|
3538
3699
|
return;
|
|
@@ -3548,6 +3709,39 @@ function injectTodoComment(unrecognized, parent, options, replacements) {
|
|
|
3548
3709
|
`
|
|
3549
3710
|
});
|
|
3550
3711
|
}
|
|
3712
|
+
function walkAst(node, visitors, ancestors = []) {
|
|
3713
|
+
if (t.isImportDeclaration(node)) {
|
|
3714
|
+
visitors.ImportDeclaration?.(node);
|
|
3715
|
+
} else if (t.isCallExpression(node)) {
|
|
3716
|
+
visitors.CallExpression?.(node, ancestors);
|
|
3717
|
+
} else if (t.isJSXAttribute(node)) {
|
|
3718
|
+
visitors.JSXAttribute?.(node, ancestors[ancestors.length - 1] ?? null);
|
|
3719
|
+
}
|
|
3720
|
+
const keys = VISITOR_KEYS[node.type];
|
|
3721
|
+
if (!keys) {
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3724
|
+
ancestors.push(node);
|
|
3725
|
+
for (const key of keys) {
|
|
3726
|
+
const child = node[key];
|
|
3727
|
+
if (Array.isArray(child)) {
|
|
3728
|
+
for (const item of child) {
|
|
3729
|
+
if (isAstNode(item)) {
|
|
3730
|
+
walkAst(item, visitors, ancestors);
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
} else if (isAstNode(child)) {
|
|
3734
|
+
walkAst(child, visitors, ancestors);
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
ancestors.pop();
|
|
3738
|
+
}
|
|
3739
|
+
function isAstNode(value) {
|
|
3740
|
+
return Boolean(value && typeof value === "object" && "type" in value);
|
|
3741
|
+
}
|
|
3742
|
+
function isClassNameJsxAttribute(node) {
|
|
3743
|
+
return t.isJSXAttribute(node) && t.isJSXIdentifier(node.name) && node.name.name === "className";
|
|
3744
|
+
}
|
|
3551
3745
|
function transformSource(source, filePath, options = {}) {
|
|
3552
3746
|
const warnings = [];
|
|
3553
3747
|
let classNamesTransformed = 0;
|
|
@@ -3558,6 +3752,15 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3558
3752
|
let clsxUsedOutsideClassName = false;
|
|
3559
3753
|
const clsxCallsitesMigrated = /* @__PURE__ */ new Set();
|
|
3560
3754
|
let hasCvaImport = false;
|
|
3755
|
+
if (source.indexOf("className") === -1 && source.indexOf("cva") === -1) {
|
|
3756
|
+
return {
|
|
3757
|
+
code: source,
|
|
3758
|
+
changed: false,
|
|
3759
|
+
warnings: [],
|
|
3760
|
+
stats: { classNamesTransformed: 0, classNamesSkipped: 0, classesUnrecognized: [] },
|
|
3761
|
+
potentiallyUnusedImports: []
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3561
3764
|
let ast;
|
|
3562
3765
|
try {
|
|
3563
3766
|
ast = parse(source, {
|
|
@@ -3575,41 +3778,35 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3575
3778
|
potentiallyUnusedImports: []
|
|
3576
3779
|
};
|
|
3577
3780
|
}
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
const src = path.node.source.value;
|
|
3781
|
+
walkAst(ast, {
|
|
3782
|
+
ImportDeclaration(node) {
|
|
3783
|
+
const src = node.source.value;
|
|
3582
3784
|
const clsxPackages = ["clsx", "clsx/lite", "classnames", "tailwind-merge"];
|
|
3583
3785
|
const isClsxPkg = clsxPackages.some((p) => src === p || src.startsWith(`${p}/`));
|
|
3584
3786
|
const cvaPkgs = ["cva", "class-variance-authority"];
|
|
3585
3787
|
if (cvaPkgs.some((p) => src === p || src.startsWith(`${p}/`))) {
|
|
3586
3788
|
hasCvaImport = true;
|
|
3587
3789
|
}
|
|
3588
|
-
for (const spec of
|
|
3790
|
+
for (const spec of node.specifiers) {
|
|
3589
3791
|
const localName = spec.local.name;
|
|
3590
3792
|
if (isClsxPkg || isClsxLikeName(localName)) {
|
|
3591
3793
|
clsxImportNames.add(localName);
|
|
3592
3794
|
}
|
|
3593
3795
|
}
|
|
3594
3796
|
},
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
const inClassName = path.findParent(
|
|
3599
|
-
(p) => t.isJSXAttribute(p.node) && t.isJSXIdentifier(p.node.name) && p.node.name.name === "className"
|
|
3600
|
-
);
|
|
3797
|
+
CallExpression(node, ancestors) {
|
|
3798
|
+
if (t.isIdentifier(node.callee) && clsxImportNames.has(node.callee.name)) {
|
|
3799
|
+
const inClassName = ancestors.some(isClassNameJsxAttribute);
|
|
3601
3800
|
if (!inClassName) {
|
|
3602
3801
|
clsxUsedOutsideClassName = true;
|
|
3603
3802
|
}
|
|
3604
3803
|
}
|
|
3605
3804
|
},
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
const attrName = path.node.name;
|
|
3805
|
+
JSXAttribute(node, parent) {
|
|
3806
|
+
const attrName = node.name;
|
|
3609
3807
|
if (!t.isJSXIdentifier(attrName) || attrName.name !== "className") {
|
|
3610
3808
|
return;
|
|
3611
3809
|
}
|
|
3612
|
-
const parent = path.parent;
|
|
3613
3810
|
if (t.isJSXOpeningElement(parent)) {
|
|
3614
3811
|
const elementName = parent.name;
|
|
3615
3812
|
const isCapitalized = t.isJSXIdentifier(elementName) && /^[A-Z]/.test(elementName.name) || t.isJSXMemberExpression(elementName);
|
|
@@ -3627,9 +3824,9 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3627
3824
|
return;
|
|
3628
3825
|
}
|
|
3629
3826
|
}
|
|
3630
|
-
const value =
|
|
3631
|
-
const attrStart =
|
|
3632
|
-
const attrEnd =
|
|
3827
|
+
const value = node.value;
|
|
3828
|
+
const attrStart = node.start;
|
|
3829
|
+
const attrEnd = node.end;
|
|
3633
3830
|
if (attrStart === null || attrStart === void 0 || attrEnd === null || attrEnd === void 0) {
|
|
3634
3831
|
return;
|
|
3635
3832
|
}
|
|
@@ -3639,7 +3836,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3639
3836
|
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3640
3837
|
classNamesTransformed++;
|
|
3641
3838
|
classesUnrecognized.push(...result.unrecognized);
|
|
3642
|
-
injectTodoComment(result.unrecognized,
|
|
3839
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3643
3840
|
} else {
|
|
3644
3841
|
classNamesSkipped++;
|
|
3645
3842
|
}
|
|
@@ -3657,7 +3854,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3657
3854
|
});
|
|
3658
3855
|
classNamesTransformed++;
|
|
3659
3856
|
classesUnrecognized.push(...result.unrecognized);
|
|
3660
|
-
injectTodoComment(result.unrecognized,
|
|
3857
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3661
3858
|
} else {
|
|
3662
3859
|
classNamesSkipped++;
|
|
3663
3860
|
}
|
|
@@ -3677,7 +3874,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3677
3874
|
classNamesSkipped++;
|
|
3678
3875
|
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3679
3876
|
}
|
|
3680
|
-
injectTodoComment(result.unrecognized,
|
|
3877
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3681
3878
|
return;
|
|
3682
3879
|
}
|
|
3683
3880
|
if (t.isCallExpression(expr) && t.isIdentifier(expr.callee) && isClsxLikeName(expr.callee.name)) {
|
|
@@ -3697,7 +3894,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3697
3894
|
classNamesSkipped++;
|
|
3698
3895
|
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3699
3896
|
}
|
|
3700
|
-
injectTodoComment(result.unrecognized,
|
|
3897
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3701
3898
|
return;
|
|
3702
3899
|
}
|
|
3703
3900
|
if (t.isConditionalExpression(expr)) {
|
|
@@ -3714,7 +3911,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3714
3911
|
classNamesSkipped++;
|
|
3715
3912
|
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3716
3913
|
}
|
|
3717
|
-
injectTodoComment(result.unrecognized,
|
|
3914
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3718
3915
|
return;
|
|
3719
3916
|
}
|
|
3720
3917
|
if (t.isLogicalExpression(expr) && expr.operator === "&&") {
|
|
@@ -3731,7 +3928,7 @@ function transformSource(source, filePath, options = {}) {
|
|
|
3731
3928
|
classNamesSkipped++;
|
|
3732
3929
|
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3733
3930
|
}
|
|
3734
|
-
injectTodoComment(result.unrecognized,
|
|
3931
|
+
injectTodoComment(result.unrecognized, parent, options, replacements);
|
|
3735
3932
|
return;
|
|
3736
3933
|
}
|
|
3737
3934
|
classNamesSkipped++;
|
|
@@ -3860,9 +4057,9 @@ function transformHtmlSourceSimple(source, filePath, options = {}) {
|
|
|
3860
4057
|
function createLogFile(cwd) {
|
|
3861
4058
|
const now = /* @__PURE__ */ new Date();
|
|
3862
4059
|
const ts = now.toISOString().slice(0, 19).replace("T", "_").replace(/:/g, "-");
|
|
3863
|
-
const logDir =
|
|
4060
|
+
const logDir = path__default.join(cwd, ".csszyx", "logs");
|
|
3864
4061
|
fs$1.mkdirSync(logDir, { recursive: true });
|
|
3865
|
-
const filePath =
|
|
4062
|
+
const filePath = path__default.join(logDir, `migrate-${ts}.log`);
|
|
3866
4063
|
const lines = [`csszyx migrate \u2014 ${now.toISOString()}`, ""];
|
|
3867
4064
|
return {
|
|
3868
4065
|
filePath,
|
|
@@ -3873,7 +4070,7 @@ function createLogFile(cwd) {
|
|
|
3873
4070
|
}
|
|
3874
4071
|
function isGitignored(cwd, pattern) {
|
|
3875
4072
|
try {
|
|
3876
|
-
const content = fs$1.readFileSync(
|
|
4073
|
+
const content = fs$1.readFileSync(path__default.join(cwd, ".gitignore"), "utf-8");
|
|
3877
4074
|
return content.split("\n").some((l) => {
|
|
3878
4075
|
const t = l.trim();
|
|
3879
4076
|
return t === pattern || t === `${pattern}/` || t === `/${pattern}`;
|
|
@@ -3916,7 +4113,7 @@ async function migrate(options = {}) {
|
|
|
3916
4113
|
}
|
|
3917
4114
|
if (resolveTodosPath) {
|
|
3918
4115
|
try {
|
|
3919
|
-
const absolutePath =
|
|
4116
|
+
const absolutePath = path__default.resolve(cwd, resolveTodosPath);
|
|
3920
4117
|
const content = fs$1.readFileSync(absolutePath, "utf-8");
|
|
3921
4118
|
customMap = JSON.parse(content);
|
|
3922
4119
|
printInfo(`Loaded resolution map from ${resolveTodosPath}`);
|
|
@@ -3986,7 +4183,10 @@ async function migrate(options = {}) {
|
|
|
3986
4183
|
}
|
|
3987
4184
|
let processSource = source;
|
|
3988
4185
|
if (resolveTodosPath && !isHtml) {
|
|
3989
|
-
processSource = processSource.replace(
|
|
4186
|
+
processSource = processSource.replace(
|
|
4187
|
+
/\{\/\*\s*@sz-todo:\s*(\S(?:.*\S)?)\s*\*\/\}\n?/g,
|
|
4188
|
+
""
|
|
4189
|
+
);
|
|
3990
4190
|
}
|
|
3991
4191
|
const result = isHtml ? transformHtmlSourceSimple(processSource, filePath, {
|
|
3992
4192
|
braces: options.braces,
|
|
@@ -4002,14 +4202,14 @@ async function migrate(options = {}) {
|
|
|
4002
4202
|
totalSkipped += result.stats.classNamesSkipped;
|
|
4003
4203
|
allUnrecognized.push(...result.stats.classesUnrecognized);
|
|
4004
4204
|
if (result.potentiallyUnusedImports.length > 0) {
|
|
4005
|
-
const rel2 =
|
|
4205
|
+
const rel2 = path__default.relative(cwd, filePath);
|
|
4006
4206
|
unusedImportFiles.push({ file: rel2, imports: result.potentiallyUnusedImports });
|
|
4007
4207
|
}
|
|
4008
4208
|
if (!dryRun) {
|
|
4009
4209
|
try {
|
|
4010
4210
|
fs$1.writeFileSync(filePath, result.code, "utf-8");
|
|
4011
4211
|
} catch (err) {
|
|
4012
|
-
const rel2 =
|
|
4212
|
+
const rel2 = path__default.relative(cwd, filePath);
|
|
4013
4213
|
printWarn(
|
|
4014
4214
|
`Could not write ${rel2}: ${err instanceof Error ? err.message : String(err)}`
|
|
4015
4215
|
);
|
|
@@ -4017,7 +4217,7 @@ async function migrate(options = {}) {
|
|
|
4017
4217
|
continue;
|
|
4018
4218
|
}
|
|
4019
4219
|
}
|
|
4020
|
-
const rel =
|
|
4220
|
+
const rel = path__default.relative(cwd, filePath);
|
|
4021
4221
|
if (dryRun) {
|
|
4022
4222
|
printInfo(` ${rel}: ${result.stats.classNamesTransformed} className(s) \u2192 sz`);
|
|
4023
4223
|
log.writeLine(` ${rel}: ${result.stats.classNamesTransformed} className(s) \u2192 sz`);
|
|
@@ -4058,7 +4258,7 @@ async function migrate(options = {}) {
|
|
|
4058
4258
|
}
|
|
4059
4259
|
}
|
|
4060
4260
|
if (audit) {
|
|
4061
|
-
const todoPath =
|
|
4261
|
+
const todoPath = path__default.join(cwd, ".csszyx-todo.json");
|
|
4062
4262
|
const unique = [...new Set(allUnrecognized)];
|
|
4063
4263
|
console.info();
|
|
4064
4264
|
if (unique.length === 0) {
|
|
@@ -4075,19 +4275,19 @@ async function migrate(options = {}) {
|
|
|
4075
4275
|
fs$1.writeFileSync(todoPath, JSON.stringify(todoObj, null, 2));
|
|
4076
4276
|
} catch (err) {
|
|
4077
4277
|
printWarn(
|
|
4078
|
-
`Could not write ${
|
|
4278
|
+
`Could not write ${path__default.relative(cwd, todoPath)}: ${err instanceof Error ? err.message : String(err)}`
|
|
4079
4279
|
);
|
|
4080
4280
|
log.flush();
|
|
4081
4281
|
return;
|
|
4082
4282
|
}
|
|
4083
4283
|
printSuccess(
|
|
4084
|
-
`Audit complete. Exported ${unique.length} unrecognized classes to ${
|
|
4284
|
+
`Audit complete. Exported ${unique.length} unrecognized classes to ${path__default.relative(cwd, todoPath)}.`
|
|
4085
4285
|
);
|
|
4086
4286
|
printInfo(
|
|
4087
4287
|
"Edit this file to map custom classes, then run: npx @csszyx/cli migrate --resolve-todos .csszyx-todo.json"
|
|
4088
4288
|
);
|
|
4089
4289
|
log.writeLine(
|
|
4090
|
-
`Audit: ${unique.length} unrecognized classes written to ${
|
|
4290
|
+
`Audit: ${unique.length} unrecognized classes written to ${path__default.relative(cwd, todoPath)}`
|
|
4091
4291
|
);
|
|
4092
4292
|
}
|
|
4093
4293
|
}
|
|
@@ -4112,13 +4312,353 @@ async function migrate(options = {}) {
|
|
|
4112
4312
|
}
|
|
4113
4313
|
try {
|
|
4114
4314
|
log.flush();
|
|
4115
|
-
printInfo(`Migration log saved to ${
|
|
4315
|
+
printInfo(`Migration log saved to ${path__default.relative(cwd, log.filePath)}`);
|
|
4116
4316
|
} catch {
|
|
4117
4317
|
}
|
|
4118
4318
|
}
|
|
4119
4319
|
|
|
4320
|
+
const DEFAULT_NEXT_SOURCE_PATTERN = "{app,pages,src}/**/*.{ts,tsx,js,jsx,mjs,cjs}";
|
|
4321
|
+
const DEFAULT_NEXT_SOURCE_IGNORE = [
|
|
4322
|
+
"node_modules/**",
|
|
4323
|
+
".git/**",
|
|
4324
|
+
".next/**",
|
|
4325
|
+
".next-turbo-*/**",
|
|
4326
|
+
".csszyx/**",
|
|
4327
|
+
"dist/**",
|
|
4328
|
+
"build/**"
|
|
4329
|
+
];
|
|
4330
|
+
|
|
4331
|
+
async function nextPrebuild(options = {}) {
|
|
4332
|
+
const cwd = path__default.resolve(options.cwd ?? process.cwd());
|
|
4333
|
+
const root = path__default.resolve(options.root ?? cwd);
|
|
4334
|
+
const pattern = options.pattern ?? DEFAULT_NEXT_SOURCE_PATTERN;
|
|
4335
|
+
try {
|
|
4336
|
+
const mode = normalizeMode(options.mode);
|
|
4337
|
+
const parserMode = normalizeParserMode$1(options.parserMode);
|
|
4338
|
+
const matches = await fg(pattern, {
|
|
4339
|
+
cwd: root,
|
|
4340
|
+
absolute: true,
|
|
4341
|
+
ignore: [...DEFAULT_NEXT_SOURCE_IGNORE, ...options.extraIgnore ?? []],
|
|
4342
|
+
dot: false,
|
|
4343
|
+
onlyFiles: true
|
|
4344
|
+
});
|
|
4345
|
+
if (matches.length === 0) {
|
|
4346
|
+
const message = `No source files matched pattern \`${pattern}\` under ${root}.`;
|
|
4347
|
+
if (options.json) {
|
|
4348
|
+
console.log(
|
|
4349
|
+
JSON.stringify(
|
|
4350
|
+
{ ok: false, reason: "no-files-matched", root, pattern, mode },
|
|
4351
|
+
null,
|
|
4352
|
+
2
|
|
4353
|
+
)
|
|
4354
|
+
);
|
|
4355
|
+
} else {
|
|
4356
|
+
console.error(`${colors.error(icons.error)} ${message}`);
|
|
4357
|
+
}
|
|
4358
|
+
return 1;
|
|
4359
|
+
}
|
|
4360
|
+
const result = runNextPrebuild({
|
|
4361
|
+
files: matches,
|
|
4362
|
+
explicitRoot: root,
|
|
4363
|
+
cwd,
|
|
4364
|
+
mode,
|
|
4365
|
+
parserMode,
|
|
4366
|
+
safelistOutputFile: options.outputFile,
|
|
4367
|
+
cacheDir: options.cacheDir,
|
|
4368
|
+
config: { mangleVars: false }
|
|
4369
|
+
// Versions intentionally omitted: runNextPrebuild's package.json
|
|
4370
|
+
// fallback reads the real installed @csszyx/unplugin and
|
|
4371
|
+
// @csszyx/compiler versions so the manifest's generation identity
|
|
4372
|
+
// tracks the engine that actually runs the transform.
|
|
4373
|
+
});
|
|
4374
|
+
if (options.json) {
|
|
4375
|
+
console.log(
|
|
4376
|
+
JSON.stringify(
|
|
4377
|
+
{
|
|
4378
|
+
ok: true,
|
|
4379
|
+
root,
|
|
4380
|
+
mode,
|
|
4381
|
+
scannedCount: result.scannedCount,
|
|
4382
|
+
transformedCount: result.transformedCount,
|
|
4383
|
+
skippedMissingCount: result.skippedMissingCount,
|
|
4384
|
+
sourceCount: result.sourceCount,
|
|
4385
|
+
classCount: result.classCount,
|
|
4386
|
+
manifestPath: result.manifestPath,
|
|
4387
|
+
safelistOutputPath: result.safelistOutputPath
|
|
4388
|
+
},
|
|
4389
|
+
null,
|
|
4390
|
+
2
|
|
4391
|
+
)
|
|
4392
|
+
);
|
|
4393
|
+
} else {
|
|
4394
|
+
console.log(`${colors.success(icons.success)} csszyx next prebuild done`);
|
|
4395
|
+
console.log(` root: ${root}`);
|
|
4396
|
+
console.log(` mode: ${mode}`);
|
|
4397
|
+
console.log(` scanned: ${result.scannedCount}`);
|
|
4398
|
+
console.log(` transformed: ${result.transformedCount}`);
|
|
4399
|
+
console.log(` skipped: ${result.skippedMissingCount}`);
|
|
4400
|
+
console.log(` sources: ${result.sourceCount}`);
|
|
4401
|
+
console.log(` classes: ${result.classCount}`);
|
|
4402
|
+
console.log(` safelist: ${result.safelistOutputPath}`);
|
|
4403
|
+
console.log(` manifest: ${result.manifestPath}`);
|
|
4404
|
+
}
|
|
4405
|
+
return 0;
|
|
4406
|
+
} catch (error) {
|
|
4407
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4408
|
+
if (options.json) {
|
|
4409
|
+
console.log(JSON.stringify({ ok: false, reason: message }, null, 2));
|
|
4410
|
+
} else {
|
|
4411
|
+
console.error(`${colors.error(icons.error)} ${message}`);
|
|
4412
|
+
}
|
|
4413
|
+
return 1;
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
function normalizeMode(mode) {
|
|
4417
|
+
if (mode === void 0) {
|
|
4418
|
+
return "production";
|
|
4419
|
+
}
|
|
4420
|
+
if (mode === "development" || mode === "production") {
|
|
4421
|
+
return mode;
|
|
4422
|
+
}
|
|
4423
|
+
throw new Error(`Invalid --mode "${mode}". Expected "development" or "production".`);
|
|
4424
|
+
}
|
|
4425
|
+
function normalizeParserMode$1(parserMode) {
|
|
4426
|
+
if (parserMode === void 0) {
|
|
4427
|
+
return void 0;
|
|
4428
|
+
}
|
|
4429
|
+
if (parserMode === "rust" || parserMode === "oxc" || parserMode === "babel") {
|
|
4430
|
+
return parserMode;
|
|
4431
|
+
}
|
|
4432
|
+
throw new Error(`Invalid --parser-mode "${parserMode}". Expected "rust", "oxc", or "babel".`);
|
|
4433
|
+
}
|
|
4434
|
+
|
|
4435
|
+
const SOURCE_EXTENSION = /\.[cm]?[jt]sx?$/i;
|
|
4436
|
+
async function startNextWatch(options = {}, dependencies = {}) {
|
|
4437
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
4438
|
+
const root = path.resolve(options.root ?? cwd);
|
|
4439
|
+
const pattern = options.pattern ?? DEFAULT_NEXT_SOURCE_PATTERN;
|
|
4440
|
+
const ignore = [...DEFAULT_NEXT_SOURCE_IGNORE, ...options.extraIgnore ?? []];
|
|
4441
|
+
const parserMode = normalizeParserMode(options.parserMode);
|
|
4442
|
+
const debounceMs = normalizeDebounceMs(options.debounceMs);
|
|
4443
|
+
const files = await fg(pattern, {
|
|
4444
|
+
cwd: root,
|
|
4445
|
+
absolute: true,
|
|
4446
|
+
ignore,
|
|
4447
|
+
dot: false,
|
|
4448
|
+
onlyFiles: true
|
|
4449
|
+
});
|
|
4450
|
+
if (files.length === 0) {
|
|
4451
|
+
throw new Error(`No source files matched pattern \`${pattern}\` under ${root}.`);
|
|
4452
|
+
}
|
|
4453
|
+
const prebuild = runNextPrebuild({
|
|
4454
|
+
files,
|
|
4455
|
+
explicitRoot: root,
|
|
4456
|
+
cwd,
|
|
4457
|
+
mode: "development",
|
|
4458
|
+
parserMode,
|
|
4459
|
+
safelistOutputFile: options.outputFile,
|
|
4460
|
+
cacheDir: options.cacheDir,
|
|
4461
|
+
config: { mangleVars: false }
|
|
4462
|
+
});
|
|
4463
|
+
let resolveFailure = () => {
|
|
4464
|
+
};
|
|
4465
|
+
let failed = false;
|
|
4466
|
+
const failure = new Promise((resolve) => {
|
|
4467
|
+
resolveFailure = resolve;
|
|
4468
|
+
});
|
|
4469
|
+
const reportFailure = (error) => {
|
|
4470
|
+
if (failed) {
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
failed = true;
|
|
4474
|
+
resolveFailure(error instanceof Error ? error : new Error(String(error)));
|
|
4475
|
+
};
|
|
4476
|
+
const controller = new NextSafelistWatcher({
|
|
4477
|
+
context: prebuild.context,
|
|
4478
|
+
debounceMs,
|
|
4479
|
+
onError: reportFailure
|
|
4480
|
+
});
|
|
4481
|
+
const watchFactory = dependencies.watch ?? watch;
|
|
4482
|
+
const fsWatcher = watchFactory(root, {
|
|
4483
|
+
ignoreInitial: true,
|
|
4484
|
+
persistent: true,
|
|
4485
|
+
atomic: true,
|
|
4486
|
+
awaitWriteFinish: {
|
|
4487
|
+
stabilityThreshold: 25,
|
|
4488
|
+
pollInterval: 10
|
|
4489
|
+
},
|
|
4490
|
+
ignored: createIgnoredMatcher(root, prebuild.context.safelist.shardsDir, ignore)
|
|
4491
|
+
});
|
|
4492
|
+
fsWatcher.on("all", (event, filePath) => {
|
|
4493
|
+
const absolutePath = path.resolve(filePath);
|
|
4494
|
+
if (event === "add" || event === "change" || event === "unlink") {
|
|
4495
|
+
if (controller.notify(event, absolutePath) || event !== "unlink" || !SOURCE_EXTENSION.test(absolutePath)) {
|
|
4496
|
+
return;
|
|
4497
|
+
}
|
|
4498
|
+
controller.notifySourceRemoval(absolutePath);
|
|
4499
|
+
}
|
|
4500
|
+
});
|
|
4501
|
+
fsWatcher.on("error", reportFailure);
|
|
4502
|
+
try {
|
|
4503
|
+
await waitForWatcherReady(fsWatcher);
|
|
4504
|
+
controller.start();
|
|
4505
|
+
} catch (error) {
|
|
4506
|
+
await fsWatcher.close();
|
|
4507
|
+
controller.close();
|
|
4508
|
+
throw error;
|
|
4509
|
+
}
|
|
4510
|
+
let closed = false;
|
|
4511
|
+
return {
|
|
4512
|
+
root,
|
|
4513
|
+
sourcePattern: pattern,
|
|
4514
|
+
safelistOutputPath: prebuild.safelistOutputPath,
|
|
4515
|
+
manifestPath: prebuild.manifestPath,
|
|
4516
|
+
failure,
|
|
4517
|
+
close: async () => {
|
|
4518
|
+
if (closed) {
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
4521
|
+
closed = true;
|
|
4522
|
+
await fsWatcher.close();
|
|
4523
|
+
controller.close();
|
|
4524
|
+
}
|
|
4525
|
+
};
|
|
4526
|
+
}
|
|
4527
|
+
async function nextWatch(options = {}) {
|
|
4528
|
+
let session;
|
|
4529
|
+
let exitCode = 0;
|
|
4530
|
+
try {
|
|
4531
|
+
session = await startNextWatch(options);
|
|
4532
|
+
if (!options.silent) {
|
|
4533
|
+
console.log(`${colors.success(icons.success)} csszyx next watch ready`);
|
|
4534
|
+
console.log(` root: ${session.root}`);
|
|
4535
|
+
console.log(` pattern: ${session.sourcePattern}`);
|
|
4536
|
+
console.log(` safelist: ${session.safelistOutputPath}`);
|
|
4537
|
+
console.log(` manifest: ${session.manifestPath}`);
|
|
4538
|
+
}
|
|
4539
|
+
const outcome = await waitForShutdown(session.failure);
|
|
4540
|
+
if (outcome) {
|
|
4541
|
+
console.error(`${colors.error(icons.error)} ${outcome.message}`);
|
|
4542
|
+
exitCode = 1;
|
|
4543
|
+
}
|
|
4544
|
+
} catch (error) {
|
|
4545
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4546
|
+
console.error(`${colors.error(icons.error)} ${message}`);
|
|
4547
|
+
exitCode = 1;
|
|
4548
|
+
}
|
|
4549
|
+
try {
|
|
4550
|
+
await session?.close();
|
|
4551
|
+
} catch (error) {
|
|
4552
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4553
|
+
console.error(`${colors.error(icons.error)} Failed to close Next watcher: ${message}`);
|
|
4554
|
+
exitCode = 1;
|
|
4555
|
+
}
|
|
4556
|
+
return exitCode;
|
|
4557
|
+
}
|
|
4558
|
+
function waitForWatcherReady(watcher) {
|
|
4559
|
+
return new Promise((resolve, reject) => {
|
|
4560
|
+
const onReady = () => {
|
|
4561
|
+
watcher.off("error", onStartupError);
|
|
4562
|
+
resolve();
|
|
4563
|
+
};
|
|
4564
|
+
const onStartupError = (error) => {
|
|
4565
|
+
watcher.off("ready", onReady);
|
|
4566
|
+
reject(error);
|
|
4567
|
+
};
|
|
4568
|
+
watcher.once("ready", onReady);
|
|
4569
|
+
watcher.once("error", onStartupError);
|
|
4570
|
+
});
|
|
4571
|
+
}
|
|
4572
|
+
function waitForShutdown(failure) {
|
|
4573
|
+
return new Promise((resolve) => {
|
|
4574
|
+
const cleanup = () => {
|
|
4575
|
+
process.off("SIGINT", onSignal);
|
|
4576
|
+
process.off("SIGTERM", onSignal);
|
|
4577
|
+
};
|
|
4578
|
+
const onSignal = () => {
|
|
4579
|
+
cleanup();
|
|
4580
|
+
resolve(void 0);
|
|
4581
|
+
};
|
|
4582
|
+
process.once("SIGINT", onSignal);
|
|
4583
|
+
process.once("SIGTERM", onSignal);
|
|
4584
|
+
failure.then((error) => {
|
|
4585
|
+
cleanup();
|
|
4586
|
+
resolve(error);
|
|
4587
|
+
});
|
|
4588
|
+
});
|
|
4589
|
+
}
|
|
4590
|
+
function createIgnoredMatcher(root, shardsDir, ignore) {
|
|
4591
|
+
const normalizedShardsDir = path.resolve(shardsDir);
|
|
4592
|
+
const matchers = ignore.flatMap((pattern) => {
|
|
4593
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
4594
|
+
const variants = normalized.endsWith("/**") ? [normalized, normalized.slice(0, -3)] : [normalized];
|
|
4595
|
+
return variants.map((variant) => new Minimatch(variant, { dot: true }));
|
|
4596
|
+
});
|
|
4597
|
+
return (candidate) => {
|
|
4598
|
+
const absolute = path.resolve(candidate);
|
|
4599
|
+
const relativeToShards = path.relative(absolute, normalizedShardsDir);
|
|
4600
|
+
if (absolute === normalizedShardsDir || absolute.startsWith(`${normalizedShardsDir}${path.sep}`) || relativeToShards !== ".." && !relativeToShards.startsWith(`..${path.sep}`) && !path.isAbsolute(relativeToShards)) {
|
|
4601
|
+
return false;
|
|
4602
|
+
}
|
|
4603
|
+
const relative = path.relative(root, absolute).replace(/\\/g, "/");
|
|
4604
|
+
if (!relative || relative.startsWith("../") || path.isAbsolute(relative)) {
|
|
4605
|
+
return false;
|
|
4606
|
+
}
|
|
4607
|
+
return matchers.some((matcher) => matcher.match(relative));
|
|
4608
|
+
};
|
|
4609
|
+
}
|
|
4610
|
+
function normalizeParserMode(parserMode) {
|
|
4611
|
+
if (parserMode === void 0) {
|
|
4612
|
+
return void 0;
|
|
4613
|
+
}
|
|
4614
|
+
if (parserMode === "rust" || parserMode === "oxc" || parserMode === "babel") {
|
|
4615
|
+
return parserMode;
|
|
4616
|
+
}
|
|
4617
|
+
throw new Error(`Invalid --parser-mode "${parserMode}". Expected "rust", "oxc", or "babel".`);
|
|
4618
|
+
}
|
|
4619
|
+
function normalizeDebounceMs(debounceMs) {
|
|
4620
|
+
if (debounceMs === void 0) {
|
|
4621
|
+
return void 0;
|
|
4622
|
+
}
|
|
4623
|
+
const parsed = typeof debounceMs === "number" ? debounceMs : Number(debounceMs);
|
|
4624
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 6e4) {
|
|
4625
|
+
throw new Error("Invalid --debounce-ms. Expected an integer between 0 and 60000.");
|
|
4626
|
+
}
|
|
4627
|
+
return parsed;
|
|
4628
|
+
}
|
|
4629
|
+
|
|
4120
4630
|
const cli = cac("csszyx");
|
|
4631
|
+
normalizeNextCommandAlias(process.argv);
|
|
4121
4632
|
const VERSION = "0.0.0";
|
|
4633
|
+
async function runNextPrebuildCommand(pattern, options) {
|
|
4634
|
+
const code = await nextPrebuild({
|
|
4635
|
+
cwd: options.cwd,
|
|
4636
|
+
root: options.root,
|
|
4637
|
+
mode: options.mode,
|
|
4638
|
+
parserMode: options.parserMode,
|
|
4639
|
+
outputFile: options.outputFile,
|
|
4640
|
+
cacheDir: options.cacheDir,
|
|
4641
|
+
pattern,
|
|
4642
|
+
extraIgnore: options.ignore ? String(options.ignore).split(",") : void 0,
|
|
4643
|
+
json: options.json
|
|
4644
|
+
});
|
|
4645
|
+
if (code !== 0) {
|
|
4646
|
+
process.exit(code);
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
async function runNextWatchCommand(pattern, options) {
|
|
4650
|
+
const code = await nextWatch({
|
|
4651
|
+
cwd: options.cwd,
|
|
4652
|
+
root: options.root,
|
|
4653
|
+
parserMode: options.parserMode,
|
|
4654
|
+
outputFile: options.outputFile,
|
|
4655
|
+
cacheDir: options.cacheDir,
|
|
4656
|
+
pattern,
|
|
4657
|
+
extraIgnore: options.ignore ? String(options.ignore).split(",") : void 0,
|
|
4658
|
+
debounceMs: options.debounceMs
|
|
4659
|
+
});
|
|
4660
|
+
process.exitCode = code;
|
|
4661
|
+
}
|
|
4122
4662
|
cli.command("init", "Setup csszyx in your project").option("--framework <name>", "Specify framework").option("--yes", "Skip prompts (use defaults)").option("--cwd <dir>", "Current working directory").action(async (options) => {
|
|
4123
4663
|
await init({
|
|
4124
4664
|
framework: options.framework,
|
|
@@ -4167,11 +4707,27 @@ cli.command("migrate [dir]", "Convert Tailwind className to sz prop").option("--
|
|
|
4167
4707
|
resolveTodos: options.resolveTodos
|
|
4168
4708
|
});
|
|
4169
4709
|
});
|
|
4710
|
+
cli.command(
|
|
4711
|
+
"next-prebuild [pattern]",
|
|
4712
|
+
"Seed the Next.js Turbopack csszyx safelist and generation manifest"
|
|
4713
|
+
).option("--root <dir>", "Next app root (defaults to cwd)").option("--cwd <dir>", "Current working directory").option("--mode <mode>", "development | production (default: production)").option("--parser-mode <mode>", "rust | oxc | babel (default: rust)").option(
|
|
4714
|
+
"--output-file <path>",
|
|
4715
|
+
"Tailwind @source safelist output (default: csszyx-classes.html)"
|
|
4716
|
+
).option("--cache-dir <dir>", "Cache directory relative to root (default: .csszyx/cache)").option("--ignore <patterns>", "Extra glob patterns to ignore (comma-separated)").option("--json", "Emit a single JSON result instead of formatted text").action(runNextPrebuildCommand);
|
|
4717
|
+
cli.command("next-watch [pattern]", "Maintain the Next.js Turbopack csszyx safelist").option("--root <dir>", "Next app root (defaults to cwd)").option("--cwd <dir>", "Current working directory").option("--parser-mode <mode>", "rust | oxc | babel (default: rust)").option(
|
|
4718
|
+
"--output-file <path>",
|
|
4719
|
+
"Tailwind @source safelist output (default: csszyx-classes.html)"
|
|
4720
|
+
).option("--cache-dir <dir>", "Cache directory relative to root (default: .csszyx/cache)").option("--ignore <patterns>", "Extra glob patterns to ignore (comma-separated)").option("--debounce-ms <ms>", "Safelist materialization debounce (default: 50)").action(runNextWatchCommand);
|
|
4170
4721
|
cli.command("").action(() => {
|
|
4171
4722
|
cli.outputHelp();
|
|
4172
4723
|
});
|
|
4173
4724
|
cli.help();
|
|
4174
4725
|
cli.version(VERSION);
|
|
4175
4726
|
cli.parse();
|
|
4727
|
+
function normalizeNextCommandAlias(argv) {
|
|
4728
|
+
if (argv[2] === "next" && (argv[3] === "prebuild" || argv[3] === "watch")) {
|
|
4729
|
+
argv.splice(2, 2, `next-${argv[3]}`);
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4176
4732
|
|
|
4177
4733
|
export { classNameToSzObject, extractScreenKeys, extractSpacingKeys, findConfigFile, flattenColors, generateAndWriteTypes, generateTypeDeclarations, generateTypes, transformSource as migrateSource, scanTailwindConfig, writeDeclarationFile };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csszyx/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Command-line tools for csszyx",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"csszyx",
|
|
@@ -27,8 +27,10 @@
|
|
|
27
27
|
"types": "./dist/index.d.mts",
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
|
-
"
|
|
31
|
-
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
32
|
+
"default": "./dist/index.mjs"
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
},
|
|
34
36
|
"files": [
|
|
@@ -36,28 +38,27 @@
|
|
|
36
38
|
],
|
|
37
39
|
"dependencies": {
|
|
38
40
|
"@babel/parser": "^7.23.0",
|
|
39
|
-
"@babel/traverse": "^7.23.0",
|
|
40
|
-
"@babel/generator": "^7.23.0",
|
|
41
41
|
"@babel/types": "^7.23.0",
|
|
42
42
|
"cac": "^6.7.14",
|
|
43
|
-
"
|
|
44
|
-
"tailwindcss": "^3.4.1",
|
|
45
|
-
"prompts": "^2.4.2",
|
|
46
|
-
"picocolors": "^1.0.0",
|
|
47
|
-
"ora": "^8.0.1",
|
|
43
|
+
"chokidar": "^5.0.0",
|
|
48
44
|
"execa": "^8.0.1",
|
|
45
|
+
"fast-glob": "^3.3.2",
|
|
49
46
|
"fs-extra": "^11.2.0",
|
|
50
|
-
"
|
|
47
|
+
"minimatch": "^10.2.4",
|
|
48
|
+
"ora": "^8.0.1",
|
|
49
|
+
"picocolors": "^1.0.0",
|
|
50
|
+
"prompts": "^2.4.2",
|
|
51
|
+
"tailwindcss": "^3.4.1",
|
|
52
|
+
"@csszyx/types": "0.9.1",
|
|
53
|
+
"@csszyx/unplugin": "0.9.1"
|
|
51
54
|
},
|
|
52
55
|
"devDependencies": {
|
|
53
|
-
"@types/
|
|
54
|
-
"@types/babel__traverse": "^7.20.5",
|
|
56
|
+
"@types/fs-extra": "^11.0.4",
|
|
55
57
|
"@types/node": "^20.11.5",
|
|
56
58
|
"@types/prompts": "^2.4.9",
|
|
57
|
-
"@types/fs-extra": "^11.0.4",
|
|
58
59
|
"typescript": "^6.0.3",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
60
|
+
"unbuild": "^3.6.1",
|
|
61
|
+
"vitest": "^4.1.6"
|
|
61
62
|
},
|
|
62
63
|
"sideEffects": false,
|
|
63
64
|
"engines": {
|