@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.
Files changed (3) hide show
  1. package/README.md +7 -0
  2. package/dist/index.js +198 -141
  3. 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(await checkTailwindConfig(baseDir));
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 existsSync2, readFileSync as readFileSync2, realpathSync, unlinkSync, writeFileSync } from "fs";
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 existsSync2(file) ? readFileSync2(file, "utf8") : null;
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 (existsSync2(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
2496
- if (existsSync2(path9.join(baseDir, "yarn.lock"))) return "yarn install";
2497
- if (existsSync2(path9.join(baseDir, "package-lock.json"))) return "npm install";
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 hasDependency(pkg, name) {
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 isPlainObject(value) {
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 (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
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(readFileSync2(plan.tokens.indexPath, "utf8"));
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 = readFileSync2(location.path, "utf8");
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 (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
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 = hasDependency(pkg, THEME_PACKAGE) === void 0;
2609
- const declared = hasDependency(pkg, TOKENS_PACKAGE);
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 = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
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 existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
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 (!existsSync3(pkgFile)) return plan;
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 = readFileSync3(pkgFile, "utf8");
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 (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
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 = hasDependency(pkg, name);
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 && !isPlainObject(pkg.dependencies)) {
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 = existsSync3(w.file) ? readFileSync3(w.file, "utf8") : null;
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 (readFileSync3(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
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`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - CLI for adding components (shadcn compatible)",
6
6
  "publishConfig": {