@axis-ds/cli 1.1.4 → 1.2.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 +21 -0
- package/dist/index.js +994 -108
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,10 +15,11 @@ import {
|
|
|
15
15
|
|
|
16
16
|
// src/index.ts
|
|
17
17
|
import { Command } from "commander";
|
|
18
|
-
import
|
|
18
|
+
import chalk9 from "chalk";
|
|
19
19
|
import ora6 from "ora";
|
|
20
|
-
import
|
|
21
|
-
import
|
|
20
|
+
import fs10 from "fs-extra";
|
|
21
|
+
import path11 from "path";
|
|
22
|
+
import { createRequire as createRequire2 } from "module";
|
|
22
23
|
import prompts2 from "prompts";
|
|
23
24
|
|
|
24
25
|
// src/library/base-collector.ts
|
|
@@ -483,11 +484,11 @@ var ShadcnCollector = class extends BaseCollector {
|
|
|
483
484
|
/**
|
|
484
485
|
* 파일 타입 추론
|
|
485
486
|
*/
|
|
486
|
-
getFileType(
|
|
487
|
-
if (
|
|
488
|
-
if (
|
|
489
|
-
if (
|
|
490
|
-
if (
|
|
487
|
+
getFileType(path12) {
|
|
488
|
+
if (path12.includes("hook") || path12.startsWith("use")) return "hook";
|
|
489
|
+
if (path12.includes("util") || path12.includes("lib")) return "util";
|
|
490
|
+
if (path12.endsWith(".css")) return "style";
|
|
491
|
+
if (path12.endsWith(".d.ts") || path12.includes("types")) return "type";
|
|
491
492
|
return "component";
|
|
492
493
|
}
|
|
493
494
|
};
|
|
@@ -1167,8 +1168,8 @@ var Publisher = class {
|
|
|
1167
1168
|
};
|
|
1168
1169
|
} catch (error) {
|
|
1169
1170
|
spinner.fail("\uB77C\uC774\uBE0C\uB7EC\uB9AC \uBC30\uCE58 \uC2E4\uD328");
|
|
1170
|
-
const
|
|
1171
|
-
errors.push(
|
|
1171
|
+
const errorMessage2 = error instanceof Error ? error.message : "Unknown error";
|
|
1172
|
+
errors.push(errorMessage2);
|
|
1172
1173
|
return {
|
|
1173
1174
|
success: false,
|
|
1174
1175
|
outputDir,
|
|
@@ -1503,7 +1504,7 @@ import chalk7 from "chalk";
|
|
|
1503
1504
|
import ora5 from "ora";
|
|
1504
1505
|
|
|
1505
1506
|
// src/template/template-apply.ts
|
|
1506
|
-
import
|
|
1507
|
+
import fs7 from "fs-extra";
|
|
1507
1508
|
import path6 from "path";
|
|
1508
1509
|
import chalk4 from "chalk";
|
|
1509
1510
|
import ora3 from "ora";
|
|
@@ -1571,6 +1572,29 @@ function deepMerge(target, source) {
|
|
|
1571
1572
|
}
|
|
1572
1573
|
}
|
|
1573
1574
|
|
|
1575
|
+
// src/config/axis-config.ts
|
|
1576
|
+
import fs6 from "fs-extra";
|
|
1577
|
+
var AXIS_CONFIG_SCHEMA_URL = "https://axis.minu.best/schema.json";
|
|
1578
|
+
var AXIS_CONFIG_FILE = "axis.config.json";
|
|
1579
|
+
function createInitConfig(answers, registry) {
|
|
1580
|
+
return {
|
|
1581
|
+
$schema: AXIS_CONFIG_SCHEMA_URL,
|
|
1582
|
+
componentsDir: answers.componentsDir,
|
|
1583
|
+
tailwindConfig: answers.tailwindConfig,
|
|
1584
|
+
globalCss: answers.globalCss,
|
|
1585
|
+
registry
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1588
|
+
function createTemplateConfig(template) {
|
|
1589
|
+
return {
|
|
1590
|
+
$schema: AXIS_CONFIG_SCHEMA_URL,
|
|
1591
|
+
template,
|
|
1592
|
+
componentsDir: "./components/ui",
|
|
1593
|
+
tailwindConfig: "./tailwind.config.ts",
|
|
1594
|
+
globalCss: "./globals.css"
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1574
1598
|
// src/template/template-apply.ts
|
|
1575
1599
|
async function applyTemplate(slug, options) {
|
|
1576
1600
|
const spinner = ora3(`'${slug}' \uD15C\uD50C\uB9BF \uAC00\uC838\uC624\uB294 \uC911...`).start();
|
|
@@ -1586,7 +1610,7 @@ async function applyTemplate(slug, options) {
|
|
|
1586
1610
|
const conflicts = [];
|
|
1587
1611
|
for (const file of detail.files) {
|
|
1588
1612
|
const dest = path6.join(baseDir, file.path);
|
|
1589
|
-
if (await
|
|
1613
|
+
if (await fs7.pathExists(dest)) {
|
|
1590
1614
|
conflicts.push(file.path);
|
|
1591
1615
|
}
|
|
1592
1616
|
}
|
|
@@ -1626,8 +1650,8 @@ async function applyTemplate(slug, options) {
|
|
|
1626
1650
|
const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
|
|
1627
1651
|
for (const file of detail.files) {
|
|
1628
1652
|
const dest = path6.join(baseDir, file.path);
|
|
1629
|
-
await
|
|
1630
|
-
await
|
|
1653
|
+
await fs7.ensureDir(path6.dirname(dest));
|
|
1654
|
+
await fs7.writeFile(dest, file.content);
|
|
1631
1655
|
}
|
|
1632
1656
|
writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
|
|
1633
1657
|
if (detail.postInstall?.length) {
|
|
@@ -1688,8 +1712,8 @@ async function initTemplate(slug, options) {
|
|
|
1688
1712
|
targetDir = dir;
|
|
1689
1713
|
}
|
|
1690
1714
|
const resolved = path6.resolve(targetDir);
|
|
1691
|
-
if (await
|
|
1692
|
-
const entries = await
|
|
1715
|
+
if (await fs7.pathExists(resolved)) {
|
|
1716
|
+
const entries = await fs7.readdir(resolved);
|
|
1693
1717
|
if (entries.length > 0) {
|
|
1694
1718
|
const { proceed } = await prompts({
|
|
1695
1719
|
type: "confirm",
|
|
@@ -1700,19 +1724,13 @@ async function initTemplate(slug, options) {
|
|
|
1700
1724
|
if (!proceed) return;
|
|
1701
1725
|
}
|
|
1702
1726
|
} else {
|
|
1703
|
-
await
|
|
1727
|
+
await fs7.ensureDir(resolved);
|
|
1704
1728
|
}
|
|
1705
1729
|
await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
|
|
1706
1730
|
const configPath = path6.join(resolved, "axis.config.json");
|
|
1707
|
-
if (!await
|
|
1708
|
-
const axisConfig =
|
|
1709
|
-
|
|
1710
|
-
template: selectedSlug,
|
|
1711
|
-
componentsDir: "./components/ui",
|
|
1712
|
-
tailwindConfig: "./tailwind.config.ts",
|
|
1713
|
-
globalCss: "./globals.css"
|
|
1714
|
-
};
|
|
1715
|
-
await fs6.writeJSON(configPath, axisConfig, { spaces: 2 });
|
|
1731
|
+
if (!await fs7.pathExists(configPath)) {
|
|
1732
|
+
const axisConfig = createTemplateConfig(selectedSlug);
|
|
1733
|
+
await fs7.writeJSON(configPath, axisConfig, { spaces: 2 });
|
|
1716
1734
|
console.log(chalk4.green("axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
|
|
1717
1735
|
}
|
|
1718
1736
|
console.log(chalk4.blue(`
|
|
@@ -1723,7 +1741,7 @@ async function initTemplate(slug, options) {
|
|
|
1723
1741
|
}
|
|
1724
1742
|
|
|
1725
1743
|
// src/template/template-diff.ts
|
|
1726
|
-
import
|
|
1744
|
+
import fs8 from "fs-extra";
|
|
1727
1745
|
import path7 from "path";
|
|
1728
1746
|
import chalk5 from "chalk";
|
|
1729
1747
|
import ora4 from "ora";
|
|
@@ -1741,11 +1759,11 @@ async function diffTemplate(slug, options) {
|
|
|
1741
1759
|
const entries = [];
|
|
1742
1760
|
for (const file of detail.files) {
|
|
1743
1761
|
const localPath = path7.join(baseDir, file.path);
|
|
1744
|
-
if (!await
|
|
1762
|
+
if (!await fs8.pathExists(localPath)) {
|
|
1745
1763
|
entries.push({ path: file.path, status: "added" });
|
|
1746
1764
|
continue;
|
|
1747
1765
|
}
|
|
1748
|
-
const localContent = await
|
|
1766
|
+
const localContent = await fs8.readFile(localPath, "utf-8");
|
|
1749
1767
|
if (localContent === file.content) {
|
|
1750
1768
|
entries.push({ path: file.path, status: "unchanged" });
|
|
1751
1769
|
} else {
|
|
@@ -1815,7 +1833,7 @@ async function collectLocalFiles(dir, base) {
|
|
|
1815
1833
|
const results = [];
|
|
1816
1834
|
let entries;
|
|
1817
1835
|
try {
|
|
1818
|
-
entries = await
|
|
1836
|
+
entries = await fs8.readdir(dir, { withFileTypes: true });
|
|
1819
1837
|
} catch {
|
|
1820
1838
|
return results;
|
|
1821
1839
|
}
|
|
@@ -1833,15 +1851,261 @@ async function collectLocalFiles(dir, base) {
|
|
|
1833
1851
|
}
|
|
1834
1852
|
|
|
1835
1853
|
// src/template/template-check.ts
|
|
1836
|
-
import
|
|
1854
|
+
import fs9 from "fs-extra";
|
|
1837
1855
|
import path8 from "path";
|
|
1838
1856
|
import chalk6 from "chalk";
|
|
1857
|
+
|
|
1858
|
+
// src/theme/brand-core.ts
|
|
1859
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
1860
|
+
import { createRequire } from "module";
|
|
1861
|
+
import { dirname, join, relative, resolve, sep } from "path";
|
|
1862
|
+
var TOKENS_PACKAGE = "@axis-ds/tokens";
|
|
1863
|
+
var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
1864
|
+
var MIN_BRAND_TOKENS_VERSION = "1.3.0";
|
|
1865
|
+
var KEY_TOKENS = [
|
|
1866
|
+
"--primary",
|
|
1867
|
+
"--primary-foreground",
|
|
1868
|
+
"--background",
|
|
1869
|
+
"--foreground",
|
|
1870
|
+
"--ring",
|
|
1871
|
+
"--radius",
|
|
1872
|
+
"--axis-surface-default",
|
|
1873
|
+
"--axis-text-primary",
|
|
1874
|
+
"--axis-text-brand",
|
|
1875
|
+
"--axis-button-bg-default",
|
|
1876
|
+
"--axis-border-focus",
|
|
1877
|
+
"--axis-font-family-sans"
|
|
1878
|
+
];
|
|
1879
|
+
var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
|
|
1880
|
+
function readJsonFile(file) {
|
|
1881
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
1882
|
+
}
|
|
1883
|
+
function errorCode(err) {
|
|
1884
|
+
return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
|
|
1885
|
+
}
|
|
1886
|
+
function findTokensPackageJson(baseDir) {
|
|
1887
|
+
let dir = resolve(baseDir);
|
|
1888
|
+
for (; ; ) {
|
|
1889
|
+
const candidate = join(dir, "node_modules", TOKENS_PACKAGE, "package.json");
|
|
1890
|
+
if (existsSync(candidate)) return candidate;
|
|
1891
|
+
const parent = dirname(dir);
|
|
1892
|
+
if (parent === dir) return void 0;
|
|
1893
|
+
dir = parent;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
function projectRequire(baseDir) {
|
|
1897
|
+
return createRequire(join(resolve(baseDir), "package.json"));
|
|
1898
|
+
}
|
|
1899
|
+
function tokensSpecifier(subpath) {
|
|
1900
|
+
return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
|
|
1901
|
+
}
|
|
1902
|
+
function resolveTokens(baseDir) {
|
|
1903
|
+
const pkgJson = findTokensPackageJson(baseDir);
|
|
1904
|
+
if (!pkgJson) return { status: "not-installed" };
|
|
1905
|
+
const pkg = readJsonFile(pkgJson);
|
|
1906
|
+
const version = typeof pkg.version === "string" ? pkg.version : void 0;
|
|
1907
|
+
try {
|
|
1908
|
+
const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
|
|
1909
|
+
return { status: "ok", version, indexPath };
|
|
1910
|
+
} catch (err) {
|
|
1911
|
+
const code = errorCode(err);
|
|
1912
|
+
if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
|
|
1913
|
+
if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
|
|
1914
|
+
throw err;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
function brandImportPath(entry) {
|
|
1918
|
+
return tokensSpecifier(entry.css);
|
|
1919
|
+
}
|
|
1920
|
+
var GLOBAL_CSS_CANDIDATES = ["app/globals.css", "src/app/globals.css", "globals.css"];
|
|
1921
|
+
function isFile(file) {
|
|
1922
|
+
try {
|
|
1923
|
+
return statSync(file).isFile();
|
|
1924
|
+
} catch {
|
|
1925
|
+
return false;
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
function findGlobalCss(baseDir, config) {
|
|
1929
|
+
const root = resolve(baseDir);
|
|
1930
|
+
const result = {};
|
|
1931
|
+
const configured = config?.globalCss;
|
|
1932
|
+
if (typeof configured === "string" && configured.trim() !== "") {
|
|
1933
|
+
const file = resolve(root, configured);
|
|
1934
|
+
if (isFile(file)) return { path: file };
|
|
1935
|
+
result.configuredMissing = configured;
|
|
1936
|
+
}
|
|
1937
|
+
for (const candidate of GLOBAL_CSS_CANDIDATES) {
|
|
1938
|
+
const file = join(root, candidate);
|
|
1939
|
+
if (isFile(file)) {
|
|
1940
|
+
result.path = file;
|
|
1941
|
+
break;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return result;
|
|
1945
|
+
}
|
|
1946
|
+
function findBrandImports(css) {
|
|
1947
|
+
const names = [];
|
|
1948
|
+
const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
|
|
1949
|
+
for (const m of stripComments(css).matchAll(pattern)) {
|
|
1950
|
+
names.push(m[1]);
|
|
1951
|
+
}
|
|
1952
|
+
return names;
|
|
1953
|
+
}
|
|
1954
|
+
var AXIS_CONFIG_FILE_NAME = "axis.config.json";
|
|
1955
|
+
function readBrandConfig(baseDir) {
|
|
1956
|
+
let parsed;
|
|
1957
|
+
try {
|
|
1958
|
+
parsed = JSON.parse(readFileSync(join(resolve(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
|
|
1959
|
+
} catch {
|
|
1960
|
+
return null;
|
|
1961
|
+
}
|
|
1962
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
1963
|
+
return parsed;
|
|
1964
|
+
}
|
|
1965
|
+
function inspectBrandImport(baseDir) {
|
|
1966
|
+
const config = readBrandConfig(baseDir);
|
|
1967
|
+
const brand = config?.brand;
|
|
1968
|
+
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
1969
|
+
const root = resolve(baseDir);
|
|
1970
|
+
const location = findGlobalCss(root, config);
|
|
1971
|
+
const base = { brand };
|
|
1972
|
+
if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
|
|
1973
|
+
if (!location.path) {
|
|
1974
|
+
return { ...base, state: "css-missing", imports: [] };
|
|
1975
|
+
}
|
|
1976
|
+
const cssFile = relative(root, location.path).split(sep).join("/");
|
|
1977
|
+
const imports = [...new Set(findBrandImports(readFileSync(location.path, "utf8")))];
|
|
1978
|
+
let state;
|
|
1979
|
+
if (imports.includes(brand)) state = "match";
|
|
1980
|
+
else if (imports.length === 0) state = "import-missing";
|
|
1981
|
+
else state = "other-brand";
|
|
1982
|
+
return { ...base, state, cssFile, imports };
|
|
1983
|
+
}
|
|
1984
|
+
function isMissingBuildFile(err) {
|
|
1985
|
+
const code = errorCode(err);
|
|
1986
|
+
return code === "MODULE_NOT_FOUND" || code === "ENOENT";
|
|
1987
|
+
}
|
|
1988
|
+
function readBrandIndex(indexPath) {
|
|
1989
|
+
const data = readJsonFile(indexPath);
|
|
1990
|
+
if (!Array.isArray(data.brands)) {
|
|
1991
|
+
throw new Error(`${indexPath}: "brands" \uBC30\uC5F4\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
1992
|
+
}
|
|
1993
|
+
return data.brands;
|
|
1994
|
+
}
|
|
1995
|
+
function readSummary(baseDir, entry) {
|
|
1996
|
+
const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
|
|
1997
|
+
const meta = readJsonFile(metaPath);
|
|
1998
|
+
return {
|
|
1999
|
+
name: entry.name,
|
|
2000
|
+
description: typeof meta.description === "string" ? meta.description : "",
|
|
2001
|
+
themes: Array.isArray(meta.themes) ? meta.themes.map(String) : [],
|
|
2002
|
+
a11y: typeof meta.a11y === "object" && meta.a11y !== null ? meta.a11y : {},
|
|
2003
|
+
importPath: brandImportPath(entry)
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
function listBrands(baseDir) {
|
|
2007
|
+
const tokens = resolveTokens(baseDir);
|
|
2008
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
2009
|
+
return { status: tokens.status, version: tokens.version, brands: [] };
|
|
2010
|
+
}
|
|
2011
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
2012
|
+
let brands;
|
|
2013
|
+
try {
|
|
2014
|
+
brands = entries.map((entry) => readSummary(baseDir, entry));
|
|
2015
|
+
} catch (err) {
|
|
2016
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
|
|
2017
|
+
throw err;
|
|
2018
|
+
}
|
|
2019
|
+
return { status: "ok", version: tokens.version, brands };
|
|
2020
|
+
}
|
|
2021
|
+
function stripComments(css) {
|
|
2022
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2023
|
+
}
|
|
2024
|
+
function parseDeclarations(body) {
|
|
2025
|
+
const out = {};
|
|
2026
|
+
for (const m of body.matchAll(/(--[A-Za-z0-9_-]+)\s*:\s*([^;]+);/g)) {
|
|
2027
|
+
out[m[1]] = m[2].trim();
|
|
2028
|
+
}
|
|
2029
|
+
return out;
|
|
2030
|
+
}
|
|
2031
|
+
function isDarkSelector(selector) {
|
|
2032
|
+
return /\.dark\b/.test(selector) || /\[data-theme=["']?dark["']?\]/.test(selector);
|
|
2033
|
+
}
|
|
2034
|
+
function parseBrandCss(css, name) {
|
|
2035
|
+
const result = { light: {}, dark: {} };
|
|
2036
|
+
let lightFound = false;
|
|
2037
|
+
let darkFound = false;
|
|
2038
|
+
const brandAttr = new RegExp(`\\[data-brand=["']?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']?\\]`);
|
|
2039
|
+
for (const m of stripComments(css).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
2040
|
+
const selectors = m[1].split(",").map((s) => s.trim());
|
|
2041
|
+
if (!selectors.some((s) => brandAttr.test(s))) continue;
|
|
2042
|
+
if (selectors.some(isDarkSelector)) {
|
|
2043
|
+
if (!darkFound) {
|
|
2044
|
+
result.dark = parseDeclarations(m[2]);
|
|
2045
|
+
darkFound = true;
|
|
2046
|
+
}
|
|
2047
|
+
} else if (!lightFound) {
|
|
2048
|
+
result.light = parseDeclarations(m[2]);
|
|
2049
|
+
lightFound = true;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
return result;
|
|
2053
|
+
}
|
|
2054
|
+
function pickKeyTokens(decls) {
|
|
2055
|
+
const out = {};
|
|
2056
|
+
for (const key of KEY_TOKENS) {
|
|
2057
|
+
if (Object.prototype.hasOwnProperty.call(decls, key)) out[key] = decls[key];
|
|
2058
|
+
}
|
|
2059
|
+
return out;
|
|
2060
|
+
}
|
|
2061
|
+
function providerExample(name) {
|
|
2062
|
+
return [
|
|
2063
|
+
'import { ThemeProvider } from "@axis-ds/theme";',
|
|
2064
|
+
"",
|
|
2065
|
+
`<ThemeProvider defaultBrand="${name}">{children}</ThemeProvider>`
|
|
2066
|
+
].join("\n");
|
|
2067
|
+
}
|
|
2068
|
+
function getBrand(baseDir, name) {
|
|
2069
|
+
const tokens = resolveTokens(baseDir);
|
|
2070
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
2071
|
+
return { status: tokens.status, version: tokens.version, brand: null, available: [] };
|
|
2072
|
+
}
|
|
2073
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
2074
|
+
const available = entries.map((e) => e.name);
|
|
2075
|
+
const entry = entries.find((e) => e.name === name);
|
|
2076
|
+
if (!entry) {
|
|
2077
|
+
return { status: "ok", version: tokens.version, brand: null, available };
|
|
2078
|
+
}
|
|
2079
|
+
let summary;
|
|
2080
|
+
let parsed;
|
|
2081
|
+
try {
|
|
2082
|
+
summary = readSummary(baseDir, entry);
|
|
2083
|
+
const cssPath = projectRequire(baseDir).resolve(summary.importPath);
|
|
2084
|
+
parsed = parseBrandCss(readFileSync(cssPath, "utf8"), name);
|
|
2085
|
+
} catch (err) {
|
|
2086
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
|
|
2087
|
+
throw err;
|
|
2088
|
+
}
|
|
2089
|
+
return {
|
|
2090
|
+
status: "ok",
|
|
2091
|
+
version: tokens.version,
|
|
2092
|
+
available,
|
|
2093
|
+
brand: {
|
|
2094
|
+
...summary,
|
|
2095
|
+
tokens: { light: pickKeyTokens(parsed.light), dark: pickKeyTokens(parsed.dark) },
|
|
2096
|
+
providerExample: providerExample(name),
|
|
2097
|
+
adjustments: { a11y: summary.a11y, reference: BRAND_ADJUSTMENT_REFERENCE }
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
// src/template/template-check.ts
|
|
1839
2103
|
var SEVERITY_ICON = {
|
|
1840
2104
|
pass: chalk6.green("PASS"),
|
|
1841
2105
|
warn: chalk6.yellow("WARN"),
|
|
1842
2106
|
fail: chalk6.red("FAIL")
|
|
1843
2107
|
};
|
|
1844
|
-
async function
|
|
2108
|
+
async function collectCheckResults(dir) {
|
|
1845
2109
|
const baseDir = path8.resolve(dir || ".");
|
|
1846
2110
|
const results = [];
|
|
1847
2111
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
@@ -1849,6 +2113,12 @@ async function runCheck(dir) {
|
|
|
1849
2113
|
results.push(await checkGlobalsCss(baseDir));
|
|
1850
2114
|
results.push(await checkUtils(baseDir));
|
|
1851
2115
|
results.push(await checkDependencies(baseDir));
|
|
2116
|
+
const brand = checkBrand(baseDir);
|
|
2117
|
+
if (brand) results.push(brand);
|
|
2118
|
+
return results;
|
|
2119
|
+
}
|
|
2120
|
+
async function runCheck(dir) {
|
|
2121
|
+
const results = await collectCheckResults(dir);
|
|
1852
2122
|
console.log(chalk6.blue("\nAXIS \uD504\uB85C\uC81D\uD2B8 \uAC80\uC99D \uACB0\uACFC:\n"));
|
|
1853
2123
|
let passCount = 0;
|
|
1854
2124
|
let warnCount = 0;
|
|
@@ -1880,7 +2150,7 @@ async function runCheck(dir) {
|
|
|
1880
2150
|
}
|
|
1881
2151
|
}
|
|
1882
2152
|
async function checkFileExists(baseDir, fileName, label) {
|
|
1883
|
-
const exists = await
|
|
2153
|
+
const exists = await fs9.pathExists(path8.join(baseDir, fileName));
|
|
1884
2154
|
return {
|
|
1885
2155
|
name: label,
|
|
1886
2156
|
severity: exists ? "pass" : "fail",
|
|
@@ -1890,8 +2160,8 @@ async function checkFileExists(baseDir, fileName, label) {
|
|
|
1890
2160
|
async function checkTailwindConfig(baseDir) {
|
|
1891
2161
|
const tsPath = path8.join(baseDir, "tailwind.config.ts");
|
|
1892
2162
|
const jsPath = path8.join(baseDir, "tailwind.config.js");
|
|
1893
|
-
if (await
|
|
1894
|
-
const content = await
|
|
2163
|
+
if (await fs9.pathExists(tsPath)) {
|
|
2164
|
+
const content = await fs9.readFile(tsPath, "utf-8");
|
|
1895
2165
|
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
1896
2166
|
return {
|
|
1897
2167
|
name: "tailwind.config",
|
|
@@ -1899,7 +2169,7 @@ async function checkTailwindConfig(baseDir) {
|
|
|
1899
2169
|
message: hasTokens ? "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" : "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
1900
2170
|
};
|
|
1901
2171
|
}
|
|
1902
|
-
if (await
|
|
2172
|
+
if (await fs9.pathExists(jsPath)) {
|
|
1903
2173
|
return {
|
|
1904
2174
|
name: "tailwind.config",
|
|
1905
2175
|
severity: "warn",
|
|
@@ -1922,8 +2192,8 @@ async function checkGlobalsCss(baseDir) {
|
|
|
1922
2192
|
];
|
|
1923
2193
|
for (const candidate of candidates) {
|
|
1924
2194
|
const fullPath = path8.join(baseDir, candidate);
|
|
1925
|
-
if (await
|
|
1926
|
-
const content = await
|
|
2195
|
+
if (await fs9.pathExists(fullPath)) {
|
|
2196
|
+
const content = await fs9.readFile(fullPath, "utf-8");
|
|
1927
2197
|
const hasTokens = content.includes("--background") && content.includes("--primary");
|
|
1928
2198
|
return {
|
|
1929
2199
|
name: "globals.css",
|
|
@@ -1948,8 +2218,8 @@ async function checkUtils(baseDir) {
|
|
|
1948
2218
|
];
|
|
1949
2219
|
for (const candidate of candidates) {
|
|
1950
2220
|
const fullPath = path8.join(baseDir, candidate);
|
|
1951
|
-
if (await
|
|
1952
|
-
const content = await
|
|
2221
|
+
if (await fs9.pathExists(fullPath)) {
|
|
2222
|
+
const content = await fs9.readFile(fullPath, "utf-8");
|
|
1953
2223
|
const hasCn = content.includes("function cn");
|
|
1954
2224
|
return {
|
|
1955
2225
|
name: "utils.ts",
|
|
@@ -1966,14 +2236,14 @@ async function checkUtils(baseDir) {
|
|
|
1966
2236
|
}
|
|
1967
2237
|
async function checkDependencies(baseDir) {
|
|
1968
2238
|
const pkgPath = path8.join(baseDir, "package.json");
|
|
1969
|
-
if (!await
|
|
2239
|
+
if (!await fs9.pathExists(pkgPath)) {
|
|
1970
2240
|
return {
|
|
1971
2241
|
name: "package.json",
|
|
1972
2242
|
severity: "fail",
|
|
1973
2243
|
message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
1974
2244
|
};
|
|
1975
2245
|
}
|
|
1976
|
-
const pkg = await
|
|
2246
|
+
const pkg = await fs9.readJSON(pkgPath);
|
|
1977
2247
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1978
2248
|
const required = ["tailwindcss"];
|
|
1979
2249
|
const recommended = ["clsx", "tailwind-merge"];
|
|
@@ -1999,6 +2269,40 @@ async function checkDependencies(baseDir) {
|
|
|
1999
2269
|
message: "\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uBAA8\uB450 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4"
|
|
2000
2270
|
};
|
|
2001
2271
|
}
|
|
2272
|
+
function checkBrand(baseDir) {
|
|
2273
|
+
const check = inspectBrandImport(baseDir);
|
|
2274
|
+
return check ? brandCheckResult(check) : null;
|
|
2275
|
+
}
|
|
2276
|
+
function brandCheckResult(check) {
|
|
2277
|
+
const { brand } = check;
|
|
2278
|
+
const suffix = check.configuredMissing !== void 0 ? ` (globalCss ${check.configuredMissing} \uC5C6\uC74C)` : "";
|
|
2279
|
+
switch (check.state) {
|
|
2280
|
+
case "match":
|
|
2281
|
+
return {
|
|
2282
|
+
name: "brand",
|
|
2283
|
+
severity: "pass",
|
|
2284
|
+
message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC788\uC2B5\uB2C8\uB2E4${suffix}`
|
|
2285
|
+
};
|
|
2286
|
+
case "css-missing":
|
|
2287
|
+
return {
|
|
2288
|
+
name: "brand",
|
|
2289
|
+
severity: "warn",
|
|
2290
|
+
message: `brand "${brand}" \uAC00 \uC124\uC815\uB410\uC9C0\uB9CC CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4${suffix}`
|
|
2291
|
+
};
|
|
2292
|
+
case "import-missing":
|
|
2293
|
+
return {
|
|
2294
|
+
name: "brand",
|
|
2295
|
+
severity: "warn",
|
|
2296
|
+
message: `brand "${brand}" import \uAC00 ${check.cssFile}\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 'axis theme add ${brand}'${suffix}`
|
|
2297
|
+
};
|
|
2298
|
+
case "other-brand":
|
|
2299
|
+
return {
|
|
2300
|
+
name: "brand",
|
|
2301
|
+
severity: "warn",
|
|
2302
|
+
message: `brand "${brand}" \uC640 import(${check.imports.join(", ")})\uAC00 \uB2E4\uB985\uB2C8\uB2E4${suffix}`
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2002
2306
|
|
|
2003
2307
|
// src/template/index.ts
|
|
2004
2308
|
function registerTemplateCommand(program2) {
|
|
@@ -2102,12 +2406,592 @@ function registerCheckCommand(program2) {
|
|
|
2102
2406
|
});
|
|
2103
2407
|
}
|
|
2104
2408
|
|
|
2409
|
+
// src/theme/index.ts
|
|
2410
|
+
import chalk8 from "chalk";
|
|
2411
|
+
import path10 from "path";
|
|
2412
|
+
|
|
2413
|
+
// src/theme/theme-add.ts
|
|
2414
|
+
import { accessSync, constants, existsSync as existsSync2, readFileSync as readFileSync2, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
2415
|
+
import path9 from "path";
|
|
2416
|
+
var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
|
|
2417
|
+
var THEME_PACKAGE = "@axis-ds/theme";
|
|
2418
|
+
function readText(file) {
|
|
2419
|
+
return existsSync2(file) ? readFileSync2(file, "utf8") : null;
|
|
2420
|
+
}
|
|
2421
|
+
function eolOf(text) {
|
|
2422
|
+
return text.includes("\r\n") ? "\r\n" : "\n";
|
|
2423
|
+
}
|
|
2424
|
+
function indentOf(text) {
|
|
2425
|
+
const m = /\n([ \t]+)\S/.exec(text);
|
|
2426
|
+
if (!m) return 2;
|
|
2427
|
+
return m[1].includes(" ") ? " " : m[1].length;
|
|
2428
|
+
}
|
|
2429
|
+
function formatJsonLike(original, value) {
|
|
2430
|
+
const eol = eolOf(original);
|
|
2431
|
+
const endsWithNewline = /\r?\n$/.test(original);
|
|
2432
|
+
let out = JSON.stringify(value, null, indentOf(original));
|
|
2433
|
+
if (eol === "\r\n") out = out.replace(/\n/g, "\r\n");
|
|
2434
|
+
return endsWithNewline ? out + eol : out;
|
|
2435
|
+
}
|
|
2436
|
+
function insertImportLine(css, line) {
|
|
2437
|
+
const bom = css.startsWith("\uFEFF") ? "\uFEFF" : "";
|
|
2438
|
+
const body = bom ? css.slice(1) : css;
|
|
2439
|
+
const eol = eolOf(body);
|
|
2440
|
+
const lines = body.split(/\r?\n/);
|
|
2441
|
+
let insertAt = 0;
|
|
2442
|
+
let inComment = false;
|
|
2443
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2444
|
+
let rest = lines[i].trim();
|
|
2445
|
+
if (inComment) {
|
|
2446
|
+
const end = rest.indexOf("*/");
|
|
2447
|
+
if (end === -1) continue;
|
|
2448
|
+
inComment = false;
|
|
2449
|
+
rest = rest.slice(end + 2).trim();
|
|
2450
|
+
}
|
|
2451
|
+
while (rest.startsWith("/*")) {
|
|
2452
|
+
const end = rest.indexOf("*/", 2);
|
|
2453
|
+
if (end === -1) {
|
|
2454
|
+
inComment = true;
|
|
2455
|
+
rest = "";
|
|
2456
|
+
break;
|
|
2457
|
+
}
|
|
2458
|
+
rest = rest.slice(end + 2).trim();
|
|
2459
|
+
}
|
|
2460
|
+
if (rest === "") continue;
|
|
2461
|
+
if (/^@(charset|import)\b/i.test(rest)) {
|
|
2462
|
+
insertAt = i + 1;
|
|
2463
|
+
continue;
|
|
2464
|
+
}
|
|
2465
|
+
break;
|
|
2466
|
+
}
|
|
2467
|
+
lines.splice(insertAt, 0, line);
|
|
2468
|
+
return bom + lines.join(eol);
|
|
2469
|
+
}
|
|
2470
|
+
function compareVersions(a, b) {
|
|
2471
|
+
const parse = (v) => {
|
|
2472
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(v.trim());
|
|
2473
|
+
return m ? { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: Boolean(m[4]) } : void 0;
|
|
2474
|
+
};
|
|
2475
|
+
const pa = parse(a);
|
|
2476
|
+
const pb = parse(b);
|
|
2477
|
+
if (!pa || !pb) return void 0;
|
|
2478
|
+
for (let i = 0; i < 3; i++) {
|
|
2479
|
+
if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1;
|
|
2480
|
+
}
|
|
2481
|
+
if (pa.pre !== pb.pre) return pa.pre ? -1 : 1;
|
|
2482
|
+
return 0;
|
|
2483
|
+
}
|
|
2484
|
+
function realPathInside(baseDir, file) {
|
|
2485
|
+
const realBase = realpathSync(baseDir);
|
|
2486
|
+
const realPath = realpathSync(file);
|
|
2487
|
+
const relPath = path9.relative(realBase, realPath);
|
|
2488
|
+
const inside = relPath !== "" && !relPath.startsWith("..") && !path9.isAbsolute(relPath);
|
|
2489
|
+
return { inside, realPath };
|
|
2490
|
+
}
|
|
2491
|
+
function isStylesheet(realPath) {
|
|
2492
|
+
return path9.extname(realPath).toLowerCase() === ".css";
|
|
2493
|
+
}
|
|
2494
|
+
function detectInstallCommand(baseDir) {
|
|
2495
|
+
if (existsSync2(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
2496
|
+
if (existsSync2(path9.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
2497
|
+
if (existsSync2(path9.join(baseDir, "package-lock.json"))) return "npm install";
|
|
2498
|
+
return "pnpm install";
|
|
2499
|
+
}
|
|
2500
|
+
function hasDependency(pkg, name) {
|
|
2501
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
2502
|
+
const deps = pkg[field];
|
|
2503
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
2504
|
+
return String(deps[name]);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
return void 0;
|
|
2508
|
+
}
|
|
2509
|
+
function isPlainObject(value) {
|
|
2510
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2511
|
+
}
|
|
2512
|
+
function planThemeAdd(baseDirInput, brand) {
|
|
2513
|
+
const baseDir = path9.resolve(baseDirInput);
|
|
2514
|
+
const plan = {
|
|
2515
|
+
baseDir,
|
|
2516
|
+
brand,
|
|
2517
|
+
importPath: brandImportPath({ css: `./css/brands/${brand}` }),
|
|
2518
|
+
tokens: { status: "not-installed" },
|
|
2519
|
+
errors: [],
|
|
2520
|
+
unverifiedBrand: false,
|
|
2521
|
+
configChanged: false,
|
|
2522
|
+
installCommand: detectInstallCommand(baseDir),
|
|
2523
|
+
writes: []
|
|
2524
|
+
};
|
|
2525
|
+
const configFile = path9.join(baseDir, AXIS_CONFIG_FILE);
|
|
2526
|
+
const configText = readText(configFile);
|
|
2527
|
+
if (configText === null) {
|
|
2528
|
+
plan.errors.push({ kind: "no-config" });
|
|
2529
|
+
return plan;
|
|
2530
|
+
}
|
|
2531
|
+
let config;
|
|
2532
|
+
try {
|
|
2533
|
+
const parsed = JSON.parse(configText);
|
|
2534
|
+
if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2535
|
+
config = parsed;
|
|
2536
|
+
} catch (err) {
|
|
2537
|
+
plan.errors.push({ kind: "invalid-config", message: err.message });
|
|
2538
|
+
return plan;
|
|
2539
|
+
}
|
|
2540
|
+
if (!BRAND_NAME_PATTERN.test(brand)) {
|
|
2541
|
+
plan.errors.push({ kind: "invalid-name", brand });
|
|
2542
|
+
return plan;
|
|
2543
|
+
}
|
|
2544
|
+
plan.tokens = resolveTokens(baseDir);
|
|
2545
|
+
if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
|
|
2546
|
+
const data = JSON.parse(readFileSync2(plan.tokens.indexPath, "utf8"));
|
|
2547
|
+
const entries = Array.isArray(data.brands) ? data.brands : [];
|
|
2548
|
+
const entry = entries.find((e) => e.name === brand);
|
|
2549
|
+
if (!entry) {
|
|
2550
|
+
plan.errors.push({
|
|
2551
|
+
kind: "unknown-brand",
|
|
2552
|
+
brand,
|
|
2553
|
+
available: entries.map((e) => e.name),
|
|
2554
|
+
version: plan.tokens.version
|
|
2555
|
+
});
|
|
2556
|
+
return plan;
|
|
2557
|
+
}
|
|
2558
|
+
plan.importPath = brandImportPath(entry);
|
|
2559
|
+
} else {
|
|
2560
|
+
plan.unverifiedBrand = true;
|
|
2561
|
+
}
|
|
2562
|
+
const location = findGlobalCss(baseDir, config);
|
|
2563
|
+
if (location.path) {
|
|
2564
|
+
const where = realPathInside(baseDir, location.path);
|
|
2565
|
+
if (!where.inside) {
|
|
2566
|
+
plan.errors.push({ kind: "css-outside-project", file: location.path, realPath: where.realPath });
|
|
2567
|
+
plan.writes = [];
|
|
2568
|
+
return plan;
|
|
2569
|
+
}
|
|
2570
|
+
if (!isStylesheet(where.realPath)) {
|
|
2571
|
+
plan.errors.push({ kind: "css-not-stylesheet", file: location.path, realPath: where.realPath });
|
|
2572
|
+
plan.writes = [];
|
|
2573
|
+
return plan;
|
|
2574
|
+
}
|
|
2575
|
+
const before = readFileSync2(location.path, "utf8");
|
|
2576
|
+
const imported = findBrandImports(before);
|
|
2577
|
+
const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
|
|
2578
|
+
if (imported.includes(brand)) {
|
|
2579
|
+
plan.css = { file: location.path, configuredMissing: location.configuredMissing, action: "exists", otherBrands };
|
|
2580
|
+
} else {
|
|
2581
|
+
plan.css = { file: location.path, configuredMissing: location.configuredMissing, action: "add", otherBrands };
|
|
2582
|
+
plan.writes.push({
|
|
2583
|
+
file: location.path,
|
|
2584
|
+
before,
|
|
2585
|
+
after: insertImportLine(before, `@import "${plan.importPath}";`)
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
} else {
|
|
2589
|
+
plan.css = { configuredMissing: location.configuredMissing, action: "manual", otherBrands: [] };
|
|
2590
|
+
}
|
|
2591
|
+
const pkgFile = path9.join(baseDir, "package.json");
|
|
2592
|
+
const pkgText = readText(pkgFile);
|
|
2593
|
+
const installed = plan.tokens.version;
|
|
2594
|
+
const upgrade = installed !== void 0 && (compareVersions(installed, MIN_BRAND_TOKENS_VERSION) ?? 0) < 0;
|
|
2595
|
+
if (pkgText === null) {
|
|
2596
|
+
plan.dependency = { action: "no-package-json", upgrade, themeMissing: false };
|
|
2597
|
+
} else {
|
|
2598
|
+
let pkg;
|
|
2599
|
+
try {
|
|
2600
|
+
const parsed = JSON.parse(pkgText);
|
|
2601
|
+
if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2602
|
+
pkg = parsed;
|
|
2603
|
+
} catch (err) {
|
|
2604
|
+
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
2605
|
+
plan.writes = [];
|
|
2606
|
+
return plan;
|
|
2607
|
+
}
|
|
2608
|
+
const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
|
|
2609
|
+
const declared = hasDependency(pkg, TOKENS_PACKAGE);
|
|
2610
|
+
if (declared !== void 0) {
|
|
2611
|
+
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
|
|
2612
|
+
} else {
|
|
2613
|
+
const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
|
|
2614
|
+
deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
|
|
2615
|
+
const next = { ...pkg, dependencies: deps };
|
|
2616
|
+
plan.dependency = { action: "add", upgrade, themeMissing };
|
|
2617
|
+
plan.writes.push({ file: pkgFile, before: pkgText, after: formatJsonLike(pkgText, next) });
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (config.brand !== brand) {
|
|
2621
|
+
plan.configChanged = true;
|
|
2622
|
+
plan.writes.push({
|
|
2623
|
+
file: configFile,
|
|
2624
|
+
before: configText,
|
|
2625
|
+
after: formatJsonLike(configText, { ...config, brand })
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
return plan;
|
|
2629
|
+
}
|
|
2630
|
+
var ThemeApplyError = class extends Error {
|
|
2631
|
+
constructor(message, failedFile, restored, restoreFailed) {
|
|
2632
|
+
super(message);
|
|
2633
|
+
this.failedFile = failedFile;
|
|
2634
|
+
this.restored = restored;
|
|
2635
|
+
this.restoreFailed = restoreFailed;
|
|
2636
|
+
this.name = "ThemeApplyError";
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
function errorMessage(err) {
|
|
2640
|
+
return err instanceof Error ? err.message : String(err);
|
|
2641
|
+
}
|
|
2642
|
+
function applyThemeAdd(plan) {
|
|
2643
|
+
if (plan.errors.length > 0) {
|
|
2644
|
+
throw new Error("\uC624\uB958\uAC00 \uC788\uB294 \uACC4\uD68D\uC740 \uC801\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
2645
|
+
}
|
|
2646
|
+
for (const w of plan.writes) {
|
|
2647
|
+
const current = readText(w.file);
|
|
2648
|
+
if (current !== w.before) {
|
|
2649
|
+
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
2650
|
+
}
|
|
2651
|
+
const where = realPathInside(plan.baseDir, w.before === null ? path9.dirname(w.file) : w.file);
|
|
2652
|
+
if (!where.inside && !(w.before === null && path9.dirname(w.file) === plan.baseDir)) {
|
|
2653
|
+
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.`);
|
|
2654
|
+
}
|
|
2655
|
+
if (!w.file.endsWith(".json") && !isStylesheet(where.realPath)) {
|
|
2656
|
+
throw new Error(`${w.file} \uC758 \uC2E4\uC81C \uB300\uC0C1(${where.realPath})\uC774 CSS \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uC4F0\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`);
|
|
2657
|
+
}
|
|
2658
|
+
if (w.file.endsWith(".json")) {
|
|
2659
|
+
JSON.parse(w.after);
|
|
2660
|
+
} else if (findBrandImports(w.after).filter((n) => n === plan.brand).length !== 1) {
|
|
2661
|
+
throw new Error(`${w.file}: \uBE0C\uB79C\uB4DC import \uAC00 \uC815\uD655\uD788 1\uC904\uC774 \uC544\uB2D9\uB2C8\uB2E4`);
|
|
2662
|
+
}
|
|
2663
|
+
try {
|
|
2664
|
+
accessSync(w.before === null ? path9.dirname(w.file) : w.file, constants.W_OK);
|
|
2665
|
+
} catch (err) {
|
|
2666
|
+
throw new Error(`${w.file} \uC5D0 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errorMessage(err)}).`);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
const done = [];
|
|
2670
|
+
for (const w of plan.writes) {
|
|
2671
|
+
try {
|
|
2672
|
+
writeFileSync(w.file, w.after);
|
|
2673
|
+
done.push(w);
|
|
2674
|
+
} catch (err) {
|
|
2675
|
+
const restored = [];
|
|
2676
|
+
const restoreFailed = [];
|
|
2677
|
+
for (const d of done.reverse()) {
|
|
2678
|
+
try {
|
|
2679
|
+
if (d.before === null) unlinkSync(d.file);
|
|
2680
|
+
else writeFileSync(d.file, d.before);
|
|
2681
|
+
restored.push(d.file);
|
|
2682
|
+
} catch {
|
|
2683
|
+
restoreFailed.push(d.file);
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
throw new ThemeApplyError(
|
|
2687
|
+
`${w.file} \uB97C \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errorMessage(err)}).`,
|
|
2688
|
+
w.file,
|
|
2689
|
+
restored,
|
|
2690
|
+
restoreFailed
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
return done.map((w) => w.file);
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
// src/theme/index.ts
|
|
2698
|
+
var TOKENS_INSTALL_COMMAND = `pnpm add ${TOKENS_PACKAGE}@^${MIN_BRAND_TOKENS_VERSION}`;
|
|
2699
|
+
function tokensStatusGuide(status, version) {
|
|
2700
|
+
switch (status) {
|
|
2701
|
+
case "not-installed":
|
|
2702
|
+
return [
|
|
2703
|
+
chalk8.yellow(`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`),
|
|
2704
|
+
` \uC124\uCE58: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
|
|
2705
|
+
];
|
|
2706
|
+
case "unsupported":
|
|
2707
|
+
return [
|
|
2708
|
+
chalk8.yellow(
|
|
2709
|
+
`${TOKENS_PACKAGE} ${version ?? "(\uBC84\uC804 \uBAA8\uB984)"} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
|
|
2710
|
+
),
|
|
2711
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
|
|
2712
|
+
];
|
|
2713
|
+
case "not-built":
|
|
2714
|
+
return [
|
|
2715
|
+
chalk8.yellow(
|
|
2716
|
+
`${TOKENS_PACKAGE}${version ? ` ${version}` : ""} \uB294 \uC788\uC9C0\uB9CC \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC5B4 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
2717
|
+
),
|
|
2718
|
+
` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk8.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
|
|
2719
|
+
];
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
function renderThemeList(result) {
|
|
2723
|
+
if (result.status !== "ok") {
|
|
2724
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
2725
|
+
}
|
|
2726
|
+
if (result.brands.length === 0) {
|
|
2727
|
+
return {
|
|
2728
|
+
lines: ["", chalk8.yellow(`\uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${result.version ?? ""} \uC5D0 \uBE0C\uB79C\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`), ""],
|
|
2729
|
+
exitCode: 0
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
const width = Math.max(...result.brands.map((b) => b.name.length));
|
|
2733
|
+
const lines = [
|
|
2734
|
+
"",
|
|
2735
|
+
chalk8.blue(`AXIS \uBE0C\uB79C\uB4DC (${result.brands.length}\uAC1C, ${TOKENS_PACKAGE} ${result.version ?? ""})`),
|
|
2736
|
+
""
|
|
2737
|
+
];
|
|
2738
|
+
for (const b of result.brands) {
|
|
2739
|
+
lines.push(
|
|
2740
|
+
` ${chalk8.cyan(b.name.padEnd(width))} ${b.description} ${chalk8.gray(`(${b.themes.join(" \xB7 ")})`)}`
|
|
2741
|
+
);
|
|
2742
|
+
}
|
|
2743
|
+
lines.push("", chalk8.gray("\uC0AC\uC6A9\uBC95: axis theme info <brand>"), "");
|
|
2744
|
+
return { lines, exitCode: 0 };
|
|
2745
|
+
}
|
|
2746
|
+
function a11yValue(value) {
|
|
2747
|
+
return value === null || value === void 0 || value === "" ? "-" : String(value);
|
|
2748
|
+
}
|
|
2749
|
+
function tokenTable(brand) {
|
|
2750
|
+
const rows = KEY_TOKENS.filter(
|
|
2751
|
+
(k) => k in brand.tokens.light || k in brand.tokens.dark
|
|
2752
|
+
).map((k) => [k, brand.tokens.light[k] ?? "-", brand.tokens.dark[k] ?? "-"]);
|
|
2753
|
+
const missing = KEY_TOKENS.filter((k) => !(k in brand.tokens.light) && !(k in brand.tokens.dark));
|
|
2754
|
+
const lines = [];
|
|
2755
|
+
if (rows.length > 0) {
|
|
2756
|
+
const header = ["\uD1A0\uD070", "\uB77C\uC774\uD2B8", "\uB2E4\uD06C"];
|
|
2757
|
+
const w0 = Math.max(header[0].length, ...rows.map((r) => r[0].length));
|
|
2758
|
+
const w1 = Math.max(header[1].length, ...rows.map((r) => r[1].length));
|
|
2759
|
+
lines.push(chalk8.gray(` ${header[0].padEnd(w0)} ${header[1].padEnd(w1)} ${header[2]}`));
|
|
2760
|
+
for (const [k, l, d] of rows) {
|
|
2761
|
+
lines.push(` ${k.padEnd(w0)} ${l.padEnd(w1)} ${d}`);
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
if (missing.length > 0) {
|
|
2765
|
+
lines.push(chalk8.gray(` \uBE0C\uB79C\uB4DC\uAC00 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC74C: ${missing.join(", ")}`));
|
|
2766
|
+
}
|
|
2767
|
+
return lines;
|
|
2768
|
+
}
|
|
2769
|
+
function renderThemeInfo(result, name) {
|
|
2770
|
+
if (result.status !== "ok") {
|
|
2771
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
2772
|
+
}
|
|
2773
|
+
const brand = result.brand;
|
|
2774
|
+
if (!brand) {
|
|
2775
|
+
return {
|
|
2776
|
+
lines: [
|
|
2777
|
+
"",
|
|
2778
|
+
chalk8.red(`\uBE0C\uB79C\uB4DC '${name}' \uAC00 \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${result.version ?? ""} \uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.`),
|
|
2779
|
+
` \uC124\uCE58\uB41C \uBE0C\uB79C\uB4DC: ${result.available.length > 0 ? result.available.join(", ") : "(\uC5C6\uC74C)"}`,
|
|
2780
|
+
chalk8.gray(" \uBAA9\uB85D: axis theme list"),
|
|
2781
|
+
""
|
|
2782
|
+
],
|
|
2783
|
+
exitCode: 1
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
const lines = [
|
|
2787
|
+
"",
|
|
2788
|
+
chalk8.blue(`\uBE0C\uB79C\uB4DC ${brand.name}`),
|
|
2789
|
+
` \uC124\uBA85: ${brand.description}`,
|
|
2790
|
+
` \uD14C\uB9C8: ${brand.themes.join(" \xB7 ")}`,
|
|
2791
|
+
"",
|
|
2792
|
+
chalk8.bold("Import (globals.css, @charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)"),
|
|
2793
|
+
` @import "${brand.importPath}";`,
|
|
2794
|
+
"",
|
|
2795
|
+
chalk8.bold("Provider (@axis-ds/theme 1.3.0 \uC774\uC0C1)"),
|
|
2796
|
+
...brand.providerExample.split("\n").map((l) => l ? ` ${l}` : ""),
|
|
2797
|
+
chalk8.gray(
|
|
2798
|
+
` ThemeProvider \uB098 <html data-brand="${brand.name}"> \uAC00 \uC5C6\uC73C\uBA74 import \uB9CC\uC73C\uB85C\uB294 \uD654\uBA74\uC774 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
|
|
2799
|
+
),
|
|
2800
|
+
"",
|
|
2801
|
+
chalk8.bold("\uC8FC\uC694 \uD1A0\uD070"),
|
|
2802
|
+
...tokenTable(brand),
|
|
2803
|
+
"",
|
|
2804
|
+
chalk8.bold("\uBCF4\uC815 \uB0B4\uC5ED"),
|
|
2805
|
+
` a11y \uC0C1\uD0DC: ${a11yValue(brand.adjustments.a11y.status)}`,
|
|
2806
|
+
` \uC810\uAC80\uC77C: ${a11yValue(brand.adjustments.a11y.checkedAt)}`,
|
|
2807
|
+
` \uAC8C\uC774\uD2B8: ${a11yValue(brand.adjustments.a11y.gate)}`,
|
|
2808
|
+
` \uADFC\uAC70 \uBB38\uC11C: ${brand.adjustments.reference}`,
|
|
2809
|
+
chalk8.gray(" \uBCF4\uC815 \uC804 \xB7 \uD6C4 \uAC12\uC740 \uC774 \uBC84\uC804\uC5D0\uC11C \uCD9C\uB825\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."),
|
|
2810
|
+
""
|
|
2811
|
+
];
|
|
2812
|
+
return { lines, exitCode: 0 };
|
|
2813
|
+
}
|
|
2814
|
+
function rel(plan, file) {
|
|
2815
|
+
return path10.relative(plan.baseDir, file) || file;
|
|
2816
|
+
}
|
|
2817
|
+
function renderThemeAdd(plan, written) {
|
|
2818
|
+
const error = plan.errors[0];
|
|
2819
|
+
if (error) {
|
|
2820
|
+
const lines2 = [""];
|
|
2821
|
+
switch (error.kind) {
|
|
2822
|
+
case "no-config":
|
|
2823
|
+
lines2.push(
|
|
2824
|
+
chalk8.red("axis.config.json \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."),
|
|
2825
|
+
` \uBA3C\uC800 ${chalk8.cyan("axis init")} \uC744 \uC2E4\uD589\uD558\uC138\uC694.`
|
|
2826
|
+
);
|
|
2827
|
+
break;
|
|
2828
|
+
case "invalid-config":
|
|
2829
|
+
lines2.push(chalk8.red(`axis.config.json \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${error.message}). \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
|
|
2830
|
+
break;
|
|
2831
|
+
case "invalid-package-json":
|
|
2832
|
+
lines2.push(chalk8.red(`package.json \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${error.message}). \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
|
|
2833
|
+
break;
|
|
2834
|
+
case "invalid-name":
|
|
2835
|
+
lines2.push(
|
|
2836
|
+
chalk8.red(`\uBE0C\uB79C\uB4DC \uC774\uB984 '${error.brand}' \uAC00 \uADDC\uCE59(\uC18C\uBB38\uC790 \xB7 \uC22B\uC790 \xB7 \uD558\uC774\uD508, \uC608: ontology)\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`)
|
|
2837
|
+
);
|
|
2838
|
+
break;
|
|
2839
|
+
case "css-outside-project":
|
|
2840
|
+
lines2.push(
|
|
2841
|
+
chalk8.red(
|
|
2842
|
+
`CSS \uD30C\uC77C ${error.file} \uC758 \uC2E4\uC81C \uC704\uCE58(${error.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
|
|
2843
|
+
),
|
|
2844
|
+
` axis.config.json \uC758 globalCss \uB97C \uD504\uB85C\uC81D\uD2B8 \uC548 \uD30C\uC77C\uB85C \uACE0\uCE58\uAC70\uB098, \uADF8 \uD30C\uC77C\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
|
|
2845
|
+
);
|
|
2846
|
+
break;
|
|
2847
|
+
case "css-not-stylesheet":
|
|
2848
|
+
lines2.push(
|
|
2849
|
+
chalk8.red(`${error.file} \uC758 \uC2E4\uC81C \uB300\uC0C1(${error.realPath})\uC774 CSS \uD30C\uC77C(.css)\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`),
|
|
2850
|
+
` axis.config.json \uC758 globalCss \uB97C \uC804\uC5ED CSS \uD30C\uC77C\uB85C \uACE0\uCE58\uAC70\uB098, \uADF8 \uD30C\uC77C\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
|
|
2851
|
+
);
|
|
2852
|
+
break;
|
|
2853
|
+
case "unknown-brand":
|
|
2854
|
+
lines2.push(
|
|
2855
|
+
chalk8.red(`\uBE0C\uB79C\uB4DC '${error.brand}' \uAC00 \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${error.version ?? ""} \uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.`),
|
|
2856
|
+
` \uC124\uCE58\uB41C \uBE0C\uB79C\uB4DC: ${error.available.length > 0 ? error.available.join(", ") : "(\uC5C6\uC74C)"}`,
|
|
2857
|
+
chalk8.gray(" \uBAA9\uB85D: axis theme list")
|
|
2858
|
+
);
|
|
2859
|
+
break;
|
|
2860
|
+
}
|
|
2861
|
+
lines2.push("");
|
|
2862
|
+
return { lines: lines2, exitCode: 1 };
|
|
2863
|
+
}
|
|
2864
|
+
const lines = ["", chalk8.blue(`\uBE0C\uB79C\uB4DC ${plan.brand} \uC801\uC6A9`), ""];
|
|
2865
|
+
if (plan.unverifiedBrand) {
|
|
2866
|
+
lines.push(
|
|
2867
|
+
chalk8.yellow(
|
|
2868
|
+
` ! ${TOKENS_PACKAGE} \uB97C \uC77D\uC744 \uC218 \uC5C6\uC5B4(${plan.tokens.status}) \uC774\uB984 \uADDC\uCE59\uB9CC \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4. \uC124\uCE58 \uD6C4 axis theme list \uB85C '${plan.brand}' \uAC00 \uC788\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
|
|
2869
|
+
)
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
const css = plan.css;
|
|
2873
|
+
if (css?.configuredMissing) {
|
|
2874
|
+
lines.push(
|
|
2875
|
+
chalk8.yellow(
|
|
2876
|
+
css.file ? ` ! axis.config.json \uC758 globalCss(${css.configuredMissing})\uAC00 \uC5C6\uC5B4 ${rel(plan, css.file)} \uC5D0 \uCD94\uAC00\uD569\uB2C8\uB2E4.` : ` ! axis.config.json \uC758 globalCss(${css.configuredMissing})\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
2877
|
+
)
|
|
2878
|
+
);
|
|
2879
|
+
}
|
|
2880
|
+
if (css?.action === "add" && css.file) {
|
|
2881
|
+
lines.push(` ${chalk8.green("\u2713")} ${rel(plan, css.file)}: @import "${plan.importPath}"; \uCD94\uAC00`);
|
|
2882
|
+
} else if (css?.action === "exists" && css.file) {
|
|
2883
|
+
lines.push(` ${chalk8.gray("-")} ${rel(plan, css.file)}: import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
|
|
2884
|
+
} else {
|
|
2885
|
+
lines.push(
|
|
2886
|
+
chalk8.yellow(" ! CSS \uC9C4\uC785\uC810(globalCss \xB7 app/globals.css \xB7 src/app/globals.css \xB7 globals.css)\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."),
|
|
2887
|
+
` \uC804\uC5ED CSS \uB9E8 \uC55E(@charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694: @import "${plan.importPath}";`
|
|
2888
|
+
);
|
|
2889
|
+
}
|
|
2890
|
+
if (css && css.otherBrands.length > 0) {
|
|
2891
|
+
lines.push(
|
|
2892
|
+
chalk8.yellow(
|
|
2893
|
+
` ! \uB2E4\uB978 \uBE0C\uB79C\uB4DC import(${css.otherBrands.join(", ")})\uB294 \uADF8\uB300\uB85C \uB450\uC5C8\uC2B5\uB2C8\uB2E4. \uC4F0\uC9C0 \uC54A\uC73C\uBA74 \uC774\uC804 \uBE0C\uB79C\uB4DC import \uB97C \uC9C0\uC6CC\uB3C4 \uB429\uB2C8\uB2E4.`
|
|
2894
|
+
)
|
|
2895
|
+
);
|
|
2896
|
+
}
|
|
2897
|
+
const dep = plan.dependency;
|
|
2898
|
+
if (dep?.action === "add") {
|
|
2899
|
+
lines.push(
|
|
2900
|
+
` ${chalk8.green("\u2713")} package.json: dependencies \uC5D0 "${TOKENS_PACKAGE}": "${TOKENS_DEPENDENCY_RANGE}" \uCD94\uAC00`,
|
|
2901
|
+
` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${chalk8.cyan(plan.installCommand)}`
|
|
2902
|
+
);
|
|
2903
|
+
} else if (dep?.action === "present") {
|
|
2904
|
+
lines.push(` ${chalk8.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
|
|
2905
|
+
} else if (dep?.action === "no-package-json") {
|
|
2906
|
+
lines.push(
|
|
2907
|
+
chalk8.yellow(` ! package.json \uC774 \uC5C6\uC5B4 \uC758\uC874\uC131\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${TOKENS_INSTALL_COMMAND}`)
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
if (dep?.upgrade) {
|
|
2911
|
+
lines.push(
|
|
2912
|
+
chalk8.yellow(
|
|
2913
|
+
` ! \uC124\uCE58\uB41C ${TOKENS_PACKAGE} ${plan.tokens.version} \uC740 \uBE0C\uB79C\uB4DC\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(${MIN_BRAND_TOKENS_VERSION} \uC774\uC0C1 \uD544\uC694).`
|
|
2914
|
+
),
|
|
2915
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk8.cyan(TOKENS_INSTALL_COMMAND)}`
|
|
2916
|
+
);
|
|
2917
|
+
}
|
|
2918
|
+
if (plan.configChanged) {
|
|
2919
|
+
lines.push(` ${chalk8.green("\u2713")} axis.config.json: "brand": "${plan.brand}" \uAE30\uB85D`);
|
|
2920
|
+
} else {
|
|
2921
|
+
lines.push(` ${chalk8.gray("-")} axis.config.json: brand \uAC00 \uC774\uBBF8 "${plan.brand}"`);
|
|
2922
|
+
}
|
|
2923
|
+
lines.push(
|
|
2924
|
+
"",
|
|
2925
|
+
chalk8.bold(`Provider (${THEME_PACKAGE} 1.3.0 \uC774\uC0C1)`),
|
|
2926
|
+
...providerExample(plan.brand).split("\n").map((l) => l ? ` ${l}` : ""),
|
|
2927
|
+
chalk8.gray(
|
|
2928
|
+
` ThemeProvider \uB098 <html data-brand="${plan.brand}"> \uAC00 \uC5C6\uC73C\uBA74 import \uB9CC\uC73C\uB85C\uB294 \uD654\uBA74\uC774 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
|
|
2929
|
+
)
|
|
2930
|
+
);
|
|
2931
|
+
if (dep?.themeMissing) {
|
|
2932
|
+
lines.push(` ${THEME_PACKAGE} \uC124\uCE58: ${chalk8.cyan(`pnpm add ${THEME_PACKAGE}@^1.3.0`)}`);
|
|
2933
|
+
}
|
|
2934
|
+
lines.push("", chalk8.gray(written.length > 0 ? `\uD30C\uC77C ${written.length}\uAC1C\uB97C \uBC14\uAFE8\uC2B5\uB2C8\uB2E4.` : "\uBC14\uAFBC \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."), "");
|
|
2935
|
+
return { lines, exitCode: 0 };
|
|
2936
|
+
}
|
|
2937
|
+
function renderThemeAddFailure(plan, err) {
|
|
2938
|
+
const lines = [""];
|
|
2939
|
+
if (err instanceof ThemeApplyError) {
|
|
2940
|
+
lines.push(chalk8.red(err.message));
|
|
2941
|
+
if (err.restored.length > 0) {
|
|
2942
|
+
lines.push(` \uBA3C\uC800 \uC4F4 \uD30C\uC77C\uC740 \uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4: ${err.restored.map((f) => rel(plan, f)).join(", ")}`);
|
|
2943
|
+
}
|
|
2944
|
+
if (err.restoreFailed.length > 0) {
|
|
2945
|
+
lines.push(
|
|
2946
|
+
chalk8.red(` \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD574 \uBC14\uB010 \uCC44 \uB0A8\uC740 \uD30C\uC77C: ${err.restoreFailed.map((f) => rel(plan, f)).join(", ")}`)
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2949
|
+
if (err.restored.length === 0 && err.restoreFailed.length === 0) {
|
|
2950
|
+
lines.push(" \uBC14\uB010 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2951
|
+
}
|
|
2952
|
+
} else {
|
|
2953
|
+
lines.push(chalk8.red(err instanceof Error ? err.message : String(err)), " \uBC14\uB010 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2954
|
+
}
|
|
2955
|
+
lines.push("");
|
|
2956
|
+
return { lines, exitCode: 1 };
|
|
2957
|
+
}
|
|
2958
|
+
function print(output) {
|
|
2959
|
+
for (const line of output.lines) console.log(line);
|
|
2960
|
+
if (output.exitCode !== 0) process.exitCode = output.exitCode;
|
|
2961
|
+
}
|
|
2962
|
+
function registerThemeCommand(program2) {
|
|
2963
|
+
const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
|
|
2964
|
+
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) => {
|
|
2965
|
+
const baseDir = path10.resolve(options.dir || ".");
|
|
2966
|
+
print(renderThemeList(listBrands(baseDir)));
|
|
2967
|
+
});
|
|
2968
|
+
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) => {
|
|
2969
|
+
const baseDir = path10.resolve(options.dir || ".");
|
|
2970
|
+
print(renderThemeInfo(getBrand(baseDir, name), name));
|
|
2971
|
+
});
|
|
2972
|
+
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) => {
|
|
2973
|
+
const baseDir = path10.resolve(options.dir || ".");
|
|
2974
|
+
const plan = planThemeAdd(baseDir, name);
|
|
2975
|
+
let written = [];
|
|
2976
|
+
if (plan.errors.length === 0) {
|
|
2977
|
+
try {
|
|
2978
|
+
written = applyThemeAdd(plan);
|
|
2979
|
+
} catch (err) {
|
|
2980
|
+
print(renderThemeAddFailure(plan, err));
|
|
2981
|
+
return;
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
print(renderThemeAdd(plan, written));
|
|
2985
|
+
});
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2105
2988
|
// src/index.ts
|
|
2989
|
+
var { version: CLI_VERSION } = createRequire2(import.meta.url)("../package.json");
|
|
2106
2990
|
var REGISTRY_URL = process.env.AXIS_REGISTRY_URL || "https://axis.minu.best/r";
|
|
2107
2991
|
var program = new Command();
|
|
2108
|
-
program.name("axis").description("AXIS Design System CLI - shadcn \uD638\uD658 \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uB3C4\uAD6C").version(
|
|
2992
|
+
program.name("axis").description("AXIS Design System CLI - shadcn \uD638\uD658 \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uB3C4\uAD6C").version(CLI_VERSION);
|
|
2109
2993
|
program.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) => {
|
|
2110
|
-
console.log(
|
|
2994
|
+
console.log(chalk9.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
|
|
2111
2995
|
const config = options.yes ? {
|
|
2112
2996
|
componentsDir: "./src/components/ui",
|
|
2113
2997
|
tailwindConfig: "./tailwind.config.ts",
|
|
@@ -2132,18 +3016,19 @@ program.command("init").description("\uD504\uB85C\uC81D\uD2B8\uC5D0 AXIS Design
|
|
|
2132
3016
|
initial: "./src/app/globals.css"
|
|
2133
3017
|
}
|
|
2134
3018
|
]);
|
|
2135
|
-
const axisConfig =
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
await
|
|
3019
|
+
const axisConfig = createInitConfig(
|
|
3020
|
+
{
|
|
3021
|
+
componentsDir: config.componentsDir,
|
|
3022
|
+
tailwindConfig: config.tailwindConfig,
|
|
3023
|
+
globalCss: config.globalCss
|
|
3024
|
+
},
|
|
3025
|
+
REGISTRY_URL
|
|
3026
|
+
);
|
|
3027
|
+
await fs10.writeJSON("axis.config.json", axisConfig, { spaces: 2 });
|
|
3028
|
+
console.log(chalk9.green("\u2713 axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
|
|
3029
|
+
const utilsPath = path11.join(config.componentsDir, "utils.ts");
|
|
3030
|
+
await fs10.ensureDir(path11.dirname(utilsPath));
|
|
3031
|
+
await fs10.writeFile(
|
|
2147
3032
|
utilsPath,
|
|
2148
3033
|
`import { type ClassValue, clsx } from "clsx";
|
|
2149
3034
|
import { twMerge } from "tailwind-merge";
|
|
@@ -2153,21 +3038,21 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
2153
3038
|
}
|
|
2154
3039
|
`
|
|
2155
3040
|
);
|
|
2156
|
-
console.log(
|
|
2157
|
-
console.log(
|
|
2158
|
-
console.log(
|
|
3041
|
+
console.log(chalk9.green("\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC"));
|
|
3042
|
+
console.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:"));
|
|
3043
|
+
console.log(chalk9.cyan(" npx axis-cli add button\n"));
|
|
2159
3044
|
});
|
|
2160
3045
|
program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00").option("--agentic", "Agentic UI \uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774 \uB36E\uC5B4\uC4F0\uAE30").action(async (component, options) => {
|
|
2161
3046
|
const spinner = ora6(`${component} \uCEF4\uD3EC\uB10C\uD2B8 \uAC00\uC838\uC624\uB294 \uC911...`).start();
|
|
2162
3047
|
try {
|
|
2163
|
-
const configPath =
|
|
2164
|
-
if (!await
|
|
3048
|
+
const configPath = path11.resolve("axis.config.json");
|
|
3049
|
+
if (!await fs10.pathExists(configPath)) {
|
|
2165
3050
|
spinner.fail(
|
|
2166
3051
|
"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"
|
|
2167
3052
|
);
|
|
2168
3053
|
process.exit(1);
|
|
2169
3054
|
}
|
|
2170
|
-
const config = await
|
|
3055
|
+
const config = await fs10.readJSON(configPath);
|
|
2171
3056
|
const category = options.agentic ? "agentic" : "ui";
|
|
2172
3057
|
const componentInfo = await getComponentInfo(component, category);
|
|
2173
3058
|
if (!componentInfo) {
|
|
@@ -2180,8 +3065,8 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
|
|
|
2180
3065
|
}
|
|
2181
3066
|
spinner.text = `${component} \uCEF4\uD3EC\uB10C\uD2B8 \uC124\uCE58 \uC911...`;
|
|
2182
3067
|
for (const file of componentInfo.files) {
|
|
2183
|
-
const filePath =
|
|
2184
|
-
if (await
|
|
3068
|
+
const filePath = path11.join(config.componentsDir, file.path);
|
|
3069
|
+
if (await fs10.pathExists(filePath)) {
|
|
2185
3070
|
if (!options.yes) {
|
|
2186
3071
|
const { overwrite } = await prompts2({
|
|
2187
3072
|
type: "confirm",
|
|
@@ -2192,13 +3077,13 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
|
|
|
2192
3077
|
if (!overwrite) continue;
|
|
2193
3078
|
}
|
|
2194
3079
|
}
|
|
2195
|
-
await
|
|
2196
|
-
await
|
|
3080
|
+
await fs10.ensureDir(path11.dirname(filePath));
|
|
3081
|
+
await fs10.writeFile(filePath, file.content);
|
|
2197
3082
|
}
|
|
2198
|
-
spinner.succeed(
|
|
3083
|
+
spinner.succeed(chalk9.green(`${component} \uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00 \uC644\uB8CC`));
|
|
2199
3084
|
if (componentInfo.dependencies.length > 0) {
|
|
2200
|
-
console.log(
|
|
2201
|
-
console.log(
|
|
3085
|
+
console.log(chalk9.yellow("\n\uD544\uC694\uD55C \uC758\uC874\uC131:"));
|
|
3086
|
+
console.log(chalk9.cyan(` pnpm add ${componentInfo.dependencies.join(" ")}`));
|
|
2202
3087
|
}
|
|
2203
3088
|
} catch (error) {
|
|
2204
3089
|
spinner.fail(
|
|
@@ -2210,7 +3095,7 @@ program.command("add <component>").description("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\
|
|
|
2210
3095
|
}
|
|
2211
3096
|
});
|
|
2212
3097
|
program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uBAA9\uB85D").option("--category <type>", "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130 (ui, agentic)").action(async (options) => {
|
|
2213
|
-
console.log(
|
|
3098
|
+
console.log(chalk9.blue("\n\u{1F4E6} AXIS Design System \uCEF4\uD3EC\uB10C\uD2B8\n"));
|
|
2214
3099
|
const components = {
|
|
2215
3100
|
ui: [
|
|
2216
3101
|
{ name: "button", description: "\uAE30\uBCF8 \uBC84\uD2BC \uCEF4\uD3EC\uB10C\uD2B8" },
|
|
@@ -2238,9 +3123,9 @@ program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3E
|
|
|
2238
3123
|
]
|
|
2239
3124
|
};
|
|
2240
3125
|
const showCategory = (category, items) => {
|
|
2241
|
-
console.log(
|
|
3126
|
+
console.log(chalk9.bold(category === "ui" ? "Core UI" : "Agentic UI"));
|
|
2242
3127
|
items.forEach((c) => {
|
|
2243
|
-
console.log(` ${
|
|
3128
|
+
console.log(` ${chalk9.cyan(c.name.padEnd(20))} ${chalk9.gray(c.description)}`);
|
|
2244
3129
|
});
|
|
2245
3130
|
console.log();
|
|
2246
3131
|
};
|
|
@@ -2250,8 +3135,8 @@ program.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3E
|
|
|
2250
3135
|
if (!options.category || options.category === "agentic") {
|
|
2251
3136
|
showCategory("agentic", components.agentic);
|
|
2252
3137
|
}
|
|
2253
|
-
console.log(
|
|
2254
|
-
console.log(
|
|
3138
|
+
console.log(chalk9.gray("\uC0AC\uC6A9\uBC95: npx axis-cli add <component-name>"));
|
|
3139
|
+
console.log(chalk9.gray("Agentic: npx axis-cli add <component-name> --agentic\n"));
|
|
2255
3140
|
});
|
|
2256
3141
|
var monetCmd = program.command("monet").description("Monet Design \uCEF4\uD3EC\uB10C\uD2B8 \uAD00\uB9AC (https://monet.design)");
|
|
2257
3142
|
monetCmd.command("list").alias("ls").description("Monet \uCE74\uD14C\uACE0\uB9AC \uBAA9\uB85D").action(async () => {
|
|
@@ -2271,24 +3156,24 @@ monetCmd.command("import").alias("i").description("\uD074\uB9BD\uBCF4\uB4DC\uC5D
|
|
|
2271
3156
|
await client.importFromClipboard();
|
|
2272
3157
|
});
|
|
2273
3158
|
monetCmd.command("setup").description("Monet MCP \uC11C\uBC84 \uC124\uC815 \uC548\uB0B4").action(() => {
|
|
2274
|
-
console.log(
|
|
2275
|
-
console.log(
|
|
2276
|
-
console.log(
|
|
2277
|
-
console.log(
|
|
2278
|
-
console.log(
|
|
2279
|
-
console.log(
|
|
2280
|
-
console.log(
|
|
2281
|
-
console.log(
|
|
3159
|
+
console.log(chalk9.blue("\n\u{1F527} Monet MCP \uC11C\uBC84 \uC124\uC815\n"));
|
|
3160
|
+
console.log(chalk9.bold("1. API \uD0A4 \uBC1C\uAE09:"));
|
|
3161
|
+
console.log(chalk9.cyan(" https://monet.design/mcp\n"));
|
|
3162
|
+
console.log(chalk9.bold("2. \uD658\uACBD \uBCC0\uC218 \uC124\uC815:"));
|
|
3163
|
+
console.log(chalk9.gray(" .env \uD30C\uC77C\uC5D0 \uCD94\uAC00:"));
|
|
3164
|
+
console.log(chalk9.cyan(" MONET_API_KEY=your-api-key-here\n"));
|
|
3165
|
+
console.log(chalk9.bold("3. Claude Code MCP \uC124\uC815:"));
|
|
3166
|
+
console.log(chalk9.gray(" .claude/mcp.json\uC5D0\uC11C monet \uC11C\uBC84 \uD65C\uC131\uD654:\n"));
|
|
2282
3167
|
console.log(
|
|
2283
|
-
|
|
3168
|
+
chalk9.cyan(` "monet": {
|
|
2284
3169
|
"url": "https://www.monet.design/api/remote/mcp",
|
|
2285
3170
|
"headers": { "Authorization": "Bearer \${MONET_API_KEY}" },
|
|
2286
3171
|
"disabled": false
|
|
2287
3172
|
}
|
|
2288
3173
|
`)
|
|
2289
3174
|
);
|
|
2290
|
-
console.log(
|
|
2291
|
-
console.log(
|
|
3175
|
+
console.log(chalk9.bold("4. Claude Code \uC7AC\uC2DC\uC791 \uD6C4 \uC0AC\uC6A9:"));
|
|
3176
|
+
console.log(chalk9.gray(' "monet\uC5D0\uC11C hero \uCEF4\uD3EC\uB10C\uD2B8 \uCC3E\uC544\uC918"\n'));
|
|
2292
3177
|
});
|
|
2293
3178
|
var v0Cmd = program.command("v0").description("V0 (v0.app) \uCF54\uB4DC \uBCC0\uD658 \uBC0F \uD1B5\uD569");
|
|
2294
3179
|
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) => {
|
|
@@ -2325,18 +3210,18 @@ libraryCmd.command("collect").alias("c").description("\uC678\uBD80 \uC18C\uC2A4\
|
|
|
2325
3210
|
total += result.collected;
|
|
2326
3211
|
failed += result.failed;
|
|
2327
3212
|
}
|
|
2328
|
-
console.log(
|
|
3213
|
+
console.log(chalk9.blue(`
|
|
2329
3214
|
\u{1F4CA} \uC218\uC9D1 \uC644\uB8CC: ${total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8`));
|
|
2330
3215
|
if (failed > 0) {
|
|
2331
|
-
console.log(
|
|
3216
|
+
console.log(chalk9.yellow(` \uC2E4\uD328: ${failed}\uAC1C`));
|
|
2332
3217
|
}
|
|
2333
3218
|
});
|
|
2334
3219
|
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) => {
|
|
2335
3220
|
const curator = new LibraryCurator();
|
|
2336
3221
|
const index = await curator.loadIndex();
|
|
2337
3222
|
if (!index) {
|
|
2338
|
-
console.log(
|
|
2339
|
-
console.log(
|
|
3223
|
+
console.log(chalk9.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
3224
|
+
console.log(chalk9.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
|
|
2340
3225
|
return;
|
|
2341
3226
|
}
|
|
2342
3227
|
let components = index.components;
|
|
@@ -2346,7 +3231,7 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
|
|
|
2346
3231
|
if (options.source) {
|
|
2347
3232
|
components = components.filter((c) => c.source.type === options.source);
|
|
2348
3233
|
}
|
|
2349
|
-
console.log(
|
|
3234
|
+
console.log(chalk9.blue(`
|
|
2350
3235
|
\u{1F4E6} Library Components (${components.length}\uAC1C)
|
|
2351
3236
|
`));
|
|
2352
3237
|
const byCategory = /* @__PURE__ */ new Map();
|
|
@@ -2358,14 +3243,14 @@ libraryCmd.command("list").alias("ls").description("\uB77C\uC774\uBE0C\uB7EC\uB9
|
|
|
2358
3243
|
byCategory.get(cat).push(comp);
|
|
2359
3244
|
}
|
|
2360
3245
|
for (const [category, items] of byCategory) {
|
|
2361
|
-
console.log(
|
|
3246
|
+
console.log(chalk9.bold(`${category} (${items.length})`));
|
|
2362
3247
|
for (const item of items.slice(0, 10)) {
|
|
2363
3248
|
console.log(
|
|
2364
|
-
` ${
|
|
3249
|
+
` ${chalk9.cyan(item.name.padEnd(25))} ${chalk9.gray(item.source.type.padEnd(8))} ${chalk9.gray(item.description.slice(0, 40))}`
|
|
2365
3250
|
);
|
|
2366
3251
|
}
|
|
2367
3252
|
if (items.length > 10) {
|
|
2368
|
-
console.log(
|
|
3253
|
+
console.log(chalk9.gray(` ... \uC678 ${items.length - 10}\uAC1C`));
|
|
2369
3254
|
}
|
|
2370
3255
|
console.log();
|
|
2371
3256
|
}
|
|
@@ -2377,21 +3262,21 @@ libraryCmd.command("search <query>").alias("s").description("\uCEF4\uD3EC\uB10C\
|
|
|
2377
3262
|
source: options.source
|
|
2378
3263
|
});
|
|
2379
3264
|
if (results.length === 0) {
|
|
2380
|
-
console.log(
|
|
3265
|
+
console.log(chalk9.yellow(`
|
|
2381
3266
|
'${query}'\uC5D0 \uB300\uD55C \uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
|
|
2382
3267
|
`));
|
|
2383
3268
|
return;
|
|
2384
3269
|
}
|
|
2385
|
-
console.log(
|
|
3270
|
+
console.log(chalk9.blue(`
|
|
2386
3271
|
\u{1F50D} '${query}' \uAC80\uC0C9 \uACB0\uACFC (${results.length}\uAC1C)
|
|
2387
3272
|
`));
|
|
2388
3273
|
for (const comp of results.slice(0, 20)) {
|
|
2389
3274
|
console.log(
|
|
2390
|
-
` ${
|
|
3275
|
+
` ${chalk9.cyan(comp.name.padEnd(25))} ${chalk9.gray(comp.source.type.padEnd(8))} ${chalk9.gray(comp.category.padEnd(12))} ${chalk9.gray(comp.description.slice(0, 30))}`
|
|
2391
3276
|
);
|
|
2392
3277
|
}
|
|
2393
3278
|
if (results.length > 20) {
|
|
2394
|
-
console.log(
|
|
3279
|
+
console.log(chalk9.gray(`
|
|
2395
3280
|
... \uC678 ${results.length - 20}\uAC1C`));
|
|
2396
3281
|
}
|
|
2397
3282
|
console.log();
|
|
@@ -2405,12 +3290,12 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
|
|
|
2405
3290
|
const publisher2 = new Publisher();
|
|
2406
3291
|
const index = await curator.loadIndex();
|
|
2407
3292
|
if (!index) {
|
|
2408
|
-
console.log(
|
|
2409
|
-
console.log(
|
|
3293
|
+
console.log(chalk9.yellow("\n\u26A0\uFE0F \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC778\uB371\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
3294
|
+
console.log(chalk9.gray(" \uD574\uACB0: npx @axis-ds/cli library collect \uBA85\uB839\uC5B4\uB85C \uC218\uC9D1\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.\n"));
|
|
2410
3295
|
return;
|
|
2411
3296
|
}
|
|
2412
|
-
console.log(
|
|
2413
|
-
console.log(
|
|
3297
|
+
console.log(chalk9.blue("\n\u{1F4E4} Library \uBC30\uCE58\n"));
|
|
3298
|
+
console.log(chalk9.gray(`\uCD1D ${index.stats.total}\uAC1C \uCEF4\uD3EC\uB10C\uD2B8
|
|
2414
3299
|
`));
|
|
2415
3300
|
if (options.clean) {
|
|
2416
3301
|
await publisher2.clean(options.output);
|
|
@@ -2421,17 +3306,17 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
|
|
|
2421
3306
|
generateSearchIndex: true
|
|
2422
3307
|
});
|
|
2423
3308
|
if (result.success) {
|
|
2424
|
-
console.log(
|
|
3309
|
+
console.log(chalk9.green(`
|
|
2425
3310
|
\u2713 \uBC30\uCE58 \uC644\uB8CC`));
|
|
2426
|
-
console.log(
|
|
2427
|
-
console.log(
|
|
2428
|
-
console.log(
|
|
2429
|
-
console.log(
|
|
3311
|
+
console.log(chalk9.gray(` - \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC: ${result.outputDir}`));
|
|
3312
|
+
console.log(chalk9.gray(` - \uC0DD\uC131\uB41C \uD30C\uC77C: ${result.files.length}\uAC1C`));
|
|
3313
|
+
console.log(chalk9.gray(` - \uCE74\uD14C\uACE0\uB9AC: ${result.stats.categoriesPublished}\uAC1C`));
|
|
3314
|
+
console.log(chalk9.gray(` - \uAC80\uC0C9 \uC778\uB371\uC2A4: ${result.stats.searchIndexSize}\uAC1C \uD56D\uBAA9`));
|
|
2430
3315
|
} else {
|
|
2431
|
-
console.log(
|
|
3316
|
+
console.log(chalk9.red(`
|
|
2432
3317
|
\u2717 \uBC30\uCE58 \uC2E4\uD328`));
|
|
2433
3318
|
for (const error of result.errors) {
|
|
2434
|
-
console.log(
|
|
3319
|
+
console.log(chalk9.red(` - ${error}`));
|
|
2435
3320
|
}
|
|
2436
3321
|
}
|
|
2437
3322
|
console.log();
|
|
@@ -2439,6 +3324,7 @@ libraryCmd.command("publish").description("\uC0AC\uC774\uD2B8\uC5D0 \uB77C\uC774
|
|
|
2439
3324
|
registerSyncCommand(program);
|
|
2440
3325
|
registerTemplateCommand(program);
|
|
2441
3326
|
registerCheckCommand(program);
|
|
3327
|
+
registerThemeCommand(program);
|
|
2442
3328
|
async function getComponentInfo(name, category) {
|
|
2443
3329
|
const localComponents = {
|
|
2444
3330
|
button: {
|