@axis-ds/cli 1.3.0 → 1.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 +57 -5
- package/dist/index.js +1973 -376
- package/dist/registry/agentic-a11y-labels.json +16 -0
- package/dist/registry/agentic-agent-avatar.json +19 -0
- package/dist/registry/agentic-approval-card.json +19 -0
- package/dist/registry/agentic-attachment-card.json +19 -0
- package/dist/registry/agentic-code-block.json +18 -0
- package/dist/registry/agentic-context-panel.json +18 -0
- package/dist/registry/agentic-diff-viewer.json +19 -0
- package/dist/registry/agentic-feedback-buttons.json +19 -0
- package/dist/registry/agentic-message-bubble.json +19 -0
- package/dist/registry/agentic-plan-card.json +19 -0
- package/dist/registry/agentic-recovery-banner.json +18 -0
- package/dist/registry/agentic-run-progress.json +19 -0
- package/dist/registry/agentic-source-panel.json +19 -0
- package/dist/registry/agentic-step-timeline.json +19 -0
- package/dist/registry/agentic-streaming-text.json +18 -0
- package/dist/registry/agentic-surface-renderer.json +18 -0
- package/dist/registry/agentic-thinking-indicator.json +18 -0
- package/dist/registry/agentic-token-usage-indicator.json +18 -0
- package/dist/registry/agentic-tool-call-card.json +19 -0
- package/dist/registry/badge.json +20 -0
- package/dist/registry/button.json +21 -0
- package/dist/registry/card.json +18 -0
- package/dist/registry/dialog.json +20 -0
- package/dist/registry/index.json +217 -0
- package/dist/registry/input.json +18 -0
- package/dist/registry/label.json +21 -0
- package/dist/registry/registry.json +218 -0
- package/dist/registry/select.json +20 -0
- package/dist/registry/separator.json +20 -0
- package/dist/registry/tabs.json +20 -0
- package/dist/registry/toast.json +21 -0
- package/dist/registry/utils.json +19 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -15,12 +15,8 @@ import {
|
|
|
15
15
|
|
|
16
16
|
// src/index.ts
|
|
17
17
|
import { Command } from "commander";
|
|
18
|
-
import
|
|
19
|
-
import ora6 from "ora";
|
|
20
|
-
import fs11 from "fs-extra";
|
|
21
|
-
import path12 from "path";
|
|
18
|
+
import chalk12 from "chalk";
|
|
22
19
|
import { createRequire as createRequire2 } from "module";
|
|
23
|
-
import prompts3 from "prompts";
|
|
24
20
|
|
|
25
21
|
// src/library/base-collector.ts
|
|
26
22
|
import crypto from "crypto";
|
|
@@ -484,11 +480,11 @@ var ShadcnCollector = class extends BaseCollector {
|
|
|
484
480
|
/**
|
|
485
481
|
* 파일 타입 추론
|
|
486
482
|
*/
|
|
487
|
-
getFileType(
|
|
488
|
-
if (
|
|
489
|
-
if (
|
|
490
|
-
if (
|
|
491
|
-
if (
|
|
483
|
+
getFileType(path16) {
|
|
484
|
+
if (path16.includes("hook") || path16.startsWith("use")) return "hook";
|
|
485
|
+
if (path16.includes("util") || path16.includes("lib")) return "util";
|
|
486
|
+
if (path16.endsWith(".css")) return "style";
|
|
487
|
+
if (path16.endsWith(".d.ts") || path16.includes("types")) return "type";
|
|
492
488
|
return "component";
|
|
493
489
|
}
|
|
494
490
|
};
|
|
@@ -1505,7 +1501,7 @@ import ora5 from "ora";
|
|
|
1505
1501
|
|
|
1506
1502
|
// src/template/template-apply.ts
|
|
1507
1503
|
import fs7 from "fs-extra";
|
|
1508
|
-
import
|
|
1504
|
+
import path7 from "path";
|
|
1509
1505
|
import chalk4 from "chalk";
|
|
1510
1506
|
import ora3 from "ora";
|
|
1511
1507
|
import prompts from "prompts";
|
|
@@ -1574,13 +1570,15 @@ function deepMerge(target, source) {
|
|
|
1574
1570
|
|
|
1575
1571
|
// src/config/axis-config.ts
|
|
1576
1572
|
import fs6 from "fs-extra";
|
|
1573
|
+
import path6 from "path";
|
|
1577
1574
|
var AXIS_CONFIG_SCHEMA_URL = "https://axis.minu.best/schema.json";
|
|
1578
1575
|
var AXIS_CONFIG_FILE = "axis.config.json";
|
|
1579
1576
|
function createInitConfig(answers, registry) {
|
|
1580
1577
|
return {
|
|
1581
1578
|
$schema: AXIS_CONFIG_SCHEMA_URL,
|
|
1582
1579
|
componentsDir: answers.componentsDir,
|
|
1583
|
-
|
|
1580
|
+
...answers.agenticDir !== void 0 ? { agenticDir: answers.agenticDir } : {},
|
|
1581
|
+
...answers.tailwindConfig !== void 0 ? { tailwindConfig: answers.tailwindConfig } : {},
|
|
1584
1582
|
globalCss: answers.globalCss,
|
|
1585
1583
|
registry
|
|
1586
1584
|
};
|
|
@@ -1594,6 +1592,11 @@ function createTemplateConfig(template) {
|
|
|
1594
1592
|
globalCss: "./globals.css"
|
|
1595
1593
|
};
|
|
1596
1594
|
}
|
|
1595
|
+
async function readAxisConfig(baseDir) {
|
|
1596
|
+
const configPath = path6.join(baseDir, AXIS_CONFIG_FILE);
|
|
1597
|
+
if (!await fs6.pathExists(configPath)) return null;
|
|
1598
|
+
return await fs6.readJSON(configPath);
|
|
1599
|
+
}
|
|
1597
1600
|
|
|
1598
1601
|
// src/template/template-apply.ts
|
|
1599
1602
|
async function applyTemplate(slug, options) {
|
|
@@ -1606,10 +1609,10 @@ async function applyTemplate(slug, options) {
|
|
|
1606
1609
|
spinner.fail(err.message);
|
|
1607
1610
|
process.exit(1);
|
|
1608
1611
|
}
|
|
1609
|
-
const baseDir =
|
|
1612
|
+
const baseDir = path7.resolve(options.dir || ".");
|
|
1610
1613
|
const conflicts = [];
|
|
1611
1614
|
for (const file of detail.files) {
|
|
1612
|
-
const dest =
|
|
1615
|
+
const dest = path7.join(baseDir, file.path);
|
|
1613
1616
|
if (await fs7.pathExists(dest)) {
|
|
1614
1617
|
conflicts.push(file.path);
|
|
1615
1618
|
}
|
|
@@ -1634,7 +1637,7 @@ async function applyTemplate(slug, options) {
|
|
|
1634
1637
|
if (options.dryRun) {
|
|
1635
1638
|
console.log(chalk4.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
|
|
1636
1639
|
for (const file of detail.files) {
|
|
1637
|
-
const dest =
|
|
1640
|
+
const dest = path7.join(baseDir, file.path);
|
|
1638
1641
|
const exists = conflicts.includes(file.path);
|
|
1639
1642
|
const label = exists ? chalk4.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk4.green("\uC0DD\uC131");
|
|
1640
1643
|
console.log(` ${label} ${dest}`);
|
|
@@ -1649,8 +1652,8 @@ async function applyTemplate(slug, options) {
|
|
|
1649
1652
|
}
|
|
1650
1653
|
const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
|
|
1651
1654
|
for (const file of detail.files) {
|
|
1652
|
-
const dest =
|
|
1653
|
-
await fs7.ensureDir(
|
|
1655
|
+
const dest = path7.join(baseDir, file.path);
|
|
1656
|
+
await fs7.ensureDir(path7.dirname(dest));
|
|
1654
1657
|
await fs7.writeFile(dest, file.content);
|
|
1655
1658
|
}
|
|
1656
1659
|
writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
|
|
@@ -1711,7 +1714,7 @@ async function initTemplate(slug, options) {
|
|
|
1711
1714
|
}
|
|
1712
1715
|
targetDir = dir;
|
|
1713
1716
|
}
|
|
1714
|
-
const resolved =
|
|
1717
|
+
const resolved = path7.resolve(targetDir);
|
|
1715
1718
|
if (await fs7.pathExists(resolved)) {
|
|
1716
1719
|
const entries = await fs7.readdir(resolved);
|
|
1717
1720
|
if (entries.length > 0) {
|
|
@@ -1727,7 +1730,7 @@ async function initTemplate(slug, options) {
|
|
|
1727
1730
|
await fs7.ensureDir(resolved);
|
|
1728
1731
|
}
|
|
1729
1732
|
await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
|
|
1730
|
-
const configPath =
|
|
1733
|
+
const configPath = path7.join(resolved, "axis.config.json");
|
|
1731
1734
|
if (!await fs7.pathExists(configPath)) {
|
|
1732
1735
|
const axisConfig = createTemplateConfig(selectedSlug);
|
|
1733
1736
|
await fs7.writeJSON(configPath, axisConfig, { spaces: 2 });
|
|
@@ -1742,7 +1745,7 @@ async function initTemplate(slug, options) {
|
|
|
1742
1745
|
|
|
1743
1746
|
// src/template/template-diff.ts
|
|
1744
1747
|
import fs8 from "fs-extra";
|
|
1745
|
-
import
|
|
1748
|
+
import path8 from "path";
|
|
1746
1749
|
import chalk5 from "chalk";
|
|
1747
1750
|
import ora4 from "ora";
|
|
1748
1751
|
async function diffTemplate(slug, options) {
|
|
@@ -1755,10 +1758,10 @@ async function diffTemplate(slug, options) {
|
|
|
1755
1758
|
spinner.fail(err.message);
|
|
1756
1759
|
process.exit(1);
|
|
1757
1760
|
}
|
|
1758
|
-
const baseDir =
|
|
1761
|
+
const baseDir = path8.resolve(options.dir || ".");
|
|
1759
1762
|
const entries = [];
|
|
1760
1763
|
for (const file of detail.files) {
|
|
1761
|
-
const localPath =
|
|
1764
|
+
const localPath = path8.join(baseDir, file.path);
|
|
1762
1765
|
if (!await fs8.pathExists(localPath)) {
|
|
1763
1766
|
entries.push({ path: file.path, status: "added" });
|
|
1764
1767
|
continue;
|
|
@@ -1839,12 +1842,12 @@ async function collectLocalFiles(dir, base) {
|
|
|
1839
1842
|
}
|
|
1840
1843
|
for (const entry of entries) {
|
|
1841
1844
|
if (ignore.has(entry.name)) continue;
|
|
1842
|
-
const fullPath =
|
|
1845
|
+
const fullPath = path8.join(dir, entry.name);
|
|
1843
1846
|
if (entry.isDirectory()) {
|
|
1844
1847
|
const nested = await collectLocalFiles(fullPath, root);
|
|
1845
1848
|
results.push(...nested);
|
|
1846
1849
|
} else {
|
|
1847
|
-
results.push(
|
|
1850
|
+
results.push(path8.relative(root, fullPath).replace(/\\/g, "/"));
|
|
1848
1851
|
}
|
|
1849
1852
|
}
|
|
1850
1853
|
return results;
|
|
@@ -1852,7 +1855,7 @@ async function collectLocalFiles(dir, base) {
|
|
|
1852
1855
|
|
|
1853
1856
|
// src/template/template-check.ts
|
|
1854
1857
|
import fs9 from "fs-extra";
|
|
1855
|
-
import
|
|
1858
|
+
import path9 from "path";
|
|
1856
1859
|
import chalk6 from "chalk";
|
|
1857
1860
|
|
|
1858
1861
|
// src/theme/brand-core.ts
|
|
@@ -2220,9 +2223,222 @@ var TAILWIND_CSS_CANDIDATES = [
|
|
|
2220
2223
|
"styles/globals.css"
|
|
2221
2224
|
];
|
|
2222
2225
|
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2226
|
+
function stripCssComments(css) {
|
|
2227
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2228
|
+
}
|
|
2223
2229
|
function hasTailwindImport(css) {
|
|
2224
|
-
return TAILWIND_IMPORT.test(css
|
|
2230
|
+
return TAILWIND_IMPORT.test(stripCssComments(css));
|
|
2231
|
+
}
|
|
2232
|
+
var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
|
|
2233
|
+
var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
|
|
2234
|
+
var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
|
|
2235
|
+
function hasTokensTailwind4Import(css) {
|
|
2236
|
+
return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
|
|
2237
|
+
}
|
|
2238
|
+
var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)["']/;
|
|
2239
|
+
function findTokensCssImport(css) {
|
|
2240
|
+
return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
|
|
2241
|
+
}
|
|
2242
|
+
function checkGlobalsCss(baseDirInput) {
|
|
2243
|
+
const baseDir = resolve2(baseDirInput);
|
|
2244
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2245
|
+
const file = join2(baseDir, candidate);
|
|
2246
|
+
if (!existsSync2(file)) continue;
|
|
2247
|
+
const content = readFileSync2(file, "utf8");
|
|
2248
|
+
if (content.includes("--background") && content.includes("--primary")) {
|
|
2249
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
2250
|
+
}
|
|
2251
|
+
const imported = findTokensCssImport(content);
|
|
2252
|
+
if (imported !== void 0) {
|
|
2253
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
|
|
2254
|
+
}
|
|
2255
|
+
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
2256
|
+
}
|
|
2257
|
+
return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2258
|
+
}
|
|
2259
|
+
var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
|
|
2260
|
+
var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2261
|
+
function lowerOf(token) {
|
|
2262
|
+
const v = versionParts(token);
|
|
2263
|
+
if (!v) return void 0;
|
|
2264
|
+
const num = (part) => isWild(part) ? 0 : Number(part);
|
|
2265
|
+
const pre = /^v?\d+(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?-/.test(token);
|
|
2266
|
+
return { core: [v.major, num(v.minor), num(v.patch)], pre };
|
|
2267
|
+
}
|
|
2268
|
+
function compareLower(a, b) {
|
|
2269
|
+
for (let i = 0; i < 3; i++) {
|
|
2270
|
+
if (a.core[i] !== b.core[i]) return a.core[i] - b.core[i];
|
|
2271
|
+
}
|
|
2272
|
+
return Number(b.pre) - Number(a.pre);
|
|
2273
|
+
}
|
|
2274
|
+
function rangeLowerVersion(range) {
|
|
2275
|
+
const r = range.trim();
|
|
2276
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2277
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2278
|
+
if (simple) return lowerOf(simple[1]);
|
|
2279
|
+
if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
|
|
2280
|
+
const [a, b] = r.split(/\s+-\s+/);
|
|
2281
|
+
return lowerOf(b) ? lowerOf(a) : void 0;
|
|
2282
|
+
}
|
|
2283
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2284
|
+
let lower;
|
|
2285
|
+
for (const t of tokens) {
|
|
2286
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2287
|
+
if (!c) return void 0;
|
|
2288
|
+
const v = versionParts(c[2]);
|
|
2289
|
+
const low = lowerOf(c[2]);
|
|
2290
|
+
if (!v || !low) return void 0;
|
|
2291
|
+
let candidate;
|
|
2292
|
+
if (c[1] === ">=" || c[1] === "=") candidate = low;
|
|
2293
|
+
else if (c[1] === ">") {
|
|
2294
|
+
if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
|
|
2295
|
+
else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
|
|
2296
|
+
else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
|
|
2297
|
+
}
|
|
2298
|
+
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2299
|
+
}
|
|
2300
|
+
return lower;
|
|
2301
|
+
}
|
|
2302
|
+
function rangeLowerAtLeast(range, min) {
|
|
2303
|
+
const lower = rangeLowerVersion(range);
|
|
2304
|
+
const target = lowerOf(min);
|
|
2305
|
+
if (!lower || !target) return void 0;
|
|
2306
|
+
return compareLower(lower, target) >= 0;
|
|
2307
|
+
}
|
|
2308
|
+
function exactVersion(version) {
|
|
2309
|
+
if (typeof version !== "string") return void 0;
|
|
2310
|
+
const v = version.trim();
|
|
2311
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2312
|
+
return v;
|
|
2313
|
+
}
|
|
2314
|
+
function installedVersion(baseDir, name) {
|
|
2315
|
+
try {
|
|
2316
|
+
const parsed = JSON.parse(readFileSync2(join2(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
|
|
2317
|
+
return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
|
|
2318
|
+
} catch {
|
|
2319
|
+
return void 0;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
function axisPackagesBelowTailwind4(pkg, baseDirInput) {
|
|
2323
|
+
if (!pkg) return [];
|
|
2324
|
+
const baseDir = baseDirInput !== void 0 ? resolve2(baseDirInput) : void 0;
|
|
2325
|
+
const out = [];
|
|
2326
|
+
const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
|
|
2327
|
+
for (const name of TAILWIND4_AXIS_PACKAGES) {
|
|
2328
|
+
const range = hasDependency(pkg, name);
|
|
2329
|
+
if (range === void 0 || range.trim().startsWith("workspace:")) continue;
|
|
2330
|
+
const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
|
|
2331
|
+
const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
|
|
2332
|
+
if (installed !== void 0 && installedLower !== void 0) {
|
|
2333
|
+
if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
|
|
2334
|
+
continue;
|
|
2335
|
+
}
|
|
2336
|
+
const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
|
|
2337
|
+
if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
|
|
2338
|
+
else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
|
|
2339
|
+
}
|
|
2340
|
+
return out;
|
|
2341
|
+
}
|
|
2342
|
+
function axisPackageVersionLabel(issue) {
|
|
2343
|
+
return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
|
|
2344
|
+
}
|
|
2345
|
+
var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
2346
|
+
function tailwind4VersionNote(issues) {
|
|
2347
|
+
const below = issues.filter((i) => i.status === "below");
|
|
2348
|
+
const unknown = issues.filter((i) => i.status === "unknown");
|
|
2349
|
+
let note = "";
|
|
2350
|
+
if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
|
|
2351
|
+
if (unknown.length > 0) note += ` (\uC124\uCE58\uB41C \uBC84\uC804\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694: ${declaredList(unknown)})`;
|
|
2352
|
+
return note;
|
|
2353
|
+
}
|
|
2354
|
+
var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2355
|
+
function componentTailwindImportLine(name) {
|
|
2356
|
+
return `@import "${name}/tailwind.css";`;
|
|
2357
|
+
}
|
|
2358
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2359
|
+
function hasComponentTailwindImport(css, name) {
|
|
2360
|
+
const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
|
|
2361
|
+
return re.test(stripCssComments(css));
|
|
2362
|
+
}
|
|
2363
|
+
function hasComponentSource(css, name) {
|
|
2364
|
+
const re = new RegExp(`@source\\s+(["'])(?!@axis-ds/)[^"'\\n]*${escapeRegExp(name)}(?:[/\\\\][^"'\\n]*)?\\1`);
|
|
2365
|
+
return re.test(stripCssComments(css));
|
|
2366
|
+
}
|
|
2367
|
+
var CREATE_NEXT_APP_DEFAULTS = [
|
|
2368
|
+
{
|
|
2369
|
+
prefix: ":root \uC0C9\uAC12",
|
|
2370
|
+
pattern: /(?<![\w-])(--(?:background|foreground))\s*:\s*(?:#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?|hwb|oklch|oklab|lab|lch|color)\()/g,
|
|
2371
|
+
item: (m) => m[1]
|
|
2372
|
+
},
|
|
2373
|
+
{
|
|
2374
|
+
prefix: "@theme",
|
|
2375
|
+
pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2376
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2377
|
+
},
|
|
2378
|
+
{
|
|
2379
|
+
prefix: "@theme",
|
|
2380
|
+
pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
|
|
2381
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2382
|
+
},
|
|
2383
|
+
{
|
|
2384
|
+
prefix: "body",
|
|
2385
|
+
pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2386
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2387
|
+
}
|
|
2388
|
+
];
|
|
2389
|
+
function findCreateNextAppDefaults(css) {
|
|
2390
|
+
const body = stripCssComments(css);
|
|
2391
|
+
const labels = [];
|
|
2392
|
+
for (const d of CREATE_NEXT_APP_DEFAULTS) {
|
|
2393
|
+
const items = [];
|
|
2394
|
+
for (const m of body.matchAll(d.pattern)) {
|
|
2395
|
+
const item = d.item(m);
|
|
2396
|
+
if (!items.includes(item)) items.push(item);
|
|
2397
|
+
}
|
|
2398
|
+
if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
|
|
2399
|
+
}
|
|
2400
|
+
return labels;
|
|
2401
|
+
}
|
|
2402
|
+
function stripJsComments(src) {
|
|
2403
|
+
let out = "";
|
|
2404
|
+
let i = 0;
|
|
2405
|
+
const n = src.length;
|
|
2406
|
+
while (i < n) {
|
|
2407
|
+
const c = src[i];
|
|
2408
|
+
const d = src[i + 1];
|
|
2409
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2410
|
+
let j = i + 1;
|
|
2411
|
+
while (j < n && src[j] !== c) {
|
|
2412
|
+
if (src[j] === "\\") j++;
|
|
2413
|
+
else if (c !== "`" && src[j] === "\n") break;
|
|
2414
|
+
j++;
|
|
2415
|
+
}
|
|
2416
|
+
out += src.slice(i, j + 1);
|
|
2417
|
+
i = j + 1;
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2420
|
+
if (c === "/" && d === "/") {
|
|
2421
|
+
const end = src.indexOf("\n", i);
|
|
2422
|
+
i = end === -1 ? n : end;
|
|
2423
|
+
continue;
|
|
2424
|
+
}
|
|
2425
|
+
if (c === "/" && d === "*") {
|
|
2426
|
+
const end = src.indexOf("*/", i + 2);
|
|
2427
|
+
i = end === -1 ? n : end + 2;
|
|
2428
|
+
out += " ";
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
out += c;
|
|
2432
|
+
i++;
|
|
2433
|
+
}
|
|
2434
|
+
return out;
|
|
2225
2435
|
}
|
|
2436
|
+
var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
|
|
2437
|
+
var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
|
|
2438
|
+
function hasTokensPresetReference(source) {
|
|
2439
|
+
return PRESET_REFERENCE.test(stripJsComments(source));
|
|
2440
|
+
}
|
|
2441
|
+
var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
|
|
2226
2442
|
function readPackageJson(baseDir) {
|
|
2227
2443
|
try {
|
|
2228
2444
|
const parsed = JSON.parse(readFileSync2(join2(baseDir, "package.json"), "utf8"));
|
|
@@ -2231,19 +2447,60 @@ function readPackageJson(baseDir) {
|
|
|
2231
2447
|
return void 0;
|
|
2232
2448
|
}
|
|
2233
2449
|
}
|
|
2450
|
+
function tailwind4Issues(css, pkg, versions) {
|
|
2451
|
+
const issues = [];
|
|
2452
|
+
const hasEntry = hasTokensTailwind4Import(css);
|
|
2453
|
+
if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
|
|
2454
|
+
const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
|
|
2455
|
+
(name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
|
|
2456
|
+
);
|
|
2457
|
+
if (missing.length > 0) {
|
|
2458
|
+
issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
|
|
2459
|
+
}
|
|
2460
|
+
if (hasEntry) {
|
|
2461
|
+
const defaults = findCreateNextAppDefaults(css);
|
|
2462
|
+
if (defaults.length > 0) issues.push(`create-next-app \uAE30\uBCF8 \uC815\uC758\uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4(${defaults.join(" \xB7 ")}) \u2192 \uC9C0\uC6B0\uC138\uC694`);
|
|
2463
|
+
if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
|
|
2464
|
+
issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC9C0\uB9CC ${TAILWIND4_AXIS_PACKAGES[0]} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2468
|
+
if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
|
|
2469
|
+
issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
return issues;
|
|
2473
|
+
}
|
|
2234
2474
|
function checkTailwindSetup(baseDirInput) {
|
|
2235
2475
|
const baseDir = resolve2(baseDirInput);
|
|
2236
|
-
const
|
|
2476
|
+
const pkg = readPackageJson(baseDir);
|
|
2477
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2237
2478
|
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2238
2479
|
const label = `Tailwind ${tailwind.major}`;
|
|
2239
2480
|
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2240
2481
|
const file = join2(baseDir, candidate);
|
|
2241
2482
|
if (!existsSync2(file)) continue;
|
|
2242
|
-
const
|
|
2483
|
+
const css = readFileSync2(file, "utf8");
|
|
2484
|
+
if (!hasTailwindImport(css)) {
|
|
2485
|
+
return {
|
|
2486
|
+
name: "tailwind.config",
|
|
2487
|
+
severity: "warn",
|
|
2488
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
2492
|
+
const issues = tailwind4Issues(css, pkg, versions);
|
|
2493
|
+
if (issues.length > 0) {
|
|
2494
|
+
return {
|
|
2495
|
+
name: "tailwind.config",
|
|
2496
|
+
severity: "warn",
|
|
2497
|
+
message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2243
2500
|
return {
|
|
2244
2501
|
name: "tailwind.config",
|
|
2245
|
-
severity:
|
|
2246
|
-
message:
|
|
2502
|
+
severity: "pass",
|
|
2503
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
|
|
2247
2504
|
};
|
|
2248
2505
|
}
|
|
2249
2506
|
return {
|
|
@@ -2257,14 +2514,20 @@ function checkTailwindSetup(baseDirInput) {
|
|
|
2257
2514
|
if (existsSync2(tsPath)) {
|
|
2258
2515
|
const content = readFileSync2(tsPath, "utf8");
|
|
2259
2516
|
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
2260
|
-
|
|
2261
|
-
name: "tailwind.config",
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2517
|
+
if (hasTokens) {
|
|
2518
|
+
return { name: "tailwind.config", severity: "pass", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" };
|
|
2519
|
+
}
|
|
2520
|
+
if (hasTokensPresetReference(content)) {
|
|
2521
|
+
return { name: "tailwind.config", severity: "pass", message: `tailwind.config.ts${PRESET_PASS_SUFFIX}` };
|
|
2522
|
+
}
|
|
2523
|
+
return { name: "tailwind.config", severity: "warn", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2265
2524
|
}
|
|
2266
2525
|
for (const file of otherFiles) {
|
|
2267
|
-
|
|
2526
|
+
const path16 = join2(baseDir, file);
|
|
2527
|
+
if (existsSync2(path16)) {
|
|
2528
|
+
if (hasTokensPresetReference(readFileSync2(path16, "utf8"))) {
|
|
2529
|
+
return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
|
|
2530
|
+
}
|
|
2268
2531
|
return { name: "tailwind.config", severity: "warn", message: `${file} \uC874\uC7AC (TypeScript \uAD8C\uC7A5)` };
|
|
2269
2532
|
}
|
|
2270
2533
|
}
|
|
@@ -2278,11 +2541,11 @@ var SEVERITY_ICON = {
|
|
|
2278
2541
|
fail: chalk6.red("FAIL")
|
|
2279
2542
|
};
|
|
2280
2543
|
async function collectCheckResults(dir) {
|
|
2281
|
-
const baseDir =
|
|
2544
|
+
const baseDir = path9.resolve(dir || ".");
|
|
2282
2545
|
const results = [];
|
|
2283
2546
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
2284
2547
|
results.push(checkTailwindSetup(baseDir));
|
|
2285
|
-
results.push(
|
|
2548
|
+
results.push(checkGlobalsCss(baseDir));
|
|
2286
2549
|
results.push(await checkUtils(baseDir));
|
|
2287
2550
|
results.push(await checkDependencies(baseDir));
|
|
2288
2551
|
const brand = checkBrand(baseDir);
|
|
@@ -2323,39 +2586,13 @@ async function runCheck(dir) {
|
|
|
2323
2586
|
return { pass: passCount, warn: warnCount, fail: failCount };
|
|
2324
2587
|
}
|
|
2325
2588
|
async function checkFileExists(baseDir, fileName, label) {
|
|
2326
|
-
const exists = await fs9.pathExists(
|
|
2589
|
+
const exists = await fs9.pathExists(path9.join(baseDir, fileName));
|
|
2327
2590
|
return {
|
|
2328
2591
|
name: label,
|
|
2329
2592
|
severity: exists ? "pass" : "fail",
|
|
2330
2593
|
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`
|
|
2331
2594
|
};
|
|
2332
2595
|
}
|
|
2333
|
-
async function checkGlobalsCss(baseDir) {
|
|
2334
|
-
const candidates = [
|
|
2335
|
-
"globals.css",
|
|
2336
|
-
"app/globals.css",
|
|
2337
|
-
"src/app/globals.css",
|
|
2338
|
-
"src/globals.css",
|
|
2339
|
-
"styles/globals.css"
|
|
2340
|
-
];
|
|
2341
|
-
for (const candidate of candidates) {
|
|
2342
|
-
const fullPath = path8.join(baseDir, candidate);
|
|
2343
|
-
if (await fs9.pathExists(fullPath)) {
|
|
2344
|
-
const content = await fs9.readFile(fullPath, "utf-8");
|
|
2345
|
-
const hasTokens = content.includes("--background") && content.includes("--primary");
|
|
2346
|
-
return {
|
|
2347
|
-
name: "globals.css",
|
|
2348
|
-
severity: hasTokens ? "pass" : "warn",
|
|
2349
|
-
message: hasTokens ? `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` : `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2350
|
-
};
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
return {
|
|
2354
|
-
name: "globals.css",
|
|
2355
|
-
severity: "fail",
|
|
2356
|
-
message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2357
|
-
};
|
|
2358
|
-
}
|
|
2359
2596
|
async function checkUtils(baseDir) {
|
|
2360
2597
|
const candidates = [
|
|
2361
2598
|
"lib/utils.ts",
|
|
@@ -2365,7 +2602,7 @@ async function checkUtils(baseDir) {
|
|
|
2365
2602
|
"utils.ts"
|
|
2366
2603
|
];
|
|
2367
2604
|
for (const candidate of candidates) {
|
|
2368
|
-
const fullPath =
|
|
2605
|
+
const fullPath = path9.join(baseDir, candidate);
|
|
2369
2606
|
if (await fs9.pathExists(fullPath)) {
|
|
2370
2607
|
const content = await fs9.readFile(fullPath, "utf-8");
|
|
2371
2608
|
const hasCn = content.includes("function cn");
|
|
@@ -2383,7 +2620,7 @@ async function checkUtils(baseDir) {
|
|
|
2383
2620
|
};
|
|
2384
2621
|
}
|
|
2385
2622
|
async function checkDependencies(baseDir) {
|
|
2386
|
-
const pkgPath =
|
|
2623
|
+
const pkgPath = path9.join(baseDir, "package.json");
|
|
2387
2624
|
if (!await fs9.pathExists(pkgPath)) {
|
|
2388
2625
|
return {
|
|
2389
2626
|
name: "package.json",
|
|
@@ -2557,11 +2794,11 @@ function registerCheckCommand(program2) {
|
|
|
2557
2794
|
|
|
2558
2795
|
// src/theme/index.ts
|
|
2559
2796
|
import chalk8 from "chalk";
|
|
2560
|
-
import
|
|
2797
|
+
import path11 from "path";
|
|
2561
2798
|
|
|
2562
2799
|
// src/theme/theme-add.ts
|
|
2563
2800
|
import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
2564
|
-
import
|
|
2801
|
+
import path10 from "path";
|
|
2565
2802
|
var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
|
|
2566
2803
|
var THEME_PACKAGE = "@axis-ds/theme";
|
|
2567
2804
|
function readText(file) {
|
|
@@ -2633,17 +2870,17 @@ function compareVersions(a, b) {
|
|
|
2633
2870
|
function realPathInside(baseDir, file) {
|
|
2634
2871
|
const realBase = realpathSync(baseDir);
|
|
2635
2872
|
const realPath = realpathSync(file);
|
|
2636
|
-
const relPath =
|
|
2637
|
-
const inside = relPath !== "" && !relPath.startsWith("..") && !
|
|
2873
|
+
const relPath = path10.relative(realBase, realPath);
|
|
2874
|
+
const inside = relPath !== "" && !relPath.startsWith("..") && !path10.isAbsolute(relPath);
|
|
2638
2875
|
return { inside, realPath };
|
|
2639
2876
|
}
|
|
2640
2877
|
function isStylesheet(realPath) {
|
|
2641
|
-
return
|
|
2878
|
+
return path10.extname(realPath).toLowerCase() === ".css";
|
|
2642
2879
|
}
|
|
2643
2880
|
function detectInstallCommand(baseDir) {
|
|
2644
|
-
if (existsSync3(
|
|
2645
|
-
if (existsSync3(
|
|
2646
|
-
if (existsSync3(
|
|
2881
|
+
if (existsSync3(path10.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
2882
|
+
if (existsSync3(path10.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
2883
|
+
if (existsSync3(path10.join(baseDir, "package-lock.json"))) return "npm install";
|
|
2647
2884
|
return "pnpm install";
|
|
2648
2885
|
}
|
|
2649
2886
|
function hasDependency2(pkg, name) {
|
|
@@ -2659,7 +2896,7 @@ function isPlainObject2(value) {
|
|
|
2659
2896
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2660
2897
|
}
|
|
2661
2898
|
function planThemeAdd(baseDirInput, brand) {
|
|
2662
|
-
const baseDir =
|
|
2899
|
+
const baseDir = path10.resolve(baseDirInput);
|
|
2663
2900
|
const plan = {
|
|
2664
2901
|
baseDir,
|
|
2665
2902
|
brand,
|
|
@@ -2671,7 +2908,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2671
2908
|
installCommand: detectInstallCommand(baseDir),
|
|
2672
2909
|
writes: []
|
|
2673
2910
|
};
|
|
2674
|
-
const configFile =
|
|
2911
|
+
const configFile = path10.join(baseDir, AXIS_CONFIG_FILE);
|
|
2675
2912
|
const configText = readText(configFile);
|
|
2676
2913
|
if (configText === null) {
|
|
2677
2914
|
plan.errors.push({ kind: "no-config" });
|
|
@@ -2737,7 +2974,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2737
2974
|
} else {
|
|
2738
2975
|
plan.css = { configuredMissing: location.configuredMissing, action: "manual", otherBrands: [] };
|
|
2739
2976
|
}
|
|
2740
|
-
const pkgFile =
|
|
2977
|
+
const pkgFile = path10.join(baseDir, "package.json");
|
|
2741
2978
|
const pkgText = readText(pkgFile);
|
|
2742
2979
|
const installed = plan.tokens.version;
|
|
2743
2980
|
const upgrade = installed !== void 0 && (compareVersions(installed, MIN_BRAND_TOKENS_VERSION) ?? 0) < 0;
|
|
@@ -2797,8 +3034,8 @@ function applyThemeAdd(plan) {
|
|
|
2797
3034
|
if (current !== w.before) {
|
|
2798
3035
|
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
2799
3036
|
}
|
|
2800
|
-
const where = realPathInside(plan.baseDir, w.before === null ?
|
|
2801
|
-
if (!where.inside && !(w.before === null &&
|
|
3037
|
+
const where = realPathInside(plan.baseDir, w.before === null ? path10.dirname(w.file) : w.file);
|
|
3038
|
+
if (!where.inside && !(w.before === null && path10.dirname(w.file) === plan.baseDir)) {
|
|
2802
3039
|
throw new Error(`${w.file} \uC758 \uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
|
|
2803
3040
|
}
|
|
2804
3041
|
if (!w.file.endsWith(".json") && !isStylesheet(where.realPath)) {
|
|
@@ -2810,7 +3047,7 @@ function applyThemeAdd(plan) {
|
|
|
2810
3047
|
throw new Error(`${w.file}: \uBE0C\uB79C\uB4DC import \uAC00 \uC815\uD655\uD788 1\uC904\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
2811
3048
|
}
|
|
2812
3049
|
try {
|
|
2813
|
-
accessSync(w.before === null ?
|
|
3050
|
+
accessSync(w.before === null ? path10.dirname(w.file) : w.file, constants.W_OK);
|
|
2814
3051
|
} catch (err) {
|
|
2815
3052
|
throw new Error(`${w.file} \uC5D0 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errorMessage(err)}).`);
|
|
2816
3053
|
}
|
|
@@ -2961,7 +3198,7 @@ function renderThemeInfo(result, name) {
|
|
|
2961
3198
|
return { lines, exitCode: 0 };
|
|
2962
3199
|
}
|
|
2963
3200
|
function rel(plan, file) {
|
|
2964
|
-
return
|
|
3201
|
+
return path11.relative(plan.baseDir, file) || file;
|
|
2965
3202
|
}
|
|
2966
3203
|
function renderThemeAdd(plan, written) {
|
|
2967
3204
|
const error = plan.errors[0];
|
|
@@ -3111,15 +3348,15 @@ function print(output) {
|
|
|
3111
3348
|
function registerThemeCommand(program2) {
|
|
3112
3349
|
const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
|
|
3113
3350
|
themeCmd.command("list").alias("ls").description("\uC124\uCE58\uB41C @axis-ds/tokens \uC758 \uBE0C\uB79C\uB4DC \uBAA9\uB85D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((options) => {
|
|
3114
|
-
const baseDir =
|
|
3351
|
+
const baseDir = path11.resolve(options.dir || ".");
|
|
3115
3352
|
print(renderThemeList(listBrands(baseDir)));
|
|
3116
3353
|
});
|
|
3117
3354
|
themeCmd.command("info <brand>").description("\uBE0C\uB79C\uB4DC \uC0C1\uC138: import \uACBD\uB85C \xB7 Provider \uC608\uC2DC \xB7 \uC8FC\uC694 \uD1A0\uD070 \xB7 \uBCF4\uC815 \uB0B4\uC5ED").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
|
|
3118
|
-
const baseDir =
|
|
3355
|
+
const baseDir = path11.resolve(options.dir || ".");
|
|
3119
3356
|
print(renderThemeInfo(getBrand(baseDir, name), name));
|
|
3120
3357
|
});
|
|
3121
3358
|
themeCmd.command("add <brand>").description("\uBE0C\uB79C\uB4DC \uC801\uC6A9: CSS import \xB7 package.json \uC758\uC874\uC131 \xB7 axis.config.json brand (\uC124\uCE58\uB294 \uC548\uB0B4\uB9CC)").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action((name, options) => {
|
|
3122
|
-
const baseDir =
|
|
3359
|
+
const baseDir = path11.resolve(options.dir || ".");
|
|
3123
3360
|
const plan = planThemeAdd(baseDir, name);
|
|
3124
3361
|
let written = [];
|
|
3125
3362
|
if (plan.errors.length === 0) {
|
|
@@ -3138,115 +3375,650 @@ function registerThemeCommand(program2) {
|
|
|
3138
3375
|
import chalk10 from "chalk";
|
|
3139
3376
|
import prompts2 from "prompts";
|
|
3140
3377
|
|
|
3141
|
-
// src/
|
|
3142
|
-
import {
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
var TAILWIND_MERGE_RANGES = {
|
|
3148
|
-
tailwind4: "^3.4.0",
|
|
3149
|
-
tailwind3: "^2.6.0"
|
|
3150
|
-
};
|
|
3151
|
-
function selectUtilsDependencies(tailwind) {
|
|
3152
|
-
return {
|
|
3153
|
-
clsx: CLSX_RANGE,
|
|
3154
|
-
"tailwind-merge": tailwind.major !== void 0 && tailwind.major >= 4 ? TAILWIND_MERGE_RANGES.tailwind4 : TAILWIND_MERGE_RANGES.tailwind3
|
|
3155
|
-
};
|
|
3378
|
+
// src/registry/schema.ts
|
|
3379
|
+
import { createHash } from "crypto";
|
|
3380
|
+
var REGISTRY_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3381
|
+
var REGISTRY_NAME_MAX_LENGTH = 64;
|
|
3382
|
+
function isValidRegistryName(name) {
|
|
3383
|
+
return typeof name === "string" && name.length > 0 && name.length <= REGISTRY_NAME_MAX_LENGTH && REGISTRY_NAME_PATTERN.test(name);
|
|
3156
3384
|
}
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3385
|
+
var REGISTRY_PUBLIC_BASE_URL = "https://axis-design-system.pages.dev/r";
|
|
3386
|
+
function redactRegistryUrl(raw) {
|
|
3387
|
+
return maskQueryAndHash(redactUserinfo(raw));
|
|
3388
|
+
}
|
|
3389
|
+
function maskQueryAndHash(value) {
|
|
3390
|
+
const hashAt = value.indexOf("#");
|
|
3391
|
+
let head = hashAt >= 0 ? value.slice(0, hashAt) : value;
|
|
3392
|
+
const queryAt = head.indexOf("?");
|
|
3393
|
+
if (queryAt >= 0) head = `${head.slice(0, queryAt)}?***`;
|
|
3394
|
+
return hashAt >= 0 ? `${head}#***` : head;
|
|
3395
|
+
}
|
|
3396
|
+
function redactUserinfo(raw) {
|
|
3397
|
+
let parsed = null;
|
|
3398
|
+
try {
|
|
3399
|
+
parsed = new URL(raw);
|
|
3400
|
+
} catch {
|
|
3401
|
+
parsed = null;
|
|
3402
|
+
}
|
|
3403
|
+
if (parsed && (parsed.username || parsed.password)) {
|
|
3404
|
+
parsed.username = "";
|
|
3405
|
+
parsed.password = "";
|
|
3406
|
+
const href = parsed.href;
|
|
3407
|
+
const scheme = `${parsed.protocol}//`;
|
|
3408
|
+
return href.startsWith(scheme) ? `${scheme}***@${href.slice(scheme.length)}` : `***@${href}`;
|
|
3409
|
+
}
|
|
3410
|
+
const authPrefix = /^\s*[A-Za-z][A-Za-z0-9+.-]*:[/\\]*/.exec(raw)?.[0] ?? "";
|
|
3411
|
+
const authority = raw.slice(authPrefix.length).split(/[/\\]/)[0];
|
|
3412
|
+
const authorityAt = authority.lastIndexOf("@");
|
|
3413
|
+
if (authPrefix && authorityAt >= 0) return `${authPrefix}***${raw.slice(authPrefix.length + authorityAt)}`;
|
|
3414
|
+
if (parsed && (parsed.protocol === "http:" || parsed.protocol === "https:")) return raw;
|
|
3415
|
+
const at = raw.lastIndexOf("@");
|
|
3416
|
+
if (at < 0) return raw;
|
|
3417
|
+
const prefix = /^\s*[A-Za-z][A-Za-z0-9+.-]*:[/\\]*/.exec(raw)?.[0] ?? "";
|
|
3418
|
+
if (prefix.length > at) return raw;
|
|
3419
|
+
return `${prefix}***${raw.slice(at)}`;
|
|
3420
|
+
}
|
|
3421
|
+
var DEFAULT_DEPENDENCY_BASES = [REGISTRY_PUBLIC_BASE_URL];
|
|
3422
|
+
function trimBase(base) {
|
|
3423
|
+
return base.replace(/\/+$/, "");
|
|
3424
|
+
}
|
|
3425
|
+
function registryDependencyName(dep, allowedBases = DEFAULT_DEPENDENCY_BASES) {
|
|
3426
|
+
if (REGISTRY_NAME_PATTERN.test(dep) && dep.length <= REGISTRY_NAME_MAX_LENGTH) return dep;
|
|
3427
|
+
if (/\s/.test(dep) || dep.includes("?") || dep.includes("#")) return null;
|
|
3428
|
+
let url;
|
|
3429
|
+
try {
|
|
3430
|
+
url = new URL(dep);
|
|
3431
|
+
} catch {
|
|
3432
|
+
return null;
|
|
3163
3433
|
}
|
|
3164
|
-
if (
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
)
|
|
3434
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
3435
|
+
if (url.username || url.password || url.search || url.hash) return null;
|
|
3436
|
+
for (const raw of allowedBases) {
|
|
3437
|
+
const prefix = `${trimBase(raw)}/`;
|
|
3438
|
+
if (!dep.startsWith(prefix) || !dep.endsWith(".json")) continue;
|
|
3439
|
+
const name = dep.slice(prefix.length, -".json".length);
|
|
3440
|
+
if (isValidRegistryName(name)) return name;
|
|
3168
3441
|
}
|
|
3169
|
-
return
|
|
3442
|
+
return null;
|
|
3170
3443
|
}
|
|
3171
|
-
function
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3444
|
+
function registryDependencyArray(obj, where, allowedBases) {
|
|
3445
|
+
const names = [];
|
|
3446
|
+
for (const dep of stringArray(obj, "registryDependencies", where)) {
|
|
3447
|
+
const name = registryDependencyName(dep, allowedBases);
|
|
3448
|
+
if (name === null) {
|
|
3449
|
+
throw new Error(
|
|
3450
|
+
`${where}: registryDependencies \uC758 ${JSON.stringify(redactRegistryUrl(dep).slice(0, 120))} \uB294 \uD56D\uBAA9 \uC774\uB984\uC774\uB098 <\uB808\uC9C0\uC2A4\uD2B8\uB9AC base>/<\uC774\uB984>.json \uD615\uD0DC\uAC00 \uC544\uB2D9\uB2C8\uB2E4(\uBC1B\uB294 base: ${allowedBases.map(trimBase).join(", ")})`
|
|
3451
|
+
);
|
|
3452
|
+
}
|
|
3453
|
+
if (!names.includes(name)) names.push(name);
|
|
3176
3454
|
}
|
|
3177
|
-
return
|
|
3455
|
+
return names;
|
|
3178
3456
|
}
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3457
|
+
function parseJsonText(text, where) {
|
|
3458
|
+
try {
|
|
3459
|
+
return JSON.parse(text);
|
|
3460
|
+
} catch {
|
|
3461
|
+
const head = text.slice(0, 40).replace(/\s+/g, " ").trim();
|
|
3462
|
+
throw new Error(`${where}: JSON \uC774 \uC544\uB2D9\uB2C8\uB2E4(\uC55E\uBD80\uBD84: ${JSON.stringify(head)})`);
|
|
3463
|
+
}
|
|
3184
3464
|
}
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
componentsDir: "./src/components/ui",
|
|
3188
|
-
tailwindConfig: "./tailwind.config.ts",
|
|
3189
|
-
globalCss: "./src/app/globals.css"
|
|
3190
|
-
};
|
|
3191
|
-
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
3192
|
-
var BOM = "\uFEFF";
|
|
3193
|
-
function addCommandFor(installCommand, deps) {
|
|
3194
|
-
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
3195
|
-
if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
|
|
3196
|
-
if (installCommand.startsWith("npm")) return `npm install ${specs}`;
|
|
3197
|
-
return `pnpm add ${specs}`;
|
|
3465
|
+
function isRecord(v) {
|
|
3466
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3198
3467
|
}
|
|
3199
|
-
function
|
|
3200
|
-
const
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3468
|
+
function optionalString(obj, key, where) {
|
|
3469
|
+
const v = obj[key];
|
|
3470
|
+
if (v === void 0) return void 0;
|
|
3471
|
+
if (typeof v !== "string") throw new Error(`${where}: ${key} \uAC00 \uBB38\uC790\uC5F4\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3472
|
+
return v;
|
|
3473
|
+
}
|
|
3474
|
+
function stringArray(obj, key, where) {
|
|
3475
|
+
const v = obj[key];
|
|
3476
|
+
if (v === void 0) return [];
|
|
3477
|
+
if (!Array.isArray(v) || v.some((s) => typeof s !== "string" || s.length === 0)) {
|
|
3478
|
+
throw new Error(`${where}: ${key} \uB294 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uBB38\uC790\uC5F4 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4`);
|
|
3479
|
+
}
|
|
3480
|
+
return v;
|
|
3481
|
+
}
|
|
3482
|
+
var DEPENDENCY_SPEC_PATTERN = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*(?:@[0-9A-Za-z.^~<>=*+| -]+)?$/;
|
|
3483
|
+
function dependencyArray(obj, key, where) {
|
|
3484
|
+
const list = stringArray(obj, key, where);
|
|
3485
|
+
const bad = list.find((s) => s.length > 214 || !DEPENDENCY_SPEC_PATTERN.test(s));
|
|
3486
|
+
if (bad !== void 0) {
|
|
3487
|
+
throw new Error(`${where}: ${key} \uC5D0 \uD328\uD0A4\uC9C0 \uC774\uB984 \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uB294 \uAC12\uC774 \uC788\uC2B5\uB2C8\uB2E4(${JSON.stringify(bad.slice(0, 60))})`);
|
|
3488
|
+
}
|
|
3489
|
+
return list;
|
|
3490
|
+
}
|
|
3491
|
+
function requireType(obj, where) {
|
|
3492
|
+
const type = obj.type;
|
|
3493
|
+
if (typeof type !== "string" || !type.startsWith("registry:")) {
|
|
3494
|
+
throw new Error(`${where}: type \uC774 registry:* \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3495
|
+
}
|
|
3496
|
+
return type;
|
|
3497
|
+
}
|
|
3498
|
+
function validateRegistryIndex(data, where = "index.json") {
|
|
3499
|
+
if (!isRecord(data)) throw new Error(`${where}: \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3500
|
+
const version = data.version;
|
|
3501
|
+
if (typeof version !== "string" || version.length === 0) {
|
|
3502
|
+
throw new Error(`${where}: version \uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
3503
|
+
}
|
|
3504
|
+
if (!Array.isArray(data.items)) throw new Error(`${where}: items \uAC00 \uBC30\uC5F4\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3505
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3506
|
+
const items = data.items.map((raw, i) => {
|
|
3507
|
+
const at = `${where} items[${i}]`;
|
|
3508
|
+
if (!isRecord(raw)) throw new Error(`${at}: \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3509
|
+
if (!isValidRegistryName(raw.name)) throw new Error(`${at}: name \uC774 slug \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
|
|
3510
|
+
if (seen.has(raw.name)) throw new Error(`${at}: name '${raw.name}' \uAC00 \uC911\uBCF5\uC785\uB2C8\uB2E4`);
|
|
3511
|
+
seen.add(raw.name);
|
|
3512
|
+
const sha256 = optionalString(raw, "sha256", at);
|
|
3513
|
+
if (sha256 !== void 0 && !/^[0-9a-f]{64}$/.test(sha256)) {
|
|
3514
|
+
throw new Error(`${at}: sha256 \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3515
|
+
}
|
|
3516
|
+
return {
|
|
3517
|
+
name: raw.name,
|
|
3518
|
+
type: requireType(raw, at),
|
|
3519
|
+
title: optionalString(raw, "title", at),
|
|
3520
|
+
description: optionalString(raw, "description", at),
|
|
3521
|
+
...sha256 !== void 0 ? { sha256 } : {}
|
|
3522
|
+
};
|
|
3523
|
+
});
|
|
3524
|
+
return {
|
|
3525
|
+
name: optionalString(data, "name", where),
|
|
3526
|
+
homepage: optionalString(data, "homepage", where),
|
|
3527
|
+
version,
|
|
3528
|
+
items
|
|
3212
3529
|
};
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3530
|
+
}
|
|
3531
|
+
function validateRegistryItem(data, expectedName, where = `${expectedName}.json`, dependencyBases = DEFAULT_DEPENDENCY_BASES) {
|
|
3532
|
+
if (!isRecord(data)) throw new Error(`${where}: \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3533
|
+
if (data.name !== expectedName) {
|
|
3534
|
+
throw new Error(`${where}: name \uC774 '${expectedName}' \uAC00 \uC544\uB2D9\uB2C8\uB2E4(${JSON.stringify(data.name)})`);
|
|
3535
|
+
}
|
|
3536
|
+
const type = requireType(data, where);
|
|
3537
|
+
if (!Array.isArray(data.files) || data.files.length === 0) {
|
|
3538
|
+
throw new Error(`${where}: files \uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`);
|
|
3539
|
+
}
|
|
3540
|
+
const files = data.files.map((raw, i) => {
|
|
3541
|
+
const at = `${where} files[${i}]`;
|
|
3542
|
+
if (!isRecord(raw)) throw new Error(`${at}: \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3543
|
+
if (typeof raw.path !== "string" || raw.path.length === 0 || raw.path.includes("\0")) {
|
|
3544
|
+
throw new Error(`${at}: path \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
3545
|
+
}
|
|
3546
|
+
if (typeof raw.content !== "string") throw new Error(`${at}: content \uAC00 \uBB38\uC790\uC5F4\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3547
|
+
const fileType = optionalString(raw, "type", at);
|
|
3548
|
+
const target = optionalString(raw, "target", at);
|
|
3549
|
+
return {
|
|
3550
|
+
path: raw.path,
|
|
3551
|
+
content: raw.content,
|
|
3552
|
+
...fileType !== void 0 ? { type: fileType } : {},
|
|
3553
|
+
...target !== void 0 ? { target } : {}
|
|
3554
|
+
};
|
|
3555
|
+
});
|
|
3556
|
+
return {
|
|
3557
|
+
name: expectedName,
|
|
3558
|
+
type,
|
|
3559
|
+
title: optionalString(data, "title", where),
|
|
3560
|
+
description: optionalString(data, "description", where),
|
|
3561
|
+
dependencies: dependencyArray(data, "dependencies", where),
|
|
3562
|
+
devDependencies: dependencyArray(data, "devDependencies", where),
|
|
3563
|
+
// URL 형태는 이름으로 바꿔 둡니다. 호출한 쪽(add 의 collectItems)은 이름만 봅니다
|
|
3564
|
+
registryDependencies: registryDependencyArray(data, where, dependencyBases),
|
|
3565
|
+
files
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
function sha256Hex(text) {
|
|
3569
|
+
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
3570
|
+
}
|
|
3571
|
+
function checkItemSha256(item, entry, where = `${item.name}.json`) {
|
|
3572
|
+
if (entry.sha256 === void 0) return;
|
|
3573
|
+
if (item.files.length !== 1) {
|
|
3574
|
+
throw new Error(`${where}: index.json \uC5D0 sha256 \uC774 \uC788\uB294\uB370 files \uAC00 ${item.files.length}\uAC1C\uB77C sha256 \uC744 \uB300\uC870\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
3221
3575
|
}
|
|
3222
|
-
|
|
3223
|
-
|
|
3576
|
+
const actual = sha256Hex(item.files[0].content);
|
|
3577
|
+
if (actual !== entry.sha256) {
|
|
3578
|
+
throw new Error(`${where}: content sha256 \uC774 index.json \uACFC \uB2E4\uB985\uB2C8\uB2E4`);
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
// src/registry/remote.ts
|
|
3583
|
+
var DEFAULT_REGISTRY_URL = REGISTRY_PUBLIC_BASE_URL;
|
|
3584
|
+
var DEFAULT_REGISTRY_TIMEOUT_MS = 5e3;
|
|
3585
|
+
var LEGACY_DEFAULT_REGISTRY_URL = "https://axis.minu.best/r";
|
|
3586
|
+
var LEGACY_REGISTRY_NOTICE = `axis.config.json \uC758 registry \uAC00 \uC885\uC804 \uAE30\uBCF8 \uC8FC\uC18C(${LEGACY_DEFAULT_REGISTRY_URL})\uB77C \uC0C8 \uAE30\uBCF8 \uC8FC\uC18C(${REGISTRY_PUBLIC_BASE_URL})\uB85C \uC870\uD68C\uD574\uC694. axis.config.json \uC758 registry \uB97C \uACE0\uCE58\uBA74 \uC774 \uC548\uB0B4\uAC00 \uC0AC\uB77C\uC838\uC694`;
|
|
3587
|
+
function isLegacyDefaultRegistryUrl(value) {
|
|
3588
|
+
let normalized;
|
|
3224
3589
|
try {
|
|
3225
|
-
|
|
3226
|
-
} catch
|
|
3227
|
-
return
|
|
3590
|
+
normalized = normalizeRegistryBaseUrl(value.trim());
|
|
3591
|
+
} catch {
|
|
3592
|
+
return false;
|
|
3228
3593
|
}
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3594
|
+
return normalized === LEGACY_DEFAULT_REGISTRY_URL;
|
|
3595
|
+
}
|
|
3596
|
+
function resolveRegistryUrl(options) {
|
|
3597
|
+
const env = options.env ?? process.env;
|
|
3598
|
+
const fromEnv = env.AXIS_REGISTRY_URL?.trim();
|
|
3599
|
+
if (fromEnv) return { url: fromEnv, source: "env" };
|
|
3600
|
+
const fromConfig = typeof options.config?.registry === "string" ? options.config.registry.trim() : "";
|
|
3601
|
+
if (fromConfig) {
|
|
3602
|
+
if (isLegacyDefaultRegistryUrl(fromConfig)) {
|
|
3603
|
+
return { url: DEFAULT_REGISTRY_URL, source: "config", migratedFrom: fromConfig };
|
|
3604
|
+
}
|
|
3605
|
+
return { url: fromConfig, source: "config" };
|
|
3606
|
+
}
|
|
3607
|
+
return { url: DEFAULT_REGISTRY_URL, source: "default" };
|
|
3608
|
+
}
|
|
3609
|
+
function normalizeRegistryBaseUrl(raw) {
|
|
3610
|
+
const shown = redactRegistryUrl(raw);
|
|
3611
|
+
if (/\s/.test(raw)) throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC5D0 \uACF5\uBC31\uC744 \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${JSON.stringify(shown)}`);
|
|
3612
|
+
if (raw.includes("?") || raw.includes("#")) throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC5D0 \uCFFC\uB9AC \xB7 \uD574\uC2DC\uB97C \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${shown}`);
|
|
3613
|
+
let parsed;
|
|
3232
3614
|
try {
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
} catch (err) {
|
|
3237
|
-
return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
|
|
3615
|
+
parsed = new URL(raw);
|
|
3616
|
+
} catch {
|
|
3617
|
+
throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4: ${shown}`);
|
|
3238
3618
|
}
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
3242
|
-
const missing = {};
|
|
3243
|
-
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
3244
|
-
const declared = hasDependency2(pkg, name);
|
|
3245
|
-
if (declared !== void 0) plan.present.push({ name, range: declared });
|
|
3246
|
-
else missing[name] = range;
|
|
3619
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
3620
|
+
throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC740 http \xB7 https \uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4: ${shown}`);
|
|
3247
3621
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
3622
|
+
if (parsed.username || parsed.password) {
|
|
3623
|
+
throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC5D0 \uC0AC\uC6A9\uC790 \uC815\uBCF4(userinfo)\uB97C \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${shown}`);
|
|
3624
|
+
}
|
|
3625
|
+
if (parsed.search || parsed.hash) throw new Error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC5D0 \uCFFC\uB9AC \xB7 \uD574\uC2DC\uB97C \uB458 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${shown}`);
|
|
3626
|
+
return `${parsed.protocol}//${parsed.host}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
3627
|
+
}
|
|
3628
|
+
var RegistryAccessError = class extends Error {
|
|
3629
|
+
constructor(message) {
|
|
3630
|
+
super(message);
|
|
3631
|
+
this.name = "RegistryAccessError";
|
|
3632
|
+
}
|
|
3633
|
+
};
|
|
3634
|
+
async function fetchRegistryJson(url, options = {}) {
|
|
3635
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_REGISTRY_TIMEOUT_MS;
|
|
3636
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
3637
|
+
if (!fetchImpl) throw new RegistryAccessError("\uC774 Node \uB7F0\uD0C0\uC784\uC5D0\uB294 fetch \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(Node 18 \uC774\uC0C1 \uD544\uC694)");
|
|
3638
|
+
const shown = redactRegistryUrl(url);
|
|
3639
|
+
const controller = new AbortController();
|
|
3640
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3641
|
+
const describe = (error) => {
|
|
3642
|
+
if (controller.signal.aborted) return new RegistryAccessError(`${shown}: ${timeoutMs}ms \uC548\uC5D0 \uC751\uB2F5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
3643
|
+
const cause = error?.cause;
|
|
3644
|
+
const detail = cause?.code ?? cause?.message ?? (error instanceof Error ? error.message : String(error));
|
|
3645
|
+
return new RegistryAccessError(`${shown}: \uC694\uCCAD \uC2E4\uD328(${detail})`);
|
|
3646
|
+
};
|
|
3647
|
+
let text;
|
|
3648
|
+
try {
|
|
3649
|
+
let res;
|
|
3650
|
+
try {
|
|
3651
|
+
res = await fetchImpl(url, { signal: controller.signal, headers: { accept: "application/json" } });
|
|
3652
|
+
} catch (error) {
|
|
3653
|
+
throw describe(error);
|
|
3654
|
+
}
|
|
3655
|
+
if (!res.ok) {
|
|
3656
|
+
await res.text().catch(() => void 0);
|
|
3657
|
+
throw new RegistryAccessError(`${shown}: HTTP ${res.status}`);
|
|
3658
|
+
}
|
|
3659
|
+
try {
|
|
3660
|
+
text = await res.text();
|
|
3661
|
+
} catch (error) {
|
|
3662
|
+
throw describe(error);
|
|
3663
|
+
}
|
|
3664
|
+
} finally {
|
|
3665
|
+
clearTimeout(timer);
|
|
3666
|
+
}
|
|
3667
|
+
return parseJsonText(text, shown);
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
// src/init/init.ts
|
|
3671
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync5, lstatSync as lstatSync2, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
3672
|
+
import path13 from "path";
|
|
3673
|
+
import chalk9 from "chalk";
|
|
3674
|
+
import fs11 from "fs-extra";
|
|
3675
|
+
|
|
3676
|
+
// src/add/safe-write.ts
|
|
3677
|
+
import { constants as fsConstants, existsSync as existsSync4, lstatSync, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
|
|
3678
|
+
import path12 from "path";
|
|
3679
|
+
import fs10 from "fs-extra";
|
|
3680
|
+
var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
|
|
3681
|
+
var OVERWRITE_FLAGS = fsConstants.O_WRONLY | (fsConstants.O_NOFOLLOW ?? 0);
|
|
3682
|
+
var HARDLINK_ERROR_CODE = "EAXISHARDLINK";
|
|
3683
|
+
var NOT_REGULAR_ERROR_CODE = "EAXISNOTREG";
|
|
3684
|
+
function codedError(code, message) {
|
|
3685
|
+
const e = new Error(message);
|
|
3686
|
+
e.code = code;
|
|
3687
|
+
return e;
|
|
3688
|
+
}
|
|
3689
|
+
function isSameOrInside(parent, child, impl = path12) {
|
|
3690
|
+
const rel3 = impl.relative(parent, child);
|
|
3691
|
+
if (rel3 === "") return true;
|
|
3692
|
+
return !(rel3 === ".." || rel3.startsWith(`..${impl.sep}`) || impl.isAbsolute(rel3));
|
|
3693
|
+
}
|
|
3694
|
+
function nearestExisting(p) {
|
|
3695
|
+
let cur = p;
|
|
3696
|
+
while (!existsSync4(cur)) {
|
|
3697
|
+
const up = path12.dirname(cur);
|
|
3698
|
+
if (up === cur) return cur;
|
|
3699
|
+
cur = up;
|
|
3700
|
+
}
|
|
3701
|
+
return cur;
|
|
3702
|
+
}
|
|
3703
|
+
function escapeReason(root, target, options = {}) {
|
|
3704
|
+
const realRoot = realpathSync2(root);
|
|
3705
|
+
if (!isSameOrInside(path12.resolve(root), path12.resolve(target)) || path12.resolve(target) === path12.resolve(root)) {
|
|
3706
|
+
return `\uACBD\uB85C\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4(${target})`;
|
|
3707
|
+
}
|
|
3708
|
+
const anchor = nearestExisting(path12.dirname(target));
|
|
3709
|
+
const realAnchor = realpathSync2(anchor);
|
|
3710
|
+
if (!isSameOrInside(realRoot, realAnchor)) {
|
|
3711
|
+
return `\uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realAnchor})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
|
|
3712
|
+
}
|
|
3713
|
+
let st = null;
|
|
3714
|
+
try {
|
|
3715
|
+
st = lstatSync(target);
|
|
3716
|
+
} catch {
|
|
3717
|
+
st = null;
|
|
3718
|
+
}
|
|
3719
|
+
if (st) {
|
|
3720
|
+
if (st.isDirectory()) return `\uAC19\uC740 \uC774\uB984\uC758 \uB514\uB809\uD130\uB9AC\uAC00 \uC788\uC2B5\uB2C8\uB2E4(${target})`;
|
|
3721
|
+
const shown = path12.relative(path12.resolve(root), path12.resolve(target)).split(path12.sep).join("/");
|
|
3722
|
+
let realTarget;
|
|
3723
|
+
try {
|
|
3724
|
+
realTarget = realpathSync2(target);
|
|
3725
|
+
} catch {
|
|
3726
|
+
return `\uAE30\uC874 \uD30C\uC77C ${shown} \uC774 \uAE68\uC9C4 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C \uB530\uB77C\uAC08 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694)`;
|
|
3727
|
+
}
|
|
3728
|
+
if (!isSameOrInside(realRoot, realTarget) && !(options.allowOutsideLink && st.isSymbolicLink())) {
|
|
3729
|
+
return `\uAE30\uC874 \uD30C\uC77C\uC758 \uC2E4\uC81C \uC704\uCE58(${realTarget})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
|
|
3730
|
+
}
|
|
3731
|
+
let followed;
|
|
3732
|
+
try {
|
|
3733
|
+
followed = statSync2(realTarget);
|
|
3734
|
+
} catch {
|
|
3735
|
+
return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
|
|
3736
|
+
}
|
|
3737
|
+
if (followed.isDirectory()) {
|
|
3738
|
+
return `\uAC19\uC740 \uC774\uB984\uC758 \uB9C1\uD06C\uAC00 \uB514\uB809\uD130\uB9AC(${realTarget})\uB97C \uAC00\uB9AC\uD0B5\uB2C8\uB2E4(${target})`;
|
|
3739
|
+
}
|
|
3740
|
+
if (!followed.isFile()) {
|
|
3741
|
+
const where = st.isSymbolicLink() ? `\uB9C1\uD06C \uB300\uC0C1(${realTarget})\uC774` : "\uAE30\uC874 \uD30C\uC77C\uC774";
|
|
3742
|
+
return `${where} \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uBE44\uAD50 \xB7 \uB36E\uC5B4\uC4F0\uAE30\uB97C \uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${shown})`;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
return null;
|
|
3746
|
+
}
|
|
3747
|
+
function isSymlink(p) {
|
|
3748
|
+
try {
|
|
3749
|
+
return lstatSync(p).isSymbolicLink();
|
|
3750
|
+
} catch {
|
|
3751
|
+
return false;
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
function outsideLinkTarget(root, target) {
|
|
3755
|
+
if (!isSymlink(target)) return null;
|
|
3756
|
+
try {
|
|
3757
|
+
const realTarget = realpathSync2(target);
|
|
3758
|
+
return isSameOrInside(realpathSync2(root), realTarget) ? null : realTarget;
|
|
3759
|
+
} catch {
|
|
3760
|
+
return null;
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
function hardLinkCount(target) {
|
|
3764
|
+
try {
|
|
3765
|
+
const st = lstatSync(target);
|
|
3766
|
+
return st.isFile() && st.nlink >= 2 ? st.nlink : null;
|
|
3767
|
+
} catch {
|
|
3768
|
+
return null;
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
function hardLinkMessage(shownPath, nlink) {
|
|
3772
|
+
return `\uAE30\uC874 \uD30C\uC77C ${shownPath} \uC774 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC9C4 \uD30C\uC77C\uC774\uB77C(\uB9C1\uD06C \uC218 ${nlink}) \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uBA74 \uC774\uC5B4\uC9C4 \uB2E4\uB978 \uACBD\uB85C\uC758 \uB0B4\uC6A9\uB3C4 \uBC14\uB01D\uB2C8\uB2E4. \uD558\uB4DC\uB9C1\uD06C\uB97C \uB04A\uC740(\uD30C\uC77C\uC744 \uBCF5\uC0AC\uD574 \uBC14\uAFBC) \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694`;
|
|
3773
|
+
}
|
|
3774
|
+
function writtenOutside(root, target) {
|
|
3775
|
+
const realRoot = realpathSync2(root);
|
|
3776
|
+
let realTarget;
|
|
3777
|
+
try {
|
|
3778
|
+
realTarget = realpathSync2(target);
|
|
3779
|
+
} catch {
|
|
3780
|
+
return target;
|
|
3781
|
+
}
|
|
3782
|
+
return isSameOrInside(realRoot, realTarget) ? null : realTarget;
|
|
3783
|
+
}
|
|
3784
|
+
async function writeNoFollow(target, content, mode) {
|
|
3785
|
+
let actual = mode;
|
|
3786
|
+
let fd;
|
|
3787
|
+
if (mode === "overwrite") {
|
|
3788
|
+
try {
|
|
3789
|
+
fd = await fs10.open(target, OVERWRITE_FLAGS);
|
|
3790
|
+
} catch (e) {
|
|
3791
|
+
if (e.code !== "ENOENT") throw e;
|
|
3792
|
+
actual = "new";
|
|
3793
|
+
fd = await fs10.open(target, NEW_FILE_FLAGS, 438);
|
|
3794
|
+
}
|
|
3795
|
+
} else {
|
|
3796
|
+
fd = await fs10.open(target, NEW_FILE_FLAGS, 438);
|
|
3797
|
+
}
|
|
3798
|
+
try {
|
|
3799
|
+
if (actual === "overwrite") {
|
|
3800
|
+
const st = await fs10.fstat(fd);
|
|
3801
|
+
if (!st.isFile()) throw codedError(NOT_REGULAR_ERROR_CODE, `${target} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3802
|
+
if (st.nlink >= 2) throw codedError(HARDLINK_ERROR_CODE, hardLinkMessage(target, st.nlink));
|
|
3803
|
+
await fs10.ftruncate(fd, 0);
|
|
3804
|
+
}
|
|
3805
|
+
await fs10.writeFile(fd, content);
|
|
3806
|
+
} finally {
|
|
3807
|
+
await fs10.close(fd);
|
|
3808
|
+
}
|
|
3809
|
+
return actual;
|
|
3810
|
+
}
|
|
3811
|
+
async function overwriteFollowingLinks(target, content) {
|
|
3812
|
+
const fd = await fs10.open(target, fsConstants.O_WRONLY | fsConstants.O_CREAT, 438);
|
|
3813
|
+
try {
|
|
3814
|
+
const st = await fs10.fstat(fd);
|
|
3815
|
+
if (!st.isFile()) throw codedError(NOT_REGULAR_ERROR_CODE, `${target} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
3816
|
+
if (st.nlink >= 2) throw codedError(HARDLINK_ERROR_CODE, hardLinkMessage(target, st.nlink));
|
|
3817
|
+
await fs10.ftruncate(fd, 0);
|
|
3818
|
+
await fs10.writeFile(fd, content);
|
|
3819
|
+
} finally {
|
|
3820
|
+
await fs10.close(fd);
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
function checkParentInside(root, target) {
|
|
3824
|
+
const realRoot = realpathSync2(root);
|
|
3825
|
+
const realParent = realpathSync2(path12.dirname(target));
|
|
3826
|
+
if (!isSameOrInside(realRoot, realParent)) {
|
|
3827
|
+
return `\uBD80\uBAA8 \uB514\uB809\uD130\uB9AC\uC758 \uC2E4\uC81C \uC704\uCE58(${realParent})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`;
|
|
3828
|
+
}
|
|
3829
|
+
return escapeReason(root, target);
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// src/init/init.ts
|
|
3833
|
+
var CLSX_RANGE = "^2.1.1";
|
|
3834
|
+
var TAILWIND_MERGE_RANGES = {
|
|
3835
|
+
tailwind4: "^3.4.0",
|
|
3836
|
+
tailwind3: "^2.6.0"
|
|
3837
|
+
};
|
|
3838
|
+
function selectUtilsDependencies(tailwind) {
|
|
3839
|
+
return {
|
|
3840
|
+
clsx: CLSX_RANGE,
|
|
3841
|
+
"tailwind-merge": tailwind.major !== void 0 && tailwind.major >= 4 ? TAILWIND_MERGE_RANGES.tailwind4 : TAILWIND_MERGE_RANGES.tailwind3
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
function tailwindWarnings(tailwind, installCommand) {
|
|
3845
|
+
const out = [];
|
|
3846
|
+
if (tailwind.source === "none" && tailwind.value !== void 0) {
|
|
3847
|
+
out.push(
|
|
3848
|
+
`! tailwindcss \uC120\uC5B8(${tailwind.value})\uC740 \uD310\uC815 \uBD88\uAC00 - \uAE30\uBCF8\uAC12 \uC0AC\uC6A9(Tailwind 3, tailwind-merge ${TAILWIND_MERGE_RANGES.tailwind3}). Tailwind 4 \uC774\uC0C1\uC774\uBA74 tailwind-merge \uB97C ${TAILWIND_MERGE_RANGES.tailwind4} \uC73C\uB85C \uBC14\uAFB8\uC138\uC694.`
|
|
3849
|
+
);
|
|
3850
|
+
}
|
|
3851
|
+
if (tailwind.mismatch) {
|
|
3852
|
+
out.push(
|
|
3853
|
+
`! \uC124\uCE58\uBCF8 tailwindcss ${tailwind.value}(major ${tailwind.major})\uC640 package.json \uC120\uC5B8 ${tailwind.mismatch.declared}(major ${tailwind.mismatch.declaredMajor})\uAC00 \uB2E4\uB984 - \uC124\uCE58\uBCF8\uC744 \uB530\uB790\uC2B5\uB2C8\uB2E4. ${installCommand} \uB4A4 tailwind-merge \uBC94\uC704\uB97C \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.`
|
|
3854
|
+
);
|
|
3855
|
+
}
|
|
3856
|
+
return out;
|
|
3857
|
+
}
|
|
3858
|
+
function describeTailwindBasis(tailwind) {
|
|
3859
|
+
if (tailwind.source === "installed") return `\uC124\uCE58\uB41C tailwindcss ${tailwind.value}`;
|
|
3860
|
+
if (tailwind.source === "declared") return `package.json \uC758 tailwindcss ${tailwind.value}`;
|
|
3861
|
+
if (tailwind.value !== void 0) {
|
|
3862
|
+
return `package.json \uC758 tailwindcss ${tailwind.value} \uB85C \uBC84\uC804\uC744 \uD310\uC815\uD558\uC9C0 \uBABB\uD574 \uAE30\uBCF8\uAC12(Tailwind 3)`;
|
|
3863
|
+
}
|
|
3864
|
+
return "tailwindcss \uB97C \uCC3E\uC9C0 \uBABB\uD574 \uAE30\uBCF8\uAC12(Tailwind 3)";
|
|
3865
|
+
}
|
|
3866
|
+
var UTILS_TS_CONTENT = `import { type ClassValue, clsx } from "clsx";
|
|
3867
|
+
import { extendTailwindMerge } from "tailwind-merge";
|
|
3868
|
+
|
|
3869
|
+
/**
|
|
3870
|
+
* \`shadow-[shadow:<CSS \uBCC0\uC218 \uCC38\uC870>]\` \uCC98\uB7FC \`shadow:\` \uD0C0\uC785 \uD78C\uD2B8\uAC00 \uBD99\uC740 \uC784\uC758\uAC12 \uADF8\uB9BC\uC790 \uD074\uB798\uC2A4\uC778\uC9C0 \uD310\uC815
|
|
3871
|
+
*
|
|
3872
|
+
* tailwind-merge \uAE30\uBCF8 \uC124\uC815\uC740 \uC774 \uD074\uB798\uC2A4\uB97C \uADF8\uB9BC\uC790 \uC0C9(shadow-color) \uADF8\uB8F9\uC73C\uB85C \uBD84\uB958\uD574\uC11C
|
|
3873
|
+
* \`cn(\uAE30\uBCF8, "shadow-none")\` \uC774 \uAE30\uBCF8 \uADF8\uB9BC\uC790\uB97C \uC9C0\uC6B0\uC9C0 \uBABB\uD558\uACE0, \`shadow-black/50\` \uC740 \uADF8\uB9BC\uC790\uB97C \uD1B5\uC9F8\uB85C \uC9C0\uC6B4\uB2E4.
|
|
3874
|
+
* \uADF8\uB9BC\uC790(shadow) \uADF8\uB8F9\uC5D0 \uB4F1\uB85D\uD574 \uC885\uC804 \`shadow-sm\` \xB7 \`shadow-lg\` \uC640 \uAC19\uC740 \uBCD1\uD569 \uACB0\uACFC\uB97C \uB0B8\uB2E4(WI-0025 U4).
|
|
3875
|
+
*/
|
|
3876
|
+
const isArbitraryShadowWithHint = (value: string) => /^\\[shadow:.+\\]$/.test(value);
|
|
3877
|
+
|
|
3878
|
+
const twMerge = extendTailwindMerge({
|
|
3879
|
+
extend: {
|
|
3880
|
+
classGroups: {
|
|
3881
|
+
shadow: [{ shadow: [isArbitraryShadowWithHint] }],
|
|
3882
|
+
},
|
|
3883
|
+
},
|
|
3884
|
+
});
|
|
3885
|
+
|
|
3886
|
+
/**
|
|
3887
|
+
* Tailwind CSS \uD074\uB798\uC2A4\uB97C \uBCD1\uD569\uD558\uB294 \uC720\uD2F8\uB9AC\uD2F0 \uD568\uC218
|
|
3888
|
+
* clsx\uB85C \uC870\uAC74\uBD80 \uD074\uB798\uC2A4\uB97C \uCC98\uB9AC\uD558\uACE0 tailwind-merge\uB85C \uCDA9\uB3CC\uC744 \uD574\uACB0
|
|
3889
|
+
*/
|
|
3890
|
+
export function cn(...inputs: ClassValue[]) {
|
|
3891
|
+
return twMerge(clsx(inputs));
|
|
3892
|
+
}
|
|
3893
|
+
`;
|
|
3894
|
+
var INIT_DEFAULTS = {
|
|
3895
|
+
componentsDir: "./src/components/ui",
|
|
3896
|
+
tailwindConfig: "./tailwind.config.ts",
|
|
3897
|
+
globalCss: "./src/app/globals.css"
|
|
3898
|
+
};
|
|
3899
|
+
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
3900
|
+
function isTailwind4(tailwind) {
|
|
3901
|
+
return tailwind.major !== void 0 && tailwind.major >= 4;
|
|
3902
|
+
}
|
|
3903
|
+
var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
|
|
3904
|
+
var TAILWIND4_CONFLICT_LINE = " ! create-next-app \uAE30\uBCF8 globals.css \uC758 :root \xB7 @theme inline \xB7 @media (prefers-color-scheme: dark) \xB7 body \uBE14\uB85D\uC740 AXIS \uC640 \uAC19\uC740 \uC774\uB984(--background \xB7 --foreground \xB7 --color-background \xB7 --font-sans \xB7 --font-mono)\uC744 \uB2E4\uB978 \uAC12\uC73C\uB85C \uC815\uC758\uD569\uB2C8\uB2E4. \uC774 \uBE14\uB85D\uB4E4\uC744 \uC9C0\uC6B0\uC138\uC694.";
|
|
3905
|
+
function readPackageJsonSafe(baseDir) {
|
|
3906
|
+
try {
|
|
3907
|
+
const text = readFileSync4(path13.join(baseDir, "package.json"), "utf8");
|
|
3908
|
+
const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
|
|
3909
|
+
return isPlainObject2(parsed) ? parsed : void 0;
|
|
3910
|
+
} catch {
|
|
3911
|
+
return void 0;
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
3915
|
+
const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0);
|
|
3916
|
+
const lines = [
|
|
3917
|
+
`Tailwind 4: \uC804\uC5ED CSS(${globalCss}) \uB9E8 \uC704\uC5D0 \uB2E4\uC74C \uC904\uC744 \uB123\uC73C\uC138\uC694(\uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4).`,
|
|
3918
|
+
' @import "tailwindcss";',
|
|
3919
|
+
` ${TOKENS_TAILWIND4_IMPORT_LINE}`,
|
|
3920
|
+
...used.map((name) => ` ${componentTailwindImportLine(name)}`)
|
|
3921
|
+
];
|
|
3922
|
+
if (used.length === 0) {
|
|
3923
|
+
lines.push(
|
|
3924
|
+
` npm \uD328\uD0A4\uC9C0 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC4F0\uBA74 \uADF8 \uD328\uD0A4\uC9C0\uC758 tailwind.css \uB3C4 \uB123\uC73C\uC138\uC694(\uC608: @import "${TAILWIND4_COMPONENT_PACKAGES[0]}/tailwind.css";).`
|
|
3925
|
+
);
|
|
3926
|
+
}
|
|
3927
|
+
lines.push(TAILWIND4_CONFLICT_LINE);
|
|
3928
|
+
if (pkg === void 0 || hasDependency2(pkg, TOKENS_PACKAGE) === void 0) {
|
|
3929
|
+
const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
|
|
3930
|
+
lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
|
|
3931
|
+
}
|
|
3932
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
3933
|
+
const unknown = versions.filter((v) => v.status === "unknown");
|
|
3934
|
+
const declaredOf = (list) => list.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
3935
|
+
const upgradeOf = (list) => addCommandFor(installCommand, Object.fromEntries(list.map((b) => [b.name, `^${TAILWIND4_MIN_AXIS_VERSION}`])));
|
|
3936
|
+
const belowDeclared = versions.filter((v) => v.status === "below" && v.source === "declared");
|
|
3937
|
+
const readableRange = (v) => rangeLowerAtLeast(v.range, TAILWIND4_MIN_AXIS_VERSION) !== void 0;
|
|
3938
|
+
const installedBelow = versions.filter((v) => v.status === "below" && v.source === "installed");
|
|
3939
|
+
const belowInstalled = installedBelow.filter(readableRange);
|
|
3940
|
+
const belowInstalledOpaque = installedBelow.filter((v) => !readableRange(v));
|
|
3941
|
+
const installedOf = (list) => list.map((v) => `${v.name} ${v.installed}, \uC120\uC5B8 ${v.range}`).join(" \xB7 ");
|
|
3942
|
+
if (belowDeclared.length > 0) {
|
|
3943
|
+
lines.push(
|
|
3944
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(belowDeclared)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowDeclared)}`
|
|
3945
|
+
);
|
|
3946
|
+
}
|
|
3947
|
+
if (belowInstalled.length > 0) {
|
|
3948
|
+
lines.push(
|
|
3949
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalled)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowInstalled)}`
|
|
3950
|
+
);
|
|
3951
|
+
}
|
|
3952
|
+
if (belowInstalledOpaque.length > 0) {
|
|
3953
|
+
lines.push(
|
|
3954
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalledOpaque)})\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uBBF8\uB9CC\uC785\uB2C8\uB2E4. \uC120\uC5B8\uC774 \uAC00\uB9AC\uD0A4\uB294 \uBC84\uC804\uC744 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 \uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694(\uC120\uC5B8\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4).`
|
|
3955
|
+
);
|
|
3956
|
+
}
|
|
3957
|
+
if (unknown.length > 0) {
|
|
3958
|
+
lines.push(
|
|
3959
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(unknown)})\uC73C\uB85C\uB294 \uBC84\uC804\uC744 \uD310\uC815\uD560 \uC218 \uC5C6\uC73C\uB2C8 \uC124\uCE58\uB41C \uBC84\uC804\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
|
|
3960
|
+
);
|
|
3961
|
+
}
|
|
3962
|
+
return lines;
|
|
3963
|
+
}
|
|
3964
|
+
var BOM = "\uFEFF";
|
|
3965
|
+
function addCommandFor(installCommand, deps) {
|
|
3966
|
+
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
3967
|
+
if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
|
|
3968
|
+
if (installCommand.startsWith("npm")) return `npm install ${specs}`;
|
|
3969
|
+
return `pnpm add ${specs}`;
|
|
3970
|
+
}
|
|
3971
|
+
function planUtilsDependencies(baseDirInput) {
|
|
3972
|
+
const baseDir = path13.resolve(baseDirInput);
|
|
3973
|
+
const installCommand = detectInstallCommand(baseDir);
|
|
3974
|
+
const tailwind0 = detectTailwind(baseDir);
|
|
3975
|
+
const ranges0 = selectUtilsDependencies(tailwind0);
|
|
3976
|
+
const plan = {
|
|
3977
|
+
action: "no-package-json",
|
|
3978
|
+
added: [],
|
|
3979
|
+
present: [],
|
|
3980
|
+
ranges: ranges0,
|
|
3981
|
+
tailwind: tailwind0,
|
|
3982
|
+
installCommand,
|
|
3983
|
+
addCommand: addCommandFor(installCommand, ranges0)
|
|
3984
|
+
};
|
|
3985
|
+
const pkgFile = path13.join(baseDir, "package.json");
|
|
3986
|
+
if (!existsSync5(pkgFile)) return plan;
|
|
3987
|
+
const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
|
|
3988
|
+
let where;
|
|
3989
|
+
try {
|
|
3990
|
+
where = realPathInside(baseDir, pkgFile);
|
|
3991
|
+
} catch (err) {
|
|
3992
|
+
return unwritable(err.message);
|
|
3993
|
+
}
|
|
3994
|
+
if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
|
|
3995
|
+
let text;
|
|
3996
|
+
try {
|
|
3997
|
+
text = readFileSync4(pkgFile, "utf8");
|
|
3998
|
+
} catch (err) {
|
|
3999
|
+
return unwritable(err.message);
|
|
4000
|
+
}
|
|
4001
|
+
const bom = text.startsWith(BOM) ? BOM : "";
|
|
4002
|
+
const body = bom ? text.slice(1) : text;
|
|
4003
|
+
let pkg;
|
|
4004
|
+
try {
|
|
4005
|
+
const parsed = JSON.parse(body);
|
|
4006
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
4007
|
+
pkg = parsed;
|
|
4008
|
+
} catch (err) {
|
|
4009
|
+
return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
|
|
4010
|
+
}
|
|
4011
|
+
plan.tailwind = detectTailwind(baseDir, pkg);
|
|
4012
|
+
plan.ranges = selectUtilsDependencies(plan.tailwind);
|
|
4013
|
+
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
4014
|
+
const missing = {};
|
|
4015
|
+
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
4016
|
+
const declared = hasDependency2(pkg, name);
|
|
4017
|
+
if (declared !== void 0) plan.present.push({ name, range: declared });
|
|
4018
|
+
else missing[name] = range;
|
|
4019
|
+
}
|
|
4020
|
+
plan.added = Object.keys(missing);
|
|
4021
|
+
plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
|
|
3250
4022
|
if (plan.added.length === 0) return { ...plan, action: "present" };
|
|
3251
4023
|
if (pkg.dependencies !== void 0 && !isPlainObject2(pkg.dependencies)) {
|
|
3252
4024
|
return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
@@ -3264,8 +4036,8 @@ var defaultWriteFile = (file, data) => writeFileSync2(file, data);
|
|
|
3264
4036
|
function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile) {
|
|
3265
4037
|
const w = plan.write;
|
|
3266
4038
|
if (plan.action !== "add" || !w) return false;
|
|
3267
|
-
const baseDir =
|
|
3268
|
-
const current =
|
|
4039
|
+
const baseDir = path13.resolve(baseDirInput);
|
|
4040
|
+
const current = existsSync5(w.file) ? readFileSync4(w.file, "utf8") : null;
|
|
3269
4041
|
if (current !== w.before) {
|
|
3270
4042
|
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
3271
4043
|
}
|
|
@@ -3316,42 +4088,232 @@ function reportDependencies(plan, log) {
|
|
|
3316
4088
|
if (plan.addCommand.includes('"tailwind-merge@')) logBasis();
|
|
3317
4089
|
}
|
|
3318
4090
|
}
|
|
4091
|
+
async function existingConfig(baseDir) {
|
|
4092
|
+
try {
|
|
4093
|
+
return await readAxisConfig(baseDir);
|
|
4094
|
+
} catch {
|
|
4095
|
+
return null;
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
function configStateNote(state) {
|
|
4099
|
+
if (state === "created") return "axis.config.json \uC740 \uC774\uBBF8 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
4100
|
+
if (state === "updated") return "axis.config.json \uC740 \uC774\uBBF8 \uAC31\uC2E0\uD588\uC2B5\uB2C8\uB2E4.";
|
|
4101
|
+
return "axis.config.json \uC740 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9).";
|
|
4102
|
+
}
|
|
4103
|
+
function nonEmptyString(value) {
|
|
4104
|
+
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
4105
|
+
}
|
|
4106
|
+
function errCode(e) {
|
|
4107
|
+
return e.code ?? e.message;
|
|
4108
|
+
}
|
|
4109
|
+
function planUtilsWrite(baseDirInput, utilsPath) {
|
|
4110
|
+
const baseDir = path13.resolve(baseDirInput);
|
|
4111
|
+
const shown = path13.relative(baseDir, utilsPath).split(path13.sep).join("/") || utilsPath;
|
|
4112
|
+
let st;
|
|
4113
|
+
try {
|
|
4114
|
+
st = lstatSync2(utilsPath);
|
|
4115
|
+
} catch (e) {
|
|
4116
|
+
if (e.code === "ENOENT") return { action: "create" };
|
|
4117
|
+
return { action: "reject", reason: `${shown} \uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4118
|
+
}
|
|
4119
|
+
if (st.isSymbolicLink()) {
|
|
4120
|
+
let real;
|
|
4121
|
+
try {
|
|
4122
|
+
real = realpathSync3(utilsPath);
|
|
4123
|
+
} catch {
|
|
4124
|
+
return { action: "reject", reason: `${shown} \uC774 \uAE68\uC9C4 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694` };
|
|
4125
|
+
}
|
|
4126
|
+
let outside = null;
|
|
4127
|
+
try {
|
|
4128
|
+
outside = isSameOrInside(realpathSync3(baseDir), real) ? null : real;
|
|
4129
|
+
} catch {
|
|
4130
|
+
outside = null;
|
|
4131
|
+
}
|
|
4132
|
+
let target;
|
|
4133
|
+
try {
|
|
4134
|
+
target = statSync3(real);
|
|
4135
|
+
} catch (e) {
|
|
4136
|
+
return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4137
|
+
}
|
|
4138
|
+
if (target.isDirectory()) return { action: "reject", reason: `${shown} \uB9C1\uD06C\uAC00 \uB514\uB809\uD130\uB9AC(${real})\uB97C \uAC00\uB9AC\uD0B5\uB2C8\uB2E4` };
|
|
4139
|
+
if (!target.isFile()) return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4` };
|
|
4140
|
+
let content2;
|
|
4141
|
+
try {
|
|
4142
|
+
content2 = readFileSync4(utilsPath, "utf8");
|
|
4143
|
+
} catch (e) {
|
|
4144
|
+
return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4145
|
+
}
|
|
4146
|
+
if (content2 === UTILS_TS_CONTENT) return { action: "keep", link: { outside } };
|
|
4147
|
+
const what = outside !== null ? `\uD504\uB85C\uC81D\uD2B8 \uBC16(${outside})\uC744 \uAC00\uB9AC\uD0A4\uB294 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C` : "\uD504\uB85C\uC81D\uD2B8 \uC548\uC744 \uAC00\uB9AC\uD0A4\uB294 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C";
|
|
4148
|
+
return {
|
|
4149
|
+
action: "reject",
|
|
4150
|
+
reason: `\uAE30\uC874 ${shown} \uC774 ${what} \uB36E\uC5B4\uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uB0B4\uC6A9\uC774 init \uC758 utils \uC640 \uB2E4\uB984). \uB9C1\uD06C\uB294 \uB530\uB77C\uAC00 \uC4F0\uC9C0 \uC54A\uC73C\uB2C8 \uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uC2E4\uC81C \uD30C\uC77C\uB85C \uBC14\uAFBC \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694`
|
|
4151
|
+
};
|
|
4152
|
+
}
|
|
4153
|
+
if (st.isDirectory()) return { action: "reject", reason: `${shown} \uC774\uB984\uC758 \uB514\uB809\uD130\uB9AC\uAC00 \uC788\uC5B4 \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
|
|
4154
|
+
if (!st.isFile()) return { action: "reject", reason: `${shown} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
|
|
4155
|
+
let content;
|
|
4156
|
+
try {
|
|
4157
|
+
content = readFileSync4(utilsPath, "utf8");
|
|
4158
|
+
} catch (e) {
|
|
4159
|
+
return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4160
|
+
}
|
|
4161
|
+
if (content === UTILS_TS_CONTENT) return { action: "keep" };
|
|
4162
|
+
const nlink = hardLinkCount(utilsPath);
|
|
4163
|
+
if (nlink !== null) return { action: "reject", reason: hardLinkMessage(shown, nlink) };
|
|
4164
|
+
try {
|
|
4165
|
+
accessSync2(utilsPath, constants2.W_OK);
|
|
4166
|
+
} catch (e) {
|
|
4167
|
+
return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC5D0 \uC4F8 \uAD8C\uD55C\uC774 \uC5C6\uC5B4 \uB36E\uC5B4\uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4168
|
+
}
|
|
4169
|
+
return { action: "overwrite" };
|
|
4170
|
+
}
|
|
3319
4171
|
async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
3320
|
-
const baseDir =
|
|
4172
|
+
const baseDir = path13.resolve(baseDirInput);
|
|
4173
|
+
const current = await existingConfig(baseDir);
|
|
4174
|
+
const existingRegistry = nonEmptyString(current?.registry);
|
|
4175
|
+
const migratedRegistry = existingRegistry !== void 0 && isLegacyDefaultRegistryUrl(existingRegistry);
|
|
4176
|
+
const registry = existingRegistry !== void 0 && !migratedRegistry ? existingRegistry : registryUrl;
|
|
4177
|
+
const existingAgenticDir = nonEmptyString(current?.agenticDir);
|
|
4178
|
+
const plan = planUtilsDependencies(baseDir);
|
|
4179
|
+
const tailwind4 = isTailwind4(plan.tailwind);
|
|
3321
4180
|
const axisConfig = createInitConfig(
|
|
3322
4181
|
{
|
|
3323
4182
|
componentsDir: answers.componentsDir,
|
|
3324
|
-
|
|
4183
|
+
agenticDir: existingAgenticDir,
|
|
4184
|
+
tailwindConfig: tailwind4 ? void 0 : answers.tailwindConfig,
|
|
3325
4185
|
globalCss: answers.globalCss
|
|
3326
4186
|
},
|
|
3327
|
-
|
|
4187
|
+
registry
|
|
3328
4188
|
);
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
4189
|
+
const configPath = path13.join(baseDir, "axis.config.json");
|
|
4190
|
+
const nextText = `${JSON.stringify(axisConfig, null, 2)}
|
|
4191
|
+
`;
|
|
4192
|
+
const rejects = [];
|
|
4193
|
+
let previousText = null;
|
|
4194
|
+
try {
|
|
4195
|
+
previousText = await fs11.readFile(configPath, "utf8");
|
|
4196
|
+
} catch (e) {
|
|
4197
|
+
if (e.code !== "ENOENT") {
|
|
4198
|
+
rejects.push(`\uAE30\uC874 axis.config.json \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})`);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
if (previousText !== null && previousText !== nextText) {
|
|
4202
|
+
try {
|
|
4203
|
+
const st = statSync3(configPath);
|
|
4204
|
+
if (st.isFile() && st.nlink >= 2) rejects.push(hardLinkMessage("axis.config.json", st.nlink));
|
|
4205
|
+
} catch {
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
const utilsPath = path13.resolve(baseDir, answers.componentsDir, "utils.ts");
|
|
4209
|
+
const utilsPlan = planUtilsWrite(baseDir, utilsPath);
|
|
4210
|
+
if (utilsPlan.action === "reject") rejects.push(utilsPlan.reason);
|
|
4211
|
+
if (rejects.length > 0) {
|
|
4212
|
+
log(chalk9.red("\u2717 \uC4F8 \uC218 \uC5C6\uB294 \uD30C\uC77C\uC774 \uC788\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(axis.config.json \xB7 utils.ts \xB7 package.json \uADF8\uB300\uB85C)."));
|
|
4213
|
+
for (const r of rejects) log(chalk9.red(` - ${r}`));
|
|
4214
|
+
process.exitCode = 1;
|
|
4215
|
+
return;
|
|
4216
|
+
}
|
|
4217
|
+
let configState;
|
|
4218
|
+
if (previousText === null) {
|
|
4219
|
+
try {
|
|
4220
|
+
await fs11.writeFile(configPath, nextText, { flag: "wx" });
|
|
4221
|
+
} catch (err) {
|
|
4222
|
+
const reason = err.code === "EEXIST" ? "\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uAC19\uC740 \uC774\uB984\uC758 \uD30C\uC77C\uC774 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569)" : err.message;
|
|
4223
|
+
log(chalk9.red(`\u2717 axis.config.json \uC744 \uB9CC\uB4E4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${reason}. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
|
|
4224
|
+
process.exitCode = 1;
|
|
4225
|
+
return;
|
|
4226
|
+
}
|
|
4227
|
+
configState = "created";
|
|
4228
|
+
log(chalk9.green("\u2713 axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
|
|
4229
|
+
} else if (previousText === nextText) {
|
|
4230
|
+
configState = "kept";
|
|
4231
|
+
log(chalk9.green("\u2713 axis.config.json \uC720\uC9C0(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9)"));
|
|
4232
|
+
} else {
|
|
4233
|
+
try {
|
|
4234
|
+
await overwriteFollowingLinks(configPath, nextText);
|
|
4235
|
+
} catch (err) {
|
|
4236
|
+
const reason = err.code === HARDLINK_ERROR_CODE ? `\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC84C\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569, D19)` : err.message;
|
|
4237
|
+
log(chalk9.red(`\u2717 axis.config.json \uC744 \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${reason}. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
|
|
4238
|
+
process.exitCode = 1;
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
configState = "updated";
|
|
4242
|
+
const registryNote = migratedRegistry ? "registry \uB97C \uC0C8 \uAE30\uBCF8 \uC8FC\uC18C\uB85C \uAC31\uC2E0" : existingRegistry !== void 0 ? "registry \uB294 \uAE30\uC874 \uAC12 \uC720\uC9C0" : "registry \uB294 \uAE30\uBCF8\uAC12";
|
|
4243
|
+
const agenticNote = existingAgenticDir !== void 0 ? ", agenticDir \uB294 \uAE30\uC874 \uAC12 \uC720\uC9C0" : "";
|
|
4244
|
+
log(chalk9.green(`\u2713 axis.config.json \uAC31\uC2E0(\uAE30\uC874 \uD30C\uC77C\uC744 init \uAC12\uC73C\uB85C \uB2E4\uC2DC \uC500, ${registryNote}${agenticNote})`));
|
|
4245
|
+
if (migratedRegistry && existingRegistry !== void 0) {
|
|
4246
|
+
log(
|
|
4247
|
+
chalk9.yellow(
|
|
4248
|
+
` registry \uB97C \uC0C8 \uAE30\uBCF8 \uC8FC\uC18C(${redactRegistryUrl(registry)})\uB85C \uAC31\uC2E0\uD588\uC2B5\uB2C8\uB2E4(\uC885\uC804 axis.minu.best: ${redactRegistryUrl(existingRegistry)}).`
|
|
4249
|
+
)
|
|
4250
|
+
);
|
|
4251
|
+
}
|
|
4252
|
+
const dropped = current ? Object.keys(current).filter((k) => !(k in axisConfig) && current[k] !== void 0) : [];
|
|
4253
|
+
if (dropped.length > 0) {
|
|
4254
|
+
log(chalk9.yellow(` \uAE30\uC874 \uC124\uC815\uC5D0\uC11C \uBE60\uC9C4 \uD0A4: ${dropped.join(", ")} (\uD544\uC694\uD558\uBA74 axis.config.json \uC5D0 \uB2E4\uC2DC \uC801\uC5B4 \uC8FC\uC138\uC694)`));
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
let utilsStateNote = "utils.ts \uB294 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9).";
|
|
4258
|
+
if (utilsPlan.action === "keep") {
|
|
4259
|
+
if (utilsPlan.link === void 0) log(chalk9.green("\u2713 utils.ts \uC720\uC9C0(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9)"));
|
|
4260
|
+
else if (utilsPlan.link.outside === null) log(chalk9.green("\u2713 utils.ts \uC720\uC9C0(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9, \uB9C1\uD06C)"));
|
|
4261
|
+
else log(chalk9.green(`\u2713 utils.ts \uC720\uC9C0(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9, \uB9C1\uD06C \uB300\uC0C1\uC774 \uD504\uB85C\uC81D\uD2B8 \uBC16: ${utilsPlan.link.outside})`));
|
|
4262
|
+
} else {
|
|
4263
|
+
let actual;
|
|
4264
|
+
try {
|
|
4265
|
+
await fs11.ensureDir(path13.dirname(utilsPath));
|
|
4266
|
+
actual = await writeNoFollow(utilsPath, UTILS_TS_CONTENT, utilsPlan.action === "create" ? "new" : "overwrite");
|
|
4267
|
+
} catch (err) {
|
|
4268
|
+
const code = err.code;
|
|
4269
|
+
const reason = code === HARDLINK_ERROR_CODE ? "\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC84C\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569, D19)" : code === "ELOOP" || code === "EEXIST" ? "\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uAC19\uC740 \uC774\uB984\uC758 \uD30C\uC77C \xB7 \uB9C1\uD06C\uAC00 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569)" : err.message;
|
|
4270
|
+
log(
|
|
4271
|
+
chalk9.red(
|
|
4272
|
+
utilsPlan.action === "create" ? `\u2717 utils.ts \uB97C \uB9CC\uB4E4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${reason}.` : `\u2717 utils.ts \uB97C \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${reason}. \uADF8 \uD30C\uC77C\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
|
|
4273
|
+
)
|
|
4274
|
+
);
|
|
4275
|
+
log(chalk9.yellow(` ${configStateNote(configState)}`));
|
|
4276
|
+
process.exitCode = 1;
|
|
4277
|
+
return;
|
|
4278
|
+
}
|
|
4279
|
+
log(
|
|
4280
|
+
chalk9.green(
|
|
4281
|
+
actual === "new" ? "\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC" : "\u2713 utils.ts \uB36E\uC5B4\uC500(\uAE30\uC874 \uB0B4\uC6A9\uACFC \uB2EC\uB77C init \uC758 utils \uB85C \uB2E4\uC2DC \uC500)"
|
|
4282
|
+
)
|
|
4283
|
+
);
|
|
4284
|
+
utilsStateNote = actual === "new" ? "utils.ts \uB294 \uC774\uBBF8 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4." : "utils.ts \uB294 \uC774\uBBF8 \uB36E\uC5B4\uC37C\uC2B5\uB2C8\uB2E4.";
|
|
4285
|
+
}
|
|
3336
4286
|
try {
|
|
3337
4287
|
applyUtilsDependencies(baseDir, plan);
|
|
3338
4288
|
} catch (err) {
|
|
3339
4289
|
log(chalk9.red(`\u2717 package.json \uC744 \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${err.message}`));
|
|
3340
|
-
log(chalk9.yellow(
|
|
4290
|
+
log(chalk9.yellow(` ${configStateNote(configState)} ${utilsStateNote}`));
|
|
3341
4291
|
log(chalk9.yellow(` utils.ts \uC758\uC874\uC131 \uC124\uCE58: ${chalk9.cyan(plan.addCommand)}`));
|
|
3342
4292
|
process.exitCode = 1;
|
|
3343
4293
|
return;
|
|
3344
4294
|
}
|
|
3345
4295
|
reportDependencies(plan, log);
|
|
4296
|
+
if (tailwind4) {
|
|
4297
|
+
const [head, ...rest] = tailwind4GuideLines(
|
|
4298
|
+
readPackageJsonSafe(baseDir),
|
|
4299
|
+
plan.installCommand,
|
|
4300
|
+
answers.globalCss,
|
|
4301
|
+
baseDir
|
|
4302
|
+
);
|
|
4303
|
+
log(chalk9.blue(`
|
|
4304
|
+
${head}`));
|
|
4305
|
+
for (const line of rest) log(line.startsWith(" !") ? chalk9.yellow(line) : chalk9.cyan(line));
|
|
4306
|
+
}
|
|
3346
4307
|
log(chalk9.blue("\n\uCD08\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C \uB2E4\uC74C \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD558\uC138\uC694:"));
|
|
3347
4308
|
log(chalk9.cyan(` ${INIT_NEXT_STEP_COMMAND}
|
|
3348
4309
|
`));
|
|
3349
4310
|
}
|
|
3350
4311
|
|
|
3351
4312
|
// src/init/index.ts
|
|
3352
|
-
function registerInitCommand(program2, registryUrl) {
|
|
4313
|
+
function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL) {
|
|
3353
4314
|
program2.command("init").description("\uD504\uB85C\uC81D\uD2B8\uC5D0 AXIS Design System \uCD08\uAE30\uD654").option("-y, --yes", "\uAE30\uBCF8\uAC12\uC73C\uB85C \uC790\uB3D9 \uC124\uC815").action(async (options) => {
|
|
3354
4315
|
console.log(chalk10.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
|
|
4316
|
+
const tailwind4 = isTailwind4(planUtilsDependencies(process.cwd()).tailwind);
|
|
3355
4317
|
const config = options.yes ? { ...INIT_DEFAULTS } : await prompts2([
|
|
3356
4318
|
{
|
|
3357
4319
|
type: "text",
|
|
@@ -3360,7 +4322,7 @@ function registerInitCommand(program2, registryUrl) {
|
|
|
3360
4322
|
initial: INIT_DEFAULTS.componentsDir
|
|
3361
4323
|
},
|
|
3362
4324
|
{
|
|
3363
|
-
type: "text",
|
|
4325
|
+
type: tailwind4 ? null : "text",
|
|
3364
4326
|
name: "tailwindConfig",
|
|
3365
4327
|
message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
|
|
3366
4328
|
initial: INIT_DEFAULTS.tailwindConfig
|
|
@@ -3376,108 +4338,803 @@ function registerInitCommand(program2, registryUrl) {
|
|
|
3376
4338
|
});
|
|
3377
4339
|
}
|
|
3378
4340
|
|
|
3379
|
-
// src/index.ts
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
4341
|
+
// src/add/index.ts
|
|
4342
|
+
import chalk11 from "chalk";
|
|
4343
|
+
import prompts3 from "prompts";
|
|
4344
|
+
|
|
4345
|
+
// src/add/add.ts
|
|
4346
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
4347
|
+
import path15 from "path";
|
|
4348
|
+
import fs12 from "fs-extra";
|
|
4349
|
+
|
|
4350
|
+
// src/registry/bundled.ts
|
|
4351
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
4352
|
+
import path14 from "path";
|
|
4353
|
+
import { fileURLToPath } from "url";
|
|
4354
|
+
function findBundledRegistryDir(moduleUrl = import.meta.url) {
|
|
4355
|
+
const here = path14.dirname(fileURLToPath(moduleUrl));
|
|
4356
|
+
for (const dir of [path14.join(here, "registry"), path14.join(here, "..", "registry")]) {
|
|
4357
|
+
if (existsSync6(path14.join(dir, "index.json"))) return dir;
|
|
4358
|
+
}
|
|
4359
|
+
return null;
|
|
4360
|
+
}
|
|
4361
|
+
function readBundledJson(dir, fileName) {
|
|
4362
|
+
const file = path14.join(dir, fileName);
|
|
4363
|
+
let text;
|
|
3387
4364
|
try {
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
4365
|
+
text = readFileSync5(file, "utf8");
|
|
4366
|
+
} catch {
|
|
4367
|
+
throw new Error(`\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 ${fileName} \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${dir})`);
|
|
4368
|
+
}
|
|
4369
|
+
return parseJsonText(text, `\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC ${fileName}`);
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
// src/registry/index.ts
|
|
4373
|
+
var RegistryError = class extends Error {
|
|
4374
|
+
constructor(code, message) {
|
|
4375
|
+
super(message);
|
|
4376
|
+
this.code = code;
|
|
4377
|
+
this.name = "RegistryError";
|
|
4378
|
+
}
|
|
4379
|
+
};
|
|
4380
|
+
function bundledFallbackMessage(version, reason, kind = "access") {
|
|
4381
|
+
const lead = kind === "invalid" ? "\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC751\uB2F5\uC774 \uD615\uC2DD \uAC80\uC99D\uC744 \uD1B5\uACFC\uD558\uC9C0 \uBABB\uD574" : "\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC811\uADFC\uD558\uC9C0 \uBABB\uD574";
|
|
4382
|
+
return `${lead} CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC(version ${version})\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4. (\uC6D0\uC778: ${reason})`;
|
|
4383
|
+
}
|
|
4384
|
+
function fallbackKindOf(error) {
|
|
4385
|
+
return error instanceof RegistryAccessError ? "access" : "invalid";
|
|
4386
|
+
}
|
|
4387
|
+
function versionMismatchMessage(remoteVersion, bundledVersion) {
|
|
4388
|
+
return `\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC(version ${remoteVersion})\uC640 CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC(version ${bundledVersion})\uC758 version \uC774 \uB2E4\uB985\uB2C8\uB2E4. \uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uC6B0\uC120 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.`;
|
|
4389
|
+
}
|
|
4390
|
+
function messageOf(error) {
|
|
4391
|
+
return error instanceof Error ? error.message : String(error);
|
|
4392
|
+
}
|
|
4393
|
+
var RegistryClient = class {
|
|
4394
|
+
baseUrl;
|
|
4395
|
+
baseUrlError;
|
|
4396
|
+
bundledDir;
|
|
4397
|
+
timeoutMs;
|
|
4398
|
+
fetchImpl;
|
|
4399
|
+
notify;
|
|
4400
|
+
mode = null;
|
|
4401
|
+
indexPromise = null;
|
|
4402
|
+
bundledIndex = null;
|
|
4403
|
+
fallbackAnnounced = false;
|
|
4404
|
+
constructor(options) {
|
|
4405
|
+
let baseUrl = null;
|
|
4406
|
+
let baseUrlError = null;
|
|
4407
|
+
if (options.url !== null) {
|
|
4408
|
+
try {
|
|
4409
|
+
baseUrl = normalizeRegistryBaseUrl(options.url);
|
|
4410
|
+
} catch (error) {
|
|
4411
|
+
baseUrlError = messageOf(error);
|
|
4412
|
+
}
|
|
4413
|
+
} else {
|
|
4414
|
+
baseUrlError = "\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4";
|
|
4415
|
+
}
|
|
4416
|
+
this.baseUrl = baseUrl;
|
|
4417
|
+
this.baseUrlError = baseUrlError;
|
|
4418
|
+
this.bundledDir = options.bundledDir === void 0 ? findBundledRegistryDir() : options.bundledDir;
|
|
4419
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_REGISTRY_TIMEOUT_MS;
|
|
4420
|
+
this.fetchImpl = options.fetchImpl;
|
|
4421
|
+
this.notify = options.notify ?? ((message) => console.warn(message));
|
|
4422
|
+
}
|
|
4423
|
+
/** 지금 쓰는 출처. index 를 읽기 전에는 null 입니다 */
|
|
4424
|
+
get origin() {
|
|
4425
|
+
return this.mode;
|
|
4426
|
+
}
|
|
4427
|
+
/** 레지스트리 목록(index.json) */
|
|
4428
|
+
getIndex() {
|
|
4429
|
+
if (!this.indexPromise) this.indexPromise = this.loadIndex();
|
|
4430
|
+
return this.indexPromise;
|
|
4431
|
+
}
|
|
4432
|
+
/** 항목 하나. 이름 검사 → index 확인 → 항목 조회 순서입니다 */
|
|
4433
|
+
async getItem(name) {
|
|
4434
|
+
if (!isValidRegistryName(name)) {
|
|
4435
|
+
throw new RegistryError(
|
|
4436
|
+
"invalid-name",
|
|
4437
|
+
`'${name}' \uB294 \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uD56D\uBAA9 \uC774\uB984 \uADDC\uCE59(\uC18C\uBB38\uC790 \xB7 \uC22B\uC790 \xB7 \uD558\uC774\uD508)\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`
|
|
3392
4438
|
);
|
|
3393
|
-
process.exit(1);
|
|
3394
4439
|
}
|
|
3395
|
-
const
|
|
3396
|
-
const
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
4440
|
+
const index = await this.getIndex();
|
|
4441
|
+
const entry = index.items.find((it) => it.name === name);
|
|
4442
|
+
if (!entry) {
|
|
4443
|
+
throw new RegistryError("not-found", `'${name}' \uD56D\uBAA9\uC774 \uB808\uC9C0\uC2A4\uD2B8\uB9AC(version ${index.version})\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
4444
|
+
}
|
|
4445
|
+
if (this.mode === "remote" && this.baseUrl) {
|
|
4446
|
+
try {
|
|
4447
|
+
const data = await fetchRegistryJson(`${this.baseUrl}/${name}.json`, this.fetchOptions());
|
|
4448
|
+
const item = validateRegistryItem(data, name, `${name}.json`, this.remoteDependencyBases());
|
|
4449
|
+
checkItemSha256(item, entry);
|
|
4450
|
+
return item;
|
|
4451
|
+
} catch (error) {
|
|
4452
|
+
await this.switchToBundled(messageOf(error), fallbackKindOf(error));
|
|
4453
|
+
return this.readBundledItem(name);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
return this.readBundledItem(name);
|
|
4457
|
+
}
|
|
4458
|
+
/** 원격 응답의 의존 URL 로 받아 주는 base: 지금 조회 중인 원격 base 와 공개 기본 base(D11) */
|
|
4459
|
+
remoteDependencyBases() {
|
|
4460
|
+
const bases = [REGISTRY_PUBLIC_BASE_URL];
|
|
4461
|
+
if (this.baseUrl && this.baseUrl !== REGISTRY_PUBLIC_BASE_URL) bases.unshift(this.baseUrl);
|
|
4462
|
+
return bases;
|
|
4463
|
+
}
|
|
4464
|
+
fetchOptions() {
|
|
4465
|
+
return { timeoutMs: this.timeoutMs, ...this.fetchImpl ? { fetchImpl: this.fetchImpl } : {} };
|
|
4466
|
+
}
|
|
4467
|
+
async loadIndex() {
|
|
4468
|
+
let remoteError;
|
|
4469
|
+
let kind = "access";
|
|
4470
|
+
if (this.baseUrl) {
|
|
4471
|
+
try {
|
|
4472
|
+
const data = await fetchRegistryJson(`${this.baseUrl}/index.json`, this.fetchOptions());
|
|
4473
|
+
const index = validateRegistryIndex(data, `${this.baseUrl}/index.json`);
|
|
4474
|
+
this.mode = "remote";
|
|
4475
|
+
this.warnVersionMismatch(index.version);
|
|
4476
|
+
return index;
|
|
4477
|
+
} catch (error) {
|
|
4478
|
+
remoteError = messageOf(error);
|
|
4479
|
+
kind = fallbackKindOf(error);
|
|
4480
|
+
}
|
|
4481
|
+
} else {
|
|
4482
|
+
remoteError = this.baseUrlError ?? "\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC URL \uC774 \uC5C6\uC2B5\uB2C8\uB2E4";
|
|
4483
|
+
}
|
|
4484
|
+
return this.switchToBundled(remoteError, kind);
|
|
4485
|
+
}
|
|
4486
|
+
/** 동봉본 index 를 읽습니다(성공하면 한 번만). 실패하면 이유를 돌려줍니다 */
|
|
4487
|
+
loadBundledIndex() {
|
|
4488
|
+
if (this.bundledIndex) return { index: this.bundledIndex };
|
|
4489
|
+
if (!this.bundledDir) return { error: "CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4" };
|
|
4490
|
+
try {
|
|
4491
|
+
this.bundledIndex = validateRegistryIndex(readBundledJson(this.bundledDir, "index.json"), "\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC index.json");
|
|
4492
|
+
return { index: this.bundledIndex };
|
|
4493
|
+
} catch (error) {
|
|
4494
|
+
return { error: messageOf(error) };
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
warnVersionMismatch(remoteVersion) {
|
|
4498
|
+
const bundled = this.loadBundledIndex();
|
|
4499
|
+
if ("index" in bundled && bundled.index.version !== remoteVersion) {
|
|
4500
|
+
this.notify(versionMismatchMessage(remoteVersion, bundled.index.version));
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
async switchToBundled(reason, kind = "access") {
|
|
4504
|
+
const bundled = this.loadBundledIndex();
|
|
4505
|
+
if ("error" in bundled) {
|
|
4506
|
+
throw new RegistryError(
|
|
4507
|
+
"unavailable",
|
|
4508
|
+
`\uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC6D0\uACA9: ${reason} / \uB3D9\uBD09\uBCF8: ${bundled.error}`
|
|
3403
4509
|
);
|
|
3404
|
-
process.exit(1);
|
|
3405
4510
|
}
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
4511
|
+
this.mode = "bundled";
|
|
4512
|
+
this.indexPromise = Promise.resolve(bundled.index);
|
|
4513
|
+
if (!this.fallbackAnnounced) {
|
|
4514
|
+
this.fallbackAnnounced = true;
|
|
4515
|
+
this.notify(bundledFallbackMessage(bundled.index.version, reason, kind));
|
|
4516
|
+
}
|
|
4517
|
+
return bundled.index;
|
|
4518
|
+
}
|
|
4519
|
+
readBundledItem(name) {
|
|
4520
|
+
const index = this.bundledIndex;
|
|
4521
|
+
const entry = index?.items.find((it) => it.name === name);
|
|
4522
|
+
if (!index || !entry || !this.bundledDir) {
|
|
4523
|
+
throw new RegistryError(
|
|
4524
|
+
"not-found",
|
|
4525
|
+
`'${name}' \uD56D\uBAA9\uC774 CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC(version ${index?.version ?? "\uC54C \uC218 \uC5C6\uC74C"})\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
4526
|
+
);
|
|
4527
|
+
}
|
|
4528
|
+
try {
|
|
4529
|
+
const item = validateRegistryItem(readBundledJson(this.bundledDir, `${name}.json`), name, `${name}.json`, DEFAULT_DEPENDENCY_BASES);
|
|
4530
|
+
checkItemSha256(item, entry);
|
|
4531
|
+
return item;
|
|
4532
|
+
} catch (error) {
|
|
4533
|
+
throw new RegistryError("unavailable", `CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 '${name}' \uD56D\uBAA9\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${messageOf(error)}`);
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
};
|
|
4537
|
+
|
|
4538
|
+
// src/add/add.ts
|
|
4539
|
+
var AGENTIC_PREFIX = "agentic-";
|
|
4540
|
+
function applyAgenticAlias(name, agentic) {
|
|
4541
|
+
if (!agentic || name.startsWith(AGENTIC_PREFIX)) return name;
|
|
4542
|
+
return `${AGENTIC_PREFIX}${name}`;
|
|
4543
|
+
}
|
|
4544
|
+
function describeMissingName(requested, resolved, index, agentic) {
|
|
4545
|
+
const names = new Set(index.items.map((it) => it.name));
|
|
4546
|
+
if (!isValidRegistryName(resolved)) {
|
|
4547
|
+
return `'${requested}': \uC774\uB984 \uADDC\uCE59(\uC18C\uBB38\uC790 \xB7 \uC22B\uC790 \xB7 \uD558\uC774\uD508)\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`;
|
|
4548
|
+
}
|
|
4549
|
+
if (agentic && resolved !== requested && names.has(requested)) {
|
|
4550
|
+
return `'${requested}': Agentic UI \uC5D0 '${resolved}' \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. '${requested}' \uB294 Core UI \uD56D\uBAA9\uC774\uB2C8 --agentic \uC5C6\uC774 \uC2E4\uD589\uD558\uC138\uC694`;
|
|
4551
|
+
}
|
|
4552
|
+
if (!agentic && names.has(`${AGENTIC_PREFIX}${requested}`)) {
|
|
4553
|
+
return `'${requested}': \uC5C6\uC2B5\uB2C8\uB2E4. Agentic UI \uD56D\uBAA9 '${AGENTIC_PREFIX}${requested}' \uB97C \uB73B\uD588\uB2E4\uBA74 \uC804\uCCB4 \uC774\uB984\uC744 \uC4F0\uAC70\uB098 --agentic \uC744 \uBD99\uC774\uC138\uC694`;
|
|
4554
|
+
}
|
|
4555
|
+
return `'${requested}': \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4`;
|
|
4556
|
+
}
|
|
4557
|
+
function layoutFromConfig(root, config) {
|
|
4558
|
+
const componentsRaw = config.componentsDir;
|
|
4559
|
+
if (typeof componentsRaw !== "string" || componentsRaw.trim() === "") {
|
|
4560
|
+
throw new Error("axis.config.json \uC5D0 componentsDir \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. 'npx @axis-ds/cli init' \uC744 \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uC801\uC73C\uC138\uC694");
|
|
4561
|
+
}
|
|
4562
|
+
const agenticRaw = config.agenticDir;
|
|
4563
|
+
if (agenticRaw !== void 0 && (typeof agenticRaw !== "string" || agenticRaw.trim() === "")) {
|
|
4564
|
+
throw new Error("axis.config.json \uC758 agenticDir \uAC00 \uBB38\uC790\uC5F4\uC774 \uC544\uB2D9\uB2C8\uB2E4");
|
|
4565
|
+
}
|
|
4566
|
+
const componentsDir = componentsRaw.replace(/\\/g, "/");
|
|
4567
|
+
const agenticDir = typeof agenticRaw === "string" ? agenticRaw.replace(/\\/g, "/") : path15.posix.join(path15.posix.dirname(componentsDir), "agentic");
|
|
4568
|
+
return { root: path15.resolve(root), componentsDir, agenticDir };
|
|
4569
|
+
}
|
|
4570
|
+
function toPosix(p, impl = path15) {
|
|
4571
|
+
return p.split(impl.sep).join("/");
|
|
4572
|
+
}
|
|
4573
|
+
function itemKind(item) {
|
|
4574
|
+
if (item.type === "registry:lib") return "lib";
|
|
4575
|
+
return item.name.startsWith(AGENTIC_PREFIX) ? "agentic" : "ui";
|
|
4576
|
+
}
|
|
4577
|
+
var INSTALL_FILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*(?:\.[A-Za-z0-9_-]+)*\.tsx?$/;
|
|
4578
|
+
function registryPathProblem(p) {
|
|
4579
|
+
if (p.length === 0) return "\uBE44\uC5B4 \uC788\uC74C";
|
|
4580
|
+
if (p.includes("\0")) return "NUL \uBB38\uC790";
|
|
4581
|
+
if (p.includes("\\")) return "\uC5ED\uC2AC\uB798\uC2DC";
|
|
4582
|
+
if (p.startsWith("/") || /^[A-Za-z]:/.test(p)) return "\uC808\uB300 \uACBD\uB85C";
|
|
4583
|
+
const segments = p.split("/");
|
|
4584
|
+
if (segments.some((seg) => seg === "" || seg === "." || seg === "..")) return "`..` \xB7 `.` \xB7 \uBE48 \uC138\uADF8\uBA3C\uD2B8";
|
|
4585
|
+
return null;
|
|
4586
|
+
}
|
|
4587
|
+
function placeFile(layout, item, filePath, target) {
|
|
4588
|
+
for (const p of target === void 0 ? [filePath] : [filePath, target]) {
|
|
4589
|
+
const problem = registryPathProblem(p);
|
|
4590
|
+
if (problem) throw new Error(`${item.name}: \uD30C\uC77C \uACBD\uB85C\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${JSON.stringify(p)}, ${problem})`);
|
|
4591
|
+
}
|
|
4592
|
+
const base = path15.posix.basename(filePath);
|
|
4593
|
+
if (!INSTALL_FILE_NAME_PATTERN.test(base)) {
|
|
4594
|
+
throw new Error(`${item.name}: \uD30C\uC77C \uACBD\uB85C\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${JSON.stringify(filePath)}, \uD30C\uC77C \uC774\uB984\uC740 .ts \xB7 .tsx \uB9CC \uC124\uCE58\uD569\uB2C8\uB2E4)`);
|
|
4595
|
+
}
|
|
4596
|
+
const dir = itemKind(item) === "agentic" ? layout.agenticDir : layout.componentsDir;
|
|
4597
|
+
return path15.resolve(layout.root, dir, base);
|
|
4598
|
+
}
|
|
4599
|
+
function stripExt(p) {
|
|
4600
|
+
return p.replace(/\.(?:tsx?|jsx?|mjs|cjs)$/, "");
|
|
4601
|
+
}
|
|
4602
|
+
function buildImportTargets(entries) {
|
|
4603
|
+
const exact = /* @__PURE__ */ new Map();
|
|
4604
|
+
const lib = /* @__PURE__ */ new Map();
|
|
4605
|
+
for (const { item, file, target } of entries) {
|
|
4606
|
+
const rel3 = stripExt(file.path.replace(/\\/g, "/").replace(/^\.?\//, ""));
|
|
4607
|
+
exact.set(`@/${rel3}`, target);
|
|
4608
|
+
if (itemKind(item) === "lib") lib.set(path15.posix.basename(rel3), target);
|
|
4609
|
+
}
|
|
4610
|
+
return { exact, lib };
|
|
4611
|
+
}
|
|
4612
|
+
function nonCodeRanges(src) {
|
|
4613
|
+
const comments = [];
|
|
4614
|
+
const strings = [];
|
|
4615
|
+
function scanTemplate(start) {
|
|
4616
|
+
let i = start + 1;
|
|
4617
|
+
let seg = start;
|
|
4618
|
+
while (i < src.length) {
|
|
4619
|
+
const c = src[i];
|
|
4620
|
+
if (c === "\\") {
|
|
4621
|
+
i += 2;
|
|
4622
|
+
} else if (c === "`") {
|
|
4623
|
+
strings.push([seg, i + 1]);
|
|
4624
|
+
return i + 1;
|
|
4625
|
+
} else if (c === "$" && src[i + 1] === "{") {
|
|
4626
|
+
strings.push([seg, i]);
|
|
4627
|
+
i = scanCode(i + 2, true);
|
|
4628
|
+
seg = i;
|
|
4629
|
+
i++;
|
|
4630
|
+
} else {
|
|
4631
|
+
i++;
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
strings.push([seg, src.length]);
|
|
4635
|
+
return src.length;
|
|
4636
|
+
}
|
|
4637
|
+
function scanCode(start, untilBrace) {
|
|
4638
|
+
let i = start;
|
|
4639
|
+
let depth = 0;
|
|
4640
|
+
while (i < src.length) {
|
|
4641
|
+
const c = src[i];
|
|
4642
|
+
if (c === "/" && src[i + 1] === "/") {
|
|
4643
|
+
const end = src.indexOf("\n", i);
|
|
4644
|
+
const stop = end === -1 ? src.length : end;
|
|
4645
|
+
comments.push([i, stop]);
|
|
4646
|
+
i = stop;
|
|
4647
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
4648
|
+
const end = src.indexOf("*/", i + 2);
|
|
4649
|
+
const stop = end === -1 ? src.length : end + 2;
|
|
4650
|
+
comments.push([i, stop]);
|
|
4651
|
+
i = stop;
|
|
4652
|
+
} else if (c === '"' || c === "'") {
|
|
4653
|
+
const s = i;
|
|
4654
|
+
i++;
|
|
4655
|
+
while (i < src.length && src[i] !== c && src[i] !== "\n") {
|
|
4656
|
+
if (src[i] === "\\") i++;
|
|
4657
|
+
i++;
|
|
3418
4658
|
}
|
|
4659
|
+
i = Math.min(i + 1, src.length);
|
|
4660
|
+
strings.push([s, i]);
|
|
4661
|
+
} else if (c === "`") {
|
|
4662
|
+
i = scanTemplate(i);
|
|
4663
|
+
} else if (c === "{") {
|
|
4664
|
+
depth++;
|
|
4665
|
+
i++;
|
|
4666
|
+
} else if (c === "}") {
|
|
4667
|
+
if (untilBrace && depth === 0) return i;
|
|
4668
|
+
depth = Math.max(0, depth - 1);
|
|
4669
|
+
i++;
|
|
4670
|
+
} else {
|
|
4671
|
+
i++;
|
|
3419
4672
|
}
|
|
3420
|
-
await fs11.ensureDir(path12.dirname(filePath));
|
|
3421
|
-
await fs11.writeFile(filePath, file.content);
|
|
3422
4673
|
}
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
4674
|
+
return src.length;
|
|
4675
|
+
}
|
|
4676
|
+
scanCode(0, false);
|
|
4677
|
+
return { comments, strings };
|
|
4678
|
+
}
|
|
4679
|
+
function insideRanges(ranges, at) {
|
|
4680
|
+
return ranges.some(([a, b]) => at >= a && at < b);
|
|
4681
|
+
}
|
|
4682
|
+
var SPECIFIER_PATTERN = /(\bfrom\s*|\bimport\s*\(\s*|\bimport\s+|\brequire\s*\(\s*)(["'])(@\/[^"'\n]+)\2/g;
|
|
4683
|
+
var STANDARD_LIB_PATTERN = /^@\/registry\/[^/]+\/lib\/(.+)$/;
|
|
4684
|
+
function relativeSpecifier(fromFile, toFile, impl = path15) {
|
|
4685
|
+
let rel3 = toPosix(impl.relative(impl.dirname(fromFile), stripExt(toFile)), impl);
|
|
4686
|
+
if (!rel3.startsWith(".")) rel3 = `./${rel3}`;
|
|
4687
|
+
return rel3;
|
|
4688
|
+
}
|
|
4689
|
+
function rewriteImports(content, fileTarget, targets) {
|
|
4690
|
+
const rewritten = [];
|
|
4691
|
+
const unresolved = [];
|
|
4692
|
+
const { comments, strings } = nonCodeRanges(content);
|
|
4693
|
+
const out = content.replace(SPECIFIER_PATTERN, (whole, lead, quote, spec, offset) => {
|
|
4694
|
+
if (insideRanges(comments, offset) || insideRanges(strings, offset)) return whole;
|
|
4695
|
+
let target = targets.exact.get(spec);
|
|
4696
|
+
if (target === void 0) {
|
|
4697
|
+
const m = STANDARD_LIB_PATTERN.exec(spec);
|
|
4698
|
+
if (m) target = targets.lib.get(m[1]);
|
|
4699
|
+
}
|
|
4700
|
+
if (target === void 0) {
|
|
4701
|
+
if (spec.startsWith("@/registry/")) unresolved.push(spec);
|
|
4702
|
+
return whole;
|
|
4703
|
+
}
|
|
4704
|
+
const to = relativeSpecifier(fileTarget, target);
|
|
4705
|
+
rewritten.push({ from: spec, to, target });
|
|
4706
|
+
return `${lead}${quote}${to}${quote}`;
|
|
4707
|
+
});
|
|
4708
|
+
return { content: out, rewritten, unresolved };
|
|
4709
|
+
}
|
|
4710
|
+
var RESOLVE_EXTS = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", "/index.ts", "/index.tsx", "/index.js"];
|
|
4711
|
+
function relativeSpecifierResolves(fromFile, spec) {
|
|
4712
|
+
const base = path15.resolve(path15.dirname(fromFile), spec);
|
|
4713
|
+
return RESOLVE_EXTS.some((ext) => {
|
|
4714
|
+
try {
|
|
4715
|
+
return statSync4(base + ext).isFile();
|
|
4716
|
+
} catch {
|
|
4717
|
+
return false;
|
|
3427
4718
|
}
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
4719
|
+
});
|
|
4720
|
+
}
|
|
4721
|
+
async function collectItems(client, roots) {
|
|
4722
|
+
const first = await collectOnce(client, roots);
|
|
4723
|
+
if (first.origin === "remote" && client.origin === "bundled") return collectOnce(client, roots);
|
|
4724
|
+
return first;
|
|
4725
|
+
}
|
|
4726
|
+
async function collectOnce(client, roots) {
|
|
4727
|
+
const index = await client.getIndex();
|
|
4728
|
+
const origin = client.origin;
|
|
4729
|
+
const known = new Set(index.items.map((it) => it.name));
|
|
4730
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4731
|
+
const items = [];
|
|
4732
|
+
const missingDeps = [];
|
|
4733
|
+
async function visit(name) {
|
|
4734
|
+
if (visited.has(name)) return;
|
|
4735
|
+
visited.add(name);
|
|
4736
|
+
const item = await client.getItem(name);
|
|
4737
|
+
for (const dep of item.registryDependencies) {
|
|
4738
|
+
if (!known.has(dep)) {
|
|
4739
|
+
missingDeps.push({ name: dep, from: name });
|
|
4740
|
+
continue;
|
|
4741
|
+
}
|
|
4742
|
+
await visit(dep);
|
|
4743
|
+
}
|
|
4744
|
+
items.push(item);
|
|
4745
|
+
}
|
|
4746
|
+
for (const root of roots) await visit(root);
|
|
4747
|
+
return { items, missingDeps, origin };
|
|
4748
|
+
}
|
|
4749
|
+
function planFiles(layout, items) {
|
|
4750
|
+
const errors = [];
|
|
4751
|
+
const placed = [];
|
|
4752
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
4753
|
+
for (const item of items) {
|
|
4754
|
+
for (const file of item.files) {
|
|
4755
|
+
let target;
|
|
4756
|
+
try {
|
|
4757
|
+
target = placeFile(layout, item, file.path, file.target);
|
|
4758
|
+
} catch (error) {
|
|
4759
|
+
errors.push(error.message);
|
|
4760
|
+
continue;
|
|
4761
|
+
}
|
|
4762
|
+
const prev = byTarget.get(target);
|
|
4763
|
+
if (prev !== void 0) {
|
|
4764
|
+
errors.push(`${item.name}: ${toPosix(path15.relative(layout.root, target))} \uB97C ${prev} \uC640 \uD568\uAED8 \uC501\uB2C8\uB2E4(\uAC19\uC740 \uC704\uCE58)`);
|
|
4765
|
+
continue;
|
|
4766
|
+
}
|
|
4767
|
+
byTarget.set(target, item.name);
|
|
4768
|
+
placed.push({ item, file, target });
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
const targets = buildImportTargets(placed);
|
|
4772
|
+
const files = [];
|
|
4773
|
+
for (const { item, file, target } of placed) {
|
|
4774
|
+
const r = rewriteImports(file.content, target, targets);
|
|
4775
|
+
for (const spec of r.unresolved) {
|
|
4776
|
+
errors.push(`${item.name}: import '${spec}' \uB97C \uC124\uCE58 \uC704\uCE58\uB85C \uBC14\uAFC0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(registryDependencies \uC5D0 \uD574\uB2F9 \uD56D\uBAA9\uC774 \uC5C6\uC74C)`);
|
|
4777
|
+
}
|
|
4778
|
+
files.push({ item, sourcePath: file.path, target, content: r.content, rewritten: r.rewritten });
|
|
4779
|
+
}
|
|
4780
|
+
for (const f of files) {
|
|
4781
|
+
const reason = escapeReason(layout.root, f.target, { allowOutsideLink: true });
|
|
4782
|
+
if (reason) errors.push(`${f.item.name}: ${reason}. \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
|
|
4783
|
+
}
|
|
4784
|
+
return { files, errors };
|
|
4785
|
+
}
|
|
4786
|
+
function missingDependencies(root, items) {
|
|
4787
|
+
const installCommand = detectInstallCommand(root);
|
|
4788
|
+
let pkg;
|
|
4789
|
+
try {
|
|
4790
|
+
const text = readFileSync6(path15.join(root, "package.json"), "utf8").replace(/^/, "");
|
|
4791
|
+
const parsed = JSON.parse(text);
|
|
4792
|
+
pkg = isPlainObject2(parsed) ? parsed : void 0;
|
|
4793
|
+
} catch {
|
|
4794
|
+
pkg = void 0;
|
|
4795
|
+
}
|
|
4796
|
+
const ranges = selectUtilsDependencies(detectTailwind(root, pkg));
|
|
4797
|
+
const specs = {};
|
|
4798
|
+
for (const item of items) {
|
|
4799
|
+
for (const dep of item.dependencies) {
|
|
4800
|
+
const name = dependencyName(dep);
|
|
4801
|
+
if (pkg !== void 0 && hasDependency2(pkg, name) !== void 0) continue;
|
|
4802
|
+
if (name in specs) continue;
|
|
4803
|
+
const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
|
|
4804
|
+
specs[name] = explicit ?? ranges[name];
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
const sorted = {};
|
|
4808
|
+
for (const name of Object.keys(specs).sort()) sorted[name] = specs[name];
|
|
4809
|
+
return { specs: sorted, installCommand };
|
|
4810
|
+
}
|
|
4811
|
+
function dependencyName(spec) {
|
|
4812
|
+
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
4813
|
+
return at > 0 ? spec.slice(0, at) : spec;
|
|
4814
|
+
}
|
|
4815
|
+
function addCommandForSpecs(installCommand, specs) {
|
|
4816
|
+
const args = Object.entries(specs).map(([name, range]) => range ? `"${name}@${range}"` : name).join(" ");
|
|
4817
|
+
if (installCommand.startsWith("yarn")) return `yarn add ${args}`;
|
|
4818
|
+
if (installCommand.startsWith("npm")) return `npm install ${args}`;
|
|
4819
|
+
return `pnpm add ${args}`;
|
|
4820
|
+
}
|
|
4821
|
+
function rel2(root, p) {
|
|
4822
|
+
return toPosix(path15.relative(root, p));
|
|
4823
|
+
}
|
|
4824
|
+
async function runAdd(cwd, requested, options, ctx) {
|
|
4825
|
+
const log = ctx.log ?? console.log;
|
|
4826
|
+
const error = ctx.error ?? console.error;
|
|
4827
|
+
const root = path15.resolve(cwd);
|
|
4828
|
+
const result = { exitCode: 1, written: [], overwritten: [], unchanged: [], skipped: [] };
|
|
4829
|
+
if (requested.length === 0) {
|
|
4830
|
+
error("\uCD94\uAC00\uD560 \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC744 \uD558\uB098 \uC774\uC0C1 \uC801\uC73C\uC138\uC694. \uBAA9\uB85D: npx @axis-ds/cli list");
|
|
4831
|
+
return result;
|
|
4832
|
+
}
|
|
4833
|
+
let config;
|
|
4834
|
+
try {
|
|
4835
|
+
config = await readAxisConfig(root);
|
|
4836
|
+
} catch (e) {
|
|
4837
|
+
error(`axis.config.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${e.message}`);
|
|
4838
|
+
return result;
|
|
4839
|
+
}
|
|
4840
|
+
if (!config) {
|
|
4841
|
+
error(
|
|
4842
|
+
"axis.config.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n \uD574\uACB0: \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0\uC11C 'npx @axis-ds/cli init'\uC744 \uC2E4\uD589\uD558\uC138\uC694.\n \uCC38\uACE0: https://axis.minu.best/docs/guides/quick-start"
|
|
3433
4843
|
);
|
|
3434
|
-
|
|
4844
|
+
return result;
|
|
3435
4845
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
4846
|
+
let layout;
|
|
4847
|
+
try {
|
|
4848
|
+
layout = layoutFromConfig(root, config);
|
|
4849
|
+
} catch (e) {
|
|
4850
|
+
error(e.message);
|
|
4851
|
+
return result;
|
|
4852
|
+
}
|
|
4853
|
+
let index;
|
|
4854
|
+
try {
|
|
4855
|
+
index = await ctx.client.getIndex();
|
|
4856
|
+
} catch (e) {
|
|
4857
|
+
error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${e.message}`);
|
|
4858
|
+
return result;
|
|
4859
|
+
}
|
|
4860
|
+
const names = new Set(index.items.map((it) => it.name));
|
|
4861
|
+
const resolved = [];
|
|
4862
|
+
const missing = [];
|
|
4863
|
+
for (const req of requested) {
|
|
4864
|
+
const name = applyAgenticAlias(req, options.agentic);
|
|
4865
|
+
if (!isValidRegistryName(name) || !names.has(name)) missing.push(describeMissingName(req, name, index, options.agentic));
|
|
4866
|
+
else if (!resolved.includes(name)) resolved.push(name);
|
|
4867
|
+
}
|
|
4868
|
+
if (missing.length > 0) {
|
|
4869
|
+
error(`\uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC124\uCE58\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(\uB808\uC9C0\uC2A4\uD2B8\uB9AC version ${index.version}).`);
|
|
4870
|
+
for (const m of missing) error(` - ${m}`);
|
|
4871
|
+
error(" \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBAA9\uB85D: npx @axis-ds/cli list");
|
|
4872
|
+
return result;
|
|
4873
|
+
}
|
|
4874
|
+
let items;
|
|
4875
|
+
try {
|
|
4876
|
+
const collected = await collectItems(ctx.client, resolved);
|
|
4877
|
+
if (collected.missingDeps.length > 0) {
|
|
4878
|
+
error("\uB808\uC9C0\uC2A4\uD2B8\uB9AC \uD56D\uBAA9\uC758 \uC758\uC874 \uD56D\uBAA9\uC774 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC5C6\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC124\uCE58\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
4879
|
+
for (const d of collected.missingDeps) error(` - ${d.from} \u2192 ${d.name}`);
|
|
4880
|
+
return result;
|
|
4881
|
+
}
|
|
4882
|
+
items = collected.items;
|
|
4883
|
+
} catch (e) {
|
|
4884
|
+
const msg = e instanceof RegistryError ? e.message : `\uB808\uC9C0\uC2A4\uD2B8\uB9AC \uD56D\uBAA9\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${e.message}`;
|
|
4885
|
+
error(msg);
|
|
4886
|
+
return result;
|
|
4887
|
+
}
|
|
4888
|
+
const plan = planFiles(layout, items);
|
|
4889
|
+
if (plan.errors.length > 0) {
|
|
4890
|
+
error("\uC124\uCE58\uD560 \uC218 \uC5C6\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
4891
|
+
for (const e of plan.errors) error(` - ${e}`);
|
|
4892
|
+
return result;
|
|
4893
|
+
}
|
|
4894
|
+
const existing = /* @__PURE__ */ new Map();
|
|
4895
|
+
const readErrors = [];
|
|
4896
|
+
for (const file of plan.files) {
|
|
4897
|
+
if (!existsSync7(file.target)) {
|
|
4898
|
+
existing.set(file, null);
|
|
4899
|
+
continue;
|
|
4900
|
+
}
|
|
4901
|
+
try {
|
|
4902
|
+
existing.set(file, readFileSync6(file.target, "utf8"));
|
|
4903
|
+
} catch (e) {
|
|
4904
|
+
readErrors.push(
|
|
4905
|
+
`${file.item.name}: \uAE30\uC874 \uD30C\uC77C ${rel2(root, file.target)} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${e.code ?? e.message})`
|
|
4906
|
+
);
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
if (readErrors.length > 0) {
|
|
4910
|
+
error("\uC124\uCE58\uD560 \uC218 \uC5C6\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
4911
|
+
for (const e of readErrors) error(` - ${e}`);
|
|
4912
|
+
return result;
|
|
4913
|
+
}
|
|
4914
|
+
const decisions = [];
|
|
4915
|
+
for (const file of plan.files) {
|
|
4916
|
+
const current = existing.get(file) ?? null;
|
|
4917
|
+
if (current === null) {
|
|
4918
|
+
decisions.push({ file, action: "write" });
|
|
4919
|
+
continue;
|
|
4920
|
+
}
|
|
4921
|
+
if (current === file.content) {
|
|
4922
|
+
decisions.push({ file, action: "unchanged" });
|
|
4923
|
+
continue;
|
|
4924
|
+
}
|
|
4925
|
+
if (options.overwrite) {
|
|
4926
|
+
decisions.push({ file, action: "overwrite" });
|
|
4927
|
+
} else if (options.yes || !ctx.confirm) {
|
|
4928
|
+
decisions.push({ file, action: "skip" });
|
|
4929
|
+
} else {
|
|
4930
|
+
const ok = await ctx.confirm(`${rel2(root, file.target)} \uC758 \uB0B4\uC6A9\uC774 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC640 \uB2E4\uB985\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`);
|
|
4931
|
+
decisions.push({ file, action: ok ? "overwrite" : "skip" });
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
const outsideLinks = /* @__PURE__ */ new Map();
|
|
4935
|
+
for (const d of decisions) {
|
|
4936
|
+
const outside = outsideLinkTarget(root, d.file.target);
|
|
4937
|
+
if (outside !== null) outsideLinks.set(d.file, outside);
|
|
4938
|
+
}
|
|
4939
|
+
const linkErrors = decisions.filter((d) => (d.action === "write" || d.action === "overwrite") && isSymlink(d.file.target)).map((d) => {
|
|
4940
|
+
const outside = outsideLinks.get(d.file);
|
|
4941
|
+
const what = outside !== void 0 ? `\uD504\uB85C\uC81D\uD2B8 \uBC16(${outside})\uC744 \uAC00\uB9AC\uD0A4\uB294 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C` : "\uD504\uB85C\uC81D\uD2B8 \uC548\uC744 \uAC00\uB9AC\uD0A4\uB294 \uC2EC\uBCFC\uB9AD \uB9C1\uD06C\uB77C";
|
|
4942
|
+
return `${d.file.item.name}: \uAE30\uC874 \uD30C\uC77C ${rel2(root, d.file.target)} \uC774 ${what} \uB36E\uC5B4\uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uB9C1\uD06C\uB294 \uB530\uB77C\uAC00 \uC4F0\uC9C0 \uC54A\uC73C\uB2C8 \uB9C1\uD06C\uB97C \uC9C0\uC6B0\uAC70\uB098 \uC2E4\uC81C \uD30C\uC77C\uB85C \uBC14\uAFBC \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694`;
|
|
4943
|
+
});
|
|
4944
|
+
for (const d of decisions) {
|
|
4945
|
+
if (d.action !== "overwrite") continue;
|
|
4946
|
+
const nlink = hardLinkCount(d.file.target);
|
|
4947
|
+
if (nlink !== null) linkErrors.push(`${d.file.item.name}: ${hardLinkMessage(rel2(root, d.file.target), nlink)}`);
|
|
4948
|
+
}
|
|
4949
|
+
if (linkErrors.length > 0) {
|
|
4950
|
+
error("\uC124\uCE58\uD560 \uC218 \uC5C6\uC5B4 \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
4951
|
+
for (const e of linkErrors) error(` - ${e}`);
|
|
4952
|
+
return result;
|
|
4953
|
+
}
|
|
4954
|
+
const stopWriting = (p, reason, tail = "\uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.") => {
|
|
4955
|
+
error(`${p}: ${reason}. ${tail}`);
|
|
4956
|
+
if (result.written.length > 0) {
|
|
4957
|
+
error(`\uC774\uBBF8 \uC4F4 \uD30C\uC77C(${result.written.length}):`);
|
|
4958
|
+
for (const w of result.written) error(` ${result.overwritten.includes(w) ? "~" : "+"} ${w}`);
|
|
4959
|
+
}
|
|
4960
|
+
return { ...result, exitCode: 1 };
|
|
3471
4961
|
};
|
|
3472
|
-
|
|
3473
|
-
|
|
4962
|
+
for (const d of decisions) {
|
|
4963
|
+
const p = rel2(root, d.file.target);
|
|
4964
|
+
if (d.action === "unchanged") {
|
|
4965
|
+
result.unchanged.push(p);
|
|
4966
|
+
continue;
|
|
4967
|
+
}
|
|
4968
|
+
if (d.action === "skip") {
|
|
4969
|
+
result.skipped.push(p);
|
|
4970
|
+
continue;
|
|
4971
|
+
}
|
|
4972
|
+
let actual = d.action === "write" ? "new" : "overwrite";
|
|
4973
|
+
try {
|
|
4974
|
+
const before = escapeReason(root, d.file.target);
|
|
4975
|
+
if (before) return stopWriting(p, before);
|
|
4976
|
+
await fs12.ensureDir(path15.dirname(d.file.target));
|
|
4977
|
+
const after = checkParentInside(root, d.file.target);
|
|
4978
|
+
if (after) return stopWriting(p, after);
|
|
4979
|
+
actual = await writeNoFollow(d.file.target, d.file.content, actual);
|
|
4980
|
+
} catch (e) {
|
|
4981
|
+
const code = e.code;
|
|
4982
|
+
if (code === "ELOOP" || code === "EEXIST" && isSymlink(d.file.target)) {
|
|
4983
|
+
return stopWriting(p, "\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uB9C1\uD06C\uB85C \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569)");
|
|
4984
|
+
}
|
|
4985
|
+
if (code === HARDLINK_ERROR_CODE) {
|
|
4986
|
+
return stopWriting(
|
|
4987
|
+
p,
|
|
4988
|
+
"\uAC80\uC0AC \uB4A4 \uC4F0\uAE30 \uC9C1\uC804\uC5D0 \uB2E4\uB978 \uACBD\uB85C\uC640 \uD558\uB4DC\uB9C1\uD06C\uB85C \uC774\uC5B4\uC84C\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569)",
|
|
4989
|
+
"\uADF8 \uD30C\uC77C\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(D19). \uD558\uB4DC\uB9C1\uD06C\uB97C \uB04A\uC740 \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694."
|
|
4990
|
+
);
|
|
4991
|
+
}
|
|
4992
|
+
if (code === "EEXIST") {
|
|
4993
|
+
return stopWriting(
|
|
4994
|
+
p,
|
|
4995
|
+
"\uC0C8 \uD30C\uC77C\uB85C \uD310\uC815\uD55C \uB4A4(\uD655\uC778 \uB300\uAE30 \uC911 \uB4F1) \uAC19\uC740 \uC774\uB984\uC758 \uD30C\uC77C\uC774 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4(\uB3D9\uC2DC \uACBD\uD569)",
|
|
4996
|
+
"\uADF8 \uD30C\uC77C\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uB0B4\uC6A9\uC744 \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694."
|
|
4997
|
+
);
|
|
4998
|
+
}
|
|
4999
|
+
return stopWriting(p, `\uC4F0\uAE30 \uC2E4\uD328(${e.message})`);
|
|
5000
|
+
}
|
|
5001
|
+
const outside = writtenOutside(root, d.file.target);
|
|
5002
|
+
if (outside !== null) {
|
|
5003
|
+
return stopWriting(
|
|
5004
|
+
p,
|
|
5005
|
+
`\uC4F4 \uB4A4 \uD655\uC778\uD55C \uC2E4\uC81C \uC704\uCE58(${outside})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4(\uAC80\uC0AC\uC640 \uC4F0\uAE30 \uC0AC\uC774\uC5D0 \uC0C1\uC704 \uB514\uB809\uD130\uB9AC\uAC00 \uBC14\uB010 \uB3D9\uC2DC \uACBD\uD569)`,
|
|
5006
|
+
`\uADF8 \uD30C\uC77C\uC740 \uC9C0\uC6B0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${outside} \uB97C \uC9C1\uC811 \uD655\uC778\uD558\uC138\uC694.`
|
|
5007
|
+
);
|
|
5008
|
+
}
|
|
5009
|
+
result.written.push(p);
|
|
5010
|
+
if (actual === "overwrite") result.overwritten.push(p);
|
|
5011
|
+
}
|
|
5012
|
+
const broken = [];
|
|
5013
|
+
for (const d of decisions) {
|
|
5014
|
+
if (d.action === "skip") continue;
|
|
5015
|
+
for (const r of d.file.rewritten) {
|
|
5016
|
+
if (!relativeSpecifierResolves(d.file.target, r.to)) {
|
|
5017
|
+
broken.push(`${rel2(root, d.file.target)}: '${r.to}'(\uC6D0\uB798 '${r.from}')\uAC00 \uAC00\uB9AC\uD0A4\uB294 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
3474
5020
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
5021
|
+
const itemNames = items.map((it) => it.name);
|
|
5022
|
+
log(`\uC124\uCE58 \uD56D\uBAA9(${items.length}): ${itemNames.join(", ")}`);
|
|
5023
|
+
for (const p of result.written) {
|
|
5024
|
+
if (result.overwritten.includes(p)) log(` ~ ${p} (\uB36E\uC5B4\uC500)`);
|
|
5025
|
+
else log(` + ${p}`);
|
|
3477
5026
|
}
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
});
|
|
5027
|
+
const outsideRel = new Set([...outsideLinks.keys()].map((f) => rel2(root, f.target)));
|
|
5028
|
+
for (const p of result.unchanged) {
|
|
5029
|
+
log(outsideRel.has(p) ? ` = ${p} (\uAC19\uC740 \uB0B4\uC6A9\uC774\uB77C \uAC74\uB108\uB700, \uB9C1\uD06C \uB300\uC0C1\uC774 \uD504\uB85C\uC81D\uD2B8 \uBC16)` : ` = ${p} (\uAC19\uC740 \uB0B4\uC6A9\uC774\uB77C \uAC74\uB108\uB700)`);
|
|
5030
|
+
}
|
|
5031
|
+
if (result.skipped.length > 0) {
|
|
5032
|
+
log(`\uB0B4\uC6A9\uC774 \uB2E4\uB978 \uAE30\uC874 \uD30C\uC77C ${result.skipped.length}\uAC1C\uB97C \uAC74\uB108\uB6F0\uC5C8\uC2B5\uB2C8\uB2E4(\uB36E\uC5B4\uC4F0\uB824\uBA74 --overwrite):`);
|
|
5033
|
+
for (const p of result.skipped) log(outsideRel.has(p) ? ` - ${p} (\uB9C1\uD06C \uB300\uC0C1\uC774 \uD504\uB85C\uC81D\uD2B8 \uBC16)` : ` - ${p}`);
|
|
5034
|
+
}
|
|
5035
|
+
if (broken.length > 0) {
|
|
5036
|
+
error("\uC124\uCE58\uD55C \uD30C\uC77C\uC758 import \uAC00 \uD480\uB9AC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4:");
|
|
5037
|
+
for (const b of broken) error(` - ${b}`);
|
|
5038
|
+
return { ...result, exitCode: 1 };
|
|
5039
|
+
}
|
|
5040
|
+
const deps = missingDependencies(root, items);
|
|
5041
|
+
if (Object.keys(deps.specs).length > 0) {
|
|
5042
|
+
log("\npackage.json \uC5D0 \uC5C6\uB294 \uC758\uC874\uC131(\uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4):");
|
|
5043
|
+
log(` ${addCommandForSpecs(deps.installCommand, deps.specs)}`);
|
|
5044
|
+
}
|
|
5045
|
+
return { ...result, exitCode: 0 };
|
|
5046
|
+
}
|
|
5047
|
+
function groupIndex(index) {
|
|
5048
|
+
const ui = [];
|
|
5049
|
+
const agentic = [];
|
|
5050
|
+
for (const it of index.items) {
|
|
5051
|
+
const kind = itemKind(it);
|
|
5052
|
+
if (kind === "lib") continue;
|
|
5053
|
+
const entry = { name: it.name, title: it.title, description: it.description };
|
|
5054
|
+
(kind === "agentic" ? agentic : ui).push(entry);
|
|
5055
|
+
}
|
|
5056
|
+
return { ui, agentic };
|
|
5057
|
+
}
|
|
5058
|
+
async function createClientFor(cwd, notify, env = process.env) {
|
|
5059
|
+
let config = null;
|
|
5060
|
+
try {
|
|
5061
|
+
config = await readAxisConfig(path15.resolve(cwd));
|
|
5062
|
+
} catch {
|
|
5063
|
+
config = null;
|
|
5064
|
+
}
|
|
5065
|
+
const resolved = resolveRegistryUrl({ config, env });
|
|
5066
|
+
const say = notify ?? ((message) => console.warn(message));
|
|
5067
|
+
if (resolved.migratedFrom !== void 0) say(LEGACY_REGISTRY_NOTICE);
|
|
5068
|
+
return new RegistryClient({ url: resolved.url, ...notify ? { notify } : {} });
|
|
5069
|
+
}
|
|
5070
|
+
|
|
5071
|
+
// src/add/index.ts
|
|
5072
|
+
function createConfirm(interactive) {
|
|
5073
|
+
if (!interactive) return void 0;
|
|
5074
|
+
return async (message) => {
|
|
5075
|
+
const { overwrite } = await prompts3({ type: "confirm", name: "overwrite", message, initial: false });
|
|
5076
|
+
return overwrite === true;
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5079
|
+
var defaultCreateClient = (cwd) => createClientFor(cwd, (m) => console.warn(chalk11.yellow(m)));
|
|
5080
|
+
function registerAddCommand(program2, deps = {}) {
|
|
5081
|
+
program2.command("add <components...>").description("\uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uD504\uB85C\uC81D\uD2B8\uC5D0 \uBCF5\uC0AC(registryDependencies \uD3EC\uD568)").option("--agentic", "\uC774\uB984 \uC55E\uC5D0 agentic- \uB97C \uBD99\uC5EC \uCC3E\uC74C(\uC804\uCCB4 \uC774\uB984\uB3C4 \uD5C8\uC6A9)").option("-y, --yes", "\uBB3B\uC9C0 \uC54A\uACE0 \uC9C4\uD589. \uB0B4\uC6A9\uC774 \uB2E4\uB978 \uAE30\uC874 \uD30C\uC77C\uC740 \uAC74\uB108\uB700").option("--overwrite", "\uB0B4\uC6A9\uC774 \uB2E4\uB978 \uAE30\uC874 \uD30C\uC77C\uC744 \uB36E\uC5B4\uC500").action(async (components, options) => {
|
|
5082
|
+
const client = await (deps.createClient ?? defaultCreateClient)(process.cwd());
|
|
5083
|
+
const confirm = createConfirm((deps.isInteractive ?? (() => process.stdin.isTTY === true))());
|
|
5084
|
+
const result = await runAdd(process.cwd(), components, options, {
|
|
5085
|
+
client,
|
|
5086
|
+
log: (...a) => console.log(...a),
|
|
5087
|
+
error: (...a) => console.error(chalk11.red(a.map(String).join(" "))),
|
|
5088
|
+
...confirm ? { confirm } : {}
|
|
5089
|
+
});
|
|
5090
|
+
process.exitCode = result.exitCode;
|
|
5091
|
+
});
|
|
5092
|
+
}
|
|
5093
|
+
function registerListCommand(program2, deps = {}) {
|
|
5094
|
+
program2.command("list").description("\uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uCEF4\uD3EC\uB10C\uD2B8 \uBAA9\uB85D").option("--category <type>", "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130 (ui, agentic)").action(async (options) => {
|
|
5095
|
+
if (options.category !== void 0 && options.category !== "ui" && options.category !== "agentic") {
|
|
5096
|
+
console.error(chalk11.red(`--category \uB294 ui \uB610\uB294 agentic \uC785\uB2C8\uB2E4(\uBC1B\uC740 \uAC12: ${options.category})`));
|
|
5097
|
+
process.exitCode = 1;
|
|
5098
|
+
return;
|
|
5099
|
+
}
|
|
5100
|
+
const client = await (deps.createClient ?? defaultCreateClient)(process.cwd());
|
|
5101
|
+
let groups;
|
|
5102
|
+
let version;
|
|
5103
|
+
try {
|
|
5104
|
+
const index = await client.getIndex();
|
|
5105
|
+
groups = groupIndex(index);
|
|
5106
|
+
version = index.version;
|
|
5107
|
+
} catch (e) {
|
|
5108
|
+
console.error(chalk11.red(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${e.message}`));
|
|
5109
|
+
process.exitCode = 1;
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
const total = groups.ui.length + groups.agentic.length;
|
|
5113
|
+
const origin = client.origin === "bundled" ? "CLI \uC5D0 \uD3EC\uD568\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC" : "\uC6D0\uACA9 \uB808\uC9C0\uC2A4\uD2B8\uB9AC";
|
|
5114
|
+
console.log(chalk11.blue(`
|
|
5115
|
+
\u{1F4E6} AXIS Design System \uCEF4\uD3EC\uB10C\uD2B8 ${total}\uAC1C (${origin}, version ${version})
|
|
5116
|
+
`));
|
|
5117
|
+
const show = (label, items) => {
|
|
5118
|
+
console.log(chalk11.bold(`${label} (${items.length})`));
|
|
5119
|
+
for (const c of items) {
|
|
5120
|
+
console.log(` ${chalk11.cyan(c.name.padEnd(32))} ${chalk11.gray(c.description ?? c.title ?? "")}`);
|
|
5121
|
+
}
|
|
5122
|
+
console.log();
|
|
5123
|
+
};
|
|
5124
|
+
if (!options.category || options.category === "ui") show("Core UI", groups.ui);
|
|
5125
|
+
if (!options.category || options.category === "agentic") show("Agentic UI", groups.agentic);
|
|
5126
|
+
console.log(chalk11.gray("\uC0AC\uC6A9\uBC95: npx @axis-ds/cli add <\uC774\uB984...> (\uC608: add button input card)"));
|
|
5127
|
+
console.log(chalk11.gray("Agentic: npx @axis-ds/cli add run-progress --agentic (= add agentic-run-progress)\n"));
|
|
5128
|
+
});
|
|
5129
|
+
}
|
|
5130
|
+
|
|
5131
|
+
// src/index.ts
|
|
5132
|
+
var { version: CLI_VERSION } = createRequire2(import.meta.url)("../package.json");
|
|
5133
|
+
var program = new Command();
|
|
5134
|
+
program.name("axis").description("AXIS Design System CLI - shadcn \uD638\uD658 \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uB3C4\uAD6C").version(CLI_VERSION);
|
|
5135
|
+
registerInitCommand(program);
|
|
5136
|
+
registerAddCommand(program);
|
|
5137
|
+
registerListCommand(program);
|
|
3481
5138
|
var monetCmd = program.command("monet").description("Monet Design \uCEF4\uD3EC\uB10C\uD2B8 \uAD00\uB9AC (https://monet.design)");
|
|
3482
5139
|
monetCmd.command("list").alias("ls").description("Monet \uCE74\uD14C\uACE0\uB9AC \uBAA9\uB85D").action(async () => {
|
|
3483
5140
|
const client = new MonetClient();
|
|
@@ -3496,24 +5153,24 @@ monetCmd.command("import").alias("i").description("\uD074\uB9BD\uBCF4\uB4DC\uC5D
|
|
|
3496
5153
|
await client.importFromClipboard();
|
|
3497
5154
|
});
|
|
3498
5155
|
monetCmd.command("setup").description("Monet MCP \uC11C\uBC84 \uC124\uC815 \uC548\uB0B4").action(() => {
|
|
3499
|
-
console.log(
|
|
3500
|
-
console.log(
|
|
3501
|
-
console.log(
|
|
3502
|
-
console.log(
|
|
3503
|
-
console.log(
|
|
3504
|
-
console.log(
|
|
3505
|
-
console.log(
|
|
3506
|
-
console.log(
|
|
5156
|
+
console.log(chalk12.blue("\n\u{1F527} Monet MCP \uC11C\uBC84 \uC124\uC815\n"));
|
|
5157
|
+
console.log(chalk12.bold("1. API \uD0A4 \uBC1C\uAE09:"));
|
|
5158
|
+
console.log(chalk12.cyan(" https://monet.design/mcp\n"));
|
|
5159
|
+
console.log(chalk12.bold("2. \uD658\uACBD \uBCC0\uC218 \uC124\uC815:"));
|
|
5160
|
+
console.log(chalk12.gray(" .env \uD30C\uC77C\uC5D0 \uCD94\uAC00:"));
|
|
5161
|
+
console.log(chalk12.cyan(" MONET_API_KEY=your-api-key-here\n"));
|
|
5162
|
+
console.log(chalk12.bold("3. Claude Code MCP \uC124\uC815:"));
|
|
5163
|
+
console.log(chalk12.gray(" .claude/mcp.json\uC5D0\uC11C monet \uC11C\uBC84 \uD65C\uC131\uD654:\n"));
|
|
3507
5164
|
console.log(
|
|
3508
|
-
|
|
5165
|
+
chalk12.cyan(` "monet": {
|
|
3509
5166
|
"url": "https://www.monet.design/api/remote/mcp",
|
|
3510
5167
|
"headers": { "Authorization": "Bearer \${MONET_API_KEY}" },
|
|
3511
5168
|
"disabled": false
|
|
3512
5169
|
}
|
|
3513
5170
|
`)
|
|
3514
5171
|
);
|
|
3515
|
-
console.log(
|
|
3516
|
-
console.log(
|
|
5172
|
+
console.log(chalk12.bold("4. Claude Code \uC7AC\uC2DC\uC791 \uD6C4 \uC0AC\uC6A9:"));
|
|
5173
|
+
console.log(chalk12.gray(' "monet\uC5D0\uC11C hero \uCEF4\uD3EC\uB10C\uD2B8 \uCC3E\uC544\uC918"\n'));
|
|
3517
5174
|
});
|
|
3518
5175
|
var v0Cmd = program.command("v0").description("V0 (v0.app) \uCF54\uB4DC \uBCC0\uD658 \uBC0F \uD1B5\uD569");
|
|
3519
5176
|
v0Cmd.command("convert <file>").alias("c").description("V0 \uCF54\uB4DC\uB97C AXIS \uC2A4\uD0C0\uC77C\uB85C \uBCC0\uD658").option("-o, --output <path>", "\uCD9C\uB825 \uD30C\uC77C \uACBD\uB85C").action(async (file, options) => {
|
|
@@ -3550,18 +5207,18 @@ libraryCmd.command("collect").alias("c").description("\uC678\uBD80 \uC18C\uC2A4\
|
|
|
3550
5207
|
total += result.collected;
|
|
3551
5208
|
failed += result.failed;
|
|
3552
5209
|
}
|
|
3553
|
-
console.log(
|
|
5210
|
+
console.log(chalk12.blue(`
|
|
3554
5211
|
\u{1F4CA} \uC218\uC9D1 \uC644\uB8CC: ${total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8`));
|
|
3555
5212
|
if (failed > 0) {
|
|
3556
|
-
console.log(
|
|
5213
|
+
console.log(chalk12.yellow(` \uC2E4\uD328: ${failed}\uAC1C`));
|
|
3557
5214
|
}
|
|
3558
5215
|
});
|
|
3559
5216
|
libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9AC \uCEF4\uD3EC\uB10C\uD2B8 \uBAA9\uB85D").option("-c, --category <category>", "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130").option("-s, --source <source>", "\uC18C\uC2A4 \uD544\uD130").action(async (options) => {
|
|
3560
5217
|
const curator = new LibraryCurator();
|
|
3561
5218
|
const index = await curator.loadIndex();
|
|
3562
5219
|
if (!index) {
|
|
3563
|
-
console.log(
|
|
3564
|
-
console.log(
|
|
5220
|
+
console.log(chalk12.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
5221
|
+
console.log(chalk12.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
|
|
3565
5222
|
return;
|
|
3566
5223
|
}
|
|
3567
5224
|
let components = index.components;
|
|
@@ -3571,7 +5228,7 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
|
|
|
3571
5228
|
if (options.source) {
|
|
3572
5229
|
components = components.filter((c) => c.source.type === options.source);
|
|
3573
5230
|
}
|
|
3574
|
-
console.log(
|
|
5231
|
+
console.log(chalk12.blue(`
|
|
3575
5232
|
\u{1F4E6} Library Components (${components.length}\uAC1C)
|
|
3576
5233
|
`));
|
|
3577
5234
|
const byCategory = /* @__PURE__ */ new Map();
|
|
@@ -3583,14 +5240,14 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
|
|
|
3583
5240
|
byCategory.get(cat).push(comp);
|
|
3584
5241
|
}
|
|
3585
5242
|
for (const [category, items] of byCategory) {
|
|
3586
|
-
console.log(
|
|
5243
|
+
console.log(chalk12.bold(`${category} (${items.length})`));
|
|
3587
5244
|
for (const item of items.slice(0, 10)) {
|
|
3588
5245
|
console.log(
|
|
3589
|
-
` ${
|
|
5246
|
+
` ${chalk12.cyan(item.name.padEnd(25))} ${chalk12.gray(item.source.type.padEnd(8))} ${chalk12.gray(item.description.slice(0, 40))}`
|
|
3590
5247
|
);
|
|
3591
5248
|
}
|
|
3592
5249
|
if (items.length > 10) {
|
|
3593
|
-
console.log(
|
|
5250
|
+
console.log(chalk12.gray(` ... \uC678 ${items.length - 10}\uAC1C`));
|
|
3594
5251
|
}
|
|
3595
5252
|
console.log();
|
|
3596
5253
|
}
|
|
@@ -3602,21 +5259,21 @@ libraryCmd.command("search <query>").alias("s").description("\uCEF4\uD3EC\uB10C\
|
|
|
3602
5259
|
source: options.source
|
|
3603
5260
|
});
|
|
3604
5261
|
if (results.length === 0) {
|
|
3605
|
-
console.log(
|
|
5262
|
+
console.log(chalk12.yellow(`
|
|
3606
5263
|
'${query}'\uC5D0 \uB300\uD55C \uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
|
|
3607
5264
|
`));
|
|
3608
5265
|
return;
|
|
3609
5266
|
}
|
|
3610
|
-
console.log(
|
|
5267
|
+
console.log(chalk12.blue(`
|
|
3611
5268
|
\u{1F50D} '${query}' \uAC80\uC0C9 \uACB0\uACFC (${results.length}\uAC1C)
|
|
3612
5269
|
`));
|
|
3613
5270
|
for (const comp of results.slice(0, 20)) {
|
|
3614
5271
|
console.log(
|
|
3615
|
-
` ${
|
|
5272
|
+
` ${chalk12.cyan(comp.name.padEnd(25))} ${chalk12.gray(comp.source.type.padEnd(8))} ${chalk12.gray(comp.category.padEnd(12))} ${chalk12.gray(comp.description.slice(0, 30))}`
|
|
3616
5273
|
);
|
|
3617
5274
|
}
|
|
3618
5275
|
if (results.length > 20) {
|
|
3619
|
-
console.log(
|
|
5276
|
+
console.log(chalk12.gray(`
|
|
3620
5277
|
... \uC678 ${results.length - 20}\uAC1C`));
|
|
3621
5278
|
}
|
|
3622
5279
|
console.log();
|
|
@@ -3630,12 +5287,12 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
|
|
|
3630
5287
|
const publisher2 = new Publisher();
|
|
3631
5288
|
const index = await curator.loadIndex();
|
|
3632
5289
|
if (!index) {
|
|
3633
|
-
console.log(
|
|
3634
|
-
console.log(
|
|
5290
|
+
console.log(chalk12.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
5291
|
+
console.log(chalk12.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
|
|
3635
5292
|
return;
|
|
3636
5293
|
}
|
|
3637
|
-
console.log(
|
|
3638
|
-
console.log(
|
|
5294
|
+
console.log(chalk12.blue("\n\u{1F4E4} Library \uBC30\uCE58\n"));
|
|
5295
|
+
console.log(chalk12.gray(`\uCD1D ${index.stats.total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8
|
|
3639
5296
|
`));
|
|
3640
5297
|
if (options.clean) {
|
|
3641
5298
|
await publisher2.clean(options.output);
|
|
@@ -3646,17 +5303,17 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
|
|
|
3646
5303
|
generateSearchIndex: true
|
|
3647
5304
|
});
|
|
3648
5305
|
if (result.success) {
|
|
3649
|
-
console.log(
|
|
5306
|
+
console.log(chalk12.green(`
|
|
3650
5307
|
\u2713 \uBC30\uCE58 \uC644\uB8CC`));
|
|
3651
|
-
console.log(
|
|
3652
|
-
console.log(
|
|
3653
|
-
console.log(
|
|
3654
|
-
console.log(
|
|
5308
|
+
console.log(chalk12.gray(` - \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC: ${result.outputDir}`));
|
|
5309
|
+
console.log(chalk12.gray(` - \uC0DD\uC131\uB41C \uD30C\uC77C: ${result.files.length}\uAC1C`));
|
|
5310
|
+
console.log(chalk12.gray(` - \uCE74\uD14C\uACE0\uB9AC: ${result.stats.categoriesPublished}\uAC1C`));
|
|
5311
|
+
console.log(chalk12.gray(` - \uAC80\uC0C9 \uC778\uB371\uC2A4: ${result.stats.searchIndexSize}\uAC1C \uD56D\uBAA9`));
|
|
3655
5312
|
} else {
|
|
3656
|
-
console.log(
|
|
5313
|
+
console.log(chalk12.red(`
|
|
3657
5314
|
\u2717 \uBC30\uCE58 \uC2E4\uD328`));
|
|
3658
5315
|
for (const error of result.errors) {
|
|
3659
|
-
console.log(
|
|
5316
|
+
console.log(chalk12.red(` - ${error}`));
|
|
3660
5317
|
}
|
|
3661
5318
|
}
|
|
3662
5319
|
console.log();
|
|
@@ -3665,64 +5322,4 @@ registerSyncCommand(program);
|
|
|
3665
5322
|
registerTemplateCommand(program);
|
|
3666
5323
|
registerCheckCommand(program);
|
|
3667
5324
|
registerThemeCommand(program);
|
|
3668
|
-
async function getComponentInfo(name, category) {
|
|
3669
|
-
const localComponents = {
|
|
3670
|
-
button: {
|
|
3671
|
-
name: "button",
|
|
3672
|
-
type: "ui",
|
|
3673
|
-
description: "Primary button component",
|
|
3674
|
-
dependencies: ["@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge"],
|
|
3675
|
-
files: [
|
|
3676
|
-
{
|
|
3677
|
-
path: "button.tsx",
|
|
3678
|
-
content: `import * as React from "react"
|
|
3679
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
3680
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
3681
|
-
import { cn } from "./utils"
|
|
3682
|
-
|
|
3683
|
-
const buttonVariants = cva(
|
|
3684
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
3685
|
-
{
|
|
3686
|
-
variants: {
|
|
3687
|
-
variant: {
|
|
3688
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
3689
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
3690
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
3691
|
-
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
3692
|
-
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
3693
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
3694
|
-
},
|
|
3695
|
-
size: {
|
|
3696
|
-
sm: "h-8 px-3 text-xs",
|
|
3697
|
-
default: "h-10 px-4 py-2",
|
|
3698
|
-
lg: "h-12 px-6 text-base",
|
|
3699
|
-
icon: "h-10 w-10",
|
|
3700
|
-
},
|
|
3701
|
-
},
|
|
3702
|
-
defaultVariants: { variant: "default", size: "default" },
|
|
3703
|
-
}
|
|
3704
|
-
)
|
|
3705
|
-
|
|
3706
|
-
export interface ButtonProps
|
|
3707
|
-
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
3708
|
-
VariantProps<typeof buttonVariants> {
|
|
3709
|
-
asChild?: boolean
|
|
3710
|
-
}
|
|
3711
|
-
|
|
3712
|
-
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
3713
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
3714
|
-
const Comp = asChild ? Slot : "button"
|
|
3715
|
-
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
|
3716
|
-
}
|
|
3717
|
-
)
|
|
3718
|
-
Button.displayName = "Button"
|
|
3719
|
-
|
|
3720
|
-
export { Button, buttonVariants }
|
|
3721
|
-
`
|
|
3722
|
-
}
|
|
3723
|
-
]
|
|
3724
|
-
}
|
|
3725
|
-
};
|
|
3726
|
-
return localComponents[name] || null;
|
|
3727
|
-
}
|
|
3728
5325
|
program.parse();
|