@csszyx/cli 0.3.1 → 0.5.0
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 +13 -1
- package/dist/index.d.ts +78 -1
- package/dist/index.js +1209 -88
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -80,25 +80,30 @@ async function audit(options = {}) {
|
|
|
80
80
|
}
|
|
81
81
|
printHeader("csszyx Audit Report");
|
|
82
82
|
printSection("\u{1F4CA} Mangle Statistics");
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
"Tier
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
83
|
+
if (stats.totalClasses === 0) {
|
|
84
|
+
console.log(" Tier distribution not yet available.");
|
|
85
|
+
console.log(" Run a production build first, then re-run csszyx audit.");
|
|
86
|
+
} else {
|
|
87
|
+
console.log(` Total Classes: ${stats.totalClasses}`);
|
|
88
|
+
console.log(` Mangled Classes: ${stats.totalClasses} (100%)`);
|
|
89
|
+
console.log(" Unmangled Classes: 0");
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(" Tier Distribution:");
|
|
92
|
+
const tierNames = [
|
|
93
|
+
"Tier 1 (a-Z)",
|
|
94
|
+
"Tier 2 (a0-Z9)",
|
|
95
|
+
"Tier 3 (aa-ZZ)",
|
|
96
|
+
"Tier 4 (a00-Z99)",
|
|
97
|
+
"Tier 5 (aaa+)"
|
|
98
|
+
];
|
|
99
|
+
for (let i = 1; i <= 5; i++) {
|
|
100
|
+
const count = stats.tierDistribution[i] || 0;
|
|
101
|
+
const percent = stats.totalClasses ? Math.round(count / stats.totalClasses * 100) : 0;
|
|
102
|
+
const bar = printBar([count], stats.totalClasses, 20);
|
|
103
|
+
console.log(
|
|
104
|
+
` \u2022 ${tierNames[i - 1].padEnd(18)} ${String(count).padStart(3)} (${String(percent).padStart(2)}%) ${colors.dim(bar)}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
102
107
|
}
|
|
103
108
|
printSection("\u{1F4BE} Bundle Size Impact");
|
|
104
109
|
if (stats.bundleSavings.originalHTML > 0) {
|
|
@@ -145,14 +150,6 @@ async function collectStats(cwd) {
|
|
|
145
150
|
stats.bundleSavings.mangledCSS = Buffer.byteLength(cssContent);
|
|
146
151
|
stats.bundleSavings.originalCSS = Math.round(stats.bundleSavings.mangledCSS * 1.71);
|
|
147
152
|
}
|
|
148
|
-
stats.totalClasses = 247;
|
|
149
|
-
stats.tierDistribution = {
|
|
150
|
-
1: 52,
|
|
151
|
-
2: 87,
|
|
152
|
-
3: 64,
|
|
153
|
-
4: 32,
|
|
154
|
-
5: 12
|
|
155
|
-
};
|
|
156
153
|
return stats;
|
|
157
154
|
}
|
|
158
155
|
function formatBytes(bytes) {
|
|
@@ -328,8 +325,6 @@ async function doctor(options = {}) {
|
|
|
328
325
|
printSuccess("\u2728 No issues found! Your setup looks good.");
|
|
329
326
|
} else {
|
|
330
327
|
printWarn(`Found ${issueCount} issue(s)`);
|
|
331
|
-
console.log();
|
|
332
|
-
console.log("Run `csszyx doctor --fix` to auto-fix common issues");
|
|
333
328
|
}
|
|
334
329
|
}
|
|
335
330
|
|
|
@@ -1283,6 +1278,16 @@ import path4 from "path";
|
|
|
1283
1278
|
import { execa } from "execa";
|
|
1284
1279
|
import fs4 from "fs-extra";
|
|
1285
1280
|
import prompts from "prompts";
|
|
1281
|
+
var VITE_FRAMEWORKS = /* @__PURE__ */ new Set(["vite-react", "vite-vue", "vite-svelte"]);
|
|
1282
|
+
var NEXTJS_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs-app", "nextjs-pages"]);
|
|
1283
|
+
var CSS_ENTRY_CANDIDATES = [
|
|
1284
|
+
"src/index.css",
|
|
1285
|
+
"src/app.css",
|
|
1286
|
+
"src/globals.css",
|
|
1287
|
+
"app/globals.css",
|
|
1288
|
+
"src/styles/index.css",
|
|
1289
|
+
"styles/globals.css"
|
|
1290
|
+
];
|
|
1286
1291
|
async function init(options = {}) {
|
|
1287
1292
|
const cwd = options.cwd || process.cwd();
|
|
1288
1293
|
const projectInfo = getProjectInfo(cwd);
|
|
@@ -1294,14 +1299,16 @@ async function init(options = {}) {
|
|
|
1294
1299
|
let config = {
|
|
1295
1300
|
enableSSR: true,
|
|
1296
1301
|
enableRecovery: true,
|
|
1297
|
-
installTailwind: !projectInfo.hasTailwind
|
|
1302
|
+
installTailwind: !projectInfo.hasTailwind,
|
|
1303
|
+
setupGitignore: true,
|
|
1304
|
+
setupTsconfig: !!projectInfo.hasTypeScript
|
|
1298
1305
|
};
|
|
1299
1306
|
if (!options.yes) {
|
|
1300
1307
|
const answers = await prompts([
|
|
1301
1308
|
{
|
|
1302
1309
|
type: projectInfo.hasTailwind ? null : "confirm",
|
|
1303
1310
|
name: "installTailwind",
|
|
1304
|
-
message: "Install Tailwind CSS?",
|
|
1311
|
+
message: "Install Tailwind CSS v4?",
|
|
1305
1312
|
initial: true
|
|
1306
1313
|
},
|
|
1307
1314
|
{
|
|
@@ -1315,6 +1322,18 @@ async function init(options = {}) {
|
|
|
1315
1322
|
name: "enableRecovery",
|
|
1316
1323
|
message: "Enable development mode recovery?",
|
|
1317
1324
|
initial: true
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
type: "confirm",
|
|
1328
|
+
name: "setupGitignore",
|
|
1329
|
+
message: "Add .csszyx to .gitignore?",
|
|
1330
|
+
initial: true
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
type: projectInfo.hasTypeScript ? "confirm" : null,
|
|
1334
|
+
name: "setupTsconfig",
|
|
1335
|
+
message: "Add .csszyx/theme.d.ts to tsconfig.json (Theme Auto-Scan)?",
|
|
1336
|
+
initial: true
|
|
1318
1337
|
}
|
|
1319
1338
|
]);
|
|
1320
1339
|
config = { ...config, ...answers };
|
|
@@ -1323,9 +1342,10 @@ async function init(options = {}) {
|
|
|
1323
1342
|
try {
|
|
1324
1343
|
await execa(projectInfo.packageManager, ["add", "csszyx"], { cwd });
|
|
1325
1344
|
if (config.installTailwind) {
|
|
1345
|
+
const twPackage = VITE_FRAMEWORKS.has(projectInfo.framework) ? "@tailwindcss/vite" : "@tailwindcss/postcss";
|
|
1326
1346
|
await execa(
|
|
1327
1347
|
projectInfo.packageManager,
|
|
1328
|
-
["add", "-D", "tailwindcss",
|
|
1348
|
+
["add", "-D", "tailwindcss", twPackage],
|
|
1329
1349
|
{ cwd }
|
|
1330
1350
|
);
|
|
1331
1351
|
}
|
|
@@ -1337,17 +1357,30 @@ async function init(options = {}) {
|
|
|
1337
1357
|
}
|
|
1338
1358
|
const spin2 = spinner.start("Creating config files...");
|
|
1339
1359
|
try {
|
|
1340
|
-
const configContent = generateConfigFile(config
|
|
1360
|
+
const configContent = generateConfigFile(config);
|
|
1341
1361
|
const configPath = path4.join(
|
|
1342
1362
|
cwd,
|
|
1343
1363
|
projectInfo.hasTypeScript ? "csszyx.config.ts" : "csszyx.config.js"
|
|
1344
1364
|
);
|
|
1345
1365
|
await fs4.writeFile(configPath, configContent);
|
|
1346
1366
|
if (config.installTailwind) {
|
|
1347
|
-
await
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1367
|
+
await setupTailwindCss(cwd, projectInfo.framework);
|
|
1368
|
+
}
|
|
1369
|
+
await injectPlugin(cwd, projectInfo.framework);
|
|
1370
|
+
if (config.setupGitignore) {
|
|
1371
|
+
const gitignorePath = path4.join(cwd, ".gitignore");
|
|
1372
|
+
const ignoreEntry = "\n# csszyx generated theme types\n.csszyx\n";
|
|
1373
|
+
if (fs4.existsSync(gitignorePath)) {
|
|
1374
|
+
const content = await fs4.readFile(gitignorePath, "utf8");
|
|
1375
|
+
if (!content.includes(".csszyx")) {
|
|
1376
|
+
await fs4.appendFile(gitignorePath, ignoreEntry);
|
|
1377
|
+
}
|
|
1378
|
+
} else {
|
|
1379
|
+
await fs4.writeFile(gitignorePath, "node_modules\n.csszyx\n");
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
if (config.setupTsconfig) {
|
|
1383
|
+
await setupTsconfig(cwd);
|
|
1351
1384
|
}
|
|
1352
1385
|
spinner.succeed(spin2, "Created configuration files");
|
|
1353
1386
|
} catch (error) {
|
|
@@ -1360,10 +1393,150 @@ async function init(options = {}) {
|
|
|
1360
1393
|
console.log();
|
|
1361
1394
|
printInfo("Next steps:");
|
|
1362
1395
|
console.log(` \u2022 Run '${projectInfo.packageManager} run dev' to start`);
|
|
1363
|
-
console.log(" \u2022
|
|
1364
|
-
console.log(" \u2022 Check the docs at https://github.com/nguyennhutien/csszyx");
|
|
1396
|
+
console.log(" \u2022 Check the docs at https://csszyx.dev");
|
|
1365
1397
|
}
|
|
1366
|
-
function
|
|
1398
|
+
async function setupTailwindCss(cwd, framework) {
|
|
1399
|
+
let cssPath;
|
|
1400
|
+
for (const candidate of CSS_ENTRY_CANDIDATES) {
|
|
1401
|
+
const full = path4.join(cwd, candidate);
|
|
1402
|
+
if (fs4.existsSync(full)) {
|
|
1403
|
+
cssPath = full;
|
|
1404
|
+
break;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
if (!cssPath) {
|
|
1408
|
+
cssPath = path4.join(cwd, "src/index.css");
|
|
1409
|
+
await fs4.ensureDir(path4.dirname(cssPath));
|
|
1410
|
+
await fs4.writeFile(cssPath, '@import "tailwindcss";\n');
|
|
1411
|
+
printInfo(`Created ${path4.relative(cwd, cssPath)} with Tailwind v4 import`);
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
const content = await fs4.readFile(cssPath, "utf8");
|
|
1415
|
+
if (!content.includes('@import "tailwindcss"') && !content.includes("@import 'tailwindcss'")) {
|
|
1416
|
+
await fs4.writeFile(cssPath, `@import "tailwindcss";
|
|
1417
|
+
|
|
1418
|
+
${content}`);
|
|
1419
|
+
printInfo(`Added Tailwind v4 import to ${path4.relative(cwd, cssPath)}`);
|
|
1420
|
+
}
|
|
1421
|
+
if (NEXTJS_FRAMEWORKS.has(framework)) {
|
|
1422
|
+
const postcssMjs = path4.join(cwd, "postcss.config.mjs");
|
|
1423
|
+
const postcssJs = path4.join(cwd, "postcss.config.js");
|
|
1424
|
+
const postcssTs = path4.join(cwd, "postcss.config.ts");
|
|
1425
|
+
if (!fs4.existsSync(postcssMjs) && !fs4.existsSync(postcssJs) && !fs4.existsSync(postcssTs)) {
|
|
1426
|
+
await fs4.writeFile(postcssMjs, generatePostcssConfig());
|
|
1427
|
+
printInfo("Created postcss.config.mjs for Tailwind v4");
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
async function injectPlugin(cwd, framework) {
|
|
1432
|
+
if (VITE_FRAMEWORKS.has(framework)) {
|
|
1433
|
+
const injected = await injectVitePlugin(cwd);
|
|
1434
|
+
if (!injected) {
|
|
1435
|
+
printWarn("Could not auto-inject csszyx plugin. Add manually to vite.config.ts:");
|
|
1436
|
+
console.log(generateVitePluginInstructions());
|
|
1437
|
+
}
|
|
1438
|
+
} else if (NEXTJS_FRAMEWORKS.has(framework)) {
|
|
1439
|
+
const injected = await injectNextPlugin(cwd);
|
|
1440
|
+
if (!injected) {
|
|
1441
|
+
printWarn("Could not auto-inject csszyx plugin. Add manually to next.config.js:");
|
|
1442
|
+
console.log(generateNextPluginInstructions());
|
|
1443
|
+
}
|
|
1444
|
+
} else {
|
|
1445
|
+
printInfo("Add csszyx plugin to your bundler config:");
|
|
1446
|
+
console.log(generateVitePluginInstructions());
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
async function injectVitePlugin(cwd) {
|
|
1450
|
+
const candidates = [
|
|
1451
|
+
path4.join(cwd, "vite.config.ts"),
|
|
1452
|
+
path4.join(cwd, "vite.config.js"),
|
|
1453
|
+
path4.join(cwd, "vite.config.mts"),
|
|
1454
|
+
path4.join(cwd, "vite.config.mjs")
|
|
1455
|
+
];
|
|
1456
|
+
let configPath;
|
|
1457
|
+
for (const c of candidates) {
|
|
1458
|
+
if (fs4.existsSync(c)) {
|
|
1459
|
+
configPath = c;
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
if (!configPath) {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
let content = await fs4.readFile(configPath, "utf8");
|
|
1467
|
+
if (content.includes("csszyx")) {
|
|
1468
|
+
return true;
|
|
1469
|
+
}
|
|
1470
|
+
const importBlock = [
|
|
1471
|
+
"import csszyx from 'csszyx/vite';",
|
|
1472
|
+
content.includes("@tailwindcss/vite") ? null : "import tailwindcss from '@tailwindcss/vite';"
|
|
1473
|
+
].filter(Boolean).join("\n");
|
|
1474
|
+
const lastImportMatch = [...content.matchAll(/^import .+$/gm)].pop();
|
|
1475
|
+
if (!lastImportMatch || lastImportMatch.index === void 0) {
|
|
1476
|
+
return false;
|
|
1477
|
+
}
|
|
1478
|
+
const insertAt = lastImportMatch.index + lastImportMatch[0].length;
|
|
1479
|
+
content = content.slice(0, insertAt) + "\n" + importBlock + content.slice(insertAt);
|
|
1480
|
+
const pluginsMatch = content.match(/plugins\s*:\s*\[/);
|
|
1481
|
+
if (!pluginsMatch || pluginsMatch.index === void 0) {
|
|
1482
|
+
return false;
|
|
1483
|
+
}
|
|
1484
|
+
const pluginsInsertAt = pluginsMatch.index + pluginsMatch[0].length;
|
|
1485
|
+
const twEntry = content.includes("tailwindcss()") ? "" : "\n tailwindcss(),";
|
|
1486
|
+
content = content.slice(0, pluginsInsertAt) + `
|
|
1487
|
+
...csszyx(), // csszyx MUST come before tailwindcss${twEntry}` + content.slice(pluginsInsertAt);
|
|
1488
|
+
await fs4.writeFile(configPath, content);
|
|
1489
|
+
printInfo(`Injected csszyx plugin into ${path4.basename(configPath)}`);
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
async function injectNextPlugin(cwd) {
|
|
1493
|
+
const candidates = [
|
|
1494
|
+
path4.join(cwd, "next.config.ts"),
|
|
1495
|
+
path4.join(cwd, "next.config.mjs"),
|
|
1496
|
+
path4.join(cwd, "next.config.js")
|
|
1497
|
+
];
|
|
1498
|
+
let configPath;
|
|
1499
|
+
for (const c of candidates) {
|
|
1500
|
+
if (fs4.existsSync(c)) {
|
|
1501
|
+
configPath = c;
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
if (!configPath) {
|
|
1506
|
+
configPath = path4.join(cwd, "next.config.js");
|
|
1507
|
+
await fs4.writeFile(configPath, generateNextConfig());
|
|
1508
|
+
printInfo("Created next.config.js with csszyx plugin");
|
|
1509
|
+
return true;
|
|
1510
|
+
}
|
|
1511
|
+
const content = await fs4.readFile(configPath, "utf8");
|
|
1512
|
+
if (content.includes("csszyx")) {
|
|
1513
|
+
return true;
|
|
1514
|
+
}
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
async function setupTsconfig(cwd) {
|
|
1518
|
+
let tsconfigPath = path4.join(cwd, "tsconfig.json");
|
|
1519
|
+
if (!fs4.existsSync(tsconfigPath)) {
|
|
1520
|
+
const viteTsConfig = path4.join(cwd, "tsconfig.app.json");
|
|
1521
|
+
if (fs4.existsSync(viteTsConfig)) {
|
|
1522
|
+
tsconfigPath = viteTsConfig;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (!fs4.existsSync(tsconfigPath)) {
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
let content = await fs4.readFile(tsconfigPath, "utf8");
|
|
1529
|
+
if (content.includes(".csszyx")) {
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
const includeMatch = content.match(/"include"\s*:\s*\[/);
|
|
1533
|
+
if (includeMatch && includeMatch.index !== void 0) {
|
|
1534
|
+
const insertPos = includeMatch.index + includeMatch[0].length;
|
|
1535
|
+
content = content.slice(0, insertPos) + '\n "./.csszyx/theme.d.ts",\n "./.csszyx",' + content.slice(insertPos);
|
|
1536
|
+
await fs4.writeFile(tsconfigPath, content);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
function generateConfigFile(config) {
|
|
1367
1540
|
return `import type { CsszyxConfig } from 'csszyx';
|
|
1368
1541
|
|
|
1369
1542
|
const config: CsszyxConfig = {
|
|
@@ -1380,27 +1553,86 @@ const config: CsszyxConfig = {
|
|
|
1380
1553
|
export default config;
|
|
1381
1554
|
`;
|
|
1382
1555
|
}
|
|
1383
|
-
function
|
|
1384
|
-
return
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
theme: {
|
|
1388
|
-
extend: {},
|
|
1556
|
+
function generatePostcssConfig() {
|
|
1557
|
+
return `export default {
|
|
1558
|
+
plugins: {
|
|
1559
|
+
'@tailwindcss/postcss': {},
|
|
1389
1560
|
},
|
|
1390
|
-
plugins: [],
|
|
1391
1561
|
};
|
|
1392
1562
|
`;
|
|
1393
1563
|
}
|
|
1564
|
+
function generateNextConfig() {
|
|
1565
|
+
return `const csszyxWebpack = require('@csszyx/unplugin/webpack').default;
|
|
1566
|
+
|
|
1567
|
+
/** @type {import('next').NextConfig} */
|
|
1568
|
+
const nextConfig = {
|
|
1569
|
+
webpack(config) {
|
|
1570
|
+
config.plugins.unshift(...csszyxWebpack());
|
|
1571
|
+
return config;
|
|
1572
|
+
},
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
module.exports = nextConfig;
|
|
1576
|
+
`;
|
|
1577
|
+
}
|
|
1578
|
+
function generateVitePluginInstructions() {
|
|
1579
|
+
return `
|
|
1580
|
+
import csszyx from 'csszyx/vite';
|
|
1581
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
1582
|
+
|
|
1583
|
+
export default defineConfig({
|
|
1584
|
+
plugins: [
|
|
1585
|
+
...csszyx(), // csszyx MUST come before tailwindcss
|
|
1586
|
+
tailwindcss(),
|
|
1587
|
+
// ...your other plugins
|
|
1588
|
+
],
|
|
1589
|
+
});
|
|
1590
|
+
`;
|
|
1591
|
+
}
|
|
1592
|
+
function generateNextPluginInstructions() {
|
|
1593
|
+
return `
|
|
1594
|
+
const csszyxWebpack = require('@csszyx/unplugin/webpack').default;
|
|
1595
|
+
|
|
1596
|
+
module.exports = {
|
|
1597
|
+
webpack(config) {
|
|
1598
|
+
config.plugins.unshift(...csszyxWebpack());
|
|
1599
|
+
return config;
|
|
1600
|
+
},
|
|
1601
|
+
};
|
|
1602
|
+
`;
|
|
1603
|
+
}
|
|
1394
1604
|
|
|
1395
1605
|
// src/commands/migrate.ts
|
|
1396
1606
|
import fs5 from "fs";
|
|
1397
1607
|
import path5 from "path";
|
|
1608
|
+
import readline from "readline";
|
|
1398
1609
|
import fg from "fast-glob";
|
|
1399
1610
|
|
|
1611
|
+
// src/migrate/ast-transformer.ts
|
|
1612
|
+
import { parse } from "@babel/parser";
|
|
1613
|
+
import _traverse from "@babel/traverse";
|
|
1614
|
+
import * as t from "@babel/types";
|
|
1615
|
+
|
|
1400
1616
|
// src/migrate/sz-codegen.ts
|
|
1401
1617
|
function generateSzExpression(obj) {
|
|
1402
1618
|
return `{${objectToString(obj)}}`;
|
|
1403
1619
|
}
|
|
1620
|
+
function generateSzHtmlValue(obj, braces = false) {
|
|
1621
|
+
const s = objectToString(obj);
|
|
1622
|
+
if (braces) {
|
|
1623
|
+
return s;
|
|
1624
|
+
}
|
|
1625
|
+
if (s.startsWith("{ ") && s.endsWith(" }")) {
|
|
1626
|
+
return s.slice(2, -2);
|
|
1627
|
+
}
|
|
1628
|
+
if (s.startsWith("{") && s.endsWith("}")) {
|
|
1629
|
+
return s.slice(1, -1).trim();
|
|
1630
|
+
}
|
|
1631
|
+
return s;
|
|
1632
|
+
}
|
|
1633
|
+
function generateSzObjectLiteral(obj) {
|
|
1634
|
+
return objectToString(obj);
|
|
1635
|
+
}
|
|
1404
1636
|
function objectToString(obj, indent = 0) {
|
|
1405
1637
|
const entries = Object.entries(obj);
|
|
1406
1638
|
if (entries.length === 0) {
|
|
@@ -1526,9 +1758,10 @@ var REVERSE_PROPERTY_MAP = {
|
|
|
1526
1758
|
// Outline (ambiguous)
|
|
1527
1759
|
"outline": "outline",
|
|
1528
1760
|
"outline-offset": "outlineOffset",
|
|
1529
|
-
// Ring
|
|
1761
|
+
// Ring (v4: outset ring + inset ring)
|
|
1530
1762
|
"ring": "ring",
|
|
1531
1763
|
"ring-offset": "ringOffset",
|
|
1764
|
+
"inset-ring": "insetRing",
|
|
1532
1765
|
// Spacing
|
|
1533
1766
|
"p": "p",
|
|
1534
1767
|
"pt": "pt",
|
|
@@ -1586,8 +1819,9 @@ var REVERSE_PROPERTY_MAP = {
|
|
|
1586
1819
|
"right": "right",
|
|
1587
1820
|
"bottom": "bottom",
|
|
1588
1821
|
"left": "left",
|
|
1589
|
-
|
|
1590
|
-
"
|
|
1822
|
+
// TW v4.2: start/end are deprecated — migrate to inset-s/inset-e
|
|
1823
|
+
"start": "insetS",
|
|
1824
|
+
"end": "insetE",
|
|
1591
1825
|
// Typography (ambiguous — text-*, font-* disambiguated)
|
|
1592
1826
|
"text": "color",
|
|
1593
1827
|
// default for text- prefix
|
|
@@ -1643,6 +1877,7 @@ var REVERSE_PROPERTY_MAP = {
|
|
|
1643
1877
|
// Effects
|
|
1644
1878
|
"shadow": "shadow",
|
|
1645
1879
|
// ambiguous (shadow vs shadowColor)
|
|
1880
|
+
"inset-shadow": "insetShadow",
|
|
1646
1881
|
"opacity": "opacity",
|
|
1647
1882
|
"mix-blend": "mixBlend",
|
|
1648
1883
|
"bg-blend": "bgBlend",
|
|
@@ -1801,16 +2036,15 @@ var REVERSE_BOOLEAN_MAP = {
|
|
|
1801
2036
|
"divide-y-reverse": "divideYReverse",
|
|
1802
2037
|
"space-x-reverse": "spaceXReverse",
|
|
1803
2038
|
"space-y-reverse": "spaceYReverse",
|
|
1804
|
-
// Ring/Outline (boolean defaults)
|
|
2039
|
+
// Ring/Outline/Border-radius (boolean defaults)
|
|
1805
2040
|
"ring": "ring",
|
|
2041
|
+
"inset-ring": "insetRing",
|
|
1806
2042
|
"outline": "outline",
|
|
2043
|
+
"rounded": "rounded",
|
|
1807
2044
|
// Transforms
|
|
1808
|
-
"scale-3d": "
|
|
1809
|
-
"
|
|
1810
|
-
|
|
1811
|
-
"transform-gpu": "transformGpu",
|
|
1812
|
-
"transform-cpu": "transformCpu",
|
|
1813
|
-
"transform-none": "transformNone",
|
|
2045
|
+
"scale-3d": "scale",
|
|
2046
|
+
"translate-3d": "translate",
|
|
2047
|
+
// transform-gpu/cpu/none use BOOLEAN_VALUE_MAP → { transform: 'gpu'/'cpu'/'none' }
|
|
1814
2048
|
// Font numeric
|
|
1815
2049
|
"normal-nums": "fontVariant",
|
|
1816
2050
|
"lining-nums": "fontVariant",
|
|
@@ -1872,7 +2106,11 @@ var BOOLEAN_VALUE_MAP = {
|
|
|
1872
2106
|
"stacked-fractions": { prop: "fontVariant", value: "stacked-fractions" },
|
|
1873
2107
|
// Appearance
|
|
1874
2108
|
"appearance-none": { prop: "appearance", value: "none" },
|
|
1875
|
-
"appearance-auto": { prop: "appearance", value: "auto" }
|
|
2109
|
+
"appearance-auto": { prop: "appearance", value: "auto" },
|
|
2110
|
+
// Transform
|
|
2111
|
+
"transform-none": { prop: "transform", value: "none" },
|
|
2112
|
+
"transform-gpu": { prop: "transform", value: "gpu" },
|
|
2113
|
+
"transform-cpu": { prop: "transform", value: "cpu" }
|
|
1876
2114
|
};
|
|
1877
2115
|
var SORTED_PREFIXES = Object.keys(REVERSE_PROPERTY_MAP).sort((a, b) => {
|
|
1878
2116
|
if (b.length !== a.length) {
|
|
@@ -2259,6 +2497,9 @@ function parseClass(cls) {
|
|
|
2259
2497
|
if (prefix === "border") {
|
|
2260
2498
|
return applyImportant({ prop: "border", value: true }, important);
|
|
2261
2499
|
}
|
|
2500
|
+
if (["border-t", "border-r", "border-b", "border-l", "border-x", "border-y", "border-s", "border-e"].includes(prefix)) {
|
|
2501
|
+
return applyImportant({ prop, value: true }, important);
|
|
2502
|
+
}
|
|
2262
2503
|
continue;
|
|
2263
2504
|
}
|
|
2264
2505
|
if (source.startsWith(prefix + "-")) {
|
|
@@ -2406,6 +2647,12 @@ function disambiguateAndParse(prefix, rawValue, negative) {
|
|
|
2406
2647
|
value = rawValue.slice(0, slashIdx);
|
|
2407
2648
|
if (opacity.startsWith("[") && opacity.endsWith("]")) {
|
|
2408
2649
|
opacity = opacity.slice(1, -1);
|
|
2650
|
+
if (!String(opacity).includes("%")) {
|
|
2651
|
+
const opNum = Number(opacity);
|
|
2652
|
+
if (!isNaN(opNum)) {
|
|
2653
|
+
opacity = opNum;
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2409
2656
|
} else if (opacity.startsWith("(") && opacity.endsWith(")")) {
|
|
2410
2657
|
opacity = opacity.slice(1, -1);
|
|
2411
2658
|
} else {
|
|
@@ -2455,6 +2702,10 @@ function disambiguate(prefix, value, negative) {
|
|
|
2455
2702
|
return disambiguateRing(value, negative);
|
|
2456
2703
|
case "ring-offset":
|
|
2457
2704
|
return disambiguateRingOffset(value);
|
|
2705
|
+
case "inset-ring":
|
|
2706
|
+
return disambiguateInsetRing(value, negative);
|
|
2707
|
+
case "inset-shadow":
|
|
2708
|
+
return disambiguateInsetShadow(value);
|
|
2458
2709
|
case "stroke":
|
|
2459
2710
|
return disambiguateStroke(value);
|
|
2460
2711
|
case "list":
|
|
@@ -2496,6 +2747,9 @@ function disambiguateText(value) {
|
|
|
2496
2747
|
if (TEXT_OVERFLOW_KEYWORDS.has(value)) {
|
|
2497
2748
|
return { prop: "textOverflow", value };
|
|
2498
2749
|
}
|
|
2750
|
+
if (isArbitraryDimension(value)) {
|
|
2751
|
+
return { prop: "text", value: parseStringValue(value) };
|
|
2752
|
+
}
|
|
2499
2753
|
return { prop: "color", value: parseStringValue(value) };
|
|
2500
2754
|
}
|
|
2501
2755
|
function disambiguateFont(value) {
|
|
@@ -2524,6 +2778,9 @@ function disambiguateBorder(value) {
|
|
|
2524
2778
|
if (BORDER_STYLE_KEYWORDS.has(value)) {
|
|
2525
2779
|
return { prop: "borderStyle", value };
|
|
2526
2780
|
}
|
|
2781
|
+
if (isArbitraryDimension(value)) {
|
|
2782
|
+
return { prop: "border", value: parseStringValue(value) };
|
|
2783
|
+
}
|
|
2527
2784
|
return { prop: "borderColor", value: parseStringValue(value) };
|
|
2528
2785
|
}
|
|
2529
2786
|
function disambiguateBg(value) {
|
|
@@ -2567,6 +2824,9 @@ function disambiguateOutline(value) {
|
|
|
2567
2824
|
if (!isNaN(num) && Number.isInteger(num)) {
|
|
2568
2825
|
return { prop: "outline", value: num };
|
|
2569
2826
|
}
|
|
2827
|
+
if (isArbitraryDimension(value)) {
|
|
2828
|
+
return { prop: "outline", value: parseStringValue(value) };
|
|
2829
|
+
}
|
|
2570
2830
|
return { prop: "outlineColor", value: parseStringValue(value) };
|
|
2571
2831
|
}
|
|
2572
2832
|
function disambiguateDecoration(value) {
|
|
@@ -2587,8 +2847,8 @@ function disambiguateRing(value, negative) {
|
|
|
2587
2847
|
if (!isNaN(num) && Number.isInteger(num)) {
|
|
2588
2848
|
return { prop: "ring", value: negative ? -num : num };
|
|
2589
2849
|
}
|
|
2590
|
-
if (value
|
|
2591
|
-
return { prop: "ring", value:
|
|
2850
|
+
if (isArbitraryDimension(value)) {
|
|
2851
|
+
return { prop: "ring", value: parseStringValue(value) };
|
|
2592
2852
|
}
|
|
2593
2853
|
return { prop: "ringColor", value: parseStringValue(value) };
|
|
2594
2854
|
}
|
|
@@ -2599,6 +2859,26 @@ function disambiguateRingOffset(value) {
|
|
|
2599
2859
|
}
|
|
2600
2860
|
return { prop: "ringOffsetColor", value: parseStringValue(value) };
|
|
2601
2861
|
}
|
|
2862
|
+
function disambiguateInsetRing(value, negative) {
|
|
2863
|
+
const num = Number(value);
|
|
2864
|
+
if (!isNaN(num) && Number.isInteger(num)) {
|
|
2865
|
+
return { prop: "insetRing", value: negative ? -num : num };
|
|
2866
|
+
}
|
|
2867
|
+
if (isArbitraryDimension(value)) {
|
|
2868
|
+
return { prop: "insetRing", value: parseStringValue(value) };
|
|
2869
|
+
}
|
|
2870
|
+
return { prop: "insetRingColor", value: parseStringValue(value) };
|
|
2871
|
+
}
|
|
2872
|
+
function disambiguateInsetShadow(value) {
|
|
2873
|
+
const INSET_SHADOW_SIZE_KEYWORDS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl", "none", "inner"]);
|
|
2874
|
+
if (INSET_SHADOW_SIZE_KEYWORDS.has(value)) {
|
|
2875
|
+
return { prop: "insetShadow", value };
|
|
2876
|
+
}
|
|
2877
|
+
if (isArbitraryDimension(value)) {
|
|
2878
|
+
return { prop: "insetShadow", value: parseStringValue(value) };
|
|
2879
|
+
}
|
|
2880
|
+
return { prop: "insetShadowColor", value: parseStringValue(value) };
|
|
2881
|
+
}
|
|
2602
2882
|
function disambiguateStroke(value) {
|
|
2603
2883
|
const num = Number(value);
|
|
2604
2884
|
if (!isNaN(num) && Number.isInteger(num)) {
|
|
@@ -2644,6 +2924,13 @@ function disambiguateTable(value) {
|
|
|
2644
2924
|
function disambiguateDivide(value) {
|
|
2645
2925
|
return { prop: "divideColor", value: parseStringValue(value) };
|
|
2646
2926
|
}
|
|
2927
|
+
var CSS_DIMENSION_RE = /^-?[\d.]+(?:px|r?em|ex|ch|vw|vh|vmin|vmax|svh|svw|dvh|dvw|lvh|lvw|cqw|cqh|cqi|cqb|%|fr|deg|rad|turn|grad|ms|s|pt|pc|cm|mm|in)$/;
|
|
2928
|
+
function isArbitraryDimension(value) {
|
|
2929
|
+
if (!value.startsWith("[") || !value.endsWith("]")) {
|
|
2930
|
+
return false;
|
|
2931
|
+
}
|
|
2932
|
+
return CSS_DIMENSION_RE.test(value.slice(1, -1));
|
|
2933
|
+
}
|
|
2647
2934
|
function isValidSpacingValue(value) {
|
|
2648
2935
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
2649
2936
|
return true;
|
|
@@ -2706,6 +2993,12 @@ function parseValue(prefix, value, negative) {
|
|
|
2706
2993
|
if (negative) {
|
|
2707
2994
|
return "-" + inner;
|
|
2708
2995
|
}
|
|
2996
|
+
if (prefix === "content") {
|
|
2997
|
+
const isQuoted = inner.startsWith("'") && inner.endsWith("'") || inner.startsWith('"') && inner.endsWith('"');
|
|
2998
|
+
if (isQuoted) {
|
|
2999
|
+
return `"${inner.slice(1, -1)}"`;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
2709
3002
|
return inner;
|
|
2710
3003
|
}
|
|
2711
3004
|
if (value.startsWith("(") && value.endsWith(")")) {
|
|
@@ -2719,7 +3012,7 @@ function parseValue(prefix, value, negative) {
|
|
|
2719
3012
|
return value;
|
|
2720
3013
|
}
|
|
2721
3014
|
if (value === "px") {
|
|
2722
|
-
return "px";
|
|
3015
|
+
return negative ? "-px" : "px";
|
|
2723
3016
|
}
|
|
2724
3017
|
if (value === "auto") {
|
|
2725
3018
|
return "auto";
|
|
@@ -2888,6 +3181,24 @@ function parseGroupPeerVariant(variant) {
|
|
|
2888
3181
|
keys.push("has");
|
|
2889
3182
|
keys.push(hasRest);
|
|
2890
3183
|
}
|
|
3184
|
+
} else if (rest.startsWith("data-")) {
|
|
3185
|
+
const dataRest = rest.slice(5);
|
|
3186
|
+
keys.push("data");
|
|
3187
|
+
if (dataRest.startsWith("[") && dataRest.endsWith("]")) {
|
|
3188
|
+
keys.push(dataRest.slice(1, -1));
|
|
3189
|
+
} else if (dataRest.startsWith("(") && dataRest.endsWith(")")) {
|
|
3190
|
+
keys.push(dataRest.slice(1, -1));
|
|
3191
|
+
} else {
|
|
3192
|
+
keys.push(dataRest);
|
|
3193
|
+
}
|
|
3194
|
+
} else if (rest.startsWith("aria-")) {
|
|
3195
|
+
const ariaRest = rest.slice(5);
|
|
3196
|
+
keys.push("aria");
|
|
3197
|
+
if (ariaRest.startsWith("[") && ariaRest.endsWith("]")) {
|
|
3198
|
+
keys.push(ariaRest.slice(1, -1));
|
|
3199
|
+
} else {
|
|
3200
|
+
keys.push(ariaRest);
|
|
3201
|
+
}
|
|
2891
3202
|
} else {
|
|
2892
3203
|
keys.push(normalizeVariantKey(rest));
|
|
2893
3204
|
}
|
|
@@ -2915,11 +3226,77 @@ function normalizeVariantKey(variant) {
|
|
|
2915
3226
|
}
|
|
2916
3227
|
return variant;
|
|
2917
3228
|
}
|
|
2918
|
-
|
|
3229
|
+
var TODO_KEEP = "sz:keep";
|
|
3230
|
+
var TODO_REMOVE = "sz:remove";
|
|
3231
|
+
var TODO_PENDING = "sz:todo";
|
|
3232
|
+
function resolveCustomMapEntry(token, customMap, resolveString) {
|
|
3233
|
+
if (!(token in customMap)) {
|
|
3234
|
+
return null;
|
|
3235
|
+
}
|
|
3236
|
+
const val = customMap[token];
|
|
3237
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
3238
|
+
return { action: "sz", value: val };
|
|
3239
|
+
}
|
|
3240
|
+
if (typeof val === "string") {
|
|
3241
|
+
if (val === TODO_KEEP) {
|
|
3242
|
+
return { action: "keep" };
|
|
3243
|
+
}
|
|
3244
|
+
if (val === TODO_REMOVE) {
|
|
3245
|
+
return { action: "remove" };
|
|
3246
|
+
}
|
|
3247
|
+
if (val === TODO_PENDING) {
|
|
3248
|
+
return { action: "unresolved" };
|
|
3249
|
+
}
|
|
3250
|
+
const result = resolveString(val);
|
|
3251
|
+
if (result && Object.keys(result.sz).length > 0) {
|
|
3252
|
+
return { action: "sz", value: result.sz, cascade: result.cascade };
|
|
3253
|
+
}
|
|
3254
|
+
return { action: "unresolved" };
|
|
3255
|
+
}
|
|
3256
|
+
return { action: "unresolved" };
|
|
3257
|
+
}
|
|
3258
|
+
function classNameToSzObject(className, customMap) {
|
|
2919
3259
|
const tokens = tokenize(className);
|
|
2920
3260
|
const szObject = {};
|
|
2921
3261
|
const unrecognized = [];
|
|
3262
|
+
const keepInClassName = [];
|
|
2922
3263
|
for (const token of tokens) {
|
|
3264
|
+
if (customMap && token in customMap) {
|
|
3265
|
+
const entry = resolveCustomMapEntry(
|
|
3266
|
+
token,
|
|
3267
|
+
customMap,
|
|
3268
|
+
// Inline resolver: parse Tailwind string recursively (no customMap to avoid infinite loop).
|
|
3269
|
+
// Returns both the sz object and any unrecognized tokens from the string value,
|
|
3270
|
+
// so partially-valid strings cascade their unknowns back to the unrecognized list.
|
|
3271
|
+
(twStr) => {
|
|
3272
|
+
const inner = classNameToSzObject(twStr);
|
|
3273
|
+
if (Object.keys(inner.szObject).length === 0) {
|
|
3274
|
+
return null;
|
|
3275
|
+
}
|
|
3276
|
+
return { sz: inner.szObject, cascade: inner.unrecognized };
|
|
3277
|
+
}
|
|
3278
|
+
);
|
|
3279
|
+
if (entry) {
|
|
3280
|
+
if (entry.action === "sz") {
|
|
3281
|
+
Object.assign(szObject, entry.value);
|
|
3282
|
+
if (entry.cascade && entry.cascade.length > 0) {
|
|
3283
|
+
unrecognized.push(...entry.cascade);
|
|
3284
|
+
}
|
|
3285
|
+
continue;
|
|
3286
|
+
}
|
|
3287
|
+
if (entry.action === "keep") {
|
|
3288
|
+
keepInClassName.push(token);
|
|
3289
|
+
continue;
|
|
3290
|
+
}
|
|
3291
|
+
if (entry.action === "remove") {
|
|
3292
|
+
continue;
|
|
3293
|
+
}
|
|
3294
|
+
if (entry.action === "unresolved") {
|
|
3295
|
+
unrecognized.push(token);
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
2923
3300
|
const { variantParts, baseClass } = extractVariants(token);
|
|
2924
3301
|
const parsed = parseClass(baseClass);
|
|
2925
3302
|
if (!parsed) {
|
|
@@ -2933,7 +3310,7 @@ function classNameToSzObject(className) {
|
|
|
2933
3310
|
}
|
|
2934
3311
|
setNestedValue(szObject, keyPath, parsed.prop, parsed.value);
|
|
2935
3312
|
}
|
|
2936
|
-
return { szObject, unrecognized };
|
|
3313
|
+
return { szObject, unrecognized, keepInClassName };
|
|
2937
3314
|
}
|
|
2938
3315
|
function setNestedValue(obj, keyPath, prop, value) {
|
|
2939
3316
|
let current = obj;
|
|
@@ -2946,21 +3323,593 @@ function setNestedValue(obj, keyPath, prop, value) {
|
|
|
2946
3323
|
current[prop] = value;
|
|
2947
3324
|
}
|
|
2948
3325
|
|
|
3326
|
+
// src/migrate/dynamic-patterns.ts
|
|
3327
|
+
var CLSX_LIKE_NAMES = /* @__PURE__ */ new Set([
|
|
3328
|
+
"clsx",
|
|
3329
|
+
"cn",
|
|
3330
|
+
"cx",
|
|
3331
|
+
"twMerge",
|
|
3332
|
+
"classNames",
|
|
3333
|
+
"classnames"
|
|
3334
|
+
]);
|
|
3335
|
+
function isClsxLikeName(name) {
|
|
3336
|
+
return CLSX_LIKE_NAMES.has(name);
|
|
3337
|
+
}
|
|
3338
|
+
function handleClsxCall(node, source, t2, customMap) {
|
|
3339
|
+
const warnings = [];
|
|
3340
|
+
const allUnrecognized = [];
|
|
3341
|
+
const elements = [];
|
|
3342
|
+
let converted = 0;
|
|
3343
|
+
for (const arg of node.arguments) {
|
|
3344
|
+
if (t2.isSpreadElement(arg)) {
|
|
3345
|
+
const argSrc2 = safeSlice(source, arg.start, arg.end);
|
|
3346
|
+
warnings.push(`Cannot migrate spread argument: ${argSrc2}`);
|
|
3347
|
+
return skip(allUnrecognized, warnings);
|
|
3348
|
+
}
|
|
3349
|
+
if (t2.isStringLiteral(arg)) {
|
|
3350
|
+
const result = migrateString(arg.value, customMap);
|
|
3351
|
+
if (!result) {
|
|
3352
|
+
return skip(allUnrecognized, warnings);
|
|
3353
|
+
}
|
|
3354
|
+
elements.push(result.objectStr);
|
|
3355
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3356
|
+
converted++;
|
|
3357
|
+
continue;
|
|
3358
|
+
}
|
|
3359
|
+
if (t2.isLogicalExpression(arg) && arg.operator === "&&") {
|
|
3360
|
+
const result = handleLogicalAndInner(arg, source, t2, customMap);
|
|
3361
|
+
if (!result) {
|
|
3362
|
+
const argSrc2 = safeSlice(source, arg.start, arg.end);
|
|
3363
|
+
warnings.push(`Cannot migrate logical expression: ${argSrc2}`);
|
|
3364
|
+
return skip(allUnrecognized, warnings);
|
|
3365
|
+
}
|
|
3366
|
+
elements.push(result.exprStr);
|
|
3367
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3368
|
+
converted++;
|
|
3369
|
+
continue;
|
|
3370
|
+
}
|
|
3371
|
+
if (t2.isConditionalExpression(arg)) {
|
|
3372
|
+
const result = handleTernaryInner(arg, source, t2, customMap);
|
|
3373
|
+
if (!result) {
|
|
3374
|
+
const argSrc2 = safeSlice(source, arg.start, arg.end);
|
|
3375
|
+
warnings.push(`Cannot migrate ternary: ${argSrc2}`);
|
|
3376
|
+
return skip(allUnrecognized, warnings);
|
|
3377
|
+
}
|
|
3378
|
+
elements.push(result.exprStr);
|
|
3379
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3380
|
+
converted++;
|
|
3381
|
+
continue;
|
|
3382
|
+
}
|
|
3383
|
+
const argSrc = safeSlice(source, arg.start, arg.end);
|
|
3384
|
+
warnings.push(`Cannot migrate argument: ${argSrc}`);
|
|
3385
|
+
return skip(allUnrecognized, warnings);
|
|
3386
|
+
}
|
|
3387
|
+
if (elements.length === 0) {
|
|
3388
|
+
return skip(allUnrecognized, warnings);
|
|
3389
|
+
}
|
|
3390
|
+
if (elements.length === 1 && !elements[0].includes("&&") && !elements[0].includes("?")) {
|
|
3391
|
+
return {
|
|
3392
|
+
replacement: `sz={${elements[0]}}`,
|
|
3393
|
+
unrecognized: allUnrecognized,
|
|
3394
|
+
warnings,
|
|
3395
|
+
converted,
|
|
3396
|
+
migrated: true
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
return {
|
|
3400
|
+
replacement: `sz={[${elements.join(", ")}]}`,
|
|
3401
|
+
unrecognized: allUnrecognized,
|
|
3402
|
+
warnings,
|
|
3403
|
+
converted,
|
|
3404
|
+
migrated: true
|
|
3405
|
+
};
|
|
3406
|
+
}
|
|
3407
|
+
function handleTernary(node, source, t2, customMap) {
|
|
3408
|
+
const result = handleTernaryInner(node, source, t2, customMap);
|
|
3409
|
+
if (!result) {
|
|
3410
|
+
return {
|
|
3411
|
+
replacement: "",
|
|
3412
|
+
unrecognized: [],
|
|
3413
|
+
warnings: ["Ternary branches must be string literals"],
|
|
3414
|
+
converted: 0,
|
|
3415
|
+
migrated: false
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3418
|
+
return {
|
|
3419
|
+
replacement: `sz={${result.exprStr}}`,
|
|
3420
|
+
unrecognized: result.unrecognized,
|
|
3421
|
+
warnings: [],
|
|
3422
|
+
converted: 1,
|
|
3423
|
+
migrated: true
|
|
3424
|
+
};
|
|
3425
|
+
}
|
|
3426
|
+
function handleLogicalAnd(node, source, t2, customMap) {
|
|
3427
|
+
if (node.operator !== "&&") {
|
|
3428
|
+
return {
|
|
3429
|
+
replacement: "",
|
|
3430
|
+
unrecognized: [],
|
|
3431
|
+
warnings: [`Unsupported logical operator: ${node.operator}`],
|
|
3432
|
+
converted: 0,
|
|
3433
|
+
migrated: false
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
const result = handleLogicalAndInner(node, source, t2, customMap);
|
|
3437
|
+
if (!result) {
|
|
3438
|
+
return {
|
|
3439
|
+
replacement: "",
|
|
3440
|
+
unrecognized: [],
|
|
3441
|
+
warnings: ["Right side of && must be a string literal"],
|
|
3442
|
+
converted: 0,
|
|
3443
|
+
migrated: false
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
return {
|
|
3447
|
+
replacement: `sz={${result.exprStr}}`,
|
|
3448
|
+
unrecognized: result.unrecognized,
|
|
3449
|
+
warnings: [],
|
|
3450
|
+
converted: 1,
|
|
3451
|
+
migrated: true
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
function handleTemplateLiteral(node, source, t2, customMap) {
|
|
3455
|
+
const warnings = [];
|
|
3456
|
+
const allUnrecognized = [];
|
|
3457
|
+
const staticText = node.quasis.map((q) => q.value.cooked ?? q.value.raw).join(" ");
|
|
3458
|
+
const trimmedStatic = staticText.replace(/\s+/g, " ").trim();
|
|
3459
|
+
let baseObject = {};
|
|
3460
|
+
if (trimmedStatic) {
|
|
3461
|
+
const { szObject, unrecognized } = classNameToSzObject(trimmedStatic, customMap);
|
|
3462
|
+
baseObject = szObject;
|
|
3463
|
+
allUnrecognized.push(...unrecognized);
|
|
3464
|
+
}
|
|
3465
|
+
const dynamicElements = [];
|
|
3466
|
+
let converted = 0;
|
|
3467
|
+
for (const expr of node.expressions) {
|
|
3468
|
+
if (!isExpression(expr, t2)) {
|
|
3469
|
+
const exprSrc2 = safeSlice(source, expr.start, expr.end);
|
|
3470
|
+
warnings.push(`Cannot migrate template expression: ${exprSrc2}`);
|
|
3471
|
+
return skip(allUnrecognized, warnings);
|
|
3472
|
+
}
|
|
3473
|
+
if (t2.isStringLiteral(expr)) {
|
|
3474
|
+
const result = migrateString(expr.value, customMap);
|
|
3475
|
+
if (result) {
|
|
3476
|
+
const { szObject } = classNameToSzObject(expr.value, customMap);
|
|
3477
|
+
baseObject = { ...baseObject, ...szObject };
|
|
3478
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3479
|
+
converted++;
|
|
3480
|
+
}
|
|
3481
|
+
continue;
|
|
3482
|
+
}
|
|
3483
|
+
if (t2.isConditionalExpression(expr)) {
|
|
3484
|
+
const result = handleTernaryInner(expr, source, t2, customMap);
|
|
3485
|
+
if (!result) {
|
|
3486
|
+
const exprSrc2 = safeSlice(source, expr.start, expr.end);
|
|
3487
|
+
warnings.push(`Cannot migrate template ternary: ${exprSrc2}`);
|
|
3488
|
+
return skip(allUnrecognized, warnings);
|
|
3489
|
+
}
|
|
3490
|
+
dynamicElements.push(result.exprStr);
|
|
3491
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3492
|
+
converted++;
|
|
3493
|
+
continue;
|
|
3494
|
+
}
|
|
3495
|
+
if (t2.isLogicalExpression(expr) && expr.operator === "&&") {
|
|
3496
|
+
const result = handleLogicalAndInner(expr, source, t2, customMap);
|
|
3497
|
+
if (!result) {
|
|
3498
|
+
const exprSrc2 = safeSlice(source, expr.start, expr.end);
|
|
3499
|
+
warnings.push(`Cannot migrate template logical expr: ${exprSrc2}`);
|
|
3500
|
+
return skip(allUnrecognized, warnings);
|
|
3501
|
+
}
|
|
3502
|
+
dynamicElements.push(result.exprStr);
|
|
3503
|
+
allUnrecognized.push(...result.unrecognized);
|
|
3504
|
+
converted++;
|
|
3505
|
+
continue;
|
|
3506
|
+
}
|
|
3507
|
+
const exprSrc = safeSlice(source, expr.start, expr.end);
|
|
3508
|
+
warnings.push(`Cannot migrate template expression: ${exprSrc}`);
|
|
3509
|
+
return skip(allUnrecognized, warnings);
|
|
3510
|
+
}
|
|
3511
|
+
const hasBase = Object.keys(baseObject).length > 0;
|
|
3512
|
+
const hasDynamic = dynamicElements.length > 0;
|
|
3513
|
+
if (!hasBase && !hasDynamic) {
|
|
3514
|
+
return skip(allUnrecognized, warnings);
|
|
3515
|
+
}
|
|
3516
|
+
if (hasBase && !hasDynamic) {
|
|
3517
|
+
return {
|
|
3518
|
+
replacement: `sz=${generateSzExpression(baseObject)}`,
|
|
3519
|
+
unrecognized: allUnrecognized,
|
|
3520
|
+
warnings,
|
|
3521
|
+
converted: converted + 1,
|
|
3522
|
+
migrated: true
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3525
|
+
const parts = [];
|
|
3526
|
+
if (hasBase) {
|
|
3527
|
+
parts.push(generateSzObjectLiteral(baseObject));
|
|
3528
|
+
}
|
|
3529
|
+
parts.push(...dynamicElements);
|
|
3530
|
+
return {
|
|
3531
|
+
replacement: `sz={[${parts.join(", ")}]}`,
|
|
3532
|
+
unrecognized: allUnrecognized,
|
|
3533
|
+
warnings,
|
|
3534
|
+
converted: converted + (hasBase ? 1 : 0),
|
|
3535
|
+
migrated: true
|
|
3536
|
+
};
|
|
3537
|
+
}
|
|
3538
|
+
function handleTernaryInner(node, source, t2, customMap) {
|
|
3539
|
+
if (!t2.isStringLiteral(node.consequent) || !t2.isStringLiteral(node.alternate)) {
|
|
3540
|
+
return null;
|
|
3541
|
+
}
|
|
3542
|
+
const condSource = safeSlice(source, node.test.start, node.test.end);
|
|
3543
|
+
const conValue = node.consequent.value.trim();
|
|
3544
|
+
const altValue = node.alternate.value.trim();
|
|
3545
|
+
if (altValue === "") {
|
|
3546
|
+
if (!conValue) {
|
|
3547
|
+
return null;
|
|
3548
|
+
}
|
|
3549
|
+
const conResult2 = migrateString(conValue, customMap);
|
|
3550
|
+
if (!conResult2 || conResult2.unrecognized.length > 0) {
|
|
3551
|
+
return null;
|
|
3552
|
+
}
|
|
3553
|
+
return {
|
|
3554
|
+
exprStr: `${condSource} && ${conResult2.objectStr}`,
|
|
3555
|
+
unrecognized: []
|
|
3556
|
+
};
|
|
3557
|
+
}
|
|
3558
|
+
if (conValue === "") {
|
|
3559
|
+
const altResult2 = migrateString(altValue, customMap);
|
|
3560
|
+
if (!altResult2 || altResult2.unrecognized.length > 0) {
|
|
3561
|
+
return null;
|
|
3562
|
+
}
|
|
3563
|
+
return {
|
|
3564
|
+
exprStr: `!${wrapCondition(condSource)} && ${altResult2.objectStr}`,
|
|
3565
|
+
unrecognized: []
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
const conResult = migrateString(conValue, customMap);
|
|
3569
|
+
const altResult = migrateString(altValue, customMap);
|
|
3570
|
+
if (!conResult || !altResult) {
|
|
3571
|
+
return null;
|
|
3572
|
+
}
|
|
3573
|
+
const unrecognized = [...conResult.unrecognized, ...altResult.unrecognized];
|
|
3574
|
+
if (unrecognized.length > 0) {
|
|
3575
|
+
return null;
|
|
3576
|
+
}
|
|
3577
|
+
return {
|
|
3578
|
+
exprStr: `${condSource} ? ${conResult.objectStr} : ${altResult.objectStr}`,
|
|
3579
|
+
unrecognized: []
|
|
3580
|
+
};
|
|
3581
|
+
}
|
|
3582
|
+
function handleLogicalAndInner(node, source, t2, customMap) {
|
|
3583
|
+
if (!t2.isStringLiteral(node.right)) {
|
|
3584
|
+
return null;
|
|
3585
|
+
}
|
|
3586
|
+
const result = migrateString(node.right.value, customMap);
|
|
3587
|
+
if (!result || result.unrecognized.length > 0) {
|
|
3588
|
+
return null;
|
|
3589
|
+
}
|
|
3590
|
+
const condSource = safeSlice(source, node.left.start, node.left.end);
|
|
3591
|
+
return {
|
|
3592
|
+
exprStr: `${condSource} && ${result.objectStr}`,
|
|
3593
|
+
unrecognized: []
|
|
3594
|
+
};
|
|
3595
|
+
}
|
|
3596
|
+
function migrateString(className, customMap) {
|
|
3597
|
+
const trimmed = className.trim();
|
|
3598
|
+
if (!trimmed) {
|
|
3599
|
+
return null;
|
|
3600
|
+
}
|
|
3601
|
+
const { szObject, unrecognized } = classNameToSzObject(trimmed, customMap);
|
|
3602
|
+
if (Object.keys(szObject).length === 0) {
|
|
3603
|
+
return null;
|
|
3604
|
+
}
|
|
3605
|
+
return {
|
|
3606
|
+
objectStr: generateSzObjectLiteral(szObject),
|
|
3607
|
+
unrecognized
|
|
3608
|
+
};
|
|
3609
|
+
}
|
|
3610
|
+
function skip(unrecognized, warnings) {
|
|
3611
|
+
return {
|
|
3612
|
+
replacement: "",
|
|
3613
|
+
unrecognized,
|
|
3614
|
+
warnings,
|
|
3615
|
+
converted: 0,
|
|
3616
|
+
migrated: false
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3619
|
+
function safeSlice(source, start, end) {
|
|
3620
|
+
if (start === null || start === void 0 || end === null || end === void 0) {
|
|
3621
|
+
return "<unknown>";
|
|
3622
|
+
}
|
|
3623
|
+
return source.slice(start, end);
|
|
3624
|
+
}
|
|
3625
|
+
function wrapCondition(cond) {
|
|
3626
|
+
if (cond.includes(" ") || cond.includes("||") || cond.includes("&&")) {
|
|
3627
|
+
return `(${cond})`;
|
|
3628
|
+
}
|
|
3629
|
+
return cond;
|
|
3630
|
+
}
|
|
3631
|
+
function isExpression(node, t2) {
|
|
3632
|
+
return t2.isExpression(node);
|
|
3633
|
+
}
|
|
3634
|
+
|
|
2949
3635
|
// src/migrate/ast-transformer.ts
|
|
2950
|
-
function
|
|
3636
|
+
var traverse = typeof _traverse === "function" ? _traverse : _traverse.default;
|
|
3637
|
+
function injectTodoComment(unrecognized, parent, options, replacements) {
|
|
3638
|
+
if (!options.injectTodos || unrecognized.length === 0) {
|
|
3639
|
+
return;
|
|
3640
|
+
}
|
|
3641
|
+
if (!t.isJSXOpeningElement(parent) || parent.start === null || parent.start === void 0) {
|
|
3642
|
+
return;
|
|
3643
|
+
}
|
|
3644
|
+
replacements.push({
|
|
3645
|
+
start: parent.start,
|
|
3646
|
+
end: parent.start,
|
|
3647
|
+
text: `
|
|
3648
|
+
{/* @sz-todo: ${unrecognized.join(", ")} */}
|
|
3649
|
+
`
|
|
3650
|
+
});
|
|
3651
|
+
}
|
|
3652
|
+
function transformSource(source, filePath, options = {}) {
|
|
3653
|
+
const warnings = [];
|
|
3654
|
+
let classNamesTransformed = 0;
|
|
3655
|
+
let classNamesSkipped = 0;
|
|
3656
|
+
const classesUnrecognized = [];
|
|
3657
|
+
const replacements = [];
|
|
3658
|
+
const clsxImportNames = /* @__PURE__ */ new Set();
|
|
3659
|
+
let clsxUsedOutsideClassName = false;
|
|
3660
|
+
const clsxCallsitesMigrated = /* @__PURE__ */ new Set();
|
|
3661
|
+
let hasCvaImport = false;
|
|
3662
|
+
let ast;
|
|
3663
|
+
try {
|
|
3664
|
+
ast = parse(source, {
|
|
3665
|
+
sourceType: "module",
|
|
3666
|
+
plugins: ["jsx", "typescript", "decorators-legacy"],
|
|
3667
|
+
ranges: true
|
|
3668
|
+
});
|
|
3669
|
+
} catch (err) {
|
|
3670
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3671
|
+
return {
|
|
3672
|
+
code: source,
|
|
3673
|
+
changed: false,
|
|
3674
|
+
warnings: [`Parse error in ${filePath}: ${msg}`],
|
|
3675
|
+
stats: { classNamesTransformed: 0, classNamesSkipped: 0, classesUnrecognized: [] },
|
|
3676
|
+
potentiallyUnusedImports: []
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3679
|
+
traverse(ast, {
|
|
3680
|
+
// Track clsx-like and CVA imports
|
|
3681
|
+
ImportDeclaration(path6) {
|
|
3682
|
+
const src = path6.node.source.value;
|
|
3683
|
+
const clsxPackages = ["clsx", "clsx/lite", "classnames", "tailwind-merge"];
|
|
3684
|
+
const isClsxPkg = clsxPackages.some((p) => src === p || src.startsWith(p + "/"));
|
|
3685
|
+
const cvaPkgs = ["cva", "class-variance-authority"];
|
|
3686
|
+
if (cvaPkgs.some((p) => src === p || src.startsWith(p + "/"))) {
|
|
3687
|
+
hasCvaImport = true;
|
|
3688
|
+
}
|
|
3689
|
+
for (const spec of path6.node.specifiers) {
|
|
3690
|
+
const localName = spec.local.name;
|
|
3691
|
+
if (isClsxPkg || isClsxLikeName(localName)) {
|
|
3692
|
+
clsxImportNames.add(localName);
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
},
|
|
3696
|
+
// Track clsx usage outside className
|
|
3697
|
+
CallExpression(path6) {
|
|
3698
|
+
if (t.isIdentifier(path6.node.callee) && clsxImportNames.has(path6.node.callee.name)) {
|
|
3699
|
+
const inClassName = path6.findParent(
|
|
3700
|
+
(p) => t.isJSXAttribute(p.node) && t.isJSXIdentifier(p.node.name) && p.node.name.name === "className"
|
|
3701
|
+
);
|
|
3702
|
+
if (!inClassName) {
|
|
3703
|
+
clsxUsedOutsideClassName = true;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
},
|
|
3707
|
+
// Main transformation: className → sz
|
|
3708
|
+
JSXAttribute(path6) {
|
|
3709
|
+
const attrName = path6.node.name;
|
|
3710
|
+
if (!t.isJSXIdentifier(attrName) || attrName.name !== "className") {
|
|
3711
|
+
return;
|
|
3712
|
+
}
|
|
3713
|
+
const parent = path6.parent;
|
|
3714
|
+
if (t.isJSXOpeningElement(parent)) {
|
|
3715
|
+
const elementName = parent.name;
|
|
3716
|
+
const isCapitalized = t.isJSXIdentifier(elementName) && /^[A-Z]/.test(elementName.name) || t.isJSXMemberExpression(elementName);
|
|
3717
|
+
if (isCapitalized) {
|
|
3718
|
+
classNamesSkipped++;
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
if (t.isJSXOpeningElement(parent)) {
|
|
3723
|
+
const hasSz = parent.attributes.some(
|
|
3724
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === "sz"
|
|
3725
|
+
);
|
|
3726
|
+
if (hasSz) {
|
|
3727
|
+
classNamesSkipped++;
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
const value = path6.node.value;
|
|
3732
|
+
const attrStart = path6.node.start;
|
|
3733
|
+
const attrEnd = path6.node.end;
|
|
3734
|
+
if (attrStart === null || attrStart === void 0 || attrEnd === null || attrEnd === void 0) {
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
if (t.isStringLiteral(value)) {
|
|
3738
|
+
const result = processStaticString(value.value, options.customMap);
|
|
3739
|
+
if (result) {
|
|
3740
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3741
|
+
classNamesTransformed++;
|
|
3742
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3743
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3744
|
+
} else {
|
|
3745
|
+
classNamesSkipped++;
|
|
3746
|
+
}
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
if (t.isJSXExpressionContainer(value)) {
|
|
3750
|
+
const expr = value.expression;
|
|
3751
|
+
if (t.isStringLiteral(expr)) {
|
|
3752
|
+
const result = processStaticString(expr.value, options.customMap);
|
|
3753
|
+
if (result) {
|
|
3754
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3755
|
+
classNamesTransformed++;
|
|
3756
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3757
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3758
|
+
} else {
|
|
3759
|
+
classNamesSkipped++;
|
|
3760
|
+
}
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
if (t.isTemplateLiteral(expr)) {
|
|
3764
|
+
const result = handleTemplateLiteral(expr, source, t, options.customMap);
|
|
3765
|
+
if (result.migrated) {
|
|
3766
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3767
|
+
classNamesTransformed += result.converted;
|
|
3768
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3769
|
+
} else {
|
|
3770
|
+
classNamesSkipped++;
|
|
3771
|
+
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3772
|
+
}
|
|
3773
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
if (t.isCallExpression(expr) && t.isIdentifier(expr.callee) && isClsxLikeName(expr.callee.name)) {
|
|
3777
|
+
const result = handleClsxCall(expr, source, t, options.customMap);
|
|
3778
|
+
if (result.migrated) {
|
|
3779
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3780
|
+
classNamesTransformed += result.converted;
|
|
3781
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3782
|
+
if (expr.start !== null && expr.start !== void 0) {
|
|
3783
|
+
clsxCallsitesMigrated.add(expr.start);
|
|
3784
|
+
}
|
|
3785
|
+
} else {
|
|
3786
|
+
classNamesSkipped++;
|
|
3787
|
+
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3788
|
+
}
|
|
3789
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3790
|
+
return;
|
|
3791
|
+
}
|
|
3792
|
+
if (t.isConditionalExpression(expr)) {
|
|
3793
|
+
const result = handleTernary(expr, source, t, options.customMap);
|
|
3794
|
+
if (result.migrated) {
|
|
3795
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3796
|
+
classNamesTransformed += result.converted;
|
|
3797
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3798
|
+
} else {
|
|
3799
|
+
classNamesSkipped++;
|
|
3800
|
+
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3801
|
+
}
|
|
3802
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3803
|
+
return;
|
|
3804
|
+
}
|
|
3805
|
+
if (t.isLogicalExpression(expr) && expr.operator === "&&") {
|
|
3806
|
+
const result = handleLogicalAnd(expr, source, t, options.customMap);
|
|
3807
|
+
if (result.migrated) {
|
|
3808
|
+
replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
|
|
3809
|
+
classNamesTransformed += result.converted;
|
|
3810
|
+
classesUnrecognized.push(...result.unrecognized);
|
|
3811
|
+
} else {
|
|
3812
|
+
classNamesSkipped++;
|
|
3813
|
+
warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
|
|
3814
|
+
}
|
|
3815
|
+
injectTodoComment(result.unrecognized, path6.parent, options, replacements);
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
classNamesSkipped++;
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
classNamesSkipped++;
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
3824
|
+
if (hasCvaImport) {
|
|
3825
|
+
warnings.push(
|
|
3826
|
+
`[${filePath}] File uses cva() \u2014 consider migrating to szv() from @csszyx/runtime for type-safe variant-based styling.`
|
|
3827
|
+
);
|
|
3828
|
+
}
|
|
3829
|
+
let output = source;
|
|
3830
|
+
const sorted = replacements.sort((a, b) => b.start - a.start);
|
|
3831
|
+
for (const r of sorted) {
|
|
3832
|
+
output = output.slice(0, r.start) + r.text + output.slice(r.end);
|
|
3833
|
+
}
|
|
3834
|
+
const potentiallyUnusedImports = [];
|
|
3835
|
+
if (clsxImportNames.size > 0 && !clsxUsedOutsideClassName && replacements.length > 0) {
|
|
3836
|
+
for (const name of clsxImportNames) {
|
|
3837
|
+
const callPattern = new RegExp(`\\b${name}\\s*\\(`, "g");
|
|
3838
|
+
if (!callPattern.test(output)) {
|
|
3839
|
+
potentiallyUnusedImports.push(name);
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
return {
|
|
3844
|
+
code: output,
|
|
3845
|
+
changed: replacements.length > 0,
|
|
3846
|
+
warnings,
|
|
3847
|
+
stats: { classNamesTransformed, classNamesSkipped, classesUnrecognized },
|
|
3848
|
+
potentiallyUnusedImports
|
|
3849
|
+
};
|
|
3850
|
+
}
|
|
3851
|
+
function processStaticString(classNameStr, customMap) {
|
|
3852
|
+
const trimmed = classNameStr.trim();
|
|
3853
|
+
if (!trimmed) {
|
|
3854
|
+
return null;
|
|
3855
|
+
}
|
|
3856
|
+
const { szObject, unrecognized, keepInClassName } = classNameToSzObject(trimmed, customMap);
|
|
3857
|
+
if (Object.keys(szObject).length === 0) {
|
|
3858
|
+
return null;
|
|
3859
|
+
}
|
|
3860
|
+
const szExpr = generateSzExpression(szObject);
|
|
3861
|
+
const remainingClassName = [...keepInClassName, ...unrecognized];
|
|
3862
|
+
if (remainingClassName.length > 0) {
|
|
3863
|
+
return {
|
|
3864
|
+
replacement: `className="${remainingClassName.join(" ")}" sz=${szExpr}`,
|
|
3865
|
+
unrecognized
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
3868
|
+
return {
|
|
3869
|
+
replacement: `sz=${szExpr}`,
|
|
3870
|
+
unrecognized: []
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
var FOUC_CSS = `<style>
|
|
3874
|
+
/* csszyx: hide [sz] elements until runtime processes them */
|
|
3875
|
+
[sz] { visibility: hidden; }
|
|
3876
|
+
body.sz-ready [sz] { visibility: visible; }
|
|
3877
|
+
</style>`;
|
|
3878
|
+
function transformHtmlSourceSimple(source, filePath, options = {}) {
|
|
3879
|
+
const {
|
|
3880
|
+
braces = false,
|
|
3881
|
+
injectFouc = true,
|
|
3882
|
+
injectRuntime = false,
|
|
3883
|
+
cdnUrl = "https://cdn.csszyx.com/runtime.js",
|
|
3884
|
+
localPath = "csszyx-runtime.js"
|
|
3885
|
+
} = options;
|
|
2951
3886
|
const warnings = [];
|
|
2952
3887
|
let classNamesTransformed = 0;
|
|
2953
3888
|
let classNamesSkipped = 0;
|
|
2954
3889
|
const classesUnrecognized = [];
|
|
2955
3890
|
let changed = false;
|
|
2956
|
-
|
|
2957
|
-
return
|
|
3891
|
+
let output = source.replace(/\bclass="([^"]*)"/g, (match, classStr) => {
|
|
3892
|
+
return processClassAttr(match, classStr, '"');
|
|
2958
3893
|
});
|
|
2959
|
-
|
|
2960
|
-
return
|
|
3894
|
+
output = output.replace(/\bclass='([^']*)'/g, (match, classStr) => {
|
|
3895
|
+
return processClassAttr(match, classStr, "'");
|
|
2961
3896
|
});
|
|
2962
|
-
|
|
2963
|
-
|
|
3897
|
+
if (injectFouc && output.includes("</head>") && !output.includes("csszyx: hide [sz]")) {
|
|
3898
|
+
output = output.replace("</head>", `${FOUC_CSS}
|
|
3899
|
+
</head>`);
|
|
3900
|
+
changed = true;
|
|
3901
|
+
}
|
|
3902
|
+
if (injectRuntime && output.includes("</body>")) {
|
|
3903
|
+
const scriptSrc = injectRuntime === "cdn" ? cdnUrl : localPath;
|
|
3904
|
+
const scriptTag = `<script src="${scriptSrc}"></script>`;
|
|
3905
|
+
if (!output.includes(scriptSrc)) {
|
|
3906
|
+
output = output.replace("</body>", `${scriptTag}
|
|
3907
|
+
</body>`);
|
|
3908
|
+
changed = true;
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
function processClassAttr(match, classStr, quote) {
|
|
3912
|
+
const trimmed = classStr.trim();
|
|
2964
3913
|
if (!trimmed) {
|
|
2965
3914
|
classNamesSkipped++;
|
|
2966
3915
|
return match;
|
|
@@ -2971,33 +3920,105 @@ function transformSourceSimple(source, filePath) {
|
|
|
2971
3920
|
classesUnrecognized.push(...unrecognized);
|
|
2972
3921
|
return match;
|
|
2973
3922
|
}
|
|
2974
|
-
const
|
|
3923
|
+
const szVal = generateSzHtmlValue(szObject, braces);
|
|
2975
3924
|
changed = true;
|
|
2976
3925
|
classNamesTransformed++;
|
|
2977
3926
|
if (unrecognized.length > 0) {
|
|
2978
3927
|
classesUnrecognized.push(...unrecognized);
|
|
2979
|
-
return `
|
|
3928
|
+
return `class=${quote}${unrecognized.join(" ")}${quote} sz="${szVal}"`;
|
|
2980
3929
|
}
|
|
2981
|
-
return `sz
|
|
3930
|
+
return `sz="${szVal}"`;
|
|
2982
3931
|
}
|
|
2983
3932
|
return {
|
|
2984
|
-
code:
|
|
3933
|
+
code: output,
|
|
2985
3934
|
changed,
|
|
2986
3935
|
warnings,
|
|
2987
|
-
stats: { classNamesTransformed, classNamesSkipped, classesUnrecognized }
|
|
3936
|
+
stats: { classNamesTransformed, classNamesSkipped, classesUnrecognized },
|
|
3937
|
+
potentiallyUnusedImports: []
|
|
2988
3938
|
};
|
|
2989
3939
|
}
|
|
2990
3940
|
|
|
2991
3941
|
// src/commands/migrate.ts
|
|
3942
|
+
function createLogFile(cwd) {
|
|
3943
|
+
const now = /* @__PURE__ */ new Date();
|
|
3944
|
+
const ts = now.toISOString().slice(0, 19).replace("T", "_").replace(/:/g, "-");
|
|
3945
|
+
const logDir = path5.join(cwd, ".csszyx", "logs");
|
|
3946
|
+
fs5.mkdirSync(logDir, { recursive: true });
|
|
3947
|
+
const filePath = path5.join(logDir, `migrate-${ts}.log`);
|
|
3948
|
+
const lines = [`csszyx migrate \u2014 ${now.toISOString()}`, ""];
|
|
3949
|
+
return {
|
|
3950
|
+
filePath,
|
|
3951
|
+
writeLine: (line) => lines.push(line),
|
|
3952
|
+
flush: () => fs5.writeFileSync(filePath, lines.join("\n") + "\n", "utf-8")
|
|
3953
|
+
};
|
|
3954
|
+
}
|
|
3955
|
+
function isGitignored(cwd, pattern) {
|
|
3956
|
+
try {
|
|
3957
|
+
const content = fs5.readFileSync(path5.join(cwd, ".gitignore"), "utf-8");
|
|
3958
|
+
return content.split("\n").some((l) => {
|
|
3959
|
+
const t2 = l.trim();
|
|
3960
|
+
return t2 === pattern || t2 === pattern + "/" || t2 === "/" + pattern;
|
|
3961
|
+
});
|
|
3962
|
+
} catch {
|
|
3963
|
+
return false;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
async function askYesNo(question) {
|
|
3967
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3968
|
+
return new Promise((resolve4) => {
|
|
3969
|
+
rl.question(question, (answer) => {
|
|
3970
|
+
rl.close();
|
|
3971
|
+
resolve4(answer.trim().toLowerCase() === "y");
|
|
3972
|
+
});
|
|
3973
|
+
});
|
|
3974
|
+
}
|
|
2992
3975
|
async function migrate(options = {}) {
|
|
2993
3976
|
const cwd = options.cwd || process.cwd();
|
|
2994
|
-
|
|
3977
|
+
let dryRun = options.dryRun || false;
|
|
2995
3978
|
const ignorePatterns = options.ignore || [];
|
|
3979
|
+
const audit2 = options.audit || false;
|
|
3980
|
+
const resolveTodosPath = options.resolveTodos;
|
|
3981
|
+
let customMap, files;
|
|
3982
|
+
if (audit2) {
|
|
3983
|
+
dryRun = true;
|
|
3984
|
+
}
|
|
3985
|
+
let injectTodos = options.injectTodos || false;
|
|
3986
|
+
if (resolveTodosPath && !injectTodos) {
|
|
3987
|
+
injectTodos = true;
|
|
3988
|
+
}
|
|
2996
3989
|
printHeader("csszyx Migration Tool");
|
|
2997
|
-
if (
|
|
3990
|
+
if (process.stdout.isTTY && !injectTodos && !audit2 && !resolveTodosPath) {
|
|
3991
|
+
const answer = await askYesNo(
|
|
3992
|
+
"Add {/* @sz-todo */} comments above elements with unrecognized classes? [y/N] "
|
|
3993
|
+
);
|
|
3994
|
+
if (answer) {
|
|
3995
|
+
injectTodos = true;
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
if (resolveTodosPath) {
|
|
3999
|
+
try {
|
|
4000
|
+
const absolutePath = path5.resolve(cwd, resolveTodosPath);
|
|
4001
|
+
const content = fs5.readFileSync(absolutePath, "utf-8");
|
|
4002
|
+
customMap = JSON.parse(content);
|
|
4003
|
+
printInfo(`Loaded resolution map from ${resolveTodosPath}`);
|
|
4004
|
+
} catch {
|
|
4005
|
+
printWarn(`Could not load resolve map from ${resolveTodosPath}. Ensure the file exists and is valid JSON.`);
|
|
4006
|
+
return;
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
if (audit2) {
|
|
4010
|
+
printInfo("Audit mode \u2014 scanning for unrecognized classes to generate a mapping file...");
|
|
4011
|
+
} else if (dryRun) {
|
|
2998
4012
|
printInfo("Dry run mode \u2014 no files will be modified");
|
|
2999
4013
|
}
|
|
3000
|
-
const
|
|
4014
|
+
const log = createLogFile(cwd);
|
|
4015
|
+
log.writeLine(`Mode: ${audit2 ? "audit" : dryRun ? "dry-run" : "migrate"}${resolveTodosPath ? ` (resolve-todos: ${resolveTodosPath})` : ""}`);
|
|
4016
|
+
log.writeLine(`injectTodos: ${injectTodos}`);
|
|
4017
|
+
log.writeLine("");
|
|
4018
|
+
if (!isGitignored(cwd, ".csszyx")) {
|
|
4019
|
+
printWarn("Tip: add .csszyx/ to your .gitignore to exclude migration logs from version control.");
|
|
4020
|
+
}
|
|
4021
|
+
const patterns = options.pattern ? [options.pattern] : ["**/*.{jsx,tsx,html}"];
|
|
3001
4022
|
const ignore = [
|
|
3002
4023
|
"**/node_modules/**",
|
|
3003
4024
|
"**/dist/**",
|
|
@@ -3007,10 +4028,19 @@ async function migrate(options = {}) {
|
|
|
3007
4028
|
...ignorePatterns
|
|
3008
4029
|
];
|
|
3009
4030
|
const s = spinner.start("Scanning for files...");
|
|
3010
|
-
|
|
4031
|
+
try {
|
|
4032
|
+
files = await fg(patterns, { cwd, ignore, absolute: true });
|
|
4033
|
+
} catch (err) {
|
|
4034
|
+
s.fail("File scan failed");
|
|
4035
|
+
printWarn(`Could not scan files: ${err instanceof Error ? err.message : String(err)}`);
|
|
4036
|
+
log.flush();
|
|
4037
|
+
return;
|
|
4038
|
+
}
|
|
3011
4039
|
s.succeed(`Found ${files.length} files`);
|
|
3012
4040
|
if (files.length === 0) {
|
|
3013
|
-
printWarn("No JSX/TSX files found");
|
|
4041
|
+
printWarn(options.pattern ? `No files found matching pattern: ${options.pattern}` : "No JSX/TSX/HTML files found");
|
|
4042
|
+
log.writeLine("No files found.");
|
|
4043
|
+
log.flush();
|
|
3014
4044
|
return;
|
|
3015
4045
|
}
|
|
3016
4046
|
let totalTransformed = 0;
|
|
@@ -3018,25 +4048,52 @@ async function migrate(options = {}) {
|
|
|
3018
4048
|
let totalFiles = 0;
|
|
3019
4049
|
const allUnrecognized = [];
|
|
3020
4050
|
const allWarnings = [];
|
|
4051
|
+
const unusedImportFiles = [];
|
|
3021
4052
|
const s2 = spinner.start("Migrating...");
|
|
3022
4053
|
for (const filePath of files) {
|
|
3023
4054
|
const source = fs5.readFileSync(filePath, "utf-8");
|
|
3024
|
-
|
|
4055
|
+
const isHtml = filePath.endsWith(".html");
|
|
4056
|
+
const hasRelevantAttr = isHtml ? source.includes("class=") : source.includes("className=");
|
|
4057
|
+
if (!hasRelevantAttr) {
|
|
3025
4058
|
continue;
|
|
3026
4059
|
}
|
|
3027
|
-
|
|
4060
|
+
let processSource = source;
|
|
4061
|
+
if (resolveTodosPath && !isHtml) {
|
|
4062
|
+
processSource = processSource.replace(/\{\/\*\s*@sz-todo:\s*(.*?)\s*\*\/\}\n?/g, "");
|
|
4063
|
+
}
|
|
4064
|
+
const result = isHtml ? transformHtmlSourceSimple(processSource, filePath, {
|
|
4065
|
+
braces: options.braces,
|
|
4066
|
+
injectFouc: options.injectFouc,
|
|
4067
|
+
injectRuntime: options.injectRuntime,
|
|
4068
|
+
cdnUrl: options.cdnUrl,
|
|
4069
|
+
localPath: options.localPath
|
|
4070
|
+
}) : transformSource(processSource, filePath, { injectTodos, customMap });
|
|
4071
|
+
allWarnings.push(...result.warnings);
|
|
3028
4072
|
if (result.changed) {
|
|
3029
4073
|
totalFiles++;
|
|
3030
4074
|
totalTransformed += result.stats.classNamesTransformed;
|
|
3031
4075
|
totalSkipped += result.stats.classNamesSkipped;
|
|
3032
4076
|
allUnrecognized.push(...result.stats.classesUnrecognized);
|
|
3033
|
-
|
|
4077
|
+
if (result.potentiallyUnusedImports.length > 0) {
|
|
4078
|
+
const rel2 = path5.relative(cwd, filePath);
|
|
4079
|
+
unusedImportFiles.push({ file: rel2, imports: result.potentiallyUnusedImports });
|
|
4080
|
+
}
|
|
3034
4081
|
if (!dryRun) {
|
|
3035
|
-
|
|
4082
|
+
try {
|
|
4083
|
+
fs5.writeFileSync(filePath, result.code, "utf-8");
|
|
4084
|
+
} catch (err) {
|
|
4085
|
+
const rel2 = path5.relative(cwd, filePath);
|
|
4086
|
+
printWarn(`Could not write ${rel2}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4087
|
+
log.writeLine(` Write error: ${rel2}`);
|
|
4088
|
+
continue;
|
|
4089
|
+
}
|
|
3036
4090
|
}
|
|
3037
4091
|
const rel = path5.relative(cwd, filePath);
|
|
3038
4092
|
if (dryRun) {
|
|
3039
4093
|
printInfo(` ${rel}: ${result.stats.classNamesTransformed} className(s) \u2192 sz`);
|
|
4094
|
+
log.writeLine(` ${rel}: ${result.stats.classNamesTransformed} className(s) \u2192 sz`);
|
|
4095
|
+
} else {
|
|
4096
|
+
log.writeLine(` ${rel}: ${result.stats.classNamesTransformed} className(s) \u2192 sz`);
|
|
3040
4097
|
}
|
|
3041
4098
|
}
|
|
3042
4099
|
}
|
|
@@ -3044,12 +4101,16 @@ async function migrate(options = {}) {
|
|
|
3044
4101
|
console.info();
|
|
3045
4102
|
printSuccess(`Files modified: ${totalFiles}`);
|
|
3046
4103
|
printSuccess(`classNames converted: ${totalTransformed}`);
|
|
4104
|
+
log.writeLine(`Files modified: ${totalFiles}`);
|
|
4105
|
+
log.writeLine(`classNames converted: ${totalTransformed}`);
|
|
3047
4106
|
if (totalSkipped > 0) {
|
|
3048
4107
|
printWarn(`classNames skipped (dynamic): ${totalSkipped}`);
|
|
4108
|
+
log.writeLine(`classNames skipped (dynamic): ${totalSkipped}`);
|
|
3049
4109
|
}
|
|
3050
4110
|
if (allUnrecognized.length > 0) {
|
|
3051
4111
|
const unique = [...new Set(allUnrecognized)];
|
|
3052
4112
|
printWarn(`Unrecognized classes (${unique.length}): ${unique.slice(0, 10).join(", ")}${unique.length > 10 ? "..." : ""}`);
|
|
4113
|
+
log.writeLine(`Unrecognized classes (${unique.length}): ${unique.join(", ")}`);
|
|
3053
4114
|
}
|
|
3054
4115
|
if (allWarnings.length > 0) {
|
|
3055
4116
|
console.info();
|
|
@@ -3059,6 +4120,57 @@ async function migrate(options = {}) {
|
|
|
3059
4120
|
if (allWarnings.length > 5) {
|
|
3060
4121
|
printWarn(`... and ${allWarnings.length - 5} more warnings`);
|
|
3061
4122
|
}
|
|
4123
|
+
log.writeLine("");
|
|
4124
|
+
log.writeLine("Warnings:");
|
|
4125
|
+
for (const w of allWarnings) {
|
|
4126
|
+
log.writeLine(` ${w}`);
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
if (audit2) {
|
|
4130
|
+
const todoPath = path5.join(cwd, ".csszyx-todo.json");
|
|
4131
|
+
const unique = [...new Set(allUnrecognized)];
|
|
4132
|
+
console.info();
|
|
4133
|
+
if (unique.length === 0) {
|
|
4134
|
+
printSuccess("Audit complete. 100% of your classes are perfectly recognized by csszyx!");
|
|
4135
|
+
log.writeLine("Audit: 100% recognized.");
|
|
4136
|
+
} else {
|
|
4137
|
+
const todoObj = {};
|
|
4138
|
+
for (const u of unique) {
|
|
4139
|
+
todoObj[u] = "sz:todo";
|
|
4140
|
+
}
|
|
4141
|
+
try {
|
|
4142
|
+
fs5.writeFileSync(todoPath, JSON.stringify(todoObj, null, 2));
|
|
4143
|
+
} catch (err) {
|
|
4144
|
+
printWarn(`Could not write ${path5.relative(cwd, todoPath)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4145
|
+
log.flush();
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
printSuccess(`Audit complete. Exported ${unique.length} unrecognized classes to ${path5.relative(cwd, todoPath)}.`);
|
|
4149
|
+
printInfo("Edit this file to map custom classes, then run: npx @csszyx/cli migrate --resolve-todos .csszyx-todo.json");
|
|
4150
|
+
log.writeLine(`Audit: ${unique.length} unrecognized classes written to ${path5.relative(cwd, todoPath)}`);
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
if (resolveTodosPath) {
|
|
4154
|
+
const unique = [...new Set(allUnrecognized)];
|
|
4155
|
+
if (unique.length > 0) {
|
|
4156
|
+
console.info();
|
|
4157
|
+
printWarn(`Still unresolved after this pass (${unique.length}): ${unique.slice(0, 10).join(", ")}${unique.length > 10 ? "..." : ""}`);
|
|
4158
|
+
printInfo("Re-run --audit to generate a fresh snapshot when ready.");
|
|
4159
|
+
log.writeLine(`Still unresolved (${unique.length}): ${unique.join(", ")}`);
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
if (unusedImportFiles.length > 0) {
|
|
4163
|
+
console.info();
|
|
4164
|
+
printWarn("Potentially unused imports (run ESLint to clean up):");
|
|
4165
|
+
for (const { file, imports } of unusedImportFiles) {
|
|
4166
|
+
printInfo(` ${file}: ${imports.map((i) => `import { ${i} }`).join(", ")}`);
|
|
4167
|
+
log.writeLine(` Unused import in ${file}: ${imports.join(", ")}`);
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
try {
|
|
4171
|
+
log.flush();
|
|
4172
|
+
printInfo(`Migration log saved to ${path5.relative(cwd, log.filePath)}`);
|
|
4173
|
+
} catch {
|
|
3062
4174
|
}
|
|
3063
4175
|
}
|
|
3064
4176
|
|
|
@@ -3072,9 +4184,8 @@ cli.command("init", "Setup csszyx in your project").option("--framework <name>",
|
|
|
3072
4184
|
cwd: options.cwd
|
|
3073
4185
|
});
|
|
3074
4186
|
});
|
|
3075
|
-
cli.command("doctor", "Diagnose mangling issues").option("--
|
|
4187
|
+
cli.command("doctor", "Diagnose mangling issues").option("--verbose", "Show detailed output").option("--cwd <dir>", "Current working directory").action(async (options) => {
|
|
3076
4188
|
await doctor({
|
|
3077
|
-
fix: options.fix,
|
|
3078
4189
|
verbose: options.verbose,
|
|
3079
4190
|
cwd: options.cwd
|
|
3080
4191
|
});
|
|
@@ -3098,12 +4209,20 @@ cli.command(
|
|
|
3098
4209
|
silent: options.silent
|
|
3099
4210
|
});
|
|
3100
4211
|
});
|
|
3101
|
-
cli.command("migrate [dir]", "Convert Tailwind className to sz prop").option("--dry-run", "Show changes without modifying files").option("--ignore <patterns>", "Glob patterns to ignore (comma-separated)").option("--pattern <glob>", "Custom glob pattern for file discovery").option("--cwd <dir>", "Current working directory").action(async (dir, options) => {
|
|
4212
|
+
cli.command("migrate [dir]", "Convert Tailwind className to sz prop").option("--dry-run", "Show changes without modifying files").option("--ignore <patterns>", "Glob patterns to ignore (comma-separated)").option("--pattern <glob>", "Custom glob pattern for file discovery").option("--cwd <dir>", "Current working directory").option("--braces", "Wrap HTML sz values in outer { } braces (default: bare)").option("--no-fouc", "Skip FOUC-prevention CSS injection into HTML files").option("--inject-runtime <mode>", "Inject runtime script into HTML: local | cdn").option("--cdn-url <url>", "Custom CDN URL for --inject-runtime cdn").option("--local-path <path>", "Local script path for --inject-runtime local (default: csszyx-runtime.js)").option("--audit", "Scan without modifying files and output .csszyx-todo.json").option("--inject-todos", "Inject {/* @sz-todo */} comments above unrecognized classes").option("--resolve-todos <file>", "Path to a JSON file mapping custom classes to sz properties").action(async (dir, options) => {
|
|
3102
4213
|
await migrate({
|
|
3103
4214
|
dryRun: options.dryRun,
|
|
3104
4215
|
ignore: options.ignore ? options.ignore.split(",") : void 0,
|
|
3105
4216
|
pattern: options.pattern,
|
|
3106
|
-
cwd: dir || options.cwd
|
|
4217
|
+
cwd: dir || options.cwd,
|
|
4218
|
+
braces: options.braces,
|
|
4219
|
+
injectFouc: options.fouc !== false,
|
|
4220
|
+
injectRuntime: options.injectRuntime === "local" ? "local" : options.injectRuntime === "cdn" ? "cdn" : false,
|
|
4221
|
+
cdnUrl: options.cdnUrl,
|
|
4222
|
+
localPath: options.localPath,
|
|
4223
|
+
audit: options.audit,
|
|
4224
|
+
injectTodos: options.injectTodos,
|
|
4225
|
+
resolveTodos: options.resolveTodos
|
|
3107
4226
|
});
|
|
3108
4227
|
});
|
|
3109
4228
|
cli.command("").action(() => {
|
|
@@ -3113,6 +4232,7 @@ cli.help();
|
|
|
3113
4232
|
cli.version(VERSION);
|
|
3114
4233
|
cli.parse();
|
|
3115
4234
|
export {
|
|
4235
|
+
classNameToSzObject,
|
|
3116
4236
|
extractScreenKeys,
|
|
3117
4237
|
extractSpacingKeys,
|
|
3118
4238
|
findConfigFile,
|
|
@@ -3120,6 +4240,7 @@ export {
|
|
|
3120
4240
|
generateAndWriteTypes,
|
|
3121
4241
|
generateTypeDeclarations,
|
|
3122
4242
|
generateTypes,
|
|
4243
|
+
transformSource as migrateSource,
|
|
3123
4244
|
scanTailwindConfig,
|
|
3124
4245
|
writeDeclarationFile
|
|
3125
4246
|
};
|