@axis-ds/cli 1.2.1 → 1.3.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 +7 -0
- package/dist/index.js +198 -141
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,13 @@ axis theme add ontology
|
|
|
44
44
|
- `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
|
|
45
45
|
- `axis check` 는 `axis.config.json` 의 `brand` 와 CSS 의 브랜드 import 가 맞는지도 봅니다.
|
|
46
46
|
|
|
47
|
+
## 프로젝트 검증 (`axis check`)
|
|
48
|
+
|
|
49
|
+
- Tailwind 구성 항목: Tailwind 4 이상(설치본, 없으면 `package.json` 선언으로 판정)은 설정 파일 대신 전역 CSS(`globals.css` · `app/globals.css` · `src/app/globals.css` · `src/globals.css` · `styles/globals.css` 순)의 `@import "tailwindcss"` 를 봅니다. Tailwind 3 이하는 `tailwind.config.ts` · `.js` · `.mjs` · `.cjs` 를 찾습니다.
|
|
50
|
+
- 이 항목은 Tailwind 진입 import 만 봅니다. `@axis-ds/tokens` 의 Tailwind 연동은 Tailwind 3 preset(`@axis-ds/tokens/tailwind`)뿐이라, Tailwind 4 에서 PASS 여도 `bg-primary` 같은 AXIS 색 클래스가 만들어진다는 뜻은 아닙니다.
|
|
51
|
+
- FAIL 이 하나라도 있으면 종료 코드 1 로 끝납니다. WARN 만 있으면 0 입니다(1.3.0 부터, 이전에는 결과와 관계없이 0).
|
|
52
|
+
- MCP `axis.check_project` 도 같은 항목 · 문구를 냅니다.
|
|
53
|
+
|
|
47
54
|
## 문서
|
|
48
55
|
|
|
49
56
|
자세한 사용법은 [AXIS Design System 문서](https://axis.minu.best)를 참고하세요.
|
package/dist/index.js
CHANGED
|
@@ -2099,6 +2099,178 @@ function getBrand(baseDir, name) {
|
|
|
2099
2099
|
};
|
|
2100
2100
|
}
|
|
2101
2101
|
|
|
2102
|
+
// src/template/tailwind-core.ts
|
|
2103
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
2104
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
2105
|
+
function hasDependency(pkg, name) {
|
|
2106
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
2107
|
+
const deps = pkg[field];
|
|
2108
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
2109
|
+
return String(deps[name]);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
return void 0;
|
|
2113
|
+
}
|
|
2114
|
+
function isPlainObject(value) {
|
|
2115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2116
|
+
}
|
|
2117
|
+
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
2118
|
+
function versionParts(token) {
|
|
2119
|
+
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
2120
|
+
if (!m) return void 0;
|
|
2121
|
+
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
2122
|
+
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
2123
|
+
}
|
|
2124
|
+
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
2125
|
+
function comparatorBounds(op, v) {
|
|
2126
|
+
switch (op) {
|
|
2127
|
+
case ">=":
|
|
2128
|
+
return { lower: v.major };
|
|
2129
|
+
case ">":
|
|
2130
|
+
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
2131
|
+
case "<=":
|
|
2132
|
+
return { upper: v.major };
|
|
2133
|
+
case "<": {
|
|
2134
|
+
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
2135
|
+
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
2136
|
+
}
|
|
2137
|
+
default:
|
|
2138
|
+
return { lower: v.major, upper: v.major };
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
function tailwindMajorBounds(range) {
|
|
2142
|
+
const r = range.trim();
|
|
2143
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2144
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2145
|
+
if (simple) {
|
|
2146
|
+
const v = versionParts(simple[1]);
|
|
2147
|
+
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
2148
|
+
}
|
|
2149
|
+
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
2150
|
+
if (hyphen) {
|
|
2151
|
+
const tokens2 = r.split(/\s+-\s+/);
|
|
2152
|
+
const a = versionParts(tokens2[0]);
|
|
2153
|
+
const b = versionParts(tokens2[1]);
|
|
2154
|
+
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
2155
|
+
}
|
|
2156
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2157
|
+
const lowers = [];
|
|
2158
|
+
const uppers = [];
|
|
2159
|
+
for (const t of tokens) {
|
|
2160
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2161
|
+
if (!c) return void 0;
|
|
2162
|
+
const v = versionParts(c[2]);
|
|
2163
|
+
if (v === void 0) return void 0;
|
|
2164
|
+
const b = comparatorBounds(c[1], v);
|
|
2165
|
+
if (b.lower !== void 0) lowers.push(b.lower);
|
|
2166
|
+
if (b.upper !== void 0) uppers.push(b.upper);
|
|
2167
|
+
}
|
|
2168
|
+
if (lowers.length === 0) return void 0;
|
|
2169
|
+
const lower = Math.max(...lowers);
|
|
2170
|
+
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
2171
|
+
if (upper !== void 0 && upper < lower) return void 0;
|
|
2172
|
+
return upper !== void 0 ? { lower, upper } : { lower };
|
|
2173
|
+
}
|
|
2174
|
+
function majorWithin(major, bounds) {
|
|
2175
|
+
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
2176
|
+
}
|
|
2177
|
+
function majorFromVersion(version) {
|
|
2178
|
+
if (typeof version !== "string") return void 0;
|
|
2179
|
+
const v = version.trim();
|
|
2180
|
+
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
2181
|
+
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2182
|
+
return Number(m[1]);
|
|
2183
|
+
}
|
|
2184
|
+
function detectTailwind(baseDirInput, pkg) {
|
|
2185
|
+
const baseDir = resolve2(baseDirInput);
|
|
2186
|
+
const installedFile = join2(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
2187
|
+
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
2188
|
+
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
2189
|
+
const declaredMajor = bounds?.lower;
|
|
2190
|
+
try {
|
|
2191
|
+
const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
|
|
2192
|
+
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
2193
|
+
const major = majorFromVersion(version);
|
|
2194
|
+
if (major !== void 0) {
|
|
2195
|
+
const found = { major, source: "installed", value: String(version) };
|
|
2196
|
+
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
2197
|
+
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
2198
|
+
}
|
|
2199
|
+
return found;
|
|
2200
|
+
}
|
|
2201
|
+
} catch {
|
|
2202
|
+
}
|
|
2203
|
+
if (declared !== void 0) {
|
|
2204
|
+
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
2205
|
+
return { source: "none", value: declared };
|
|
2206
|
+
}
|
|
2207
|
+
return { source: "none" };
|
|
2208
|
+
}
|
|
2209
|
+
var TAILWIND_CONFIG_FILES = [
|
|
2210
|
+
"tailwind.config.ts",
|
|
2211
|
+
"tailwind.config.js",
|
|
2212
|
+
"tailwind.config.mjs",
|
|
2213
|
+
"tailwind.config.cjs"
|
|
2214
|
+
];
|
|
2215
|
+
var TAILWIND_CSS_CANDIDATES = [
|
|
2216
|
+
"globals.css",
|
|
2217
|
+
"app/globals.css",
|
|
2218
|
+
"src/app/globals.css",
|
|
2219
|
+
"src/globals.css",
|
|
2220
|
+
"styles/globals.css"
|
|
2221
|
+
];
|
|
2222
|
+
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2223
|
+
function hasTailwindImport(css) {
|
|
2224
|
+
return TAILWIND_IMPORT.test(css.replace(/\/\*[\s\S]*?\*\//g, ""));
|
|
2225
|
+
}
|
|
2226
|
+
function readPackageJson(baseDir) {
|
|
2227
|
+
try {
|
|
2228
|
+
const parsed = JSON.parse(readFileSync2(join2(baseDir, "package.json"), "utf8"));
|
|
2229
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
2230
|
+
} catch {
|
|
2231
|
+
return void 0;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
function checkTailwindSetup(baseDirInput) {
|
|
2235
|
+
const baseDir = resolve2(baseDirInput);
|
|
2236
|
+
const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
|
|
2237
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2238
|
+
const label = `Tailwind ${tailwind.major}`;
|
|
2239
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2240
|
+
const file = join2(baseDir, candidate);
|
|
2241
|
+
if (!existsSync2(file)) continue;
|
|
2242
|
+
const found = hasTailwindImport(readFileSync2(file, "utf8"));
|
|
2243
|
+
return {
|
|
2244
|
+
name: "tailwind.config",
|
|
2245
|
+
severity: found ? "pass" : "warn",
|
|
2246
|
+
message: found ? `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC788\uC2B5\uB2C8\uB2E4` : `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
return {
|
|
2250
|
+
name: "tailwind.config",
|
|
2251
|
+
severity: "warn",
|
|
2252
|
+
message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
const [tsFile, ...otherFiles] = TAILWIND_CONFIG_FILES;
|
|
2256
|
+
const tsPath = join2(baseDir, tsFile);
|
|
2257
|
+
if (existsSync2(tsPath)) {
|
|
2258
|
+
const content = readFileSync2(tsPath, "utf8");
|
|
2259
|
+
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
2260
|
+
return {
|
|
2261
|
+
name: "tailwind.config",
|
|
2262
|
+
severity: hasTokens ? "pass" : "warn",
|
|
2263
|
+
message: hasTokens ? "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" : "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
for (const file of otherFiles) {
|
|
2267
|
+
if (existsSync2(join2(baseDir, file))) {
|
|
2268
|
+
return { name: "tailwind.config", severity: "warn", message: `${file} \uC874\uC7AC (TypeScript \uAD8C\uC7A5)` };
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
return { name: "tailwind.config", severity: "fail", message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2102
2274
|
// src/template/template-check.ts
|
|
2103
2275
|
var SEVERITY_ICON = {
|
|
2104
2276
|
pass: chalk6.green("PASS"),
|
|
@@ -2109,7 +2281,7 @@ async function collectCheckResults(dir) {
|
|
|
2109
2281
|
const baseDir = path8.resolve(dir || ".");
|
|
2110
2282
|
const results = [];
|
|
2111
2283
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
2112
|
-
results.push(
|
|
2284
|
+
results.push(checkTailwindSetup(baseDir));
|
|
2113
2285
|
results.push(await checkGlobalsCss(baseDir));
|
|
2114
2286
|
results.push(await checkUtils(baseDir));
|
|
2115
2287
|
results.push(await checkDependencies(baseDir));
|
|
@@ -2148,6 +2320,7 @@ async function runCheck(dir) {
|
|
|
2148
2320
|
} else {
|
|
2149
2321
|
console.log(chalk6.green("\n\uBAA8\uB4E0 \uAC80\uC99D\uC744 \uD1B5\uACFC\uD588\uC2B5\uB2C8\uB2E4!"));
|
|
2150
2322
|
}
|
|
2323
|
+
return { pass: passCount, warn: warnCount, fail: failCount };
|
|
2151
2324
|
}
|
|
2152
2325
|
async function checkFileExists(baseDir, fileName, label) {
|
|
2153
2326
|
const exists = await fs9.pathExists(path8.join(baseDir, fileName));
|
|
@@ -2157,31 +2330,6 @@ async function checkFileExists(baseDir, fileName, label) {
|
|
|
2157
2330
|
message: exists ? `${label} \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4` : `${label} \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 'axis init'\uC744 \uC2E4\uD589\uD558\uC138\uC694`
|
|
2158
2331
|
};
|
|
2159
2332
|
}
|
|
2160
|
-
async function checkTailwindConfig(baseDir) {
|
|
2161
|
-
const tsPath = path8.join(baseDir, "tailwind.config.ts");
|
|
2162
|
-
const jsPath = path8.join(baseDir, "tailwind.config.js");
|
|
2163
|
-
if (await fs9.pathExists(tsPath)) {
|
|
2164
|
-
const content = await fs9.readFile(tsPath, "utf-8");
|
|
2165
|
-
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
2166
|
-
return {
|
|
2167
|
-
name: "tailwind.config",
|
|
2168
|
-
severity: hasTokens ? "pass" : "warn",
|
|
2169
|
-
message: hasTokens ? "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" : "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2170
|
-
};
|
|
2171
|
-
}
|
|
2172
|
-
if (await fs9.pathExists(jsPath)) {
|
|
2173
|
-
return {
|
|
2174
|
-
name: "tailwind.config",
|
|
2175
|
-
severity: "warn",
|
|
2176
|
-
message: "tailwind.config.js \uC874\uC7AC (TypeScript \uAD8C\uC7A5)"
|
|
2177
|
-
};
|
|
2178
|
-
}
|
|
2179
|
-
return {
|
|
2180
|
-
name: "tailwind.config",
|
|
2181
|
-
severity: "fail",
|
|
2182
|
-
message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2183
|
-
};
|
|
2184
|
-
}
|
|
2185
2333
|
async function checkGlobalsCss(baseDir) {
|
|
2186
2334
|
const candidates = [
|
|
2187
2335
|
"globals.css",
|
|
@@ -2402,7 +2550,8 @@ function registerTemplateCommand(program2) {
|
|
|
2402
2550
|
}
|
|
2403
2551
|
function registerCheckCommand(program2) {
|
|
2404
2552
|
program2.command("check").description("AXIS \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uAC80\uC99D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action(async (options) => {
|
|
2405
|
-
await runCheck(options.dir);
|
|
2553
|
+
const summary = await runCheck(options.dir);
|
|
2554
|
+
if (summary.fail > 0) process.exitCode = 1;
|
|
2406
2555
|
});
|
|
2407
2556
|
}
|
|
2408
2557
|
|
|
@@ -2411,12 +2560,12 @@ import chalk8 from "chalk";
|
|
|
2411
2560
|
import path10 from "path";
|
|
2412
2561
|
|
|
2413
2562
|
// src/theme/theme-add.ts
|
|
2414
|
-
import { accessSync, constants, existsSync as
|
|
2563
|
+
import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
2415
2564
|
import path9 from "path";
|
|
2416
2565
|
var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
|
|
2417
2566
|
var THEME_PACKAGE = "@axis-ds/theme";
|
|
2418
2567
|
function readText(file) {
|
|
2419
|
-
return
|
|
2568
|
+
return existsSync3(file) ? readFileSync3(file, "utf8") : null;
|
|
2420
2569
|
}
|
|
2421
2570
|
function eolOf(text) {
|
|
2422
2571
|
return text.includes("\r\n") ? "\r\n" : "\n";
|
|
@@ -2492,12 +2641,12 @@ function isStylesheet(realPath) {
|
|
|
2492
2641
|
return path9.extname(realPath).toLowerCase() === ".css";
|
|
2493
2642
|
}
|
|
2494
2643
|
function detectInstallCommand(baseDir) {
|
|
2495
|
-
if (
|
|
2496
|
-
if (
|
|
2497
|
-
if (
|
|
2644
|
+
if (existsSync3(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
2645
|
+
if (existsSync3(path9.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
2646
|
+
if (existsSync3(path9.join(baseDir, "package-lock.json"))) return "npm install";
|
|
2498
2647
|
return "pnpm install";
|
|
2499
2648
|
}
|
|
2500
|
-
function
|
|
2649
|
+
function hasDependency2(pkg, name) {
|
|
2501
2650
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
2502
2651
|
const deps = pkg[field];
|
|
2503
2652
|
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
@@ -2506,7 +2655,7 @@ function hasDependency(pkg, name) {
|
|
|
2506
2655
|
}
|
|
2507
2656
|
return void 0;
|
|
2508
2657
|
}
|
|
2509
|
-
function
|
|
2658
|
+
function isPlainObject2(value) {
|
|
2510
2659
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2511
2660
|
}
|
|
2512
2661
|
function planThemeAdd(baseDirInput, brand) {
|
|
@@ -2531,7 +2680,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2531
2680
|
let config;
|
|
2532
2681
|
try {
|
|
2533
2682
|
const parsed = JSON.parse(configText);
|
|
2534
|
-
if (!
|
|
2683
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2535
2684
|
config = parsed;
|
|
2536
2685
|
} catch (err) {
|
|
2537
2686
|
plan.errors.push({ kind: "invalid-config", message: err.message });
|
|
@@ -2543,7 +2692,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2543
2692
|
}
|
|
2544
2693
|
plan.tokens = resolveTokens(baseDir);
|
|
2545
2694
|
if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
|
|
2546
|
-
const data = JSON.parse(
|
|
2695
|
+
const data = JSON.parse(readFileSync3(plan.tokens.indexPath, "utf8"));
|
|
2547
2696
|
const entries = Array.isArray(data.brands) ? data.brands : [];
|
|
2548
2697
|
const entry = entries.find((e) => e.name === brand);
|
|
2549
2698
|
if (!entry) {
|
|
@@ -2572,7 +2721,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2572
2721
|
plan.writes = [];
|
|
2573
2722
|
return plan;
|
|
2574
2723
|
}
|
|
2575
|
-
const before =
|
|
2724
|
+
const before = readFileSync3(location.path, "utf8");
|
|
2576
2725
|
const imported = findBrandImports(before);
|
|
2577
2726
|
const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
|
|
2578
2727
|
if (imported.includes(brand)) {
|
|
@@ -2598,19 +2747,19 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2598
2747
|
let pkg;
|
|
2599
2748
|
try {
|
|
2600
2749
|
const parsed = JSON.parse(pkgText);
|
|
2601
|
-
if (!
|
|
2750
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2602
2751
|
pkg = parsed;
|
|
2603
2752
|
} catch (err) {
|
|
2604
2753
|
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
2605
2754
|
plan.writes = [];
|
|
2606
2755
|
return plan;
|
|
2607
2756
|
}
|
|
2608
|
-
const themeMissing =
|
|
2609
|
-
const declared =
|
|
2757
|
+
const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
|
|
2758
|
+
const declared = hasDependency2(pkg, TOKENS_PACKAGE);
|
|
2610
2759
|
if (declared !== void 0) {
|
|
2611
2760
|
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
|
|
2612
2761
|
} else {
|
|
2613
|
-
const deps =
|
|
2762
|
+
const deps = isPlainObject2(pkg.dependencies) ? { ...pkg.dependencies } : {};
|
|
2614
2763
|
deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
|
|
2615
2764
|
const next = { ...pkg, dependencies: deps };
|
|
2616
2765
|
plan.dependency = { action: "add", upgrade, themeMissing };
|
|
@@ -2990,7 +3139,7 @@ import chalk10 from "chalk";
|
|
|
2990
3139
|
import prompts2 from "prompts";
|
|
2991
3140
|
|
|
2992
3141
|
// src/init/init.ts
|
|
2993
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as
|
|
3142
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
2994
3143
|
import path11 from "path";
|
|
2995
3144
|
import chalk9 from "chalk";
|
|
2996
3145
|
import fs10 from "fs-extra";
|
|
@@ -2999,98 +3148,6 @@ var TAILWIND_MERGE_RANGES = {
|
|
|
2999
3148
|
tailwind4: "^3.4.0",
|
|
3000
3149
|
tailwind3: "^2.6.0"
|
|
3001
3150
|
};
|
|
3002
|
-
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
3003
|
-
function versionParts(token) {
|
|
3004
|
-
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
3005
|
-
if (!m) return void 0;
|
|
3006
|
-
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
3007
|
-
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
3008
|
-
}
|
|
3009
|
-
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
3010
|
-
function comparatorBounds(op, v) {
|
|
3011
|
-
switch (op) {
|
|
3012
|
-
case ">=":
|
|
3013
|
-
return { lower: v.major };
|
|
3014
|
-
case ">":
|
|
3015
|
-
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
3016
|
-
case "<=":
|
|
3017
|
-
return { upper: v.major };
|
|
3018
|
-
case "<": {
|
|
3019
|
-
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
3020
|
-
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
3021
|
-
}
|
|
3022
|
-
default:
|
|
3023
|
-
return { lower: v.major, upper: v.major };
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
function tailwindMajorBounds(range) {
|
|
3027
|
-
const r = range.trim();
|
|
3028
|
-
if (r === "" || r.includes("||")) return void 0;
|
|
3029
|
-
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
3030
|
-
if (simple) {
|
|
3031
|
-
const v = versionParts(simple[1]);
|
|
3032
|
-
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
3033
|
-
}
|
|
3034
|
-
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
3035
|
-
if (hyphen) {
|
|
3036
|
-
const tokens2 = r.split(/\s+-\s+/);
|
|
3037
|
-
const a = versionParts(tokens2[0]);
|
|
3038
|
-
const b = versionParts(tokens2[1]);
|
|
3039
|
-
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
3040
|
-
}
|
|
3041
|
-
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
3042
|
-
const lowers = [];
|
|
3043
|
-
const uppers = [];
|
|
3044
|
-
for (const t of tokens) {
|
|
3045
|
-
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
3046
|
-
if (!c) return void 0;
|
|
3047
|
-
const v = versionParts(c[2]);
|
|
3048
|
-
if (v === void 0) return void 0;
|
|
3049
|
-
const b = comparatorBounds(c[1], v);
|
|
3050
|
-
if (b.lower !== void 0) lowers.push(b.lower);
|
|
3051
|
-
if (b.upper !== void 0) uppers.push(b.upper);
|
|
3052
|
-
}
|
|
3053
|
-
if (lowers.length === 0) return void 0;
|
|
3054
|
-
const lower = Math.max(...lowers);
|
|
3055
|
-
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
3056
|
-
if (upper !== void 0 && upper < lower) return void 0;
|
|
3057
|
-
return upper !== void 0 ? { lower, upper } : { lower };
|
|
3058
|
-
}
|
|
3059
|
-
function majorWithin(major, bounds) {
|
|
3060
|
-
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
3061
|
-
}
|
|
3062
|
-
function majorFromVersion(version) {
|
|
3063
|
-
if (typeof version !== "string") return void 0;
|
|
3064
|
-
const v = version.trim();
|
|
3065
|
-
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
3066
|
-
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
3067
|
-
return Number(m[1]);
|
|
3068
|
-
}
|
|
3069
|
-
function detectTailwind(baseDirInput, pkg) {
|
|
3070
|
-
const baseDir = path11.resolve(baseDirInput);
|
|
3071
|
-
const installedFile = path11.join(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
3072
|
-
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
3073
|
-
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
3074
|
-
const declaredMajor = bounds?.lower;
|
|
3075
|
-
try {
|
|
3076
|
-
const installed = JSON.parse(readFileSync3(installedFile, "utf8"));
|
|
3077
|
-
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
3078
|
-
const major = majorFromVersion(version);
|
|
3079
|
-
if (major !== void 0) {
|
|
3080
|
-
const found = { major, source: "installed", value: String(version) };
|
|
3081
|
-
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
3082
|
-
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
3083
|
-
}
|
|
3084
|
-
return found;
|
|
3085
|
-
}
|
|
3086
|
-
} catch {
|
|
3087
|
-
}
|
|
3088
|
-
if (declared !== void 0) {
|
|
3089
|
-
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
3090
|
-
return { source: "none", value: declared };
|
|
3091
|
-
}
|
|
3092
|
-
return { source: "none" };
|
|
3093
|
-
}
|
|
3094
3151
|
function selectUtilsDependencies(tailwind) {
|
|
3095
3152
|
return {
|
|
3096
3153
|
clsx: CLSX_RANGE,
|
|
@@ -3154,7 +3211,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3154
3211
|
addCommand: addCommandFor(installCommand, ranges0)
|
|
3155
3212
|
};
|
|
3156
3213
|
const pkgFile = path11.join(baseDir, "package.json");
|
|
3157
|
-
if (!
|
|
3214
|
+
if (!existsSync4(pkgFile)) return plan;
|
|
3158
3215
|
const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
|
|
3159
3216
|
let where;
|
|
3160
3217
|
try {
|
|
@@ -3165,7 +3222,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3165
3222
|
if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
|
|
3166
3223
|
let text;
|
|
3167
3224
|
try {
|
|
3168
|
-
text =
|
|
3225
|
+
text = readFileSync4(pkgFile, "utf8");
|
|
3169
3226
|
} catch (err) {
|
|
3170
3227
|
return unwritable(err.message);
|
|
3171
3228
|
}
|
|
@@ -3174,7 +3231,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3174
3231
|
let pkg;
|
|
3175
3232
|
try {
|
|
3176
3233
|
const parsed = JSON.parse(body);
|
|
3177
|
-
if (!
|
|
3234
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3178
3235
|
pkg = parsed;
|
|
3179
3236
|
} catch (err) {
|
|
3180
3237
|
return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
|
|
@@ -3184,14 +3241,14 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3184
3241
|
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
3185
3242
|
const missing = {};
|
|
3186
3243
|
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
3187
|
-
const declared =
|
|
3244
|
+
const declared = hasDependency2(pkg, name);
|
|
3188
3245
|
if (declared !== void 0) plan.present.push({ name, range: declared });
|
|
3189
3246
|
else missing[name] = range;
|
|
3190
3247
|
}
|
|
3191
3248
|
plan.added = Object.keys(missing);
|
|
3192
3249
|
plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
|
|
3193
3250
|
if (plan.added.length === 0) return { ...plan, action: "present" };
|
|
3194
|
-
if (pkg.dependencies !== void 0 && !
|
|
3251
|
+
if (pkg.dependencies !== void 0 && !isPlainObject2(pkg.dependencies)) {
|
|
3195
3252
|
return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3196
3253
|
}
|
|
3197
3254
|
try {
|
|
@@ -3208,7 +3265,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
3208
3265
|
const w = plan.write;
|
|
3209
3266
|
if (plan.action !== "add" || !w) return false;
|
|
3210
3267
|
const baseDir = path11.resolve(baseDirInput);
|
|
3211
|
-
const current =
|
|
3268
|
+
const current = existsSync4(w.file) ? readFileSync4(w.file, "utf8") : null;
|
|
3212
3269
|
if (current !== w.before) {
|
|
3213
3270
|
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
3214
3271
|
}
|
|
@@ -3224,7 +3281,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
3224
3281
|
let restored;
|
|
3225
3282
|
try {
|
|
3226
3283
|
writeFile(w.file, w.before);
|
|
3227
|
-
if (
|
|
3284
|
+
if (readFileSync4(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
|
|
3228
3285
|
restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
|
|
3229
3286
|
} catch (restoreErr) {
|
|
3230
3287
|
restored = `\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${restoreErr.message}). \uD30C\uC77C\uC774 \uC798\uB838\uAC70\uB098 \uBE44\uC5C8\uC744 \uC218 \uC788\uC73C\uB2C8 \uBC84\uC804 \uAD00\uB9AC \uB3C4\uAD6C \uB4F1\uC73C\uB85C \uBCF5\uAD6C\uD558\uC138\uC694`;
|