@axis-ds/cli 1.5.4 → 1.6.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 +11 -5
- package/dist/{chunk-QORBOSUA.js → chunk-7CDXEBEE.js} +2 -2
- package/dist/index.js +1428 -901
- package/dist/registry/agentic-message-bubble.json +1 -1
- package/dist/registry/agentic-plan-card.json +1 -1
- package/dist/registry/agentic-run-progress.json +1 -1
- package/dist/registry/agentic-step-timeline.json +1 -1
- package/dist/registry/agentic-streaming-text.json +1 -1
- package/dist/registry/agentic-surface-renderer.json +1 -1
- package/dist/registry/agentic-thinking-indicator.json +1 -1
- package/dist/registry/agentic-tool-call-card.json +1 -1
- package/dist/registry/dialog.json +1 -1
- package/dist/registry/index.json +12 -12
- package/dist/registry/registry.json +12 -12
- package/dist/registry/select.json +1 -1
- package/dist/registry/toast.json +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/v0.js +1 -1
- package/package.json +4 -2
- /package/dist/{chunk-AHQT77FJ.js → chunk-NNFSJISD.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-ZVVACWEW.js";
|
|
5
5
|
import {
|
|
6
6
|
V0Client
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NNFSJISD.js";
|
|
8
8
|
import {
|
|
9
9
|
registerSyncCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7CDXEBEE.js";
|
|
11
11
|
import {
|
|
12
12
|
AXIS_QUICK_START_URL,
|
|
13
13
|
AXIS_SITE_URL,
|
|
@@ -411,7 +411,7 @@ var ShadcnCollector = class extends BaseCollector {
|
|
|
411
411
|
];
|
|
412
412
|
}
|
|
413
413
|
return meta;
|
|
414
|
-
} catch
|
|
414
|
+
} catch {
|
|
415
415
|
return this.createBaseMeta(name, `shadcn/ui ${name} component`, [], {
|
|
416
416
|
registry: "@shadcn",
|
|
417
417
|
url: `${this.baseUrl}/docs/components/${name}`
|
|
@@ -546,7 +546,8 @@ var MonetCollector = class extends BaseCollector {
|
|
|
546
546
|
sourceType = "monet";
|
|
547
547
|
baseUrl = "https://www.monet.design";
|
|
548
548
|
registryUrl = "https://registry.monet.design";
|
|
549
|
-
|
|
549
|
+
// 예전 판은 쓰지 않는 `options: { apiKey?: string }` 인자를 받았어요. 호출부는 인자 없이 만들고 있어 뺐습니다(WI-0039)
|
|
550
|
+
constructor() {
|
|
550
551
|
super();
|
|
551
552
|
}
|
|
552
553
|
/**
|
|
@@ -584,7 +585,7 @@ var MonetCollector = class extends BaseCollector {
|
|
|
584
585
|
const name = id.replace("monet-", "");
|
|
585
586
|
const category = MONET_CATEGORIES.find((c) => c.id === name);
|
|
586
587
|
let example;
|
|
587
|
-
for (const [
|
|
588
|
+
for (const [, examples] of Object.entries(MONET_EXAMPLES)) {
|
|
588
589
|
const found = examples.find((e) => e.id === name);
|
|
589
590
|
if (found) {
|
|
590
591
|
example = found;
|
|
@@ -690,7 +691,6 @@ var V0Collector = class extends BaseCollector {
|
|
|
690
691
|
const content = await fs.readFile(file, "utf-8");
|
|
691
692
|
if (this.isV0Code(content)) {
|
|
692
693
|
const name = path.basename(file, path.extname(file));
|
|
693
|
-
const relativePath = path.relative(this.v0Directory, file);
|
|
694
694
|
items.push({
|
|
695
695
|
id: `v0-${this.generateSlug(name)}`,
|
|
696
696
|
name: this.formatName(name),
|
|
@@ -1283,7 +1283,8 @@ async function readJson(file) {
|
|
|
1283
1283
|
return JSON.parse(await fs4.readFile(file, "utf-8"));
|
|
1284
1284
|
}
|
|
1285
1285
|
function withoutUpdatedAt(c) {
|
|
1286
|
-
const
|
|
1286
|
+
const rest = { ...c };
|
|
1287
|
+
delete rest.updatedAt;
|
|
1287
1288
|
return JSON.parse(serialize(rest));
|
|
1288
1289
|
}
|
|
1289
1290
|
function computeStats(entries) {
|
|
@@ -1601,7 +1602,7 @@ var LibraryCurator = class {
|
|
|
1601
1602
|
*/
|
|
1602
1603
|
async generateIndex() {
|
|
1603
1604
|
const components = [];
|
|
1604
|
-
for (const [
|
|
1605
|
+
for (const [, collector] of this.collectors) {
|
|
1605
1606
|
try {
|
|
1606
1607
|
const list = await collector.listComponents();
|
|
1607
1608
|
for (const item of list) {
|
|
@@ -1832,7 +1833,7 @@ function createTemplateConfig(template) {
|
|
|
1832
1833
|
template,
|
|
1833
1834
|
componentsDir: "./components/ui",
|
|
1834
1835
|
tailwindConfig: "./tailwind.config.ts",
|
|
1835
|
-
globalCss: "./globals.css"
|
|
1836
|
+
globalCss: "./app/globals.css"
|
|
1836
1837
|
};
|
|
1837
1838
|
}
|
|
1838
1839
|
async function readAxisConfig(baseDir) {
|
|
@@ -1841,142 +1842,807 @@ async function readAxisConfig(baseDir) {
|
|
|
1841
1842
|
return await fs7.readJSON(configPath);
|
|
1842
1843
|
}
|
|
1843
1844
|
|
|
1844
|
-
// src/template/
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
spinner.fail(err.message);
|
|
1853
|
-
process.exit(1);
|
|
1854
|
-
}
|
|
1855
|
-
const baseDir = path8.resolve(options.dir || ".");
|
|
1856
|
-
const conflicts = [];
|
|
1857
|
-
for (const file of detail.files) {
|
|
1858
|
-
const dest = path8.join(baseDir, file.path);
|
|
1859
|
-
if (await fs8.pathExists(dest)) {
|
|
1860
|
-
conflicts.push(file.path);
|
|
1845
|
+
// ../axis-registry-core/src/template/tailwind-core.ts
|
|
1846
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from "fs";
|
|
1847
|
+
import { join, resolve } from "path";
|
|
1848
|
+
function hasDependency(pkg, name) {
|
|
1849
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
1850
|
+
const deps = pkg[field];
|
|
1851
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
1852
|
+
return String(deps[name]);
|
|
1861
1853
|
}
|
|
1862
1854
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1855
|
+
return void 0;
|
|
1856
|
+
}
|
|
1857
|
+
function isPlainObject(value) {
|
|
1858
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1859
|
+
}
|
|
1860
|
+
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
1861
|
+
function versionParts(token) {
|
|
1862
|
+
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
1863
|
+
if (!m) return void 0;
|
|
1864
|
+
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
1865
|
+
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
1866
|
+
}
|
|
1867
|
+
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
1868
|
+
function comparatorBounds(op, v) {
|
|
1869
|
+
switch (op) {
|
|
1870
|
+
case ">=":
|
|
1871
|
+
return { lower: v.major };
|
|
1872
|
+
case ">":
|
|
1873
|
+
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
1874
|
+
case "<=":
|
|
1875
|
+
return { upper: v.major };
|
|
1876
|
+
case "<": {
|
|
1877
|
+
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
1878
|
+
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
1878
1879
|
}
|
|
1880
|
+
default:
|
|
1881
|
+
return { lower: v.major, upper: v.major };
|
|
1879
1882
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
}
|
|
1888
|
-
if (detail.postInstall?.length) {
|
|
1889
|
-
console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] postInstall \uD328\uCE58:"));
|
|
1890
|
-
for (const p of detail.postInstall) {
|
|
1891
|
-
console.log(chalk5.gray(` ${p.type}: ${p.file}`));
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
return;
|
|
1883
|
+
}
|
|
1884
|
+
function tailwindMajorBounds(range) {
|
|
1885
|
+
const r = range.trim();
|
|
1886
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
1887
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
1888
|
+
if (simple) {
|
|
1889
|
+
const v = versionParts(simple[1]);
|
|
1890
|
+
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
1895
1891
|
}
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
const
|
|
1899
|
-
|
|
1900
|
-
|
|
1892
|
+
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
1893
|
+
if (hyphen) {
|
|
1894
|
+
const tokens2 = r.split(/\s+-\s+/);
|
|
1895
|
+
const a = versionParts(tokens2[0]);
|
|
1896
|
+
const b = versionParts(tokens2[1]);
|
|
1897
|
+
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
1901
1898
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1899
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
1900
|
+
const lowers = [];
|
|
1901
|
+
const uppers = [];
|
|
1902
|
+
for (const t of tokens) {
|
|
1903
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
1904
|
+
if (!c) return void 0;
|
|
1905
|
+
const v = versionParts(c[2]);
|
|
1906
|
+
if (v === void 0) return void 0;
|
|
1907
|
+
const b = comparatorBounds(c[1], v);
|
|
1908
|
+
if (b.lower !== void 0) lowers.push(b.lower);
|
|
1909
|
+
if (b.upper !== void 0) uppers.push(b.upper);
|
|
1906
1910
|
}
|
|
1907
|
-
if (
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1911
|
+
if (lowers.length === 0) return void 0;
|
|
1912
|
+
const lower = Math.max(...lowers);
|
|
1913
|
+
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
1914
|
+
if (upper !== void 0 && upper < lower) return void 0;
|
|
1915
|
+
return upper !== void 0 ? { lower, upper } : { lower };
|
|
1916
|
+
}
|
|
1917
|
+
function tailwindMajorFromRange(range) {
|
|
1918
|
+
return tailwindMajorBounds(range)?.lower;
|
|
1919
|
+
}
|
|
1920
|
+
function majorWithin(major, bounds) {
|
|
1921
|
+
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
1922
|
+
}
|
|
1923
|
+
function majorFromVersion(version) {
|
|
1924
|
+
if (typeof version !== "string") return void 0;
|
|
1925
|
+
const v = version.trim();
|
|
1926
|
+
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
1927
|
+
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
1928
|
+
return Number(m[1]);
|
|
1929
|
+
}
|
|
1930
|
+
function detectTailwind(baseDirInput, pkg) {
|
|
1931
|
+
const baseDir = resolve(baseDirInput);
|
|
1932
|
+
const installedFile = join(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
1933
|
+
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
1934
|
+
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
1935
|
+
const declaredMajor = bounds?.lower;
|
|
1936
|
+
try {
|
|
1937
|
+
const installed = JSON.parse(readFileSync(installedFile, "utf8"));
|
|
1938
|
+
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
1939
|
+
const major = majorFromVersion(version);
|
|
1940
|
+
if (major !== void 0) {
|
|
1941
|
+
const found = { major, source: "installed", value: String(version) };
|
|
1942
|
+
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
1943
|
+
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
1919
1944
|
}
|
|
1945
|
+
return found;
|
|
1920
1946
|
}
|
|
1947
|
+
} catch {
|
|
1921
1948
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
}
|
|
1925
|
-
async function initTemplate(slug, options) {
|
|
1926
|
-
let selectedSlug = slug;
|
|
1927
|
-
if (!selectedSlug) {
|
|
1928
|
-
const { fetchTemplateIndex: fetchTemplateIndex2 } = await import("./registry-client-6WSGKPF2.js");
|
|
1929
|
-
const index = await fetchTemplateIndex2();
|
|
1930
|
-
const { choice } = await prompts({
|
|
1931
|
-
type: "select",
|
|
1932
|
-
name: "choice",
|
|
1933
|
-
message: "\uC0AC\uC6A9\uD560 \uD15C\uD50C\uB9BF\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
1934
|
-
choices: index.templates.map((t) => ({
|
|
1935
|
-
title: `${t.name} (${t.category})`,
|
|
1936
|
-
description: t.description,
|
|
1937
|
-
value: t.slug
|
|
1938
|
-
}))
|
|
1939
|
-
});
|
|
1940
|
-
if (!choice) {
|
|
1941
|
-
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
1942
|
-
return;
|
|
1943
|
-
}
|
|
1944
|
-
selectedSlug = choice;
|
|
1949
|
+
if (declared !== void 0) {
|
|
1950
|
+
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
1951
|
+
return { source: "none", value: declared };
|
|
1945
1952
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1953
|
+
return { source: "none" };
|
|
1954
|
+
}
|
|
1955
|
+
var TAILWIND_CONFIG_FILES = [
|
|
1956
|
+
"tailwind.config.ts",
|
|
1957
|
+
"tailwind.config.js",
|
|
1958
|
+
"tailwind.config.mjs",
|
|
1959
|
+
"tailwind.config.cjs"
|
|
1960
|
+
];
|
|
1961
|
+
var TAILWIND_CSS_CANDIDATES = [
|
|
1962
|
+
"globals.css",
|
|
1963
|
+
"app/globals.css",
|
|
1964
|
+
"src/app/globals.css",
|
|
1965
|
+
"src/globals.css",
|
|
1966
|
+
"styles/globals.css"
|
|
1967
|
+
];
|
|
1968
|
+
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
1969
|
+
function stripCssComments(css) {
|
|
1970
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
1971
|
+
}
|
|
1972
|
+
function hasTailwindImport(css) {
|
|
1973
|
+
return TAILWIND_IMPORT.test(stripCssComments(css));
|
|
1974
|
+
}
|
|
1975
|
+
var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
|
|
1976
|
+
var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
|
|
1977
|
+
var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
|
|
1978
|
+
function hasTokensTailwind4Import(css) {
|
|
1979
|
+
return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
|
|
1980
|
+
}
|
|
1981
|
+
var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)["']/;
|
|
1982
|
+
function findTokensCssImport(css) {
|
|
1983
|
+
return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
|
|
1984
|
+
}
|
|
1985
|
+
function checkGlobalsCss(baseDirInput) {
|
|
1986
|
+
const baseDir = resolve(baseDirInput);
|
|
1987
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
1988
|
+
const file = join(baseDir, candidate);
|
|
1989
|
+
if (!existsSync(file)) continue;
|
|
1990
|
+
const content = readFileSync(file, "utf8");
|
|
1991
|
+
if (content.includes("--background") && content.includes("--primary")) {
|
|
1992
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
1957
1993
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
if (await fs8.pathExists(resolved)) {
|
|
1962
|
-
const entries = await fs8.readdir(resolved);
|
|
1963
|
-
if (entries.length > 0) {
|
|
1964
|
-
const { proceed } = await prompts({
|
|
1965
|
-
type: "confirm",
|
|
1966
|
-
name: "proceed",
|
|
1967
|
-
message: `'${targetDir}'\uC5D0 \uC774\uBBF8 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uACC4\uC18D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`,
|
|
1968
|
-
initial: false
|
|
1969
|
-
});
|
|
1970
|
-
if (!proceed) return;
|
|
1994
|
+
const imported = findTokensCssImport(content);
|
|
1995
|
+
if (imported !== void 0) {
|
|
1996
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
|
|
1971
1997
|
}
|
|
1972
|
-
|
|
1973
|
-
await fs8.ensureDir(resolved);
|
|
1998
|
+
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
1974
1999
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2000
|
+
return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2001
|
+
}
|
|
2002
|
+
var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
|
|
2003
|
+
var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2004
|
+
function lowerOf(token) {
|
|
2005
|
+
const v = versionParts(token);
|
|
2006
|
+
if (!v) return void 0;
|
|
2007
|
+
const num = (part) => isWild(part) ? 0 : Number(part);
|
|
2008
|
+
const pre = /^v?\d+(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?-/.test(token);
|
|
2009
|
+
return { core: [v.major, num(v.minor), num(v.patch)], pre };
|
|
2010
|
+
}
|
|
2011
|
+
function compareLower(a, b) {
|
|
2012
|
+
for (let i = 0; i < 3; i++) {
|
|
2013
|
+
if (a.core[i] !== b.core[i]) return a.core[i] - b.core[i];
|
|
2014
|
+
}
|
|
2015
|
+
return Number(b.pre) - Number(a.pre);
|
|
2016
|
+
}
|
|
2017
|
+
function rangeLowerVersion(range) {
|
|
2018
|
+
const r = range.trim();
|
|
2019
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2020
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2021
|
+
if (simple) return lowerOf(simple[1]);
|
|
2022
|
+
if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
|
|
2023
|
+
const [a, b] = r.split(/\s+-\s+/);
|
|
2024
|
+
return lowerOf(b) ? lowerOf(a) : void 0;
|
|
2025
|
+
}
|
|
2026
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2027
|
+
let lower;
|
|
2028
|
+
for (const t of tokens) {
|
|
2029
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2030
|
+
if (!c) return void 0;
|
|
2031
|
+
const v = versionParts(c[2]);
|
|
2032
|
+
const low = lowerOf(c[2]);
|
|
2033
|
+
if (!v || !low) return void 0;
|
|
2034
|
+
let candidate;
|
|
2035
|
+
if (c[1] === ">=" || c[1] === "=") candidate = low;
|
|
2036
|
+
else if (c[1] === ">") {
|
|
2037
|
+
if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
|
|
2038
|
+
else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
|
|
2039
|
+
else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
|
|
2040
|
+
}
|
|
2041
|
+
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2042
|
+
}
|
|
2043
|
+
return lower;
|
|
2044
|
+
}
|
|
2045
|
+
function rangeLowerAtLeast(range, min) {
|
|
2046
|
+
const lower = rangeLowerVersion(range);
|
|
2047
|
+
const target = lowerOf(min);
|
|
2048
|
+
if (!lower || !target) return void 0;
|
|
2049
|
+
return compareLower(lower, target) >= 0;
|
|
2050
|
+
}
|
|
2051
|
+
function exactVersion(version) {
|
|
2052
|
+
if (typeof version !== "string") return void 0;
|
|
2053
|
+
const v = version.trim();
|
|
2054
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2055
|
+
return v;
|
|
2056
|
+
}
|
|
2057
|
+
function installedVersion(baseDir, name) {
|
|
2058
|
+
try {
|
|
2059
|
+
const parsed = JSON.parse(readFileSync(join(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
|
|
2060
|
+
return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
|
|
2061
|
+
} catch {
|
|
2062
|
+
return void 0;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
function axisPackagesBelowTailwind4(pkg, baseDirInput) {
|
|
2066
|
+
if (!pkg) return [];
|
|
2067
|
+
const baseDir = baseDirInput !== void 0 ? resolve(baseDirInput) : void 0;
|
|
2068
|
+
const out = [];
|
|
2069
|
+
const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
|
|
2070
|
+
for (const name of TAILWIND4_AXIS_PACKAGES) {
|
|
2071
|
+
const range = hasDependency(pkg, name);
|
|
2072
|
+
if (range === void 0 || range.trim().startsWith("workspace:")) continue;
|
|
2073
|
+
const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
|
|
2074
|
+
const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
|
|
2075
|
+
if (installed !== void 0 && installedLower !== void 0) {
|
|
2076
|
+
if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
|
|
2077
|
+
continue;
|
|
2078
|
+
}
|
|
2079
|
+
const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
|
|
2080
|
+
if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
|
|
2081
|
+
else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
|
|
2082
|
+
}
|
|
2083
|
+
return out;
|
|
2084
|
+
}
|
|
2085
|
+
function axisPackageVersionLabel(issue) {
|
|
2086
|
+
return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
|
|
2087
|
+
}
|
|
2088
|
+
var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
2089
|
+
function tailwind4VersionNote(issues) {
|
|
2090
|
+
const below = issues.filter((i) => i.status === "below");
|
|
2091
|
+
const unknown = issues.filter((i) => i.status === "unknown");
|
|
2092
|
+
let note = "";
|
|
2093
|
+
if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
|
|
2094
|
+
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)})`;
|
|
2095
|
+
return note;
|
|
2096
|
+
}
|
|
2097
|
+
var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2098
|
+
function componentTailwindImportLine(name) {
|
|
2099
|
+
return `@import "${name}/tailwind.css";`;
|
|
2100
|
+
}
|
|
2101
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2102
|
+
function hasComponentTailwindImport(css, name) {
|
|
2103
|
+
const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
|
|
2104
|
+
return re.test(stripCssComments(css));
|
|
2105
|
+
}
|
|
2106
|
+
function hasComponentSource(css, name) {
|
|
2107
|
+
const re = new RegExp(`@source\\s+(["'])(?!@axis-ds/)[^"'\\n]*${escapeRegExp(name)}(?:[/\\\\][^"'\\n]*)?\\1`);
|
|
2108
|
+
return re.test(stripCssComments(css));
|
|
2109
|
+
}
|
|
2110
|
+
var CREATE_NEXT_APP_DEFAULTS = [
|
|
2111
|
+
{
|
|
2112
|
+
prefix: ":root \uC0C9\uAC12",
|
|
2113
|
+
pattern: /(?<![\w-])(--(?:background|foreground))\s*:\s*(?:#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?|hwb|oklch|oklab|lab|lch|color)\()/g,
|
|
2114
|
+
item: (m) => m[1]
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
prefix: "@theme",
|
|
2118
|
+
pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2119
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
prefix: "@theme",
|
|
2123
|
+
pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
|
|
2124
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2125
|
+
},
|
|
2126
|
+
{
|
|
2127
|
+
prefix: "body",
|
|
2128
|
+
pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2129
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2130
|
+
}
|
|
2131
|
+
];
|
|
2132
|
+
function findCreateNextAppDefaults(css) {
|
|
2133
|
+
const body = stripCssComments(css);
|
|
2134
|
+
const labels = [];
|
|
2135
|
+
for (const d of CREATE_NEXT_APP_DEFAULTS) {
|
|
2136
|
+
const items = [];
|
|
2137
|
+
for (const m of body.matchAll(d.pattern)) {
|
|
2138
|
+
const item = d.item(m);
|
|
2139
|
+
if (!items.includes(item)) items.push(item);
|
|
2140
|
+
}
|
|
2141
|
+
if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
|
|
2142
|
+
}
|
|
2143
|
+
return labels;
|
|
2144
|
+
}
|
|
2145
|
+
function stripJsComments(src) {
|
|
2146
|
+
let out = "";
|
|
2147
|
+
let i = 0;
|
|
2148
|
+
const n = src.length;
|
|
2149
|
+
while (i < n) {
|
|
2150
|
+
const c = src[i];
|
|
2151
|
+
const d = src[i + 1];
|
|
2152
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2153
|
+
let j = i + 1;
|
|
2154
|
+
while (j < n && src[j] !== c) {
|
|
2155
|
+
if (src[j] === "\\") j++;
|
|
2156
|
+
else if (c !== "`" && src[j] === "\n") break;
|
|
2157
|
+
j++;
|
|
2158
|
+
}
|
|
2159
|
+
out += src.slice(i, j + 1);
|
|
2160
|
+
i = j + 1;
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
if (c === "/" && d === "/") {
|
|
2164
|
+
const end = src.indexOf("\n", i);
|
|
2165
|
+
i = end === -1 ? n : end;
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
if (c === "/" && d === "*") {
|
|
2169
|
+
const end = src.indexOf("*/", i + 2);
|
|
2170
|
+
i = end === -1 ? n : end + 2;
|
|
2171
|
+
out += " ";
|
|
2172
|
+
continue;
|
|
2173
|
+
}
|
|
2174
|
+
out += c;
|
|
2175
|
+
i++;
|
|
2176
|
+
}
|
|
2177
|
+
return out;
|
|
2178
|
+
}
|
|
2179
|
+
var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
|
|
2180
|
+
var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
|
|
2181
|
+
function hasTokensPresetReference(source) {
|
|
2182
|
+
return PRESET_REFERENCE.test(stripJsComments(source));
|
|
2183
|
+
}
|
|
2184
|
+
var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
|
|
2185
|
+
function readPackageJson(baseDir) {
|
|
2186
|
+
try {
|
|
2187
|
+
const parsed = JSON.parse(readFileSync(join(baseDir, "package.json"), "utf8"));
|
|
2188
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
2189
|
+
} catch {
|
|
2190
|
+
return void 0;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
function tailwind4Issues(css, pkg, versions) {
|
|
2194
|
+
const issues = [];
|
|
2195
|
+
const hasEntry = hasTokensTailwind4Import(css);
|
|
2196
|
+
if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
|
|
2197
|
+
const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
|
|
2198
|
+
(name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
|
|
2199
|
+
);
|
|
2200
|
+
if (missing.length > 0) {
|
|
2201
|
+
issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
|
|
2202
|
+
}
|
|
2203
|
+
if (hasEntry) {
|
|
2204
|
+
const defaults = findCreateNextAppDefaults(css);
|
|
2205
|
+
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`);
|
|
2206
|
+
if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
|
|
2207
|
+
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`);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2211
|
+
if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
|
|
2212
|
+
issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
return issues;
|
|
2216
|
+
}
|
|
2217
|
+
function checkTailwindSetup(baseDirInput) {
|
|
2218
|
+
const baseDir = resolve(baseDirInput);
|
|
2219
|
+
const pkg = readPackageJson(baseDir);
|
|
2220
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2221
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2222
|
+
const label = `Tailwind ${tailwind.major}`;
|
|
2223
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2224
|
+
const file = join(baseDir, candidate);
|
|
2225
|
+
if (!existsSync(file)) continue;
|
|
2226
|
+
const css = readFileSync(file, "utf8");
|
|
2227
|
+
if (!hasTailwindImport(css)) {
|
|
2228
|
+
return {
|
|
2229
|
+
name: "tailwind.config",
|
|
2230
|
+
severity: "warn",
|
|
2231
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
2235
|
+
const issues = tailwind4Issues(css, pkg, versions);
|
|
2236
|
+
if (issues.length > 0) {
|
|
2237
|
+
return {
|
|
2238
|
+
name: "tailwind.config",
|
|
2239
|
+
severity: "warn",
|
|
2240
|
+
message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
return {
|
|
2244
|
+
name: "tailwind.config",
|
|
2245
|
+
severity: "pass",
|
|
2246
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
return {
|
|
2250
|
+
name: "tailwind.config",
|
|
2251
|
+
severity: "warn",
|
|
2252
|
+
message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
for (const file of TAILWIND_CONFIG_FILES) {
|
|
2256
|
+
const path18 = join(baseDir, file);
|
|
2257
|
+
if (!existsSync(path18)) continue;
|
|
2258
|
+
const content = readFileSync(path18, "utf8");
|
|
2259
|
+
if (hasTokensPresetReference(content)) {
|
|
2260
|
+
return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
|
|
2261
|
+
}
|
|
2262
|
+
const ownMapping = content.includes("--background") || content.includes("hsl(var(");
|
|
2263
|
+
return {
|
|
2264
|
+
name: "tailwind.config",
|
|
2265
|
+
severity: "warn",
|
|
2266
|
+
message: ownMapping ? `${file}\uC5D0 AXIS preset(${TOKENS_TAILWIND3_PRESET})\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uCCB4 CSS \uBCC0\uC218 \uB9E4\uD551\uB9CC \uC788\uC74C, presets \uC5D0 \uB123\uC73C\uC138\uC694)` : `${file}\uC5D0 AXIS preset(${TOKENS_TAILWIND3_PRESET})\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (presets \uC5D0 \uB123\uC73C\uC138\uC694)`
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
return { name: "tailwind.config", severity: "fail", message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2270
|
+
}
|
|
2271
|
+
function readAxisConfigLike(baseDir) {
|
|
2272
|
+
try {
|
|
2273
|
+
const parsed = JSON.parse(readFileSync(join(baseDir, "axis.config.json"), "utf8"));
|
|
2274
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
2275
|
+
} catch {
|
|
2276
|
+
return void 0;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
function contentGlobToRegExp(glob) {
|
|
2280
|
+
const g = glob.trim().replace(/^\.\//, "");
|
|
2281
|
+
let re = "";
|
|
2282
|
+
for (let i = 0; i < g.length; i++) {
|
|
2283
|
+
const c = g[i];
|
|
2284
|
+
if (c === "*") {
|
|
2285
|
+
if (g[i + 1] === "*") {
|
|
2286
|
+
const slash = g[i + 2] === "/";
|
|
2287
|
+
re += slash ? "(?:.*/)?" : ".*";
|
|
2288
|
+
i += slash ? 2 : 1;
|
|
2289
|
+
} else re += "[^/]*";
|
|
2290
|
+
} else if (c === "?") re += "[^/]";
|
|
2291
|
+
else if (c === "{") {
|
|
2292
|
+
const end = g.indexOf("}", i);
|
|
2293
|
+
if (end === -1) {
|
|
2294
|
+
re += "\\{";
|
|
2295
|
+
continue;
|
|
2296
|
+
}
|
|
2297
|
+
re += `(?:${g.slice(i + 1, end).split(",").map((part) => part.replace(/[.+^$()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*")).join("|")})`;
|
|
2298
|
+
i = end;
|
|
2299
|
+
} else if (c === "[") {
|
|
2300
|
+
const end = g.indexOf("]", i);
|
|
2301
|
+
if (end === -1) re += "\\[";
|
|
2302
|
+
else {
|
|
2303
|
+
re += g.slice(i, end + 1);
|
|
2304
|
+
i = end;
|
|
2305
|
+
}
|
|
2306
|
+
} else re += c.replace(/[.+^$()|\\]/g, "\\$&");
|
|
2307
|
+
}
|
|
2308
|
+
return new RegExp(`^${re}$`);
|
|
2309
|
+
}
|
|
2310
|
+
function balancedSlice(src, start) {
|
|
2311
|
+
const open = src[start];
|
|
2312
|
+
const close = open === "[" ? "]" : "}";
|
|
2313
|
+
let depth = 0;
|
|
2314
|
+
for (let i = start; i < src.length; i++) {
|
|
2315
|
+
const c = src[i];
|
|
2316
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2317
|
+
let j = i + 1;
|
|
2318
|
+
while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
|
|
2319
|
+
i = j;
|
|
2320
|
+
continue;
|
|
2321
|
+
}
|
|
2322
|
+
if (c === open) depth++;
|
|
2323
|
+
else if (c === close && --depth === 0) return src.slice(start, i + 1);
|
|
2324
|
+
}
|
|
2325
|
+
return void 0;
|
|
2326
|
+
}
|
|
2327
|
+
function stringLiterals(src) {
|
|
2328
|
+
return [...src.matchAll(/(["'`])((?:\\.|(?!\1)[^\\])*)\1/g)].map((m) => m[2]).filter((s) => !s.includes("${"));
|
|
2329
|
+
}
|
|
2330
|
+
function readTailwindContent(source) {
|
|
2331
|
+
const src = stripJsComments(source);
|
|
2332
|
+
const key = /\bcontent\s*:\s*/g;
|
|
2333
|
+
for (const m of src.matchAll(key)) {
|
|
2334
|
+
let at = (m.index ?? 0) + m[0].length;
|
|
2335
|
+
let block = src[at] === "[" || src[at] === "{" ? balancedSlice(src, at) : void 0;
|
|
2336
|
+
if (block === void 0) continue;
|
|
2337
|
+
if (block.startsWith("{")) {
|
|
2338
|
+
const files = /\bfiles\s*:\s*\[/.exec(block);
|
|
2339
|
+
if (!files) return { globs: [], dynamic: true };
|
|
2340
|
+
at = files.index + files[0].length - 1;
|
|
2341
|
+
block = balancedSlice(block, at);
|
|
2342
|
+
if (block === void 0) return { globs: [], dynamic: true };
|
|
2343
|
+
}
|
|
2344
|
+
const inner = block.slice(1, -1);
|
|
2345
|
+
const globs = stringLiterals(inner);
|
|
2346
|
+
const rest = inner.replace(/(["'`])((?:\\.|(?!\1)[^\\])*)\1/g, "").replace(/[\s,]/g, "");
|
|
2347
|
+
return { globs, dynamic: rest !== "" };
|
|
2348
|
+
}
|
|
2349
|
+
return void 0;
|
|
2350
|
+
}
|
|
2351
|
+
function normalizeRel(p) {
|
|
2352
|
+
const s = p.trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
2353
|
+
if (s === "" || s.startsWith("../") || s.startsWith("/") || /^[A-Za-z]:/.test(s)) return void 0;
|
|
2354
|
+
return s;
|
|
2355
|
+
}
|
|
2356
|
+
function inspectTailwindContent(baseDirInput) {
|
|
2357
|
+
const baseDir = resolve(baseDirInput);
|
|
2358
|
+
const pkg = readPackageJson(baseDir);
|
|
2359
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2360
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) return null;
|
|
2361
|
+
const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
|
|
2362
|
+
if (configFile === void 0) return null;
|
|
2363
|
+
const targets = [];
|
|
2364
|
+
const componentsDir = readAxisConfigLike(baseDir)?.componentsDir;
|
|
2365
|
+
const rel3 = typeof componentsDir === "string" ? normalizeRel(componentsDir) : void 0;
|
|
2366
|
+
if (rel3 !== void 0) {
|
|
2367
|
+
targets.push({ label: `componentsDir(${componentsDir})`, sample: `${rel3}/button.tsx`, suggest: `./${rel3}/**/*.{ts,tsx}` });
|
|
2368
|
+
}
|
|
2369
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2370
|
+
if (pkg !== void 0 && hasDependency(pkg, name) !== void 0) {
|
|
2371
|
+
targets.push({ label: name, sample: `node_modules/${name}/dist/index.js`, suggest: `./node_modules/${name}/dist/**/*.{js,mjs}` });
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
if (targets.length === 0) return null;
|
|
2375
|
+
const read = readTailwindContent(readFileSync(join(baseDir, configFile), "utf8"));
|
|
2376
|
+
const patterns = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!")).map(contentGlobToRegExp);
|
|
2377
|
+
return {
|
|
2378
|
+
configFile,
|
|
2379
|
+
unreadable: read === void 0,
|
|
2380
|
+
dynamic: read?.dynamic ?? false,
|
|
2381
|
+
targets: targets.map((t) => ({ ...t, covered: patterns.some((re) => re.test(t.sample)) }))
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
function checkTailwindContent(baseDir) {
|
|
2385
|
+
const r = inspectTailwindContent(baseDir);
|
|
2386
|
+
if (r === null) return null;
|
|
2387
|
+
const missing = r.targets.filter((t) => !t.covered);
|
|
2388
|
+
if (missing.length === 0) {
|
|
2389
|
+
return {
|
|
2390
|
+
name: "tailwind.content",
|
|
2391
|
+
severity: "pass",
|
|
2392
|
+
message: `${r.configFile}\uC758 content \uAC00 ${r.targets.map((t) => t.label).join(" \xB7 ")} \uB97C \uB36E\uC2B5\uB2C8\uB2E4`
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
const list = missing.map((t) => `${t.label} \u2192 "${t.suggest}"`).join(" \xB7 ");
|
|
2396
|
+
if (r.unreadable || r.dynamic) {
|
|
2397
|
+
return {
|
|
2398
|
+
name: "tailwind.content",
|
|
2399
|
+
severity: "warn",
|
|
2400
|
+
message: `${r.configFile}\uC758 content \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${list}`
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
return {
|
|
2404
|
+
name: "tailwind.content",
|
|
2405
|
+
severity: "fail",
|
|
2406
|
+
message: `${r.configFile}\uC758 content \uAC00 \uCEF4\uD3EC\uB10C\uD2B8 \uACBD\uB85C\uB97C \uB36E\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uD074\uB798\uC2A4\uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC74C): ${list}`
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2409
|
+
var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
|
|
2410
|
+
var ANIMATION_PLUGIN_TAILWIND4 = "tw-animate-css";
|
|
2411
|
+
var ANIMATION_SCAN_ENTRY_LIMIT = 2e3;
|
|
2412
|
+
var ANIMATION_SCAN_DEPTH_LIMIT = 8;
|
|
2413
|
+
var ANIMATION_SCAN_FILE_BYTES = 512 * 1024;
|
|
2414
|
+
function componentsUseAnimation(baseDir, componentsDir) {
|
|
2415
|
+
const rel3 = normalizeRel(componentsDir);
|
|
2416
|
+
if (rel3 === void 0) return false;
|
|
2417
|
+
const stack = [[join(baseDir, rel3), 0]];
|
|
2418
|
+
let visited = 0;
|
|
2419
|
+
while (stack.length > 0) {
|
|
2420
|
+
const [dir, depth] = stack.pop();
|
|
2421
|
+
let names;
|
|
2422
|
+
try {
|
|
2423
|
+
names = readdirSync(dir);
|
|
2424
|
+
} catch {
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
for (const name of names) {
|
|
2428
|
+
if (++visited > ANIMATION_SCAN_ENTRY_LIMIT) return false;
|
|
2429
|
+
const p = join(dir, name);
|
|
2430
|
+
let st;
|
|
2431
|
+
try {
|
|
2432
|
+
st = lstatSync(p);
|
|
2433
|
+
} catch {
|
|
2434
|
+
continue;
|
|
2435
|
+
}
|
|
2436
|
+
if (st.isSymbolicLink()) continue;
|
|
2437
|
+
if (st.isDirectory()) {
|
|
2438
|
+
if (name !== "node_modules" && depth < ANIMATION_SCAN_DEPTH_LIMIT) stack.push([p, depth + 1]);
|
|
2439
|
+
} else if (st.isFile() && st.size <= ANIMATION_SCAN_FILE_BYTES && /\.(tsx|ts|jsx|js)$/.test(name)) {
|
|
2440
|
+
if (/\banimate-(?:in|out)\b/.test(readFileSync(p, "utf8"))) return true;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
return false;
|
|
2445
|
+
}
|
|
2446
|
+
function checkAnimationPlugin(baseDirInput) {
|
|
2447
|
+
const baseDir = resolve(baseDirInput);
|
|
2448
|
+
const pkg = readPackageJson(baseDir);
|
|
2449
|
+
const config = readAxisConfigLike(baseDir);
|
|
2450
|
+
const declared = pkg !== void 0 && hasDependency(pkg, "@axis-ds/ui-react") !== void 0;
|
|
2451
|
+
const copied = typeof config?.componentsDir === "string" && componentsUseAnimation(baseDir, config.componentsDir);
|
|
2452
|
+
if (!declared && !copied) return null;
|
|
2453
|
+
const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
|
|
2454
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2455
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2456
|
+
const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync(join(baseDir, c)));
|
|
2457
|
+
const css = file !== void 0 ? stripCssComments(readFileSync(join(baseDir, file), "utf8")) : "";
|
|
2458
|
+
const ok = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css) || new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css);
|
|
2459
|
+
return ok ? { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` } : {
|
|
2460
|
+
name: "animation",
|
|
2461
|
+
severity: "warn",
|
|
2462
|
+
message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND4} \uC124\uCE58 \uB4A4 @import "${ANIMATION_PLUGIN_TAILWIND4}";`
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync(join(baseDir, f)));
|
|
2466
|
+
const source = configFile !== void 0 ? stripJsComments(readFileSync(join(baseDir, configFile), "utf8")) : "";
|
|
2467
|
+
const pluginRef = new RegExp(`["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(source);
|
|
2468
|
+
const pluginDeclared = pkg !== void 0 && hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
|
|
2469
|
+
if (pluginRef && pluginDeclared) {
|
|
2470
|
+
return { name: "animation", severity: "pass", message: `${configFile}\uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
2471
|
+
}
|
|
2472
|
+
const why = !pluginDeclared ? `${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58` : `${configFile ?? "tailwind.config"} plugins \uC5D0 \uC5C6\uC74C`;
|
|
2473
|
+
return {
|
|
2474
|
+
name: "animation",
|
|
2475
|
+
severity: "warn",
|
|
2476
|
+
message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${why}): Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2192 ${ANIMATION_PLUGIN_TAILWIND3} \uC124\uCE58 \uB4A4 plugins \uC5D0 require("${ANIMATION_PLUGIN_TAILWIND3}")`
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
// src/template/template-apply.ts
|
|
2481
|
+
async function templateApplyWarnings(baseDir, detail) {
|
|
2482
|
+
const warnings = [];
|
|
2483
|
+
const pkgPath = path8.join(baseDir, "package.json");
|
|
2484
|
+
const templateRange = detail.devDependencies?.tailwindcss ?? detail.dependencies?.tailwindcss;
|
|
2485
|
+
const templateMajor = templateRange !== void 0 ? tailwindMajorFromRange(templateRange) : void 0;
|
|
2486
|
+
if (templateMajor !== void 0 && await fs8.pathExists(pkgPath)) {
|
|
2487
|
+
let pkg;
|
|
2488
|
+
try {
|
|
2489
|
+
pkg = await fs8.readJSON(pkgPath);
|
|
2490
|
+
} catch {
|
|
2491
|
+
pkg = void 0;
|
|
2492
|
+
}
|
|
2493
|
+
const project = detectTailwind(baseDir, pkg);
|
|
2494
|
+
if (project.major !== void 0 && project.major !== templateMajor) {
|
|
2495
|
+
warnings.push(
|
|
2496
|
+
`\uD15C\uD50C\uB9BF\uC740 Tailwind ${templateMajor} \uAE30\uC900\uC778\uB370 \uC774 \uD504\uB85C\uC81D\uD2B8\uB294 Tailwind ${project.major}(${project.value}) \uC785\uB2C8\uB2E4. \uBE4C\uB4DC \xB7 \uC2A4\uD0C0\uC77C\uC774 \uB9DE\uC9C0 \uC54A\uC744 \uC218 \uC788\uC5B4 \uBE48 \uB514\uB809\uD130\uB9AC\uC5D0 'axis template init' \uC73C\uB85C \uB9CC\uB4DC\uB294 \uAC83\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.`
|
|
2497
|
+
);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
const usesRootApp = detail.files.some((f) => f.path.startsWith("app/"));
|
|
2501
|
+
if (usesRootApp && await fs8.pathExists(path8.join(baseDir, "src", "app"))) {
|
|
2502
|
+
warnings.push(
|
|
2503
|
+
"src/app \uC774 \uC788\uB294\uB370 \uD15C\uD50C\uB9BF\uC740 \uB8E8\uD2B8 app/ \uC744 \uC501\uB2C8\uB2E4. Next.js \uB294 \uB8E8\uD2B8 app/ \uC774 \uC788\uC73C\uBA74 src/app \uC744 \uC4F0\uC9C0 \uC54A\uC544 \uAE30\uC874 \uB77C\uC6B0\uD2B8\uAC00 \uBE60\uC9D1\uB2C8\uB2E4."
|
|
2504
|
+
);
|
|
2505
|
+
}
|
|
2506
|
+
return warnings;
|
|
2507
|
+
}
|
|
2508
|
+
async function applyTemplate(slug, options) {
|
|
2509
|
+
const spinner = ora3(`'${slug}' \uD15C\uD50C\uB9BF \uAC00\uC838\uC624\uB294 \uC911...`).start();
|
|
2510
|
+
let detail;
|
|
2511
|
+
try {
|
|
2512
|
+
detail = await fetchTemplateDetail(slug);
|
|
2513
|
+
spinner.succeed(`'${detail.name}' \uD15C\uD50C\uB9BF \uB85C\uB4DC \uC644\uB8CC (${detail.files.length}\uAC1C \uD30C\uC77C)`);
|
|
2514
|
+
} catch (err) {
|
|
2515
|
+
spinner.fail(err.message);
|
|
2516
|
+
process.exit(1);
|
|
2517
|
+
}
|
|
2518
|
+
const baseDir = path8.resolve(options.dir || ".");
|
|
2519
|
+
for (const w of await templateApplyWarnings(baseDir, detail)) {
|
|
2520
|
+
console.log(chalk5.yellow(`! ${w}`));
|
|
2521
|
+
}
|
|
2522
|
+
const conflicts = [];
|
|
2523
|
+
for (const file of detail.files) {
|
|
2524
|
+
const dest = path8.join(baseDir, file.path);
|
|
2525
|
+
if (await fs8.pathExists(dest)) {
|
|
2526
|
+
conflicts.push(file.path);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
if (conflicts.length > 0 && !options.yes && !options.dryRun) {
|
|
2530
|
+
console.log(chalk5.yellow(`
|
|
2531
|
+
\uAE30\uC874 \uD30C\uC77C\uACFC \uCDA9\uB3CC\uD558\uB294 ${conflicts.length}\uAC1C \uD30C\uC77C:`));
|
|
2532
|
+
for (const c of conflicts) {
|
|
2533
|
+
console.log(chalk5.gray(` - ${c}`));
|
|
2534
|
+
}
|
|
2535
|
+
const { proceed } = await prompts({
|
|
2536
|
+
type: "confirm",
|
|
2537
|
+
name: "proceed",
|
|
2538
|
+
message: "\uCDA9\uB3CC \uD30C\uC77C\uC744 \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
2539
|
+
initial: false
|
|
2540
|
+
});
|
|
2541
|
+
if (!proceed) {
|
|
2542
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
if (options.dryRun) {
|
|
2547
|
+
console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
|
|
2548
|
+
for (const file of detail.files) {
|
|
2549
|
+
const dest = path8.join(baseDir, file.path);
|
|
2550
|
+
const exists = conflicts.includes(file.path);
|
|
2551
|
+
const label = exists ? chalk5.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk5.green("\uC0DD\uC131");
|
|
2552
|
+
console.log(` ${label} ${dest}`);
|
|
2553
|
+
}
|
|
2554
|
+
if (detail.postInstall?.length) {
|
|
2555
|
+
console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] postInstall \uD328\uCE58:"));
|
|
2556
|
+
for (const p of detail.postInstall) {
|
|
2557
|
+
console.log(chalk5.gray(` ${p.type}: ${p.file}`));
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
|
|
2563
|
+
for (const file of detail.files) {
|
|
2564
|
+
const dest = path8.join(baseDir, file.path);
|
|
2565
|
+
await fs8.ensureDir(path8.dirname(dest));
|
|
2566
|
+
await fs8.writeFile(dest, file.content);
|
|
2567
|
+
}
|
|
2568
|
+
writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
|
|
2569
|
+
if (detail.postInstall?.length) {
|
|
2570
|
+
console.log(chalk5.blue("\npostInstall \uD328\uCE58 \uC2E4\uD589 \uC911..."));
|
|
2571
|
+
await runPostInstall(detail.postInstall, baseDir);
|
|
2572
|
+
}
|
|
2573
|
+
if (!options.skipDeps) {
|
|
2574
|
+
const allDeps = { ...detail.dependencies, ...detail.devDependencies };
|
|
2575
|
+
const depList = Object.entries(allDeps);
|
|
2576
|
+
if (depList.length > 0) {
|
|
2577
|
+
console.log(chalk5.yellow("\n\uD544\uC694\uD55C \uC758\uC874\uC131:"));
|
|
2578
|
+
const deps = Object.entries(detail.dependencies || {}).map(([k, v]) => `${k}@${v}`).join(" ");
|
|
2579
|
+
const devDeps = Object.entries(detail.devDependencies || {}).map(([k, v]) => `${k}@${v}`).join(" ");
|
|
2580
|
+
if (deps) {
|
|
2581
|
+
console.log(chalk5.cyan(` pnpm add ${deps}`));
|
|
2582
|
+
}
|
|
2583
|
+
if (devDeps) {
|
|
2584
|
+
console.log(chalk5.cyan(` pnpm add -D ${devDeps}`));
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
console.log(chalk5.green(`
|
|
2589
|
+
'${detail.name}' \uD15C\uD50C\uB9BF \uC801\uC6A9 \uC644\uB8CC!`));
|
|
2590
|
+
}
|
|
2591
|
+
async function initTemplate(slug, options) {
|
|
2592
|
+
let selectedSlug = slug;
|
|
2593
|
+
if (!selectedSlug) {
|
|
2594
|
+
const { fetchTemplateIndex: fetchTemplateIndex2 } = await import("./registry-client-6WSGKPF2.js");
|
|
2595
|
+
const index = await fetchTemplateIndex2();
|
|
2596
|
+
const { choice } = await prompts({
|
|
2597
|
+
type: "select",
|
|
2598
|
+
name: "choice",
|
|
2599
|
+
message: "\uC0AC\uC6A9\uD560 \uD15C\uD50C\uB9BF\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
2600
|
+
choices: index.templates.map((t) => ({
|
|
2601
|
+
title: `${t.name} (${t.category})`,
|
|
2602
|
+
description: t.description,
|
|
2603
|
+
value: t.slug
|
|
2604
|
+
}))
|
|
2605
|
+
});
|
|
2606
|
+
if (!choice) {
|
|
2607
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2608
|
+
return;
|
|
2609
|
+
}
|
|
2610
|
+
selectedSlug = choice;
|
|
2611
|
+
}
|
|
2612
|
+
let targetDir = options.dir;
|
|
2613
|
+
if (!targetDir) {
|
|
2614
|
+
const { dir } = await prompts({
|
|
2615
|
+
type: "text",
|
|
2616
|
+
name: "dir",
|
|
2617
|
+
message: "\uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
|
|
2618
|
+
initial: selectedSlug
|
|
2619
|
+
});
|
|
2620
|
+
if (!dir) {
|
|
2621
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2622
|
+
return;
|
|
2623
|
+
}
|
|
2624
|
+
targetDir = dir;
|
|
2625
|
+
}
|
|
2626
|
+
const resolved = path8.resolve(targetDir);
|
|
2627
|
+
if (await fs8.pathExists(resolved)) {
|
|
2628
|
+
const entries = await fs8.readdir(resolved);
|
|
2629
|
+
if (entries.length > 0) {
|
|
2630
|
+
const { proceed } = await prompts({
|
|
2631
|
+
type: "confirm",
|
|
2632
|
+
name: "proceed",
|
|
2633
|
+
message: `'${targetDir}'\uC5D0 \uC774\uBBF8 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uACC4\uC18D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`,
|
|
2634
|
+
initial: false
|
|
2635
|
+
});
|
|
2636
|
+
if (!proceed) return;
|
|
2637
|
+
}
|
|
2638
|
+
} else {
|
|
2639
|
+
await fs8.ensureDir(resolved);
|
|
2640
|
+
}
|
|
2641
|
+
await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
|
|
2642
|
+
const configPath = path8.join(resolved, "axis.config.json");
|
|
2643
|
+
if (!await fs8.pathExists(configPath)) {
|
|
2644
|
+
const axisConfig = createTemplateConfig(selectedSlug);
|
|
2645
|
+
await fs8.writeJSON(configPath, axisConfig, { spaces: 2 });
|
|
1980
2646
|
console.log(chalk5.green("axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
|
|
1981
2647
|
}
|
|
1982
2648
|
console.log(chalk5.blue(`
|
|
@@ -2062,293 +2728,60 @@ async function diffTemplate(slug, options) {
|
|
|
2062
2728
|
break;
|
|
2063
2729
|
case "unchanged":
|
|
2064
2730
|
unchanged++;
|
|
2065
|
-
break;
|
|
2066
|
-
case "extra":
|
|
2067
|
-
extra++;
|
|
2068
|
-
break;
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
console.log(chalk6.blue("\n\uC694\uC57D:"));
|
|
2072
|
-
console.log(
|
|
2073
|
-
` \uCD94\uAC00 \uD544\uC694: ${chalk6.green(String(added))} | \uBCC0\uACBD\uB428: ${chalk6.yellow(String(modified))} | \uB3D9\uC77C: ${chalk6.gray(String(unchanged))}${extra > 0 ? ` | \uB85C\uCEEC \uC804\uC6A9: ${chalk6.cyan(String(extra))}` : ""}`
|
|
2074
|
-
);
|
|
2075
|
-
}
|
|
2076
|
-
async function collectLocalFiles(dir, base) {
|
|
2077
|
-
const root = base || dir;
|
|
2078
|
-
const ignore = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist"]);
|
|
2079
|
-
const results = [];
|
|
2080
|
-
let entries;
|
|
2081
|
-
try {
|
|
2082
|
-
entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
2083
|
-
} catch {
|
|
2084
|
-
return results;
|
|
2085
|
-
}
|
|
2086
|
-
for (const entry of entries) {
|
|
2087
|
-
if (ignore.has(entry.name)) continue;
|
|
2088
|
-
const fullPath = path9.join(dir, entry.name);
|
|
2089
|
-
if (entry.isDirectory()) {
|
|
2090
|
-
const nested = await collectLocalFiles(fullPath, root);
|
|
2091
|
-
results.push(...nested);
|
|
2092
|
-
} else {
|
|
2093
|
-
results.push(path9.relative(root, fullPath).replace(/\\/g, "/"));
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
return results;
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
// src/template/template-check.ts
|
|
2100
|
-
import fs10 from "fs-extra";
|
|
2101
|
-
import path10 from "path";
|
|
2102
|
-
import chalk7 from "chalk";
|
|
2103
|
-
|
|
2104
|
-
// src/theme/brand-core.ts
|
|
2105
|
-
import { existsSync, readFileSync, statSync } from "fs";
|
|
2106
|
-
import { createRequire } from "module";
|
|
2107
|
-
import { dirname, join, relative, resolve, sep } from "path";
|
|
2108
|
-
var TOKENS_PACKAGE = "@axis-ds/tokens";
|
|
2109
|
-
var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
2110
|
-
var MIN_BRAND_TOKENS_VERSION = "1.3.0";
|
|
2111
|
-
var KEY_TOKENS = [
|
|
2112
|
-
"--primary",
|
|
2113
|
-
"--primary-foreground",
|
|
2114
|
-
"--background",
|
|
2115
|
-
"--foreground",
|
|
2116
|
-
"--ring",
|
|
2117
|
-
"--radius",
|
|
2118
|
-
"--axis-surface-default",
|
|
2119
|
-
"--axis-text-primary",
|
|
2120
|
-
"--axis-text-brand",
|
|
2121
|
-
"--axis-button-bg-default",
|
|
2122
|
-
"--axis-border-focus",
|
|
2123
|
-
"--axis-font-family-sans"
|
|
2124
|
-
];
|
|
2125
|
-
var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
|
|
2126
|
-
function readJsonFile(file) {
|
|
2127
|
-
return JSON.parse(readFileSync(file, "utf8"));
|
|
2128
|
-
}
|
|
2129
|
-
function errorCode(err) {
|
|
2130
|
-
return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
|
|
2131
|
-
}
|
|
2132
|
-
function findTokensPackageJson(baseDir) {
|
|
2133
|
-
let dir = resolve(baseDir);
|
|
2134
|
-
for (; ; ) {
|
|
2135
|
-
const candidate = join(dir, "node_modules", TOKENS_PACKAGE, "package.json");
|
|
2136
|
-
if (existsSync(candidate)) return candidate;
|
|
2137
|
-
const parent = dirname(dir);
|
|
2138
|
-
if (parent === dir) return void 0;
|
|
2139
|
-
dir = parent;
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
function projectRequire(baseDir) {
|
|
2143
|
-
return createRequire(join(resolve(baseDir), "package.json"));
|
|
2144
|
-
}
|
|
2145
|
-
function tokensSpecifier(subpath) {
|
|
2146
|
-
return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
|
|
2147
|
-
}
|
|
2148
|
-
function resolveTokens(baseDir) {
|
|
2149
|
-
const pkgJson = findTokensPackageJson(baseDir);
|
|
2150
|
-
if (!pkgJson) return { status: "not-installed" };
|
|
2151
|
-
const pkg = readJsonFile(pkgJson);
|
|
2152
|
-
const version = typeof pkg.version === "string" ? pkg.version : void 0;
|
|
2153
|
-
try {
|
|
2154
|
-
const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
|
|
2155
|
-
return { status: "ok", version, indexPath };
|
|
2156
|
-
} catch (err) {
|
|
2157
|
-
const code = errorCode(err);
|
|
2158
|
-
if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
|
|
2159
|
-
if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
|
|
2160
|
-
throw err;
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
function brandImportPath(entry) {
|
|
2164
|
-
return tokensSpecifier(entry.css);
|
|
2165
|
-
}
|
|
2166
|
-
var GLOBAL_CSS_CANDIDATES = ["app/globals.css", "src/app/globals.css", "globals.css"];
|
|
2167
|
-
function isFile(file) {
|
|
2168
|
-
try {
|
|
2169
|
-
return statSync(file).isFile();
|
|
2170
|
-
} catch {
|
|
2171
|
-
return false;
|
|
2172
|
-
}
|
|
2173
|
-
}
|
|
2174
|
-
function findGlobalCss(baseDir, config) {
|
|
2175
|
-
const root = resolve(baseDir);
|
|
2176
|
-
const result = {};
|
|
2177
|
-
const configured = config?.globalCss;
|
|
2178
|
-
if (typeof configured === "string" && configured.trim() !== "") {
|
|
2179
|
-
const file = resolve(root, configured);
|
|
2180
|
-
if (isFile(file)) return { path: file };
|
|
2181
|
-
result.configuredMissing = configured;
|
|
2182
|
-
}
|
|
2183
|
-
for (const candidate of GLOBAL_CSS_CANDIDATES) {
|
|
2184
|
-
const file = join(root, candidate);
|
|
2185
|
-
if (isFile(file)) {
|
|
2186
|
-
result.path = file;
|
|
2187
|
-
break;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
return result;
|
|
2191
|
-
}
|
|
2192
|
-
function findBrandImports(css) {
|
|
2193
|
-
const names = [];
|
|
2194
|
-
const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
|
|
2195
|
-
for (const m of stripComments(css).matchAll(pattern)) {
|
|
2196
|
-
names.push(m[1]);
|
|
2197
|
-
}
|
|
2198
|
-
return names;
|
|
2199
|
-
}
|
|
2200
|
-
var AXIS_CONFIG_FILE_NAME = "axis.config.json";
|
|
2201
|
-
function readBrandConfig(baseDir) {
|
|
2202
|
-
let parsed;
|
|
2203
|
-
try {
|
|
2204
|
-
parsed = JSON.parse(readFileSync(join(resolve(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
|
|
2205
|
-
} catch {
|
|
2206
|
-
return null;
|
|
2207
|
-
}
|
|
2208
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
2209
|
-
return parsed;
|
|
2210
|
-
}
|
|
2211
|
-
function inspectBrandImport(baseDir) {
|
|
2212
|
-
const config = readBrandConfig(baseDir);
|
|
2213
|
-
const brand = config?.brand;
|
|
2214
|
-
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
2215
|
-
const root = resolve(baseDir);
|
|
2216
|
-
const location = findGlobalCss(root, config);
|
|
2217
|
-
const base = { brand };
|
|
2218
|
-
if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
|
|
2219
|
-
if (!location.path) {
|
|
2220
|
-
return { ...base, state: "css-missing", imports: [] };
|
|
2221
|
-
}
|
|
2222
|
-
const cssFile = relative(root, location.path).split(sep).join("/");
|
|
2223
|
-
const imports = [...new Set(findBrandImports(readFileSync(location.path, "utf8")))];
|
|
2224
|
-
let state;
|
|
2225
|
-
if (imports.includes(brand)) state = "match";
|
|
2226
|
-
else if (imports.length === 0) state = "import-missing";
|
|
2227
|
-
else state = "other-brand";
|
|
2228
|
-
return { ...base, state, cssFile, imports };
|
|
2229
|
-
}
|
|
2230
|
-
function isMissingBuildFile(err) {
|
|
2231
|
-
const code = errorCode(err);
|
|
2232
|
-
return code === "MODULE_NOT_FOUND" || code === "ENOENT";
|
|
2233
|
-
}
|
|
2234
|
-
function readBrandIndex(indexPath) {
|
|
2235
|
-
const data = readJsonFile(indexPath);
|
|
2236
|
-
if (!Array.isArray(data.brands)) {
|
|
2237
|
-
throw new Error(`${indexPath}: "brands" \uBC30\uC5F4\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
2238
|
-
}
|
|
2239
|
-
return data.brands;
|
|
2240
|
-
}
|
|
2241
|
-
function readSummary(baseDir, entry) {
|
|
2242
|
-
const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
|
|
2243
|
-
const meta = readJsonFile(metaPath);
|
|
2244
|
-
return {
|
|
2245
|
-
name: entry.name,
|
|
2246
|
-
description: typeof meta.description === "string" ? meta.description : "",
|
|
2247
|
-
themes: Array.isArray(meta.themes) ? meta.themes.map(String) : [],
|
|
2248
|
-
a11y: typeof meta.a11y === "object" && meta.a11y !== null ? meta.a11y : {},
|
|
2249
|
-
importPath: brandImportPath(entry)
|
|
2250
|
-
};
|
|
2251
|
-
}
|
|
2252
|
-
function listBrands(baseDir) {
|
|
2253
|
-
const tokens = resolveTokens(baseDir);
|
|
2254
|
-
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
2255
|
-
return { status: tokens.status, version: tokens.version, brands: [] };
|
|
2256
|
-
}
|
|
2257
|
-
const entries = readBrandIndex(tokens.indexPath);
|
|
2258
|
-
let brands;
|
|
2259
|
-
try {
|
|
2260
|
-
brands = entries.map((entry) => readSummary(baseDir, entry));
|
|
2261
|
-
} catch (err) {
|
|
2262
|
-
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
|
|
2263
|
-
throw err;
|
|
2264
|
-
}
|
|
2265
|
-
return { status: "ok", version: tokens.version, brands };
|
|
2266
|
-
}
|
|
2267
|
-
function stripComments(css) {
|
|
2268
|
-
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2269
|
-
}
|
|
2270
|
-
function parseDeclarations(body) {
|
|
2271
|
-
const out = {};
|
|
2272
|
-
for (const m of body.matchAll(/(--[A-Za-z0-9_-]+)\s*:\s*([^;]+);/g)) {
|
|
2273
|
-
out[m[1]] = m[2].trim();
|
|
2274
|
-
}
|
|
2275
|
-
return out;
|
|
2276
|
-
}
|
|
2277
|
-
function isDarkSelector(selector) {
|
|
2278
|
-
return /\.dark\b/.test(selector) || /\[data-theme=["']?dark["']?\]/.test(selector);
|
|
2279
|
-
}
|
|
2280
|
-
function parseBrandCss(css, name) {
|
|
2281
|
-
const result = { light: {}, dark: {} };
|
|
2282
|
-
let lightFound = false;
|
|
2283
|
-
let darkFound = false;
|
|
2284
|
-
const brandAttr = new RegExp(`\\[data-brand=["']?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']?\\]`);
|
|
2285
|
-
for (const m of stripComments(css).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
2286
|
-
const selectors = m[1].split(",").map((s) => s.trim());
|
|
2287
|
-
if (!selectors.some((s) => brandAttr.test(s))) continue;
|
|
2288
|
-
if (selectors.some(isDarkSelector)) {
|
|
2289
|
-
if (!darkFound) {
|
|
2290
|
-
result.dark = parseDeclarations(m[2]);
|
|
2291
|
-
darkFound = true;
|
|
2292
|
-
}
|
|
2293
|
-
} else if (!lightFound) {
|
|
2294
|
-
result.light = parseDeclarations(m[2]);
|
|
2295
|
-
lightFound = true;
|
|
2731
|
+
break;
|
|
2732
|
+
case "extra":
|
|
2733
|
+
extra++;
|
|
2734
|
+
break;
|
|
2296
2735
|
}
|
|
2297
2736
|
}
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
for (const key of KEY_TOKENS) {
|
|
2303
|
-
if (Object.prototype.hasOwnProperty.call(decls, key)) out[key] = decls[key];
|
|
2304
|
-
}
|
|
2305
|
-
return out;
|
|
2306
|
-
}
|
|
2307
|
-
function providerExample(name) {
|
|
2308
|
-
return [
|
|
2309
|
-
'import { ThemeProvider } from "@axis-ds/theme";',
|
|
2310
|
-
"",
|
|
2311
|
-
`<ThemeProvider defaultBrand="${name}">{children}</ThemeProvider>`
|
|
2312
|
-
].join("\n");
|
|
2737
|
+
console.log(chalk6.blue("\n\uC694\uC57D:"));
|
|
2738
|
+
console.log(
|
|
2739
|
+
` \uCD94\uAC00 \uD544\uC694: ${chalk6.green(String(added))} | \uBCC0\uACBD\uB428: ${chalk6.yellow(String(modified))} | \uB3D9\uC77C: ${chalk6.gray(String(unchanged))}${extra > 0 ? ` | \uB85C\uCEEC \uC804\uC6A9: ${chalk6.cyan(String(extra))}` : ""}`
|
|
2740
|
+
);
|
|
2313
2741
|
}
|
|
2314
|
-
function
|
|
2315
|
-
const
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
const entries = readBrandIndex(tokens.indexPath);
|
|
2320
|
-
const available = entries.map((e) => e.name);
|
|
2321
|
-
const entry = entries.find((e) => e.name === name);
|
|
2322
|
-
if (!entry) {
|
|
2323
|
-
return { status: "ok", version: tokens.version, brand: null, available };
|
|
2324
|
-
}
|
|
2325
|
-
let summary;
|
|
2326
|
-
let parsed;
|
|
2742
|
+
async function collectLocalFiles(dir, base) {
|
|
2743
|
+
const root = base || dir;
|
|
2744
|
+
const ignore = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist"]);
|
|
2745
|
+
const results = [];
|
|
2746
|
+
let entries;
|
|
2327
2747
|
try {
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
} catch (err) {
|
|
2332
|
-
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
|
|
2333
|
-
throw err;
|
|
2748
|
+
entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
2749
|
+
} catch {
|
|
2750
|
+
return results;
|
|
2334
2751
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
...
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
adjustments: { a11y: summary.a11y, reference: BRAND_ADJUSTMENT_REFERENCE }
|
|
2752
|
+
for (const entry of entries) {
|
|
2753
|
+
if (ignore.has(entry.name)) continue;
|
|
2754
|
+
const fullPath = path9.join(dir, entry.name);
|
|
2755
|
+
if (entry.isDirectory()) {
|
|
2756
|
+
const nested = await collectLocalFiles(fullPath, root);
|
|
2757
|
+
results.push(...nested);
|
|
2758
|
+
} else {
|
|
2759
|
+
results.push(path9.relative(root, fullPath).replace(/\\/g, "/"));
|
|
2344
2760
|
}
|
|
2345
|
-
}
|
|
2761
|
+
}
|
|
2762
|
+
return results;
|
|
2346
2763
|
}
|
|
2347
2764
|
|
|
2348
|
-
//
|
|
2349
|
-
import
|
|
2350
|
-
import
|
|
2351
|
-
|
|
2765
|
+
// src/template/template-check.ts
|
|
2766
|
+
import fs10 from "fs-extra";
|
|
2767
|
+
import path11 from "path";
|
|
2768
|
+
import chalk7 from "chalk";
|
|
2769
|
+
|
|
2770
|
+
// src/theme/brand-core.ts
|
|
2771
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
2772
|
+
import { createRequire } from "module";
|
|
2773
|
+
import { dirname, join as join2, relative, resolve as resolve2, sep } from "path";
|
|
2774
|
+
|
|
2775
|
+
// ../axis-registry-core/src/project.ts
|
|
2776
|
+
import { existsSync as existsSync2, statSync } from "fs";
|
|
2777
|
+
import path10 from "path";
|
|
2778
|
+
function detectInstallCommand(baseDir) {
|
|
2779
|
+
if (existsSync2(path10.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
2780
|
+
if (existsSync2(path10.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
2781
|
+
if (existsSync2(path10.join(baseDir, "package-lock.json"))) return "npm install";
|
|
2782
|
+
return "pnpm install";
|
|
2783
|
+
}
|
|
2784
|
+
function hasDependency2(pkg, name) {
|
|
2352
2785
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
2353
2786
|
const deps = pkg[field];
|
|
2354
2787
|
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
@@ -2357,424 +2790,352 @@ function hasDependency(pkg, name) {
|
|
|
2357
2790
|
}
|
|
2358
2791
|
return void 0;
|
|
2359
2792
|
}
|
|
2360
|
-
function
|
|
2793
|
+
function isPlainObject2(value) {
|
|
2361
2794
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2362
2795
|
}
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
if (
|
|
2367
|
-
|
|
2368
|
-
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
2369
|
-
}
|
|
2370
|
-
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
2371
|
-
function comparatorBounds(op, v) {
|
|
2372
|
-
switch (op) {
|
|
2373
|
-
case ">=":
|
|
2374
|
-
return { lower: v.major };
|
|
2375
|
-
case ">":
|
|
2376
|
-
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
2377
|
-
case "<=":
|
|
2378
|
-
return { upper: v.major };
|
|
2379
|
-
case "<": {
|
|
2380
|
-
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
2381
|
-
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
2382
|
-
}
|
|
2383
|
-
default:
|
|
2384
|
-
return { lower: v.major, upper: v.major };
|
|
2385
|
-
}
|
|
2386
|
-
}
|
|
2387
|
-
function tailwindMajorBounds(range) {
|
|
2388
|
-
const r = range.trim();
|
|
2389
|
-
if (r === "" || r.includes("||")) return void 0;
|
|
2390
|
-
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2391
|
-
if (simple) {
|
|
2392
|
-
const v = versionParts(simple[1]);
|
|
2393
|
-
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
2394
|
-
}
|
|
2395
|
-
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
2396
|
-
if (hyphen) {
|
|
2397
|
-
const tokens2 = r.split(/\s+-\s+/);
|
|
2398
|
-
const a = versionParts(tokens2[0]);
|
|
2399
|
-
const b = versionParts(tokens2[1]);
|
|
2400
|
-
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
2401
|
-
}
|
|
2402
|
-
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2403
|
-
const lowers = [];
|
|
2404
|
-
const uppers = [];
|
|
2405
|
-
for (const t of tokens) {
|
|
2406
|
-
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2407
|
-
if (!c) return void 0;
|
|
2408
|
-
const v = versionParts(c[2]);
|
|
2409
|
-
if (v === void 0) return void 0;
|
|
2410
|
-
const b = comparatorBounds(c[1], v);
|
|
2411
|
-
if (b.lower !== void 0) lowers.push(b.lower);
|
|
2412
|
-
if (b.upper !== void 0) uppers.push(b.upper);
|
|
2413
|
-
}
|
|
2414
|
-
if (lowers.length === 0) return void 0;
|
|
2415
|
-
const lower = Math.max(...lowers);
|
|
2416
|
-
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
2417
|
-
if (upper !== void 0 && upper < lower) return void 0;
|
|
2418
|
-
return upper !== void 0 ? { lower, upper } : { lower };
|
|
2419
|
-
}
|
|
2420
|
-
function majorWithin(major, bounds) {
|
|
2421
|
-
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
2422
|
-
}
|
|
2423
|
-
function majorFromVersion(version) {
|
|
2424
|
-
if (typeof version !== "string") return void 0;
|
|
2425
|
-
const v = version.trim();
|
|
2426
|
-
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
2427
|
-
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2428
|
-
return Number(m[1]);
|
|
2429
|
-
}
|
|
2430
|
-
function detectTailwind(baseDirInput, pkg) {
|
|
2431
|
-
const baseDir = resolve2(baseDirInput);
|
|
2432
|
-
const installedFile = join2(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
2433
|
-
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
2434
|
-
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
2435
|
-
const declaredMajor = bounds?.lower;
|
|
2436
|
-
try {
|
|
2437
|
-
const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
|
|
2438
|
-
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
2439
|
-
const major = majorFromVersion(version);
|
|
2440
|
-
if (major !== void 0) {
|
|
2441
|
-
const found = { major, source: "installed", value: String(version) };
|
|
2442
|
-
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
2443
|
-
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
2444
|
-
}
|
|
2445
|
-
return found;
|
|
2446
|
-
}
|
|
2447
|
-
} catch {
|
|
2448
|
-
}
|
|
2449
|
-
if (declared !== void 0) {
|
|
2450
|
-
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
2451
|
-
return { source: "none", value: declared };
|
|
2452
|
-
}
|
|
2453
|
-
return { source: "none" };
|
|
2796
|
+
function addCommandFor(installCommand, deps) {
|
|
2797
|
+
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
2798
|
+
if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
|
|
2799
|
+
if (installCommand.startsWith("npm")) return `npm install ${specs}`;
|
|
2800
|
+
return `pnpm add ${specs}`;
|
|
2454
2801
|
}
|
|
2455
|
-
var
|
|
2802
|
+
var GLOBAL_CSS_CANDIDATES = [
|
|
2803
|
+
"app/globals.css",
|
|
2804
|
+
"src/app/globals.css",
|
|
2805
|
+
"styles/globals.css",
|
|
2806
|
+
"src/styles/globals.css",
|
|
2807
|
+
"globals.css"
|
|
2808
|
+
];
|
|
2809
|
+
var TAILWIND_CONFIG_CANDIDATES = [
|
|
2456
2810
|
"tailwind.config.ts",
|
|
2457
2811
|
"tailwind.config.js",
|
|
2458
2812
|
"tailwind.config.mjs",
|
|
2459
2813
|
"tailwind.config.cjs"
|
|
2460
2814
|
];
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
];
|
|
2468
|
-
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2469
|
-
function stripCssComments(css) {
|
|
2470
|
-
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2815
|
+
function isFile(file) {
|
|
2816
|
+
try {
|
|
2817
|
+
return statSync(file).isFile();
|
|
2818
|
+
} catch {
|
|
2819
|
+
return false;
|
|
2820
|
+
}
|
|
2471
2821
|
}
|
|
2472
|
-
function
|
|
2473
|
-
|
|
2822
|
+
function isDirectory(dir) {
|
|
2823
|
+
try {
|
|
2824
|
+
return statSync(dir).isDirectory();
|
|
2825
|
+
} catch {
|
|
2826
|
+
return false;
|
|
2827
|
+
}
|
|
2474
2828
|
}
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
|
|
2478
|
-
function hasTokensTailwind4Import(css) {
|
|
2479
|
-
return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
|
|
2829
|
+
function findFirstFile(baseDir, candidates) {
|
|
2830
|
+
return candidates.find((c) => isFile(path10.join(baseDir, c)));
|
|
2480
2831
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2832
|
+
function detectProjectPaths(baseDirInput) {
|
|
2833
|
+
const baseDir = path10.resolve(baseDirInput);
|
|
2834
|
+
const hasSrc = isDirectory(path10.join(baseDir, "src"));
|
|
2835
|
+
const css = findFirstFile(baseDir, GLOBAL_CSS_CANDIDATES);
|
|
2836
|
+
const tw = findFirstFile(baseDir, TAILWIND_CONFIG_CANDIDATES);
|
|
2837
|
+
return {
|
|
2838
|
+
componentsDir: hasSrc ? "./src/components/ui" : "./components/ui",
|
|
2839
|
+
globalCss: css !== void 0 ? `./${css}` : hasSrc ? "./src/app/globals.css" : "./app/globals.css",
|
|
2840
|
+
globalCssSource: css !== void 0 ? "found" : "default",
|
|
2841
|
+
tailwindConfig: tw !== void 0 ? `./${tw}` : "./tailwind.config.ts",
|
|
2842
|
+
tailwindConfigSource: tw !== void 0 ? "found" : "default"
|
|
2843
|
+
};
|
|
2484
2844
|
}
|
|
2485
|
-
function
|
|
2486
|
-
|
|
2487
|
-
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2488
|
-
const file = join2(baseDir, candidate);
|
|
2489
|
-
if (!existsSync2(file)) continue;
|
|
2490
|
-
const content = readFileSync2(file, "utf8");
|
|
2491
|
-
if (content.includes("--background") && content.includes("--primary")) {
|
|
2492
|
-
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
2493
|
-
}
|
|
2494
|
-
const imported = findTokensCssImport(content);
|
|
2495
|
-
if (imported !== void 0) {
|
|
2496
|
-
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
|
|
2497
|
-
}
|
|
2498
|
-
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
2499
|
-
}
|
|
2500
|
-
return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2845
|
+
function projectFileExists(baseDir, relPath) {
|
|
2846
|
+
return isFile(path10.resolve(baseDir, relPath));
|
|
2501
2847
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2848
|
+
|
|
2849
|
+
// src/theme/brand-core.ts
|
|
2850
|
+
var TOKENS_PACKAGE = "@axis-ds/tokens";
|
|
2851
|
+
var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
2852
|
+
var MIN_BRAND_TOKENS_VERSION = "1.3.0";
|
|
2853
|
+
var TOKENS_DEPENDENCY_MIN_VERSION = "1.6.0";
|
|
2854
|
+
var KEY_TOKENS = [
|
|
2855
|
+
"--primary",
|
|
2856
|
+
"--primary-foreground",
|
|
2857
|
+
"--background",
|
|
2858
|
+
"--foreground",
|
|
2859
|
+
"--ring",
|
|
2860
|
+
"--radius",
|
|
2861
|
+
"--axis-surface-default",
|
|
2862
|
+
"--axis-text-primary",
|
|
2863
|
+
"--axis-text-brand",
|
|
2864
|
+
"--axis-button-bg-default",
|
|
2865
|
+
"--axis-border-focus",
|
|
2866
|
+
"--axis-font-family-sans"
|
|
2867
|
+
];
|
|
2868
|
+
var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
|
|
2869
|
+
function readJsonFile(file) {
|
|
2870
|
+
return JSON.parse(readFileSync2(file, "utf8"));
|
|
2871
|
+
}
|
|
2872
|
+
function errorCode(err) {
|
|
2873
|
+
return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
|
|
2510
2874
|
}
|
|
2511
|
-
function
|
|
2512
|
-
|
|
2513
|
-
|
|
2875
|
+
function findTokensPackageJson(baseDir) {
|
|
2876
|
+
let dir = resolve2(baseDir);
|
|
2877
|
+
for (; ; ) {
|
|
2878
|
+
const candidate = join2(dir, "node_modules", TOKENS_PACKAGE, "package.json");
|
|
2879
|
+
if (existsSync3(candidate)) return candidate;
|
|
2880
|
+
const parent = dirname(dir);
|
|
2881
|
+
if (parent === dir) return void 0;
|
|
2882
|
+
dir = parent;
|
|
2514
2883
|
}
|
|
2515
|
-
return Number(b.pre) - Number(a.pre);
|
|
2516
2884
|
}
|
|
2517
|
-
function
|
|
2518
|
-
|
|
2519
|
-
if (r === "" || r.includes("||")) return void 0;
|
|
2520
|
-
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2521
|
-
if (simple) return lowerOf(simple[1]);
|
|
2522
|
-
if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
|
|
2523
|
-
const [a, b] = r.split(/\s+-\s+/);
|
|
2524
|
-
return lowerOf(b) ? lowerOf(a) : void 0;
|
|
2525
|
-
}
|
|
2526
|
-
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2527
|
-
let lower;
|
|
2528
|
-
for (const t of tokens) {
|
|
2529
|
-
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2530
|
-
if (!c) return void 0;
|
|
2531
|
-
const v = versionParts(c[2]);
|
|
2532
|
-
const low = lowerOf(c[2]);
|
|
2533
|
-
if (!v || !low) return void 0;
|
|
2534
|
-
let candidate;
|
|
2535
|
-
if (c[1] === ">=" || c[1] === "=") candidate = low;
|
|
2536
|
-
else if (c[1] === ">") {
|
|
2537
|
-
if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
|
|
2538
|
-
else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
|
|
2539
|
-
else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
|
|
2540
|
-
}
|
|
2541
|
-
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2542
|
-
}
|
|
2543
|
-
return lower;
|
|
2885
|
+
function projectRequire(baseDir) {
|
|
2886
|
+
return createRequire(join2(resolve2(baseDir), "package.json"));
|
|
2544
2887
|
}
|
|
2545
|
-
function
|
|
2546
|
-
|
|
2547
|
-
const target = lowerOf(min);
|
|
2548
|
-
if (!lower || !target) return void 0;
|
|
2549
|
-
return compareLower(lower, target) >= 0;
|
|
2888
|
+
function tokensSpecifier(subpath) {
|
|
2889
|
+
return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
|
|
2550
2890
|
}
|
|
2551
|
-
function
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2891
|
+
function resolveTokens(baseDir) {
|
|
2892
|
+
const pkgJson = findTokensPackageJson(baseDir);
|
|
2893
|
+
if (!pkgJson) return { status: "not-installed" };
|
|
2894
|
+
const pkg = readJsonFile(pkgJson);
|
|
2895
|
+
const version = typeof pkg.version === "string" ? pkg.version : void 0;
|
|
2896
|
+
try {
|
|
2897
|
+
const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
|
|
2898
|
+
return { status: "ok", version, indexPath };
|
|
2899
|
+
} catch (err) {
|
|
2900
|
+
const code = errorCode(err);
|
|
2901
|
+
if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
|
|
2902
|
+
if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
|
|
2903
|
+
throw err;
|
|
2904
|
+
}
|
|
2556
2905
|
}
|
|
2557
|
-
function
|
|
2906
|
+
function brandImportPath(entry) {
|
|
2907
|
+
return tokensSpecifier(entry.css);
|
|
2908
|
+
}
|
|
2909
|
+
function isFile2(file) {
|
|
2558
2910
|
try {
|
|
2559
|
-
|
|
2560
|
-
return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
|
|
2911
|
+
return statSync2(file).isFile();
|
|
2561
2912
|
} catch {
|
|
2562
|
-
return
|
|
2913
|
+
return false;
|
|
2563
2914
|
}
|
|
2564
2915
|
}
|
|
2565
|
-
function
|
|
2566
|
-
|
|
2567
|
-
const
|
|
2568
|
-
const
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2916
|
+
function findGlobalCss(baseDir, config) {
|
|
2917
|
+
const root = resolve2(baseDir);
|
|
2918
|
+
const result = {};
|
|
2919
|
+
const configured = config?.globalCss;
|
|
2920
|
+
if (typeof configured === "string" && configured.trim() !== "") {
|
|
2921
|
+
const file = resolve2(root, configured);
|
|
2922
|
+
if (isFile2(file)) return { path: file };
|
|
2923
|
+
result.configuredMissing = configured;
|
|
2924
|
+
}
|
|
2925
|
+
for (const candidate of GLOBAL_CSS_CANDIDATES) {
|
|
2926
|
+
const file = join2(root, candidate);
|
|
2927
|
+
if (isFile2(file)) {
|
|
2928
|
+
result.path = file;
|
|
2929
|
+
break;
|
|
2578
2930
|
}
|
|
2579
|
-
const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
|
|
2580
|
-
if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
|
|
2581
|
-
else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
|
|
2582
2931
|
}
|
|
2583
|
-
return
|
|
2584
|
-
}
|
|
2585
|
-
function axisPackageVersionLabel(issue) {
|
|
2586
|
-
return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
|
|
2587
|
-
}
|
|
2588
|
-
var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
2589
|
-
function tailwind4VersionNote(issues) {
|
|
2590
|
-
const below = issues.filter((i) => i.status === "below");
|
|
2591
|
-
const unknown = issues.filter((i) => i.status === "unknown");
|
|
2592
|
-
let note = "";
|
|
2593
|
-
if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
|
|
2594
|
-
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)})`;
|
|
2595
|
-
return note;
|
|
2596
|
-
}
|
|
2597
|
-
var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2598
|
-
function componentTailwindImportLine(name) {
|
|
2599
|
-
return `@import "${name}/tailwind.css";`;
|
|
2600
|
-
}
|
|
2601
|
-
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2602
|
-
function hasComponentTailwindImport(css, name) {
|
|
2603
|
-
const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
|
|
2604
|
-
return re.test(stripCssComments(css));
|
|
2932
|
+
return result;
|
|
2605
2933
|
}
|
|
2606
|
-
function
|
|
2607
|
-
const
|
|
2608
|
-
|
|
2934
|
+
function findBrandImports(css) {
|
|
2935
|
+
const names = [];
|
|
2936
|
+
const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
|
|
2937
|
+
for (const m of stripComments(css).matchAll(pattern)) {
|
|
2938
|
+
names.push(m[1]);
|
|
2939
|
+
}
|
|
2940
|
+
return names;
|
|
2609
2941
|
}
|
|
2610
|
-
var
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
prefix: "@theme",
|
|
2618
|
-
pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2619
|
-
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2620
|
-
},
|
|
2621
|
-
{
|
|
2622
|
-
prefix: "@theme",
|
|
2623
|
-
pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
|
|
2624
|
-
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2625
|
-
},
|
|
2626
|
-
{
|
|
2627
|
-
prefix: "body",
|
|
2628
|
-
pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2629
|
-
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2942
|
+
var AXIS_CONFIG_FILE_NAME = "axis.config.json";
|
|
2943
|
+
function readBrandConfig(baseDir) {
|
|
2944
|
+
let parsed;
|
|
2945
|
+
try {
|
|
2946
|
+
parsed = JSON.parse(readFileSync2(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
|
|
2947
|
+
} catch {
|
|
2948
|
+
return null;
|
|
2630
2949
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2950
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
2951
|
+
return parsed;
|
|
2952
|
+
}
|
|
2953
|
+
function inspectBrandImport(baseDir) {
|
|
2954
|
+
const config = readBrandConfig(baseDir);
|
|
2955
|
+
const brand = config?.brand;
|
|
2956
|
+
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
2957
|
+
const root = resolve2(baseDir);
|
|
2958
|
+
const location = findGlobalCss(root, config);
|
|
2959
|
+
const base = { brand };
|
|
2960
|
+
if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
|
|
2961
|
+
if (!location.path) {
|
|
2962
|
+
return { ...base, state: "css-missing", imports: [] };
|
|
2642
2963
|
}
|
|
2643
|
-
|
|
2964
|
+
const cssFile = relative(root, location.path).split(sep).join("/");
|
|
2965
|
+
const imports = [...new Set(findBrandImports(readFileSync2(location.path, "utf8")))];
|
|
2966
|
+
let state;
|
|
2967
|
+
if (imports.includes(brand)) state = "match";
|
|
2968
|
+
else if (imports.length === 0) state = "import-missing";
|
|
2969
|
+
else state = "other-brand";
|
|
2970
|
+
return { ...base, state, cssFile, imports };
|
|
2644
2971
|
}
|
|
2645
|
-
function
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
let j = i + 1;
|
|
2654
|
-
while (j < n && src[j] !== c) {
|
|
2655
|
-
if (src[j] === "\\") j++;
|
|
2656
|
-
else if (c !== "`" && src[j] === "\n") break;
|
|
2657
|
-
j++;
|
|
2658
|
-
}
|
|
2659
|
-
out += src.slice(i, j + 1);
|
|
2660
|
-
i = j + 1;
|
|
2661
|
-
continue;
|
|
2662
|
-
}
|
|
2663
|
-
if (c === "/" && d === "/") {
|
|
2664
|
-
const end = src.indexOf("\n", i);
|
|
2665
|
-
i = end === -1 ? n : end;
|
|
2666
|
-
continue;
|
|
2667
|
-
}
|
|
2668
|
-
if (c === "/" && d === "*") {
|
|
2669
|
-
const end = src.indexOf("*/", i + 2);
|
|
2670
|
-
i = end === -1 ? n : end + 2;
|
|
2671
|
-
out += " ";
|
|
2672
|
-
continue;
|
|
2673
|
-
}
|
|
2674
|
-
out += c;
|
|
2675
|
-
i++;
|
|
2972
|
+
function isMissingBuildFile(err) {
|
|
2973
|
+
const code = errorCode(err);
|
|
2974
|
+
return code === "MODULE_NOT_FOUND" || code === "ENOENT";
|
|
2975
|
+
}
|
|
2976
|
+
function readBrandIndex(indexPath) {
|
|
2977
|
+
const data = readJsonFile(indexPath);
|
|
2978
|
+
if (!Array.isArray(data.brands)) {
|
|
2979
|
+
throw new Error(`${indexPath}: "brands" \uBC30\uC5F4\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
2676
2980
|
}
|
|
2677
|
-
return
|
|
2981
|
+
return data.brands;
|
|
2678
2982
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
return
|
|
2983
|
+
function readSummary(baseDir, entry) {
|
|
2984
|
+
const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
|
|
2985
|
+
const meta = readJsonFile(metaPath);
|
|
2986
|
+
return {
|
|
2987
|
+
name: entry.name,
|
|
2988
|
+
description: typeof meta.description === "string" ? meta.description : "",
|
|
2989
|
+
themes: Array.isArray(meta.themes) ? meta.themes.map(String) : [],
|
|
2990
|
+
a11y: typeof meta.a11y === "object" && meta.a11y !== null ? meta.a11y : {},
|
|
2991
|
+
importPath: brandImportPath(entry)
|
|
2992
|
+
};
|
|
2683
2993
|
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2994
|
+
function listBrands(baseDir) {
|
|
2995
|
+
const tokens = resolveTokens(baseDir);
|
|
2996
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
2997
|
+
return { status: tokens.status, version: tokens.version, brands: [] };
|
|
2998
|
+
}
|
|
2999
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
3000
|
+
let brands;
|
|
2686
3001
|
try {
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
3002
|
+
brands = entries.map((entry) => readSummary(baseDir, entry));
|
|
3003
|
+
} catch (err) {
|
|
3004
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
|
|
3005
|
+
throw err;
|
|
2691
3006
|
}
|
|
3007
|
+
return { status: "ok", version: tokens.version, brands };
|
|
2692
3008
|
}
|
|
2693
|
-
function
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
const
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
if (missing.length > 0) {
|
|
2701
|
-
issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
|
|
3009
|
+
function stripComments(css) {
|
|
3010
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
3011
|
+
}
|
|
3012
|
+
function parseDeclarations(body) {
|
|
3013
|
+
const out = {};
|
|
3014
|
+
for (const m of body.matchAll(/(--[A-Za-z0-9_-]+)\s*:\s*([^;]+);/g)) {
|
|
3015
|
+
out[m[1]] = m[2].trim();
|
|
2702
3016
|
}
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
3017
|
+
return out;
|
|
3018
|
+
}
|
|
3019
|
+
function isDarkSelector(selector) {
|
|
3020
|
+
return /\.dark\b/.test(selector) || /\[data-theme=["']?dark["']?\]/.test(selector);
|
|
3021
|
+
}
|
|
3022
|
+
function parseBrandCss(css, name) {
|
|
3023
|
+
const result = { light: {}, dark: {} };
|
|
3024
|
+
let lightFound = false;
|
|
3025
|
+
let darkFound = false;
|
|
3026
|
+
const brandAttr = new RegExp(`\\[data-brand=["']?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']?\\]`);
|
|
3027
|
+
for (const m of stripComments(css).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
3028
|
+
const selectors = m[1].split(",").map((s) => s.trim());
|
|
3029
|
+
if (!selectors.some((s) => brandAttr.test(s))) continue;
|
|
3030
|
+
if (selectors.some(isDarkSelector)) {
|
|
3031
|
+
if (!darkFound) {
|
|
3032
|
+
result.dark = parseDeclarations(m[2]);
|
|
3033
|
+
darkFound = true;
|
|
3034
|
+
}
|
|
3035
|
+
} else if (!lightFound) {
|
|
3036
|
+
result.light = parseDeclarations(m[2]);
|
|
3037
|
+
lightFound = true;
|
|
2708
3038
|
}
|
|
2709
3039
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
3040
|
+
return result;
|
|
3041
|
+
}
|
|
3042
|
+
function pickKeyTokens(decls) {
|
|
3043
|
+
const out = {};
|
|
3044
|
+
for (const key of KEY_TOKENS) {
|
|
3045
|
+
if (Object.prototype.hasOwnProperty.call(decls, key)) out[key] = decls[key];
|
|
2714
3046
|
}
|
|
2715
|
-
return
|
|
3047
|
+
return out;
|
|
2716
3048
|
}
|
|
2717
|
-
function
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3049
|
+
function providerExample(name) {
|
|
3050
|
+
return [
|
|
3051
|
+
"// 1) Provider \uC5C6\uC774: \uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx)\uC758 <html> \uC5D0 \uBD99\uC785\uB2C8\uB2E4(\uCCAB \uD654\uBA74\uBD80\uD130 \uC801\uC6A9)",
|
|
3052
|
+
`<html lang="ko" data-brand="${name}">`,
|
|
3053
|
+
"",
|
|
3054
|
+
"// 2) ThemeProvider \uB97C \uC4F0\uBA74 \uB9C8\uC6B4\uD2B8 \uB54C \uBE0C\uB79C\uB4DC\uAC00 \uC5C6\uC73C\uBA74 \uC18D\uC131\uC744 \uC9C0\uC6B0\uBBC0\uB85C setBrand \uB85C \uCF2D\uB2C8\uB2E4(\uC800\uC7A5\uB3FC \uC720\uC9C0, setBrand(undefined) \uB85C \uB054)",
|
|
3055
|
+
'import { useTheme } from "@axis-ds/theme";',
|
|
3056
|
+
"const { setBrand } = useTheme();",
|
|
3057
|
+
`setBrand("${name}");`
|
|
3058
|
+
].join("\n");
|
|
3059
|
+
}
|
|
3060
|
+
var BRAND_ACTIVATION_FILES = [
|
|
3061
|
+
"app/layout.tsx",
|
|
3062
|
+
"app/layout.jsx",
|
|
3063
|
+
"app/layout.js",
|
|
3064
|
+
"src/app/layout.tsx",
|
|
3065
|
+
"src/app/layout.jsx",
|
|
3066
|
+
"src/app/layout.js",
|
|
3067
|
+
"pages/_app.tsx",
|
|
3068
|
+
"pages/_app.jsx",
|
|
3069
|
+
"pages/_document.tsx",
|
|
3070
|
+
"pages/_document.jsx",
|
|
3071
|
+
"src/pages/_app.tsx",
|
|
3072
|
+
"src/pages/_app.jsx",
|
|
3073
|
+
"src/pages/_document.tsx",
|
|
3074
|
+
"src/pages/_document.jsx"
|
|
3075
|
+
];
|
|
3076
|
+
var BRAND_ACTIVATION_PATTERN = /data-brand|setBrand\s*\(|defaultBrand\s*=/;
|
|
3077
|
+
function stripJsLikeComments(src) {
|
|
3078
|
+
return src.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:"'`])\/\/[^\n]*/g, "$1");
|
|
3079
|
+
}
|
|
3080
|
+
function findBrandActivation(baseDir) {
|
|
3081
|
+
const root = resolve2(baseDir);
|
|
3082
|
+
const layoutFiles = [];
|
|
3083
|
+
for (const candidate of BRAND_ACTIVATION_FILES) {
|
|
3084
|
+
const file = join2(root, candidate);
|
|
3085
|
+
if (!isFile2(file)) continue;
|
|
3086
|
+
layoutFiles.push(candidate);
|
|
3087
|
+
const text = stripJsLikeComments(readFileSync2(file, "utf8"));
|
|
3088
|
+
if (BRAND_ACTIVATION_PATTERN.test(text)) return { found: candidate, layoutFiles };
|
|
3089
|
+
for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
|
|
3090
|
+
for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
|
|
3091
|
+
const rel3 = `${dirname(candidate)}/${m[1]}${ext}`;
|
|
3092
|
+
const p = join2(root, rel3);
|
|
3093
|
+
if (isFile2(p) && BRAND_ACTIVATION_PATTERN.test(stripJsLikeComments(readFileSync2(p, "utf8")))) {
|
|
3094
|
+
return { found: rel3, layoutFiles };
|
|
3095
|
+
}
|
|
2742
3096
|
}
|
|
2743
|
-
return {
|
|
2744
|
-
name: "tailwind.config",
|
|
2745
|
-
severity: "pass",
|
|
2746
|
-
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
|
|
2747
|
-
};
|
|
2748
3097
|
}
|
|
2749
|
-
return {
|
|
2750
|
-
name: "tailwind.config",
|
|
2751
|
-
severity: "warn",
|
|
2752
|
-
message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
|
|
2753
|
-
};
|
|
2754
3098
|
}
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
return {
|
|
3099
|
+
return { layoutFiles };
|
|
3100
|
+
}
|
|
3101
|
+
function inspectBrandActivation(baseDir) {
|
|
3102
|
+
const config = readBrandConfig(baseDir);
|
|
3103
|
+
const brand = config?.brand;
|
|
3104
|
+
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
3105
|
+
return { brand, ...findBrandActivation(baseDir) };
|
|
3106
|
+
}
|
|
3107
|
+
function getBrand(baseDir, name) {
|
|
3108
|
+
const tokens = resolveTokens(baseDir);
|
|
3109
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
3110
|
+
return { status: tokens.status, version: tokens.version, brand: null, available: [] };
|
|
2767
3111
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
}
|
|
2774
|
-
return { name: "tailwind.config", severity: "warn", message: `${file} \uC874\uC7AC (TypeScript \uAD8C\uC7A5)` };
|
|
2775
|
-
}
|
|
3112
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
3113
|
+
const available = entries.map((e) => e.name);
|
|
3114
|
+
const entry = entries.find((e) => e.name === name);
|
|
3115
|
+
if (!entry) {
|
|
3116
|
+
return { status: "ok", version: tokens.version, brand: null, available };
|
|
2776
3117
|
}
|
|
2777
|
-
|
|
3118
|
+
let summary;
|
|
3119
|
+
let parsed;
|
|
3120
|
+
try {
|
|
3121
|
+
summary = readSummary(baseDir, entry);
|
|
3122
|
+
const cssPath = projectRequire(baseDir).resolve(summary.importPath);
|
|
3123
|
+
parsed = parseBrandCss(readFileSync2(cssPath, "utf8"), name);
|
|
3124
|
+
} catch (err) {
|
|
3125
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
|
|
3126
|
+
throw err;
|
|
3127
|
+
}
|
|
3128
|
+
return {
|
|
3129
|
+
status: "ok",
|
|
3130
|
+
version: tokens.version,
|
|
3131
|
+
available,
|
|
3132
|
+
brand: {
|
|
3133
|
+
...summary,
|
|
3134
|
+
tokens: { light: pickKeyTokens(parsed.light), dark: pickKeyTokens(parsed.dark) },
|
|
3135
|
+
providerExample: providerExample(name),
|
|
3136
|
+
adjustments: { a11y: summary.a11y, reference: BRAND_ADJUSTMENT_REFERENCE }
|
|
3137
|
+
}
|
|
3138
|
+
};
|
|
2778
3139
|
}
|
|
2779
3140
|
|
|
2780
3141
|
// src/template/template-check.ts
|
|
@@ -2784,7 +3145,7 @@ var SEVERITY_ICON = {
|
|
|
2784
3145
|
fail: chalk7.red("FAIL")
|
|
2785
3146
|
};
|
|
2786
3147
|
async function collectCheckResults(dir) {
|
|
2787
|
-
const baseDir =
|
|
3148
|
+
const baseDir = path11.resolve(dir || ".");
|
|
2788
3149
|
const results = [];
|
|
2789
3150
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
2790
3151
|
results.push(checkTailwindSetup(baseDir));
|
|
@@ -2793,6 +3154,12 @@ async function collectCheckResults(dir) {
|
|
|
2793
3154
|
results.push(await checkDependencies(baseDir));
|
|
2794
3155
|
const brand = checkBrand(baseDir);
|
|
2795
3156
|
if (brand) results.push(brand);
|
|
3157
|
+
const activation = inspectBrandActivation(baseDir);
|
|
3158
|
+
if (activation) results.push(brandActivationResult(activation));
|
|
3159
|
+
const content = checkTailwindContent(baseDir);
|
|
3160
|
+
if (content) results.push(content);
|
|
3161
|
+
const animation = checkAnimationPlugin(baseDir);
|
|
3162
|
+
if (animation) results.push(animation);
|
|
2796
3163
|
return results;
|
|
2797
3164
|
}
|
|
2798
3165
|
async function runCheck(dir) {
|
|
@@ -2829,7 +3196,7 @@ async function runCheck(dir) {
|
|
|
2829
3196
|
return { pass: passCount, warn: warnCount, fail: failCount };
|
|
2830
3197
|
}
|
|
2831
3198
|
async function checkFileExists(baseDir, fileName, label) {
|
|
2832
|
-
const exists = await fs10.pathExists(
|
|
3199
|
+
const exists = await fs10.pathExists(path11.join(baseDir, fileName));
|
|
2833
3200
|
return {
|
|
2834
3201
|
name: label,
|
|
2835
3202
|
severity: exists ? "pass" : "fail",
|
|
@@ -2845,7 +3212,7 @@ async function checkUtils(baseDir) {
|
|
|
2845
3212
|
"utils.ts"
|
|
2846
3213
|
];
|
|
2847
3214
|
for (const candidate of candidates) {
|
|
2848
|
-
const fullPath =
|
|
3215
|
+
const fullPath = path11.join(baseDir, candidate);
|
|
2849
3216
|
if (await fs10.pathExists(fullPath)) {
|
|
2850
3217
|
const content = await fs10.readFile(fullPath, "utf-8");
|
|
2851
3218
|
const hasCn = content.includes("function cn");
|
|
@@ -2863,7 +3230,7 @@ async function checkUtils(baseDir) {
|
|
|
2863
3230
|
};
|
|
2864
3231
|
}
|
|
2865
3232
|
async function checkDependencies(baseDir) {
|
|
2866
|
-
const pkgPath =
|
|
3233
|
+
const pkgPath = path11.join(baseDir, "package.json");
|
|
2867
3234
|
if (!await fs10.pathExists(pkgPath)) {
|
|
2868
3235
|
return {
|
|
2869
3236
|
name: "package.json",
|
|
@@ -2931,6 +3298,21 @@ function brandCheckResult(check) {
|
|
|
2931
3298
|
};
|
|
2932
3299
|
}
|
|
2933
3300
|
}
|
|
3301
|
+
function brandActivationResult(check) {
|
|
3302
|
+
if (check.found) {
|
|
3303
|
+
return {
|
|
3304
|
+
name: "brand.activation",
|
|
3305
|
+
severity: "pass",
|
|
3306
|
+
message: `${check.found}\uC5D0 \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uAC00 \uC788\uC2B5\uB2C8\uB2E4`
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
const where = check.layoutFiles.length > 0 ? check.layoutFiles.join(" \xB7 ") : "\uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx \uB4F1)";
|
|
3310
|
+
return {
|
|
3311
|
+
name: "brand.activation",
|
|
3312
|
+
severity: "warn",
|
|
3313
|
+
message: `brand "${check.brand}" \uAC00 \uC124\uC815\uB410\uC9C0\uB9CC ${where}\uC5D0 \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(ThemeProvider \uB9CC\uC73C\uB85C\uB294 \uB9C8\uC6B4\uD2B8 \uB54C \uAEBC\uC9D0) \u2192 <html data-brand="${check.brand}"> \uB610\uB294 setBrand("${check.brand}")`
|
|
3314
|
+
};
|
|
3315
|
+
}
|
|
2934
3316
|
|
|
2935
3317
|
// src/template/index.ts
|
|
2936
3318
|
function registerTemplateCommand(program2) {
|
|
@@ -3042,32 +3424,10 @@ import path13 from "path";
|
|
|
3042
3424
|
// src/theme/theme-add.ts
|
|
3043
3425
|
import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
3044
3426
|
import path12 from "path";
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
import { existsSync as existsSync3 } from "fs";
|
|
3048
|
-
import path11 from "path";
|
|
3049
|
-
function detectInstallCommand(baseDir) {
|
|
3050
|
-
if (existsSync3(path11.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
3051
|
-
if (existsSync3(path11.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
3052
|
-
if (existsSync3(path11.join(baseDir, "package-lock.json"))) return "npm install";
|
|
3053
|
-
return "pnpm install";
|
|
3054
|
-
}
|
|
3055
|
-
function hasDependency2(pkg, name) {
|
|
3056
|
-
for (const field of ["dependencies", "devDependencies"]) {
|
|
3057
|
-
const deps = pkg[field];
|
|
3058
|
-
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
3059
|
-
return String(deps[name]);
|
|
3060
|
-
}
|
|
3061
|
-
}
|
|
3062
|
-
return void 0;
|
|
3063
|
-
}
|
|
3064
|
-
function isPlainObject2(value) {
|
|
3065
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3066
|
-
}
|
|
3067
|
-
|
|
3068
|
-
// src/theme/theme-add.ts
|
|
3069
|
-
var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
|
|
3427
|
+
var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
|
|
3428
|
+
var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
|
|
3070
3429
|
var THEME_PACKAGE = "@axis-ds/theme";
|
|
3430
|
+
var THEME_MIN_VERSION = "1.3.0";
|
|
3071
3431
|
function readText(file) {
|
|
3072
3432
|
return existsSync4(file) ? readFileSync3(file, "utf8") : null;
|
|
3073
3433
|
}
|
|
@@ -3120,6 +3480,31 @@ function insertImportLine(css, line) {
|
|
|
3120
3480
|
lines.splice(insertAt, 0, line);
|
|
3121
3481
|
return bom + lines.join(eol);
|
|
3122
3482
|
}
|
|
3483
|
+
function insertImportLines(css, lines) {
|
|
3484
|
+
if (lines.length === 0) return css;
|
|
3485
|
+
const body = css.startsWith("\uFEFF") ? css.slice(1) : css;
|
|
3486
|
+
return insertImportLine(css, lines.join(eolOf(body)));
|
|
3487
|
+
}
|
|
3488
|
+
function findLateImports(css) {
|
|
3489
|
+
const body = css.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
|
|
3490
|
+
const lines = body.split(/\r?\n/);
|
|
3491
|
+
let rulesStarted = false;
|
|
3492
|
+
const late = [];
|
|
3493
|
+
for (const raw of lines) {
|
|
3494
|
+
const line = raw.trim();
|
|
3495
|
+
if (line === "") continue;
|
|
3496
|
+
if (/^@(charset|import)\b/i.test(line)) {
|
|
3497
|
+
if (rulesStarted && /^@import\b/i.test(line)) late.push(line);
|
|
3498
|
+
continue;
|
|
3499
|
+
}
|
|
3500
|
+
rulesStarted = true;
|
|
3501
|
+
}
|
|
3502
|
+
return late;
|
|
3503
|
+
}
|
|
3504
|
+
function hasCssImport(css, specifier) {
|
|
3505
|
+
const esc = specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3506
|
+
return new RegExp(`@import\\s+(?:url\\(\\s*)?["']${esc}(?:\\.css)?["']`).test(css.replace(/\/\*[\s\S]*?\*\//g, ""));
|
|
3507
|
+
}
|
|
3123
3508
|
function compareVersions(a, b) {
|
|
3124
3509
|
const parse = (v) => {
|
|
3125
3510
|
const m = /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(v.trim());
|
|
@@ -3194,6 +3579,28 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3194
3579
|
} else {
|
|
3195
3580
|
plan.unverifiedBrand = true;
|
|
3196
3581
|
}
|
|
3582
|
+
const pkgFile = path12.join(baseDir, "package.json");
|
|
3583
|
+
const pkgText = readText(pkgFile);
|
|
3584
|
+
let pkg;
|
|
3585
|
+
if (pkgText !== null) {
|
|
3586
|
+
try {
|
|
3587
|
+
const parsed = JSON.parse(pkgText);
|
|
3588
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3589
|
+
pkg = parsed;
|
|
3590
|
+
} catch (err) {
|
|
3591
|
+
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
3592
|
+
plan.writes = [];
|
|
3593
|
+
return plan;
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
3597
|
+
const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
|
|
3598
|
+
const requiredBaseImports = tailwind4 ? [
|
|
3599
|
+
TOKENS_TAILWIND4_ENTRY,
|
|
3600
|
+
...TAILWIND4_COMPONENT_PACKAGES.filter((n) => pkg !== void 0 && hasDependency2(pkg, n) !== void 0).map(
|
|
3601
|
+
(n) => `${n}/tailwind.css`
|
|
3602
|
+
)
|
|
3603
|
+
] : [...TAILWIND3_BASE_IMPORTS];
|
|
3197
3604
|
const location = findGlobalCss(baseDir, config);
|
|
3198
3605
|
if (location.path) {
|
|
3199
3606
|
const where = realPathInside(baseDir, location.path);
|
|
@@ -3210,45 +3617,62 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3210
3617
|
const before = readFileSync3(location.path, "utf8");
|
|
3211
3618
|
const imported = findBrandImports(before);
|
|
3212
3619
|
const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
}
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3620
|
+
const brandAdded = !imported.includes(brand);
|
|
3621
|
+
const baseImports = requiredBaseImports.filter((spec) => !hasCssImport(before, spec));
|
|
3622
|
+
const lines = [...baseImports.map((spec) => `@import "${spec}";`), ...brandAdded ? [`@import "${plan.importPath}";`] : []];
|
|
3623
|
+
plan.css = {
|
|
3624
|
+
file: location.path,
|
|
3625
|
+
configuredMissing: location.configuredMissing,
|
|
3626
|
+
action: lines.length > 0 ? "add" : "exists",
|
|
3627
|
+
otherBrands,
|
|
3628
|
+
brandAdded,
|
|
3629
|
+
baseImports,
|
|
3630
|
+
requiredBaseImports,
|
|
3631
|
+
lateImports: findLateImports(before),
|
|
3632
|
+
tailwind4
|
|
3633
|
+
};
|
|
3634
|
+
if (lines.length > 0) {
|
|
3635
|
+
plan.writes.push({ file: location.path, before, after: insertImportLines(before, lines) });
|
|
3222
3636
|
}
|
|
3223
3637
|
} else {
|
|
3224
|
-
plan.css = {
|
|
3638
|
+
plan.css = {
|
|
3639
|
+
configuredMissing: location.configuredMissing,
|
|
3640
|
+
action: "manual",
|
|
3641
|
+
otherBrands: [],
|
|
3642
|
+
brandAdded: true,
|
|
3643
|
+
baseImports: requiredBaseImports,
|
|
3644
|
+
requiredBaseImports,
|
|
3645
|
+
lateImports: [],
|
|
3646
|
+
tailwind4
|
|
3647
|
+
};
|
|
3225
3648
|
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3649
|
+
if (!tailwind4) {
|
|
3650
|
+
const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync4(path12.join(baseDir, f)));
|
|
3651
|
+
const content = inspectTailwindContent(baseDir);
|
|
3652
|
+
plan.tailwindConfig = {
|
|
3653
|
+
configFile: configFile2,
|
|
3654
|
+
presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync3(path12.join(baseDir, configFile2), "utf8")),
|
|
3655
|
+
contentMissing: content?.targets.filter((t) => !t.covered) ?? [],
|
|
3656
|
+
contentUnknown: content !== null && (content.unreadable || content.dynamic)
|
|
3657
|
+
};
|
|
3658
|
+
}
|
|
3659
|
+
plan.activation = findBrandActivation(baseDir);
|
|
3228
3660
|
const installed = plan.tokens.version;
|
|
3229
3661
|
const upgrade = installed !== void 0 && (compareVersions(installed, MIN_BRAND_TOKENS_VERSION) ?? 0) < 0;
|
|
3230
|
-
|
|
3231
|
-
|
|
3662
|
+
const tokensAddCommand = addCommandFor(plan.installCommand, { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
3663
|
+
const themeAddCommand = addCommandFor(plan.installCommand, { [THEME_PACKAGE]: `^${THEME_MIN_VERSION}` });
|
|
3664
|
+
if (pkgText === null || pkg === void 0) {
|
|
3665
|
+
plan.dependency = { action: "no-package-json", upgrade, themeMissing: false, tokensAddCommand, themeAddCommand };
|
|
3232
3666
|
} else {
|
|
3233
|
-
let pkg;
|
|
3234
|
-
try {
|
|
3235
|
-
const parsed = JSON.parse(pkgText);
|
|
3236
|
-
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3237
|
-
pkg = parsed;
|
|
3238
|
-
} catch (err) {
|
|
3239
|
-
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
3240
|
-
plan.writes = [];
|
|
3241
|
-
return plan;
|
|
3242
|
-
}
|
|
3243
3667
|
const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
|
|
3244
3668
|
const declared = hasDependency2(pkg, TOKENS_PACKAGE);
|
|
3245
3669
|
if (declared !== void 0) {
|
|
3246
|
-
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
|
|
3670
|
+
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing, tokensAddCommand, themeAddCommand };
|
|
3247
3671
|
} else {
|
|
3248
3672
|
const deps = isPlainObject2(pkg.dependencies) ? { ...pkg.dependencies } : {};
|
|
3249
3673
|
deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
|
|
3250
3674
|
const next = { ...pkg, dependencies: deps };
|
|
3251
|
-
plan.dependency = { action: "add", upgrade, themeMissing };
|
|
3675
|
+
plan.dependency = { action: "add", upgrade, themeMissing, tokensAddCommand, themeAddCommand };
|
|
3252
3676
|
plan.writes.push({ file: pkgFile, before: pkgText, after: formatJsonLike(pkgText, next) });
|
|
3253
3677
|
}
|
|
3254
3678
|
}
|
|
@@ -3330,33 +3754,36 @@ function applyThemeAdd(plan) {
|
|
|
3330
3754
|
}
|
|
3331
3755
|
|
|
3332
3756
|
// src/theme/index.ts
|
|
3333
|
-
|
|
3334
|
-
|
|
3757
|
+
function tokensInstallCommand(baseDir) {
|
|
3758
|
+
return addCommandFor(detectInstallCommand(baseDir), { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
3759
|
+
}
|
|
3760
|
+
var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
3761
|
+
function tokensStatusGuide(status, version, installCommand = TOKENS_INSTALL_COMMAND) {
|
|
3335
3762
|
switch (status) {
|
|
3336
3763
|
case "not-installed":
|
|
3337
3764
|
return [
|
|
3338
3765
|
chalk9.yellow(`${TOKENS_PACKAGE} \uAC00 \uC124\uCE58\uB3FC \uC788\uC9C0 \uC54A\uC544 \uBE0C\uB79C\uB4DC\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`),
|
|
3339
|
-
` \uC124\uCE58: ${chalk9.cyan(
|
|
3766
|
+
` \uC124\uCE58: ${chalk9.cyan(installCommand)}`
|
|
3340
3767
|
];
|
|
3341
3768
|
case "unsupported":
|
|
3342
3769
|
return [
|
|
3343
3770
|
chalk9.yellow(
|
|
3344
3771
|
`${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).`
|
|
3345
3772
|
),
|
|
3346
|
-
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(
|
|
3773
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(installCommand)}`
|
|
3347
3774
|
];
|
|
3348
3775
|
case "not-built":
|
|
3349
3776
|
return [
|
|
3350
3777
|
chalk9.yellow(
|
|
3351
3778
|
`${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.`
|
|
3352
3779
|
),
|
|
3353
|
-
` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk9.cyan(
|
|
3780
|
+
` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk9.cyan(installCommand)}`
|
|
3354
3781
|
];
|
|
3355
3782
|
}
|
|
3356
3783
|
}
|
|
3357
|
-
function renderThemeList(result) {
|
|
3784
|
+
function renderThemeList(result, installCommand) {
|
|
3358
3785
|
if (result.status !== "ok") {
|
|
3359
|
-
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
3786
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version, installCommand), ""], exitCode: 1 };
|
|
3360
3787
|
}
|
|
3361
3788
|
if (result.brands.length === 0) {
|
|
3362
3789
|
return {
|
|
@@ -3401,9 +3828,9 @@ function tokenTable(brand) {
|
|
|
3401
3828
|
}
|
|
3402
3829
|
return lines;
|
|
3403
3830
|
}
|
|
3404
|
-
function renderThemeInfo(result, name) {
|
|
3831
|
+
function renderThemeInfo(result, name, installCommand) {
|
|
3405
3832
|
if (result.status !== "ok") {
|
|
3406
|
-
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
3833
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version, installCommand), ""], exitCode: 1 };
|
|
3407
3834
|
}
|
|
3408
3835
|
const brand = result.brand;
|
|
3409
3836
|
if (!brand) {
|
|
@@ -3427,7 +3854,7 @@ function renderThemeInfo(result, name) {
|
|
|
3427
3854
|
chalk9.bold("Import (globals.css, @charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)"),
|
|
3428
3855
|
` @import "${brand.importPath}";`,
|
|
3429
3856
|
"",
|
|
3430
|
-
chalk9.bold("
|
|
3857
|
+
chalk9.bold("\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 @axis-ds/theme 1.3.0 \uC774\uC0C1)"),
|
|
3431
3858
|
...brand.providerExample.split("\n").map((l) => l ? ` ${l}` : ""),
|
|
3432
3859
|
chalk9.gray(
|
|
3433
3860
|
` 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.`
|
|
@@ -3512,14 +3939,31 @@ function renderThemeAdd(plan, written) {
|
|
|
3512
3939
|
)
|
|
3513
3940
|
);
|
|
3514
3941
|
}
|
|
3942
|
+
const brandLine = `@import "${plan.importPath}";`;
|
|
3515
3943
|
if (css?.action === "add" && css.file) {
|
|
3516
|
-
|
|
3944
|
+
for (const spec of css.baseImports) {
|
|
3945
|
+
lines.push(` ${chalk9.green("\u2713")} ${rel(plan, css.file)}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS, \uBE0C\uB79C\uB4DC \uC55E)`);
|
|
3946
|
+
}
|
|
3947
|
+
if (css.brandAdded) lines.push(` ${chalk9.green("\u2713")} ${rel(plan, css.file)}: ${brandLine} \uCD94\uAC00`);
|
|
3948
|
+
else lines.push(` ${chalk9.gray("-")} ${rel(plan, css.file)}: \uBE0C\uB79C\uB4DC import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
|
|
3517
3949
|
} else if (css?.action === "exists" && css.file) {
|
|
3518
3950
|
lines.push(` ${chalk9.gray("-")} ${rel(plan, css.file)}: import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
|
|
3519
3951
|
} else {
|
|
3520
3952
|
lines.push(
|
|
3521
|
-
chalk9.yellow(
|
|
3522
|
-
|
|
3953
|
+
chalk9.yellow(
|
|
3954
|
+
" ! CSS \uC9C4\uC785\uC810(globalCss \xB7 app/globals.css \xB7 src/app/globals.css \xB7 styles/globals.css \xB7 src/styles/globals.css \xB7 globals.css)\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."
|
|
3955
|
+
),
|
|
3956
|
+
` \uC804\uC5ED CSS \uB9E8 \uC55E(@charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)\uC5D0 \uC774 \uC21C\uC11C\uB85C \uC9C1\uC811 \uB123\uC73C\uC138\uC694: ${[
|
|
3957
|
+
...(css?.requiredBaseImports ?? []).map((spec) => `@import "${spec}";`),
|
|
3958
|
+
brandLine
|
|
3959
|
+
].join(" ")}`
|
|
3960
|
+
);
|
|
3961
|
+
}
|
|
3962
|
+
if (css && css.lateImports.length > 0) {
|
|
3963
|
+
lines.push(
|
|
3964
|
+
chalk9.yellow(
|
|
3965
|
+
` ! \uADDC\uCE59(@tailwind \uB4F1) \uB4A4\uC5D0 \uC788\uB294 @import ${css.lateImports.length}\uC904\uC740 CSS \uADDC\uCE59\uC0C1 \uBB34\uC2DC\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4(Next.js \uB294 \uC55E\uC73C\uB85C \uB04C\uC5B4\uC62C\uB824 \uC801\uC6A9). \uB9E8 \uC55E\uC73C\uB85C \uC62E\uAE30\uC138\uC694: ${css.lateImports.join(" ")}`
|
|
3966
|
+
)
|
|
3523
3967
|
);
|
|
3524
3968
|
}
|
|
3525
3969
|
if (css && css.otherBrands.length > 0) {
|
|
@@ -3538,16 +3982,14 @@ function renderThemeAdd(plan, written) {
|
|
|
3538
3982
|
} else if (dep?.action === "present") {
|
|
3539
3983
|
lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
|
|
3540
3984
|
} else if (dep?.action === "no-package-json") {
|
|
3541
|
-
lines.push(
|
|
3542
|
-
chalk9.yellow(` ! package.json \uC774 \uC5C6\uC5B4 \uC758\uC874\uC131\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${TOKENS_INSTALL_COMMAND}`)
|
|
3543
|
-
);
|
|
3985
|
+
lines.push(chalk9.yellow(` ! package.json \uC774 \uC5C6\uC5B4 \uC758\uC874\uC131\uC744 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${dep.tokensAddCommand}`));
|
|
3544
3986
|
}
|
|
3545
3987
|
if (dep?.upgrade) {
|
|
3546
3988
|
lines.push(
|
|
3547
3989
|
chalk9.yellow(
|
|
3548
3990
|
` ! \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).`
|
|
3549
3991
|
),
|
|
3550
|
-
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(
|
|
3992
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(dep.tokensAddCommand)}`
|
|
3551
3993
|
);
|
|
3552
3994
|
}
|
|
3553
3995
|
if (plan.configChanged) {
|
|
@@ -3555,16 +3997,36 @@ function renderThemeAdd(plan, written) {
|
|
|
3555
3997
|
} else {
|
|
3556
3998
|
lines.push(` ${chalk9.gray("-")} axis.config.json: brand \uAC00 \uC774\uBBF8 "${plan.brand}"`);
|
|
3557
3999
|
}
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
chalk9.bold(`
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
4000
|
+
const tw = plan.tailwindConfig;
|
|
4001
|
+
if (tw && (tw.presetMissing || tw.contentMissing.length > 0)) {
|
|
4002
|
+
lines.push("", chalk9.bold(`Tailwind \uC124\uC815 (${tw.configFile ?? "tailwind.config"}, \uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4)`));
|
|
4003
|
+
if (tw.presetMissing) {
|
|
4004
|
+
lines.push(
|
|
4005
|
+
chalk9.yellow(` ! AXIS preset \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. presets \uC5D0 \uB123\uC73C\uC138\uC694: presets: [require("${TOKENS_TAILWIND3_PRESET}")]`) + chalk9.gray(` (ESM \uC774\uBA74 import axisPreset from "${TOKENS_TAILWIND3_PRESET}")`)
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
for (const t of tw.contentMissing) {
|
|
4009
|
+
lines.push(
|
|
4010
|
+
chalk9.yellow(
|
|
4011
|
+
` ! content \uAC00 ${t.label} \uB97C \uB36E\uC9C0 ${tw.contentUnknown ? "\uC54A\uB294 \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4(\uC815\uC801 \uD310\uB3C5)" : "\uC54A\uC2B5\uB2C8\uB2E4"}. \uB123\uC73C\uC138\uC694: "${t.suggest}"`
|
|
4012
|
+
)
|
|
4013
|
+
);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
const act = plan.activation;
|
|
4017
|
+
lines.push("", chalk9.bold(`\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 ${THEME_PACKAGE} ${THEME_MIN_VERSION} \uC774\uC0C1)`));
|
|
4018
|
+
if (act?.found) {
|
|
4019
|
+
lines.push(` ${chalk9.gray("-")} ${act.found} \uC5D0 \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uAC00 \uC788\uC2B5\uB2C8\uB2E4. "${plan.brand}" \uB85C \uCF1C\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`);
|
|
4020
|
+
} else {
|
|
4021
|
+
lines.push(
|
|
4022
|
+
...providerExample(plan.brand).split("\n").map((l) => l ? ` ${l}` : ""),
|
|
4023
|
+
chalk9.yellow(
|
|
4024
|
+
` ! ${act && act.layoutFiles.length > 0 ? act.layoutFiles.join(" \xB7 ") : "\uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3"} \uC5D0\uC11C \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB458 \uB2E4 \uC5C6\uC73C\uBA74 import \uB9CC\uC73C\uB85C\uB294 \uD654\uBA74\uC774 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
|
|
4025
|
+
)
|
|
4026
|
+
);
|
|
4027
|
+
}
|
|
3566
4028
|
if (dep?.themeMissing) {
|
|
3567
|
-
lines.push(` ${THEME_PACKAGE} \uC124\uCE58: ${chalk9.cyan(
|
|
4029
|
+
lines.push(` ThemeProvider \uB97C \uC4F0\uBA74 ${THEME_PACKAGE} \uC124\uCE58: ${chalk9.cyan(dep.themeAddCommand)}`);
|
|
3568
4030
|
}
|
|
3569
4031
|
lines.push("", chalk9.gray(written.length > 0 ? `\uD30C\uC77C ${written.length}\uAC1C\uB97C \uBC14\uAFE8\uC2B5\uB2C8\uB2E4.` : "\uBC14\uAFBC \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."), "");
|
|
3570
4032
|
return { lines, exitCode: 0 };
|
|
@@ -3598,11 +4060,11 @@ function registerThemeCommand(program2) {
|
|
|
3598
4060
|
const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
|
|
3599
4061
|
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) => {
|
|
3600
4062
|
const baseDir = path13.resolve(options.dir || ".");
|
|
3601
|
-
print(renderThemeList(listBrands(baseDir)));
|
|
4063
|
+
print(renderThemeList(listBrands(baseDir), tokensInstallCommand(baseDir)));
|
|
3602
4064
|
});
|
|
3603
4065
|
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) => {
|
|
3604
4066
|
const baseDir = path13.resolve(options.dir || ".");
|
|
3605
|
-
print(renderThemeInfo(getBrand(baseDir, name), name));
|
|
4067
|
+
print(renderThemeInfo(getBrand(baseDir, name), name, tokensInstallCommand(baseDir)));
|
|
3606
4068
|
});
|
|
3607
4069
|
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) => {
|
|
3608
4070
|
const baseDir = path13.resolve(options.dir || ".");
|
|
@@ -3925,13 +4387,13 @@ async function fetchRegistryJson(url, options = {}) {
|
|
|
3925
4387
|
}
|
|
3926
4388
|
|
|
3927
4389
|
// src/init/init.ts
|
|
3928
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as
|
|
4390
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
3929
4391
|
import path15 from "path";
|
|
3930
4392
|
import chalk10 from "chalk";
|
|
3931
4393
|
import fs12 from "fs-extra";
|
|
3932
4394
|
|
|
3933
4395
|
// ../axis-registry-core/src/add/safe-write.ts
|
|
3934
|
-
import { constants as fsConstants, existsSync as existsSync5, lstatSync, realpathSync as realpathSync2, statSync as
|
|
4396
|
+
import { constants as fsConstants, existsSync as existsSync5, lstatSync as lstatSync2, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
|
|
3935
4397
|
import path14 from "path";
|
|
3936
4398
|
import fs11 from "fs-extra";
|
|
3937
4399
|
var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
|
|
@@ -3969,7 +4431,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
3969
4431
|
}
|
|
3970
4432
|
let st = null;
|
|
3971
4433
|
try {
|
|
3972
|
-
st =
|
|
4434
|
+
st = lstatSync2(target);
|
|
3973
4435
|
} catch {
|
|
3974
4436
|
st = null;
|
|
3975
4437
|
}
|
|
@@ -3987,7 +4449,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
3987
4449
|
}
|
|
3988
4450
|
let followed;
|
|
3989
4451
|
try {
|
|
3990
|
-
followed =
|
|
4452
|
+
followed = statSync3(realTarget);
|
|
3991
4453
|
} catch {
|
|
3992
4454
|
return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
|
|
3993
4455
|
}
|
|
@@ -4003,7 +4465,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
4003
4465
|
}
|
|
4004
4466
|
function isSymlink(p) {
|
|
4005
4467
|
try {
|
|
4006
|
-
return
|
|
4468
|
+
return lstatSync2(p).isSymbolicLink();
|
|
4007
4469
|
} catch {
|
|
4008
4470
|
return false;
|
|
4009
4471
|
}
|
|
@@ -4019,7 +4481,7 @@ function outsideLinkTarget(root, target) {
|
|
|
4019
4481
|
}
|
|
4020
4482
|
function hardLinkCount(target) {
|
|
4021
4483
|
try {
|
|
4022
|
-
const st =
|
|
4484
|
+
const st = lstatSync2(target);
|
|
4023
4485
|
return st.isFile() && st.nlink >= 2 ? st.nlink : null;
|
|
4024
4486
|
} catch {
|
|
4025
4487
|
return null;
|
|
@@ -4150,11 +4612,45 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
4150
4612
|
return twMerge(clsx(inputs));
|
|
4151
4613
|
}
|
|
4152
4614
|
`;
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4615
|
+
async function resolveInitAnswers(baseDirInput, tailwind4) {
|
|
4616
|
+
const baseDir = path15.resolve(baseDirInput);
|
|
4617
|
+
const tw4 = tailwind4 ?? isTailwind4(planUtilsDependencies(baseDir).tailwind);
|
|
4618
|
+
const current = await existingConfig(baseDir);
|
|
4619
|
+
const found = detectProjectPaths(baseDir);
|
|
4620
|
+
const notes = [];
|
|
4621
|
+
const currentComponents = nonEmptyString(current?.componentsDir);
|
|
4622
|
+
const componentsDir = currentComponents ?? found.componentsDir;
|
|
4623
|
+
const pickFile = (key, value, source, label) => {
|
|
4624
|
+
const existing = nonEmptyString(current?.[key]);
|
|
4625
|
+
if (existing !== void 0 && projectFileExists(baseDir, existing)) return existing;
|
|
4626
|
+
if (existing !== void 0) {
|
|
4627
|
+
if (source === "found") {
|
|
4628
|
+
notes.push(`! \uAE30\uC874 ${key}(${existing})\uAC00 \uC5C6\uC5B4 \uCC3E\uC740 \uD30C\uC77C ${value} \uB85C \uBC14\uAFC9\uB2C8\uB2E4.`);
|
|
4629
|
+
return value;
|
|
4630
|
+
}
|
|
4631
|
+
notes.push(`! \uAE30\uC874 ${key}(${existing}) \uD30C\uC77C\uC774 \uC5C6\uACE0 \uB2E4\uB978 ${label} \uD30C\uC77C\uB3C4 \uCC3E\uC9C0 \uBABB\uD574 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4. \uD30C\uC77C \uC704\uCE58\uC5D0 \uB9DE\uAC8C axis.config.json \uC744 \uACE0\uCE58\uC138\uC694.`);
|
|
4632
|
+
return existing;
|
|
4633
|
+
} else if (source === "default") {
|
|
4634
|
+
notes.push(`! ${label} \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD574 \uAE30\uBCF8\uAC12 ${value} \uB97C \uAE30\uB85D\uD569\uB2C8\uB2E4. \uD30C\uC77C \uC704\uCE58\uC5D0 \uB9DE\uAC8C axis.config.json \uC744 \uACE0\uCE58\uC138\uC694.`);
|
|
4635
|
+
}
|
|
4636
|
+
return value;
|
|
4637
|
+
};
|
|
4638
|
+
const globalCss = pickFile("globalCss", found.globalCss, found.globalCssSource, "\uC804\uC5ED CSS");
|
|
4639
|
+
const answers = { componentsDir, globalCss };
|
|
4640
|
+
if (!tw4) {
|
|
4641
|
+
answers.tailwindConfig = pickFile("tailwindConfig", found.tailwindConfig, found.tailwindConfigSource, "Tailwind \uC124\uC815");
|
|
4642
|
+
}
|
|
4643
|
+
return { answers, notes };
|
|
4644
|
+
}
|
|
4645
|
+
function animationGuideLine(pkg, tailwind4, installCommand) {
|
|
4646
|
+
const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
|
|
4647
|
+
if (pkg !== void 0 && (hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
|
|
4648
|
+
return void 0;
|
|
4649
|
+
}
|
|
4650
|
+
const add = `${addCommandFor(installCommand, {}).trimEnd()} ${name}`;
|
|
4651
|
+
const where = tailwind4 ? `\uC804\uC5ED CSS \uC5D0 @import "${name}"; \uB97C \uB123\uC73C\uC138\uC694` : `tailwind.config \uC758 plugins \uC5D0 require("${name}") \uB97C \uB123\uC73C\uC138\uC694`;
|
|
4652
|
+
return `\uC560\uB2C8\uBA54\uC774\uC158: Dialog \xB7 Select \uB4F1\uC758 \uC5F4\uACE0 \uB2EB\uB294 \uC560\uB2C8\uBA54\uC774\uC158(animate-in \uB958)\uC740 \uD50C\uB7EC\uADF8\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. ${add} \uB4A4 ${where}.`;
|
|
4653
|
+
}
|
|
4158
4654
|
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
4159
4655
|
function isTailwind4(tailwind) {
|
|
4160
4656
|
return tailwind.major !== void 0 && tailwind.major >= 4;
|
|
@@ -4221,12 +4717,6 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
|
4221
4717
|
return lines;
|
|
4222
4718
|
}
|
|
4223
4719
|
var BOM = "\uFEFF";
|
|
4224
|
-
function addCommandFor(installCommand, deps) {
|
|
4225
|
-
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
4226
|
-
if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
|
|
4227
|
-
if (installCommand.startsWith("npm")) return `npm install ${specs}`;
|
|
4228
|
-
return `pnpm add ${specs}`;
|
|
4229
|
-
}
|
|
4230
4720
|
function planUtilsDependencies(baseDirInput) {
|
|
4231
4721
|
const baseDir = path15.resolve(baseDirInput);
|
|
4232
4722
|
const installCommand = detectInstallCommand(baseDir);
|
|
@@ -4349,11 +4839,36 @@ function reportDependencies(plan, log) {
|
|
|
4349
4839
|
}
|
|
4350
4840
|
async function existingConfig(baseDir) {
|
|
4351
4841
|
try {
|
|
4352
|
-
|
|
4842
|
+
const parsed = await readAxisConfig(baseDir);
|
|
4843
|
+
return isPlainObject2(parsed) ? parsed : null;
|
|
4353
4844
|
} catch {
|
|
4354
4845
|
return null;
|
|
4355
4846
|
}
|
|
4356
4847
|
}
|
|
4848
|
+
var INIT_MANAGED_KEYS = ["$schema", "componentsDir", "tailwindConfig", "globalCss", "registry"];
|
|
4849
|
+
function mergeInitConfig(current, next) {
|
|
4850
|
+
const removed = [];
|
|
4851
|
+
const entries = [];
|
|
4852
|
+
for (const [k, v] of Object.entries(current)) {
|
|
4853
|
+
if (k in next) entries.push([k, next[k]]);
|
|
4854
|
+
else if (INIT_MANAGED_KEYS.includes(k)) removed.push(k);
|
|
4855
|
+
else entries.push([k, v]);
|
|
4856
|
+
}
|
|
4857
|
+
const nextKeys = Object.keys(next);
|
|
4858
|
+
nextKeys.forEach((k, i) => {
|
|
4859
|
+
if (k in current) return;
|
|
4860
|
+
let at = 0;
|
|
4861
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
4862
|
+
const idx = entries.findIndex(([key]) => key === nextKeys[j]);
|
|
4863
|
+
if (idx !== -1) {
|
|
4864
|
+
at = idx + 1;
|
|
4865
|
+
break;
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
entries.splice(at, 0, [k, next[k]]);
|
|
4869
|
+
});
|
|
4870
|
+
return { merged: Object.fromEntries(entries), removed };
|
|
4871
|
+
}
|
|
4357
4872
|
function configStateNote(state) {
|
|
4358
4873
|
if (state === "created") return "axis.config.json \uC740 \uC774\uBBF8 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
4359
4874
|
if (state === "updated") return "axis.config.json \uC740 \uC774\uBBF8 \uAC31\uC2E0\uD588\uC2B5\uB2C8\uB2E4.";
|
|
@@ -4370,7 +4885,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4370
4885
|
const shown = path15.relative(baseDir, utilsPath).split(path15.sep).join("/") || utilsPath;
|
|
4371
4886
|
let st;
|
|
4372
4887
|
try {
|
|
4373
|
-
st =
|
|
4888
|
+
st = lstatSync3(utilsPath);
|
|
4374
4889
|
} catch (e) {
|
|
4375
4890
|
if (e.code === "ENOENT") return { action: "create" };
|
|
4376
4891
|
return { action: "reject", reason: `${shown} \uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
@@ -4390,7 +4905,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4390
4905
|
}
|
|
4391
4906
|
let target;
|
|
4392
4907
|
try {
|
|
4393
|
-
target =
|
|
4908
|
+
target = statSync4(real);
|
|
4394
4909
|
} catch (e) {
|
|
4395
4910
|
return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4396
4911
|
}
|
|
@@ -4446,8 +4961,6 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4446
4961
|
registry
|
|
4447
4962
|
);
|
|
4448
4963
|
const configPath = path15.join(baseDir, "axis.config.json");
|
|
4449
|
-
const nextText = `${JSON.stringify(axisConfig, null, 2)}
|
|
4450
|
-
`;
|
|
4451
4964
|
const rejects = [];
|
|
4452
4965
|
let previousText = null;
|
|
4453
4966
|
try {
|
|
@@ -4457,9 +4970,18 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4457
4970
|
rejects.push(`\uAE30\uC874 axis.config.json \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})`);
|
|
4458
4971
|
}
|
|
4459
4972
|
}
|
|
4973
|
+
let removedKeys = [];
|
|
4974
|
+
let nextText = `${JSON.stringify(axisConfig, null, 2)}
|
|
4975
|
+
`;
|
|
4976
|
+
if (previousText !== null && current !== null) {
|
|
4977
|
+
const { merged, removed } = mergeInitConfig(current, axisConfig);
|
|
4978
|
+
removedKeys = removed;
|
|
4979
|
+
const body = previousText.startsWith(BOM) ? previousText.slice(1) : previousText;
|
|
4980
|
+
nextText = (previousText.startsWith(BOM) ? BOM : "") + formatJsonLike(body, merged);
|
|
4981
|
+
}
|
|
4460
4982
|
if (previousText !== null && previousText !== nextText) {
|
|
4461
4983
|
try {
|
|
4462
|
-
const st =
|
|
4984
|
+
const st = statSync4(configPath);
|
|
4463
4985
|
if (st.isFile() && st.nlink >= 2) rejects.push(hardLinkMessage("axis.config.json", st.nlink));
|
|
4464
4986
|
} catch {
|
|
4465
4987
|
}
|
|
@@ -4500,7 +5022,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4500
5022
|
configState = "updated";
|
|
4501
5023
|
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";
|
|
4502
5024
|
const agenticNote = existingAgenticDir !== void 0 ? ", agenticDir \uB294 \uAE30\uC874 \uAC12 \uC720\uC9C0" : "";
|
|
4503
|
-
|
|
5025
|
+
const mergeNote = current !== null ? "init \uC774 \uB2E4\uB8E8\uB294 \uD0A4\uB9CC \uBC14\uAFB8\uACE0 \uB098\uBA38\uC9C0 \uD0A4\uB294 \uADF8\uB300\uB85C \uB460" : "\uC77D\uC9C0 \uBABB\uD55C \uAE30\uC874 \uD30C\uC77C\uC744 init \uAC12\uC73C\uB85C \uB2E4\uC2DC \uC500";
|
|
5026
|
+
log(chalk10.green(`\u2713 axis.config.json \uAC31\uC2E0(${mergeNote}, ${registryNote}${agenticNote})`));
|
|
4504
5027
|
if (migratedRegistry && existingRegistry !== void 0) {
|
|
4505
5028
|
log(
|
|
4506
5029
|
chalk10.yellow(
|
|
@@ -4508,9 +5031,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4508
5031
|
)
|
|
4509
5032
|
);
|
|
4510
5033
|
}
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
log(chalk10.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)`));
|
|
5034
|
+
if (removedKeys.length > 0) {
|
|
5035
|
+
log(chalk10.yellow(` \uC9C0\uC6B4 \uD0A4: ${removedKeys.join(", ")} (Tailwind 4 \uC774\uC0C1\uC740 \uC124\uC815 \uD30C\uC77C\uC744 \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4)`));
|
|
4514
5036
|
}
|
|
4515
5037
|
}
|
|
4516
5038
|
let utilsStateNote = "utils.ts \uB294 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9).";
|
|
@@ -4552,6 +5074,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4552
5074
|
return;
|
|
4553
5075
|
}
|
|
4554
5076
|
reportDependencies(plan, log);
|
|
5077
|
+
const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand);
|
|
5078
|
+
if (animation !== void 0) log(chalk10.yellow(` ${animation}`));
|
|
4555
5079
|
if (tailwind4) {
|
|
4556
5080
|
const [head, ...rest] = tailwind4GuideLines(
|
|
4557
5081
|
readPackageJsonSafe(baseDir),
|
|
@@ -4572,28 +5096,31 @@ ${head}`));
|
|
|
4572
5096
|
function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL) {
|
|
4573
5097
|
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) => {
|
|
4574
5098
|
console.log(chalk11.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
|
|
4575
|
-
const
|
|
4576
|
-
const
|
|
5099
|
+
const baseDir = process.cwd();
|
|
5100
|
+
const tailwind4 = isTailwind4(planUtilsDependencies(baseDir).tailwind);
|
|
5101
|
+
const resolved = await resolveInitAnswers(baseDir, tailwind4);
|
|
5102
|
+
for (const note of resolved.notes) console.log(note.startsWith("!") ? chalk11.yellow(note) : chalk11.gray(note));
|
|
5103
|
+
const config = options.yes ? { ...resolved.answers } : await prompts2([
|
|
4577
5104
|
{
|
|
4578
5105
|
type: "text",
|
|
4579
5106
|
name: "componentsDir",
|
|
4580
5107
|
message: "\uCEF4\uD3EC\uB10C\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
|
|
4581
|
-
initial:
|
|
5108
|
+
initial: resolved.answers.componentsDir
|
|
4582
5109
|
},
|
|
4583
5110
|
{
|
|
4584
5111
|
type: tailwind4 ? null : "text",
|
|
4585
5112
|
name: "tailwindConfig",
|
|
4586
5113
|
message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
|
|
4587
|
-
initial:
|
|
5114
|
+
initial: resolved.answers.tailwindConfig
|
|
4588
5115
|
},
|
|
4589
5116
|
{
|
|
4590
5117
|
type: "text",
|
|
4591
5118
|
name: "globalCss",
|
|
4592
5119
|
message: "\uAE00\uB85C\uBC8C CSS \uD30C\uC77C:",
|
|
4593
|
-
initial:
|
|
5120
|
+
initial: resolved.answers.globalCss
|
|
4594
5121
|
}
|
|
4595
5122
|
]);
|
|
4596
|
-
await runInit(
|
|
5123
|
+
await runInit(baseDir, config, registryUrl);
|
|
4597
5124
|
});
|
|
4598
5125
|
}
|
|
4599
5126
|
|
|
@@ -4602,7 +5129,7 @@ import chalk12 from "chalk";
|
|
|
4602
5129
|
import prompts3 from "prompts";
|
|
4603
5130
|
|
|
4604
5131
|
// ../axis-registry-core/src/add/add.ts
|
|
4605
|
-
import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as
|
|
5132
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
4606
5133
|
import path17 from "path";
|
|
4607
5134
|
import fs13 from "fs-extra";
|
|
4608
5135
|
|
|
@@ -5261,7 +5788,7 @@ function relativeSpecifierResolves(fromFile, spec) {
|
|
|
5261
5788
|
const base = path17.resolve(path17.dirname(fromFile), spec);
|
|
5262
5789
|
return RESOLVE_EXTS.some((ext) => {
|
|
5263
5790
|
try {
|
|
5264
|
-
return
|
|
5791
|
+
return statSync5(base + ext).isFile();
|
|
5265
5792
|
} catch {
|
|
5266
5793
|
return false;
|
|
5267
5794
|
}
|
|
@@ -5336,7 +5863,7 @@ function missingDependencies(root, items) {
|
|
|
5336
5863
|
const installCommand = detectInstallCommand(root);
|
|
5337
5864
|
let pkg;
|
|
5338
5865
|
try {
|
|
5339
|
-
const text = readFileSync6(path17.join(root, "package.json"), "utf8").replace(
|
|
5866
|
+
const text = readFileSync6(path17.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
|
|
5340
5867
|
const parsed = JSON.parse(text);
|
|
5341
5868
|
pkg = isPlainObject2(parsed) ? parsed : void 0;
|
|
5342
5869
|
} catch {
|