@axis-ds/cli 1.5.4 → 1.6.1
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 +15 -6
- package/dist/{chunk-QORBOSUA.js → chunk-7CDXEBEE.js} +2 -2
- package/dist/index.js +1815 -1002
- 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/button.json +1 -1
- package/dist/registry/card.json +1 -1
- package/dist/registry/dialog.json +1 -1
- package/dist/registry/index.json +15 -15
- package/dist/registry/input.json +1 -1
- package/dist/registry/registry.json +15 -15
- 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) {
|
|
@@ -1744,7 +1745,7 @@ import ora5 from "ora";
|
|
|
1744
1745
|
|
|
1745
1746
|
// src/template/template-apply.ts
|
|
1746
1747
|
import fs8 from "fs-extra";
|
|
1747
|
-
import
|
|
1748
|
+
import path9 from "path";
|
|
1748
1749
|
import chalk5 from "chalk";
|
|
1749
1750
|
import ora3 from "ora";
|
|
1750
1751
|
import prompts from "prompts";
|
|
@@ -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,940 +1842,1585 @@ 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
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1845
|
+
// ../axis-registry-core/src/template/tailwind-core.ts
|
|
1846
|
+
import { existsSync as existsSync2, lstatSync, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
1847
|
+
import { extname, join, resolve } from "path";
|
|
1848
|
+
|
|
1849
|
+
// ../axis-registry-core/src/project.ts
|
|
1850
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
1851
|
+
import path8 from "path";
|
|
1852
|
+
function detectInstallCommand(baseDir) {
|
|
1853
|
+
if (existsSync(path8.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
1854
|
+
if (existsSync(path8.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
1855
|
+
if (existsSync(path8.join(baseDir, "package-lock.json"))) return "npm install";
|
|
1856
|
+
return "pnpm install";
|
|
1857
|
+
}
|
|
1858
|
+
function hasDependency(pkg, name) {
|
|
1859
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
1860
|
+
const deps = pkg[field];
|
|
1861
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
1862
|
+
return String(deps[name]);
|
|
1861
1863
|
}
|
|
1862
1864
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1865
|
+
return void 0;
|
|
1866
|
+
}
|
|
1867
|
+
function isPlainObject(value) {
|
|
1868
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1869
|
+
}
|
|
1870
|
+
function addCommandFor(installCommand, deps) {
|
|
1871
|
+
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
1872
|
+
if (installCommand.startsWith("yarn")) return `yarn add ${specs}`;
|
|
1873
|
+
if (installCommand.startsWith("npm")) return `npm install ${specs}`;
|
|
1874
|
+
return `pnpm add ${specs}`;
|
|
1875
|
+
}
|
|
1876
|
+
var GLOBAL_CSS_CANDIDATES = [
|
|
1877
|
+
"app/globals.css",
|
|
1878
|
+
"src/app/globals.css",
|
|
1879
|
+
"styles/globals.css",
|
|
1880
|
+
"src/styles/globals.css",
|
|
1881
|
+
"globals.css"
|
|
1882
|
+
];
|
|
1883
|
+
var TAILWIND_CONFIG_CANDIDATES = [
|
|
1884
|
+
"tailwind.config.ts",
|
|
1885
|
+
"tailwind.config.js",
|
|
1886
|
+
"tailwind.config.mjs",
|
|
1887
|
+
"tailwind.config.cjs"
|
|
1888
|
+
];
|
|
1889
|
+
function isFile(file) {
|
|
1890
|
+
try {
|
|
1891
|
+
return statSync(file).isFile();
|
|
1892
|
+
} catch {
|
|
1893
|
+
return false;
|
|
1879
1894
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1895
|
+
}
|
|
1896
|
+
function isDirectory(dir) {
|
|
1897
|
+
try {
|
|
1898
|
+
return statSync(dir).isDirectory();
|
|
1899
|
+
} catch {
|
|
1900
|
+
return false;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
function findFirstFile(baseDir, candidates) {
|
|
1904
|
+
return candidates.find((c) => isFile(path8.join(baseDir, c)));
|
|
1905
|
+
}
|
|
1906
|
+
function detectProjectPaths(baseDirInput) {
|
|
1907
|
+
const baseDir = path8.resolve(baseDirInput);
|
|
1908
|
+
const hasSrc = isDirectory(path8.join(baseDir, "src"));
|
|
1909
|
+
const css = findFirstFile(baseDir, GLOBAL_CSS_CANDIDATES);
|
|
1910
|
+
const tw = findFirstFile(baseDir, TAILWIND_CONFIG_CANDIDATES);
|
|
1911
|
+
return {
|
|
1912
|
+
componentsDir: hasSrc ? "./src/components/ui" : "./components/ui",
|
|
1913
|
+
globalCss: css !== void 0 ? `./${css}` : hasSrc ? "./src/app/globals.css" : "./app/globals.css",
|
|
1914
|
+
globalCssSource: css !== void 0 ? "found" : "default",
|
|
1915
|
+
tailwindConfig: tw !== void 0 ? `./${tw}` : "./tailwind.config.ts",
|
|
1916
|
+
tailwindConfigSource: tw !== void 0 ? "found" : "default"
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
function projectFileExists(baseDir, relPath) {
|
|
1920
|
+
return isFile(path8.resolve(baseDir, relPath));
|
|
1921
|
+
}
|
|
1922
|
+
var ROOT_LAYOUT_FILES = [
|
|
1923
|
+
"app/layout.tsx",
|
|
1924
|
+
"app/layout.jsx",
|
|
1925
|
+
"app/layout.js",
|
|
1926
|
+
"src/app/layout.tsx",
|
|
1927
|
+
"src/app/layout.jsx",
|
|
1928
|
+
"src/app/layout.js",
|
|
1929
|
+
"pages/_app.tsx",
|
|
1930
|
+
"pages/_app.jsx",
|
|
1931
|
+
"pages/_document.tsx",
|
|
1932
|
+
"pages/_document.jsx",
|
|
1933
|
+
"src/pages/_app.tsx",
|
|
1934
|
+
"src/pages/_app.jsx",
|
|
1935
|
+
"src/pages/_document.tsx",
|
|
1936
|
+
"src/pages/_document.jsx"
|
|
1937
|
+
];
|
|
1938
|
+
function exactVersionOf(version) {
|
|
1939
|
+
if (typeof version !== "string") return void 0;
|
|
1940
|
+
const v = version.trim();
|
|
1941
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
1942
|
+
return v;
|
|
1943
|
+
}
|
|
1944
|
+
function findInstalledPackage(baseDirInput, name) {
|
|
1945
|
+
let dir = path8.resolve(baseDirInput);
|
|
1946
|
+
for (; ; ) {
|
|
1947
|
+
const pkgDir = path8.join(dir, "node_modules", ...name.split("/"));
|
|
1948
|
+
const file = path8.join(pkgDir, "package.json");
|
|
1949
|
+
if (isFile(file)) {
|
|
1950
|
+
let version;
|
|
1951
|
+
try {
|
|
1952
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
1953
|
+
version = isPlainObject(parsed) ? exactVersionOf(parsed.version) : void 0;
|
|
1954
|
+
} catch {
|
|
1955
|
+
version = void 0;
|
|
1892
1956
|
}
|
|
1957
|
+
return { dir: pkgDir, version };
|
|
1893
1958
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
for (const file of detail.files) {
|
|
1898
|
-
const dest = path8.join(baseDir, file.path);
|
|
1899
|
-
await fs8.ensureDir(path8.dirname(dest));
|
|
1900
|
-
await fs8.writeFile(dest, file.content);
|
|
1959
|
+
const parent = path8.dirname(dir);
|
|
1960
|
+
if (parent === dir) return void 0;
|
|
1961
|
+
dir = parent;
|
|
1901
1962
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1963
|
+
}
|
|
1964
|
+
function isPnpProject(baseDirInput) {
|
|
1965
|
+
let dir = path8.resolve(baseDirInput);
|
|
1966
|
+
for (; ; ) {
|
|
1967
|
+
if (isFile(path8.join(dir, ".pnp.cjs")) || isFile(path8.join(dir, ".pnp.js"))) return true;
|
|
1968
|
+
const parent = path8.dirname(dir);
|
|
1969
|
+
if (parent === dir) return false;
|
|
1970
|
+
dir = parent;
|
|
1906
1971
|
}
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1972
|
+
}
|
|
1973
|
+
function compareExactVersions(a, b) {
|
|
1974
|
+
const parse = (v) => {
|
|
1975
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?/.exec(v.trim());
|
|
1976
|
+
return m ? { core: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] !== void 0 } : void 0;
|
|
1977
|
+
};
|
|
1978
|
+
const x = parse(a);
|
|
1979
|
+
const y = parse(b);
|
|
1980
|
+
if (!x || !y) return void 0;
|
|
1981
|
+
for (let i = 0; i < 3; i++) if (x.core[i] !== y.core[i]) return x.core[i] - y.core[i];
|
|
1982
|
+
return Number(y.pre) - Number(x.pre);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// ../axis-registry-core/src/template/tailwind-core.ts
|
|
1986
|
+
function hasDependency2(pkg, name) {
|
|
1987
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
1988
|
+
const deps = pkg[field];
|
|
1989
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
1990
|
+
return String(deps[name]);
|
|
1920
1991
|
}
|
|
1921
1992
|
}
|
|
1922
|
-
|
|
1923
|
-
'${detail.name}' \uD15C\uD50C\uB9BF \uC801\uC6A9 \uC644\uB8CC!`));
|
|
1993
|
+
return void 0;
|
|
1924
1994
|
}
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1995
|
+
function isPlainObject2(value) {
|
|
1996
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1997
|
+
}
|
|
1998
|
+
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
1999
|
+
function versionParts(token) {
|
|
2000
|
+
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
2001
|
+
if (!m) return void 0;
|
|
2002
|
+
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
2003
|
+
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
2004
|
+
}
|
|
2005
|
+
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
2006
|
+
function comparatorBounds(op, v) {
|
|
2007
|
+
switch (op) {
|
|
2008
|
+
case ">=":
|
|
2009
|
+
return { lower: v.major };
|
|
2010
|
+
case ">":
|
|
2011
|
+
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
2012
|
+
case "<=":
|
|
2013
|
+
return { upper: v.major };
|
|
2014
|
+
case "<": {
|
|
2015
|
+
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
2016
|
+
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
1943
2017
|
}
|
|
1944
|
-
|
|
2018
|
+
default:
|
|
2019
|
+
return { lower: v.major, upper: v.major };
|
|
1945
2020
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
}
|
|
1954
|
-
if (!dir) {
|
|
1955
|
-
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
1956
|
-
return;
|
|
1957
|
-
}
|
|
1958
|
-
targetDir = dir;
|
|
2021
|
+
}
|
|
2022
|
+
function tailwindMajorBounds(range) {
|
|
2023
|
+
const r = range.trim();
|
|
2024
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2025
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2026
|
+
if (simple) {
|
|
2027
|
+
const v = versionParts(simple[1]);
|
|
2028
|
+
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
1959
2029
|
}
|
|
1960
|
-
const
|
|
1961
|
-
if (
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
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;
|
|
1971
|
-
}
|
|
1972
|
-
} else {
|
|
1973
|
-
await fs8.ensureDir(resolved);
|
|
2030
|
+
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
2031
|
+
if (hyphen) {
|
|
2032
|
+
const tokens2 = r.split(/\s+-\s+/);
|
|
2033
|
+
const a = versionParts(tokens2[0]);
|
|
2034
|
+
const b = versionParts(tokens2[1]);
|
|
2035
|
+
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
1974
2036
|
}
|
|
1975
|
-
|
|
1976
|
-
const
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2037
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2038
|
+
const lowers = [];
|
|
2039
|
+
const uppers = [];
|
|
2040
|
+
for (const t of tokens) {
|
|
2041
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2042
|
+
if (!c) return void 0;
|
|
2043
|
+
const v = versionParts(c[2]);
|
|
2044
|
+
if (v === void 0) return void 0;
|
|
2045
|
+
const b = comparatorBounds(c[1], v);
|
|
2046
|
+
if (b.lower !== void 0) lowers.push(b.lower);
|
|
2047
|
+
if (b.upper !== void 0) uppers.push(b.upper);
|
|
1981
2048
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2049
|
+
if (lowers.length === 0) return void 0;
|
|
2050
|
+
const lower = Math.max(...lowers);
|
|
2051
|
+
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
2052
|
+
if (upper !== void 0 && upper < lower) return void 0;
|
|
2053
|
+
return upper !== void 0 ? { lower, upper } : { lower };
|
|
1987
2054
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2055
|
+
function tailwindMajorFromRange(range) {
|
|
2056
|
+
return tailwindMajorBounds(range)?.lower;
|
|
2057
|
+
}
|
|
2058
|
+
function majorWithin(major, bounds) {
|
|
2059
|
+
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
2060
|
+
}
|
|
2061
|
+
function majorFromVersion(version) {
|
|
2062
|
+
if (typeof version !== "string") return void 0;
|
|
2063
|
+
const v = version.trim();
|
|
2064
|
+
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
2065
|
+
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2066
|
+
return Number(m[1]);
|
|
2067
|
+
}
|
|
2068
|
+
function detectTailwind(baseDirInput, pkg) {
|
|
2069
|
+
const baseDir = resolve(baseDirInput);
|
|
2070
|
+
const installedFile = join(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
2071
|
+
const declared = pkg ? hasDependency2(pkg, "tailwindcss") : void 0;
|
|
2072
|
+
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
2073
|
+
const declaredMajor = bounds?.lower;
|
|
1997
2074
|
try {
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
const entries = [];
|
|
2006
|
-
for (const file of detail.files) {
|
|
2007
|
-
const localPath = path9.join(baseDir, file.path);
|
|
2008
|
-
if (!await fs9.pathExists(localPath)) {
|
|
2009
|
-
entries.push({ path: file.path, status: "added" });
|
|
2010
|
-
continue;
|
|
2011
|
-
}
|
|
2012
|
-
const localContent = await fs9.readFile(localPath, "utf-8");
|
|
2013
|
-
if (localContent === file.content) {
|
|
2014
|
-
entries.push({ path: file.path, status: "unchanged" });
|
|
2015
|
-
} else {
|
|
2016
|
-
entries.push({
|
|
2017
|
-
path: file.path,
|
|
2018
|
-
status: "modified",
|
|
2019
|
-
localLines: localContent.split("\n").length,
|
|
2020
|
-
remoteLines: file.content.split("\n").length
|
|
2021
|
-
});
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
if (options.verbose) {
|
|
2025
|
-
const templatePaths = new Set(detail.files.map((f) => f.path));
|
|
2026
|
-
const localFiles = await collectLocalFiles(baseDir);
|
|
2027
|
-
for (const lf of localFiles) {
|
|
2028
|
-
if (!templatePaths.has(lf)) {
|
|
2029
|
-
entries.push({ path: lf, status: "extra" });
|
|
2075
|
+
const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
|
|
2076
|
+
const version = isPlainObject2(installed) ? installed.version : void 0;
|
|
2077
|
+
const major = majorFromVersion(version);
|
|
2078
|
+
if (major !== void 0) {
|
|
2079
|
+
const found = { major, source: "installed", value: String(version) };
|
|
2080
|
+
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
2081
|
+
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
2030
2082
|
}
|
|
2083
|
+
return found;
|
|
2031
2084
|
}
|
|
2032
|
-
}
|
|
2033
|
-
console.log(chalk6.blue(`
|
|
2034
|
-
'${detail.name}' \uD15C\uD50C\uB9BF diff \uACB0\uACFC:
|
|
2035
|
-
`));
|
|
2036
|
-
const statusIcon = {
|
|
2037
|
-
added: chalk6.green("+ \uCD94\uAC00 \uD544\uC694"),
|
|
2038
|
-
modified: chalk6.yellow("~ \uBCC0\uACBD\uB428"),
|
|
2039
|
-
unchanged: chalk6.gray("= \uB3D9\uC77C"),
|
|
2040
|
-
extra: chalk6.cyan("? \uB85C\uCEEC \uC804\uC6A9")
|
|
2041
|
-
};
|
|
2042
|
-
let added = 0;
|
|
2043
|
-
let modified = 0;
|
|
2044
|
-
let unchanged = 0;
|
|
2045
|
-
let extra = 0;
|
|
2046
|
-
for (const entry of entries) {
|
|
2047
|
-
const icon = statusIcon[entry.status];
|
|
2048
|
-
console.log(` ${icon.padEnd(28)} ${entry.path}`);
|
|
2049
|
-
if (entry.status === "modified" && options.verbose) {
|
|
2050
|
-
console.log(
|
|
2051
|
-
chalk6.gray(
|
|
2052
|
-
` \uB85C\uCEEC ${entry.localLines}\uC904 / \uC6D0\uBCF8 ${entry.remoteLines}\uC904`
|
|
2053
|
-
)
|
|
2054
|
-
);
|
|
2055
|
-
}
|
|
2056
|
-
switch (entry.status) {
|
|
2057
|
-
case "added":
|
|
2058
|
-
added++;
|
|
2059
|
-
break;
|
|
2060
|
-
case "modified":
|
|
2061
|
-
modified++;
|
|
2062
|
-
break;
|
|
2063
|
-
case "unchanged":
|
|
2064
|
-
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
2085
|
} catch {
|
|
2084
|
-
return results;
|
|
2085
2086
|
}
|
|
2086
|
-
|
|
2087
|
-
if (
|
|
2088
|
-
|
|
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
|
-
}
|
|
2087
|
+
if (declared !== void 0) {
|
|
2088
|
+
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
2089
|
+
return { source: "none", value: declared };
|
|
2095
2090
|
}
|
|
2096
|
-
return
|
|
2091
|
+
return { source: "none" };
|
|
2097
2092
|
}
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
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"
|
|
2093
|
+
var TAILWIND_CONFIG_FILES = [
|
|
2094
|
+
"tailwind.config.ts",
|
|
2095
|
+
"tailwind.config.js",
|
|
2096
|
+
"tailwind.config.mjs",
|
|
2097
|
+
"tailwind.config.cjs"
|
|
2124
2098
|
];
|
|
2125
|
-
var
|
|
2126
|
-
|
|
2127
|
-
|
|
2099
|
+
var TAILWIND_CSS_CANDIDATES = [
|
|
2100
|
+
"globals.css",
|
|
2101
|
+
"app/globals.css",
|
|
2102
|
+
"src/app/globals.css",
|
|
2103
|
+
"src/globals.css",
|
|
2104
|
+
"styles/globals.css"
|
|
2105
|
+
];
|
|
2106
|
+
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2107
|
+
function stripCssComments(css) {
|
|
2108
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2128
2109
|
}
|
|
2129
|
-
function
|
|
2130
|
-
return
|
|
2110
|
+
function hasTailwindImport(css) {
|
|
2111
|
+
return TAILWIND_IMPORT.test(stripCssComments(css));
|
|
2131
2112
|
}
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
const parent = dirname(dir);
|
|
2138
|
-
if (parent === dir) return void 0;
|
|
2139
|
-
dir = parent;
|
|
2140
|
-
}
|
|
2113
|
+
var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
|
|
2114
|
+
var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
|
|
2115
|
+
var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
|
|
2116
|
+
function hasTokensTailwind4Import(css) {
|
|
2117
|
+
return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
|
|
2141
2118
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2119
|
+
var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)["']/;
|
|
2120
|
+
function findTokensCssImport(css) {
|
|
2121
|
+
return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
|
|
2144
2122
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2123
|
+
var TOKENS_CSS_JS_IMPORT = /(?:\bimport\s+|\bfrom\s+|\brequire\s*\(\s*)(["'])(@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)\1/;
|
|
2124
|
+
var AXIS_VARIABLE_DEFINITION = /(?<![\w-])--axis-[\w-]+\s*:/;
|
|
2125
|
+
function findLayoutTokensCssImport(baseDirInput) {
|
|
2126
|
+
const baseDir = resolve(baseDirInput);
|
|
2127
|
+
for (const candidate of ROOT_LAYOUT_FILES) {
|
|
2128
|
+
const file = join(baseDir, candidate);
|
|
2129
|
+
if (!existsSync2(file)) continue;
|
|
2130
|
+
let text;
|
|
2131
|
+
try {
|
|
2132
|
+
text = readFileSync2(file, "utf8");
|
|
2133
|
+
} catch {
|
|
2134
|
+
continue;
|
|
2135
|
+
}
|
|
2136
|
+
const m = TOKENS_CSS_JS_IMPORT.exec(stripJsComments(text));
|
|
2137
|
+
if (m) return { file: candidate, spec: m[2] };
|
|
2138
|
+
}
|
|
2139
|
+
return void 0;
|
|
2147
2140
|
}
|
|
2148
|
-
function
|
|
2149
|
-
const
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
const
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
if (
|
|
2159
|
-
|
|
2160
|
-
|
|
2141
|
+
function checkGlobalsCss(baseDirInput) {
|
|
2142
|
+
const baseDir = resolve(baseDirInput);
|
|
2143
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2144
|
+
const file = join(baseDir, candidate);
|
|
2145
|
+
if (!existsSync2(file)) continue;
|
|
2146
|
+
const content = readFileSync2(file, "utf8");
|
|
2147
|
+
const css = stripCssComments(content);
|
|
2148
|
+
const imported = findTokensCssImport(content);
|
|
2149
|
+
let pass;
|
|
2150
|
+
if (imported !== void 0) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)`;
|
|
2151
|
+
else if (AXIS_VARIABLE_DEFINITION.test(css)) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218(--axis-*)\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`;
|
|
2152
|
+
else {
|
|
2153
|
+
const layout = findLayoutTokensCssImport(baseDir);
|
|
2154
|
+
if (layout) pass = `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${layout.file}\uC758 ${layout.spec} import)`;
|
|
2155
|
+
}
|
|
2156
|
+
if (pass !== void 0) {
|
|
2157
|
+
const tailwind = detectTailwind(baseDir, readPackageJson(baseDir));
|
|
2158
|
+
const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
|
|
2159
|
+
if (!tailwind4 && findCreateNextAppDefaults(content).some((d) => d.includes("font-family: Arial"))) {
|
|
2160
|
+
return {
|
|
2161
|
+
name: "globals.css",
|
|
2162
|
+
severity: "warn",
|
|
2163
|
+
message: `${pass}. \uB2E4\uB9CC create-next-app \uAE30\uBCF8 body font-family: Arial \uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2192 \uC9C0\uC6B0\uC138\uC694(AXIS \uAE00\uAF34 \uB300\uC2E0 Arial \uC774 \uC801\uC6A9\uB428)`
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
return { name: "globals.css", severity: "pass", message: pass };
|
|
2167
|
+
}
|
|
2168
|
+
if (css.includes("--background") && css.includes("--primary")) {
|
|
2169
|
+
return {
|
|
2170
|
+
name: "globals.css",
|
|
2171
|
+
severity: "warn",
|
|
2172
|
+
message: `${candidate}\uC5D0 \uC790\uCCB4 CSS \uBCC0\uC218(--background \xB7 --primary)\uB9CC \uC788\uACE0 AXIS \uD1A0\uD070\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 @axis-ds/tokens CSS \uB97C import \uD558\uC138\uC694`
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
2161
2176
|
}
|
|
2177
|
+
return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2162
2178
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2179
|
+
var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
|
|
2180
|
+
var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2181
|
+
function lowerOf(token) {
|
|
2182
|
+
const v = versionParts(token);
|
|
2183
|
+
if (!v) return void 0;
|
|
2184
|
+
const num = (part) => isWild(part) ? 0 : Number(part);
|
|
2185
|
+
const pre = /^v?\d+(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?-/.test(token);
|
|
2186
|
+
return { core: [v.major, num(v.minor), num(v.patch)], pre };
|
|
2165
2187
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
return statSync(file).isFile();
|
|
2170
|
-
} catch {
|
|
2171
|
-
return false;
|
|
2188
|
+
function compareLower(a, b) {
|
|
2189
|
+
for (let i = 0; i < 3; i++) {
|
|
2190
|
+
if (a.core[i] !== b.core[i]) return a.core[i] - b.core[i];
|
|
2172
2191
|
}
|
|
2192
|
+
return Number(b.pre) - Number(a.pre);
|
|
2173
2193
|
}
|
|
2174
|
-
function
|
|
2175
|
-
const
|
|
2176
|
-
|
|
2177
|
-
const
|
|
2178
|
-
if (
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2194
|
+
function rangeLowerVersion(range) {
|
|
2195
|
+
const r = range.trim();
|
|
2196
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2197
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2198
|
+
if (simple) return lowerOf(simple[1]);
|
|
2199
|
+
if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
|
|
2200
|
+
const [a, b] = r.split(/\s+-\s+/);
|
|
2201
|
+
return lowerOf(b) ? lowerOf(a) : void 0;
|
|
2182
2202
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2203
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2204
|
+
let lower;
|
|
2205
|
+
for (const t of tokens) {
|
|
2206
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2207
|
+
if (!c) return void 0;
|
|
2208
|
+
const v = versionParts(c[2]);
|
|
2209
|
+
const low = lowerOf(c[2]);
|
|
2210
|
+
if (!v || !low) return void 0;
|
|
2211
|
+
let candidate;
|
|
2212
|
+
if (c[1] === ">=" || c[1] === "=") candidate = low;
|
|
2213
|
+
else if (c[1] === ">") {
|
|
2214
|
+
if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
|
|
2215
|
+
else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
|
|
2216
|
+
else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
|
|
2188
2217
|
}
|
|
2218
|
+
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2189
2219
|
}
|
|
2190
|
-
return
|
|
2220
|
+
return lower;
|
|
2191
2221
|
}
|
|
2192
|
-
function
|
|
2193
|
-
const
|
|
2194
|
-
const
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
}
|
|
2198
|
-
return names;
|
|
2222
|
+
function rangeLowerAtLeast(range, min) {
|
|
2223
|
+
const lower = rangeLowerVersion(range);
|
|
2224
|
+
const target = lowerOf(min);
|
|
2225
|
+
if (!lower || !target) return void 0;
|
|
2226
|
+
return compareLower(lower, target) >= 0;
|
|
2199
2227
|
}
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2228
|
+
function exactVersion(version) {
|
|
2229
|
+
if (typeof version !== "string") return void 0;
|
|
2230
|
+
const v = version.trim();
|
|
2231
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2232
|
+
return v;
|
|
2233
|
+
}
|
|
2234
|
+
function installedVersion(baseDir, name) {
|
|
2203
2235
|
try {
|
|
2204
|
-
parsed = JSON.parse(
|
|
2236
|
+
const parsed = JSON.parse(readFileSync2(join(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
|
|
2237
|
+
return isPlainObject2(parsed) ? exactVersion(parsed.version) : void 0;
|
|
2205
2238
|
} catch {
|
|
2206
|
-
return
|
|
2239
|
+
return void 0;
|
|
2207
2240
|
}
|
|
2208
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
2209
|
-
return parsed;
|
|
2210
2241
|
}
|
|
2211
|
-
function
|
|
2212
|
-
|
|
2213
|
-
const
|
|
2214
|
-
|
|
2215
|
-
const
|
|
2216
|
-
const
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2242
|
+
function axisPackagesBelowTailwind4(pkg, baseDirInput) {
|
|
2243
|
+
if (!pkg) return [];
|
|
2244
|
+
const baseDir = baseDirInput !== void 0 ? resolve(baseDirInput) : void 0;
|
|
2245
|
+
const out = [];
|
|
2246
|
+
const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
|
|
2247
|
+
for (const name of TAILWIND4_AXIS_PACKAGES) {
|
|
2248
|
+
const range = hasDependency2(pkg, name);
|
|
2249
|
+
if (range === void 0 || range.trim().startsWith("workspace:")) continue;
|
|
2250
|
+
const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
|
|
2251
|
+
const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
|
|
2252
|
+
if (installed !== void 0 && installedLower !== void 0) {
|
|
2253
|
+
if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
|
|
2254
|
+
continue;
|
|
2255
|
+
}
|
|
2256
|
+
const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
|
|
2257
|
+
if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
|
|
2258
|
+
else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
|
|
2221
2259
|
}
|
|
2222
|
-
|
|
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 };
|
|
2260
|
+
return out;
|
|
2229
2261
|
}
|
|
2230
|
-
function
|
|
2231
|
-
|
|
2232
|
-
return code === "MODULE_NOT_FOUND" || code === "ENOENT";
|
|
2262
|
+
function axisPackageVersionLabel(issue) {
|
|
2263
|
+
return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
|
|
2233
2264
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2265
|
+
var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
2266
|
+
function tailwind4VersionNote(issues) {
|
|
2267
|
+
const below = issues.filter((i) => i.status === "below");
|
|
2268
|
+
const unknown = issues.filter((i) => i.status === "unknown");
|
|
2269
|
+
let note = "";
|
|
2270
|
+
if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
|
|
2271
|
+
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)})`;
|
|
2272
|
+
return note;
|
|
2240
2273
|
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
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
|
-
};
|
|
2274
|
+
var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2275
|
+
function componentTailwindImportLine(name) {
|
|
2276
|
+
return `@import "${name}/tailwind.css";`;
|
|
2251
2277
|
}
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
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 };
|
|
2278
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2279
|
+
function hasComponentTailwindImport(css, name) {
|
|
2280
|
+
const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
|
|
2281
|
+
return re.test(stripCssComments(css));
|
|
2266
2282
|
}
|
|
2267
|
-
function
|
|
2268
|
-
|
|
2283
|
+
function hasComponentSource(css, name) {
|
|
2284
|
+
const re = new RegExp(`@source\\s+(["'])(?!@axis-ds/)[^"'\\n]*${escapeRegExp(name)}(?:[/\\\\][^"'\\n]*)?\\1`);
|
|
2285
|
+
return re.test(stripCssComments(css));
|
|
2269
2286
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2287
|
+
var CREATE_NEXT_APP_DEFAULTS = [
|
|
2288
|
+
{
|
|
2289
|
+
prefix: ":root \uC0C9\uAC12",
|
|
2290
|
+
pattern: /(?<![\w-])(--(?:background|foreground))\s*:\s*(?:#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?|hwb|oklch|oklab|lab|lch|color)\()/g,
|
|
2291
|
+
item: (m) => m[1]
|
|
2292
|
+
},
|
|
2293
|
+
{
|
|
2294
|
+
prefix: "@theme",
|
|
2295
|
+
pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2296
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2297
|
+
},
|
|
2298
|
+
{
|
|
2299
|
+
prefix: "@theme",
|
|
2300
|
+
pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
|
|
2301
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2302
|
+
},
|
|
2303
|
+
{
|
|
2304
|
+
prefix: "body",
|
|
2305
|
+
// WI-0070: create-next-app 의 body `font-family: Arial, Helvetica, sans-serif` 도 같은 특징으로 봅니다. 레이어 밖 규칙이라
|
|
2306
|
+
// AXIS 글꼴(Pretendard, html 에 적용)을 이기고 Button 등이 `font-family: inherit` 로 Arial 을 물려받습니다.
|
|
2307
|
+
pattern: /(?<![\w-])(?:(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)|font-family\s*:\s*Arial\b)/g,
|
|
2308
|
+
item: (m) => m[1] !== void 0 ? `${m[1]}: var(${m[2]})` : "font-family: Arial"
|
|
2274
2309
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
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;
|
|
2310
|
+
];
|
|
2311
|
+
function findCreateNextAppDefaults(css) {
|
|
2312
|
+
const body = stripCssComments(css);
|
|
2313
|
+
const labels = [];
|
|
2314
|
+
for (const d of CREATE_NEXT_APP_DEFAULTS) {
|
|
2315
|
+
const items = [];
|
|
2316
|
+
for (const m of body.matchAll(d.pattern)) {
|
|
2317
|
+
const item = d.item(m);
|
|
2318
|
+
if (!items.includes(item)) items.push(item);
|
|
2296
2319
|
}
|
|
2320
|
+
if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
|
|
2297
2321
|
}
|
|
2298
|
-
return
|
|
2322
|
+
return labels;
|
|
2299
2323
|
}
|
|
2300
|
-
function
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2324
|
+
function stripJsComments(src) {
|
|
2325
|
+
let out = "";
|
|
2326
|
+
let i = 0;
|
|
2327
|
+
const n = src.length;
|
|
2328
|
+
while (i < n) {
|
|
2329
|
+
const c = src[i];
|
|
2330
|
+
const d = src[i + 1];
|
|
2331
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2332
|
+
let j = i + 1;
|
|
2333
|
+
while (j < n && src[j] !== c) {
|
|
2334
|
+
if (src[j] === "\\") j++;
|
|
2335
|
+
else if (c !== "`" && src[j] === "\n") break;
|
|
2336
|
+
j++;
|
|
2337
|
+
}
|
|
2338
|
+
out += src.slice(i, j + 1);
|
|
2339
|
+
i = j + 1;
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
if (c === "/" && d === "/") {
|
|
2343
|
+
const end = src.indexOf("\n", i);
|
|
2344
|
+
i = end === -1 ? n : end;
|
|
2345
|
+
continue;
|
|
2346
|
+
}
|
|
2347
|
+
if (c === "/" && d === "*") {
|
|
2348
|
+
const end = src.indexOf("*/", i + 2);
|
|
2349
|
+
i = end === -1 ? n : end + 2;
|
|
2350
|
+
out += " ";
|
|
2351
|
+
continue;
|
|
2352
|
+
}
|
|
2353
|
+
out += c;
|
|
2354
|
+
i++;
|
|
2304
2355
|
}
|
|
2305
2356
|
return out;
|
|
2306
2357
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
`<ThemeProvider defaultBrand="${name}">{children}</ThemeProvider>`
|
|
2312
|
-
].join("\n");
|
|
2358
|
+
var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
|
|
2359
|
+
var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
|
|
2360
|
+
function hasTokensPresetReference(source) {
|
|
2361
|
+
return PRESET_REFERENCE.test(stripJsComments(source));
|
|
2313
2362
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
const
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2363
|
+
var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
|
|
2364
|
+
var TOKENS_CJS_PRESET_FIXED_VERSION = "1.7.0";
|
|
2365
|
+
var TOKENS_TAILWIND3_CJS_REQUIRE = `require("${TOKENS_TAILWIND3_PRESET}").default`;
|
|
2366
|
+
var PRESET_REQUIRE_CALL = /\brequire\s*\(\s*(["'])@axis-ds\/tokens\/tailwind\1\s*\)/g;
|
|
2367
|
+
var DEFAULT_ACCESS_AHEAD = /^\s*(?:\.\s*default\b|\[\s*["']default["']\s*\])/;
|
|
2368
|
+
function hasBareCjsPresetRequire(code) {
|
|
2369
|
+
for (const m of code.matchAll(PRESET_REQUIRE_CALL)) {
|
|
2370
|
+
const start = m.index ?? 0;
|
|
2371
|
+
const end = start + m[0].length;
|
|
2372
|
+
if (DEFAULT_ACCESS_AHEAD.test(code.slice(end))) continue;
|
|
2373
|
+
const before = code.slice(0, start);
|
|
2374
|
+
if (/\b(?:const|let|var)\s*\{[^{}]*\}\s*=\s*$/.test(before)) continue;
|
|
2375
|
+
const bound = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*$/.exec(before);
|
|
2376
|
+
if (!bound) return true;
|
|
2377
|
+
const ident = escapeRegExp(bound[1]);
|
|
2378
|
+
const rest = code.slice(0, bound.index) + code.slice(end);
|
|
2379
|
+
const bareUse = new RegExp(`(?<![\\w$.])${ident}(?![\\w$])(?!\\s*(?:\\.\\s*default\\b|\\[\\s*["']default["']\\s*\\]))`);
|
|
2380
|
+
if (bareUse.test(rest)) return true;
|
|
2381
|
+
}
|
|
2382
|
+
return false;
|
|
2383
|
+
}
|
|
2384
|
+
function isCommonJsConfig(file, source) {
|
|
2385
|
+
return extname(file) === ".cjs" || /\bmodule\.exports\b/.test(source);
|
|
2386
|
+
}
|
|
2387
|
+
function packageVersionGate(baseDirInput, pkg, name, min) {
|
|
2388
|
+
const baseDir = resolve(baseDirInput);
|
|
2389
|
+
if (!isPnpProject(baseDir)) {
|
|
2390
|
+
const installed = findInstalledPackage(baseDir, name)?.version;
|
|
2391
|
+
if (installed !== void 0) {
|
|
2392
|
+
const cmp = compareExactVersions(installed, min);
|
|
2393
|
+
if (cmp !== void 0) return { status: cmp >= 0 ? "ok" : "below", source: "installed", value: installed };
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
const declared = pkg ? hasDependency2(pkg, name) : void 0;
|
|
2397
|
+
if (declared !== void 0) {
|
|
2398
|
+
const atLeast = rangeLowerAtLeast(declared, min);
|
|
2399
|
+
if (atLeast !== void 0) return { status: atLeast ? "ok" : "below", source: "declared", value: declared };
|
|
2400
|
+
return { status: "unknown", source: "declared", value: declared };
|
|
2324
2401
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2402
|
+
return { status: "unknown", source: "none" };
|
|
2403
|
+
}
|
|
2404
|
+
function versionGateLabel(gate) {
|
|
2405
|
+
if (gate.source === "installed") return `\uC124\uCE58\uBCF8 ${gate.value}`;
|
|
2406
|
+
if (gate.source === "declared") return `\uC120\uC5B8 ${gate.value}`;
|
|
2407
|
+
return "\uC124\uCE58\uBCF8 \xB7 \uC120\uC5B8 \uC5C6\uC74C";
|
|
2408
|
+
}
|
|
2409
|
+
function readPackageJson(baseDir) {
|
|
2327
2410
|
try {
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
|
|
2333
|
-
throw err;
|
|
2411
|
+
const parsed = JSON.parse(readFileSync2(join(baseDir, "package.json"), "utf8"));
|
|
2412
|
+
return isPlainObject2(parsed) ? parsed : void 0;
|
|
2413
|
+
} catch {
|
|
2414
|
+
return void 0;
|
|
2334
2415
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2416
|
+
}
|
|
2417
|
+
function tailwind4Issues(css, pkg, versions) {
|
|
2418
|
+
const issues = [];
|
|
2419
|
+
const hasEntry = hasTokensTailwind4Import(css);
|
|
2420
|
+
if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
|
|
2421
|
+
const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
|
|
2422
|
+
(name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
|
|
2423
|
+
);
|
|
2424
|
+
if (missing.length > 0) {
|
|
2425
|
+
issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
|
|
2426
|
+
}
|
|
2427
|
+
if (hasEntry) {
|
|
2428
|
+
const defaults = findCreateNextAppDefaults(css);
|
|
2429
|
+
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`);
|
|
2430
|
+
if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
|
|
2431
|
+
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`);
|
|
2344
2432
|
}
|
|
2345
|
-
}
|
|
2433
|
+
}
|
|
2434
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2435
|
+
if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
|
|
2436
|
+
issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
return issues;
|
|
2346
2440
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
const
|
|
2354
|
-
|
|
2355
|
-
|
|
2441
|
+
function checkTailwindSetup(baseDirInput) {
|
|
2442
|
+
const baseDir = resolve(baseDirInput);
|
|
2443
|
+
const pkg = readPackageJson(baseDir);
|
|
2444
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2445
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2446
|
+
const label = `Tailwind ${tailwind.major}`;
|
|
2447
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2448
|
+
const file = join(baseDir, candidate);
|
|
2449
|
+
if (!existsSync2(file)) continue;
|
|
2450
|
+
const css = readFileSync2(file, "utf8");
|
|
2451
|
+
if (!hasTailwindImport(css)) {
|
|
2452
|
+
return {
|
|
2453
|
+
name: "tailwind.config",
|
|
2454
|
+
severity: "warn",
|
|
2455
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
2459
|
+
const issues = tailwind4Issues(css, pkg, versions);
|
|
2460
|
+
if (issues.length > 0) {
|
|
2461
|
+
return {
|
|
2462
|
+
name: "tailwind.config",
|
|
2463
|
+
severity: "warn",
|
|
2464
|
+
message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
return {
|
|
2468
|
+
name: "tailwind.config",
|
|
2469
|
+
severity: "pass",
|
|
2470
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
|
|
2471
|
+
};
|
|
2356
2472
|
}
|
|
2473
|
+
return {
|
|
2474
|
+
name: "tailwind.config",
|
|
2475
|
+
severity: "warn",
|
|
2476
|
+
message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
|
|
2477
|
+
};
|
|
2357
2478
|
}
|
|
2358
|
-
|
|
2479
|
+
for (const file of TAILWIND_CONFIG_FILES) {
|
|
2480
|
+
const path18 = join(baseDir, file);
|
|
2481
|
+
if (!existsSync2(path18)) continue;
|
|
2482
|
+
const content = readFileSync2(path18, "utf8");
|
|
2483
|
+
if (hasTokensPresetReference(content)) {
|
|
2484
|
+
const code = stripJsComments(content);
|
|
2485
|
+
if (isCommonJsConfig(file, code) && hasBareCjsPresetRequire(code)) {
|
|
2486
|
+
const gate = packageVersionGate(baseDir, pkg, "@axis-ds/tokens", TOKENS_CJS_PRESET_FIXED_VERSION);
|
|
2487
|
+
if (gate.status !== "ok") {
|
|
2488
|
+
const why = gate.status === "below" ? `@axis-ds/tokens ${versionGateLabel(gate)} \uC5D0\uC11C\uB294 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uAC00 preset \uC774 \uC544\uB2C8\uB77C { default } \uB97C \uB3CC\uB824\uC918 \uC0C9 \xB7 keyframes \uAC00 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` : `@axis-ds/tokens \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${versionGateLabel(gate)}). ${TOKENS_CJS_PRESET_FIXED_VERSION} \uBBF8\uB9CC\uC774\uBA74 CommonJS \uC758 require("${TOKENS_TAILWIND3_PRESET}") \uB85C\uB294 preset \uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`;
|
|
2489
|
+
return {
|
|
2490
|
+
name: "tailwind.config",
|
|
2491
|
+
severity: "warn",
|
|
2492
|
+
message: `${file}\uC5D0 AXIS preset \uCC38\uC870\uAC00 \uC788\uC9C0\uB9CC ${why} \u2192 ${TOKENS_TAILWIND3_CJS_REQUIRE} \uB85C \uBC14\uAFB8\uAC70\uB098 @axis-ds/tokens ${TOKENS_CJS_PRESET_FIXED_VERSION} \uC774\uC0C1`
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
|
|
2497
|
+
}
|
|
2498
|
+
const ownMapping = content.includes("--background") || content.includes("hsl(var(");
|
|
2499
|
+
return {
|
|
2500
|
+
name: "tailwind.config",
|
|
2501
|
+
severity: "warn",
|
|
2502
|
+
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)`
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2505
|
+
return { name: "tailwind.config", severity: "fail", message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2359
2506
|
}
|
|
2360
|
-
function
|
|
2361
|
-
|
|
2507
|
+
function readAxisConfigLike(baseDir) {
|
|
2508
|
+
try {
|
|
2509
|
+
const parsed = JSON.parse(readFileSync2(join(baseDir, "axis.config.json"), "utf8"));
|
|
2510
|
+
return isPlainObject2(parsed) ? parsed : void 0;
|
|
2511
|
+
} catch {
|
|
2512
|
+
return void 0;
|
|
2513
|
+
}
|
|
2362
2514
|
}
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2515
|
+
function contentGlobToRegExp(glob) {
|
|
2516
|
+
const g = glob.trim().replace(/^\.\//, "");
|
|
2517
|
+
let re = "";
|
|
2518
|
+
for (let i = 0; i < g.length; i++) {
|
|
2519
|
+
const c = g[i];
|
|
2520
|
+
if (c === "*") {
|
|
2521
|
+
if (g[i + 1] === "*") {
|
|
2522
|
+
const slash = g[i + 2] === "/";
|
|
2523
|
+
re += slash ? "(?:.*/)?" : ".*";
|
|
2524
|
+
i += slash ? 2 : 1;
|
|
2525
|
+
} else re += "[^/]*";
|
|
2526
|
+
} else if (c === "?") re += "[^/]";
|
|
2527
|
+
else if (c === "{") {
|
|
2528
|
+
const end = g.indexOf("}", i);
|
|
2529
|
+
if (end === -1) {
|
|
2530
|
+
re += "\\{";
|
|
2531
|
+
continue;
|
|
2532
|
+
}
|
|
2533
|
+
re += `(?:${g.slice(i + 1, end).split(",").map((part) => part.replace(/[.+^$()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*")).join("|")})`;
|
|
2534
|
+
i = end;
|
|
2535
|
+
} else if (c === "[") {
|
|
2536
|
+
const end = g.indexOf("]", i);
|
|
2537
|
+
if (end === -1) re += "\\[";
|
|
2538
|
+
else {
|
|
2539
|
+
re += g.slice(i, end + 1);
|
|
2540
|
+
i = end;
|
|
2541
|
+
}
|
|
2542
|
+
} else re += c.replace(/[.+^$()|\\]/g, "\\$&");
|
|
2543
|
+
}
|
|
2544
|
+
return new RegExp(`^${re}$`);
|
|
2369
2545
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
2546
|
+
function balancedSlice(src, start) {
|
|
2547
|
+
const open = src[start];
|
|
2548
|
+
const close = open === "[" ? "]" : "}";
|
|
2549
|
+
let depth = 0;
|
|
2550
|
+
for (let i = start; i < src.length; i++) {
|
|
2551
|
+
const c = src[i];
|
|
2552
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2553
|
+
let j = i + 1;
|
|
2554
|
+
while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
|
|
2555
|
+
i = j;
|
|
2556
|
+
continue;
|
|
2382
2557
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
2558
|
+
if (c === open) depth++;
|
|
2559
|
+
else if (c === close && --depth === 0) return src.slice(start, i + 1);
|
|
2385
2560
|
}
|
|
2561
|
+
return void 0;
|
|
2386
2562
|
}
|
|
2387
|
-
function
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2563
|
+
function stringLiterals(src) {
|
|
2564
|
+
return [...src.matchAll(/(["'`])((?:\\.|(?!\1)[^\\])*)\1/g)].map((m) => m[2]).filter((s) => !s.includes("${"));
|
|
2565
|
+
}
|
|
2566
|
+
function readTailwindContent(source) {
|
|
2567
|
+
const src = stripJsComments(source);
|
|
2568
|
+
const key = /\bcontent\s*:\s*/g;
|
|
2569
|
+
for (const m of src.matchAll(key)) {
|
|
2570
|
+
let at = (m.index ?? 0) + m[0].length;
|
|
2571
|
+
let block = src[at] === "[" || src[at] === "{" ? balancedSlice(src, at) : void 0;
|
|
2572
|
+
if (block === void 0) continue;
|
|
2573
|
+
if (block.startsWith("{")) {
|
|
2574
|
+
const files = /\bfiles\s*:\s*\[/.exec(block);
|
|
2575
|
+
if (!files) return { globs: [], dynamic: true };
|
|
2576
|
+
at = files.index + files[0].length - 1;
|
|
2577
|
+
block = balancedSlice(block, at);
|
|
2578
|
+
if (block === void 0) return { globs: [], dynamic: true };
|
|
2579
|
+
}
|
|
2580
|
+
const inner = block.slice(1, -1);
|
|
2581
|
+
const globs = stringLiterals(inner);
|
|
2582
|
+
const rest = inner.replace(/(["'`])((?:\\.|(?!\1)[^\\])*)\1/g, "").replace(/[\s,]/g, "");
|
|
2583
|
+
return { globs, dynamic: rest !== "" };
|
|
2394
2584
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2585
|
+
return void 0;
|
|
2586
|
+
}
|
|
2587
|
+
function normalizeRel(p) {
|
|
2588
|
+
const s = p.trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
2589
|
+
if (s === "" || s.startsWith("../") || s.startsWith("/") || /^[A-Za-z]:/.test(s)) return void 0;
|
|
2590
|
+
return s;
|
|
2591
|
+
}
|
|
2592
|
+
function inspectTailwindContent(baseDirInput) {
|
|
2593
|
+
const baseDir = resolve(baseDirInput);
|
|
2594
|
+
const pkg = readPackageJson(baseDir);
|
|
2595
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2596
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) return null;
|
|
2597
|
+
const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
|
|
2598
|
+
if (configFile === void 0) return null;
|
|
2599
|
+
const targets = [];
|
|
2600
|
+
const componentsDir = readAxisConfigLike(baseDir)?.componentsDir;
|
|
2601
|
+
const rel3 = typeof componentsDir === "string" ? normalizeRel(componentsDir) : void 0;
|
|
2602
|
+
if (rel3 !== void 0) {
|
|
2603
|
+
targets.push({ label: `componentsDir(${componentsDir})`, sample: `${rel3}/button.tsx`, suggest: `./${rel3}/**/*.{ts,tsx}` });
|
|
2401
2604
|
}
|
|
2402
|
-
const
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
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);
|
|
2605
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2606
|
+
if (pkg !== void 0 && hasDependency2(pkg, name) !== void 0) {
|
|
2607
|
+
targets.push({ label: name, sample: `node_modules/${name}/dist/index.js`, suggest: `./node_modules/${name}/dist/**/*.{js,mjs}` });
|
|
2608
|
+
}
|
|
2413
2609
|
}
|
|
2414
|
-
if (
|
|
2415
|
-
const
|
|
2416
|
-
const
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2610
|
+
if (targets.length === 0) return null;
|
|
2611
|
+
const read = readTailwindContent(readFileSync2(join(baseDir, configFile), "utf8"));
|
|
2612
|
+
const patterns = (read?.globs ?? []).filter((g) => !g.trim().startsWith("!")).map(contentGlobToRegExp);
|
|
2613
|
+
return {
|
|
2614
|
+
configFile,
|
|
2615
|
+
unreadable: read === void 0,
|
|
2616
|
+
dynamic: read?.dynamic ?? false,
|
|
2617
|
+
targets: targets.map((t) => ({ ...t, covered: patterns.some((re) => re.test(t.sample)) }))
|
|
2618
|
+
};
|
|
2422
2619
|
}
|
|
2423
|
-
function
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
const
|
|
2427
|
-
if (
|
|
2428
|
-
|
|
2620
|
+
function checkTailwindContent(baseDir) {
|
|
2621
|
+
const r = inspectTailwindContent(baseDir);
|
|
2622
|
+
if (r === null) return null;
|
|
2623
|
+
const missing = r.targets.filter((t) => !t.covered);
|
|
2624
|
+
if (missing.length === 0) {
|
|
2625
|
+
return {
|
|
2626
|
+
name: "tailwind.content",
|
|
2627
|
+
severity: "pass",
|
|
2628
|
+
message: `${r.configFile}\uC758 content \uAC00 ${r.targets.map((t) => t.label).join(" \xB7 ")} \uB97C \uB36E\uC2B5\uB2C8\uB2E4`
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
const list = missing.map((t) => `${t.label} \u2192 "${t.suggest}"`).join(" \xB7 ");
|
|
2632
|
+
if (r.unreadable || r.dynamic) {
|
|
2633
|
+
return {
|
|
2634
|
+
name: "tailwind.content",
|
|
2635
|
+
severity: "warn",
|
|
2636
|
+
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}`
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
return {
|
|
2640
|
+
name: "tailwind.content",
|
|
2641
|
+
severity: "fail",
|
|
2642
|
+
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}`
|
|
2643
|
+
};
|
|
2429
2644
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2645
|
+
var ANIMATION_PLUGIN_TAILWIND3 = "tailwindcss-animate";
|
|
2646
|
+
var ANIMATION_PLUGIN_TAILWIND4 = "tw-animate-css";
|
|
2647
|
+
var ANIMATION_SCAN_ENTRY_LIMIT = 2e3;
|
|
2648
|
+
var ANIMATION_SCAN_DEPTH_LIMIT = 8;
|
|
2649
|
+
var ANIMATION_SCAN_FILE_BYTES = 512 * 1024;
|
|
2650
|
+
function componentsUseAnimation(baseDir, componentsDir) {
|
|
2651
|
+
const rel3 = normalizeRel(componentsDir);
|
|
2652
|
+
if (rel3 === void 0) return false;
|
|
2653
|
+
const stack = [[join(baseDir, rel3), 0]];
|
|
2654
|
+
let visited = 0;
|
|
2655
|
+
while (stack.length > 0) {
|
|
2656
|
+
const [dir, depth] = stack.pop();
|
|
2657
|
+
let names;
|
|
2658
|
+
try {
|
|
2659
|
+
names = readdirSync(dir);
|
|
2660
|
+
} catch {
|
|
2661
|
+
continue;
|
|
2662
|
+
}
|
|
2663
|
+
for (const name of names) {
|
|
2664
|
+
if (++visited > ANIMATION_SCAN_ENTRY_LIMIT) return false;
|
|
2665
|
+
const p = join(dir, name);
|
|
2666
|
+
let st;
|
|
2667
|
+
try {
|
|
2668
|
+
st = lstatSync(p);
|
|
2669
|
+
} catch {
|
|
2670
|
+
continue;
|
|
2671
|
+
}
|
|
2672
|
+
if (st.isSymbolicLink()) continue;
|
|
2673
|
+
if (st.isDirectory()) {
|
|
2674
|
+
if (name !== "node_modules" && depth < ANIMATION_SCAN_DEPTH_LIMIT) stack.push([p, depth + 1]);
|
|
2675
|
+
} else if (st.isFile() && st.size <= ANIMATION_SCAN_FILE_BYTES && /\.(tsx|ts|jsx|js)$/.test(name)) {
|
|
2676
|
+
if (/\banimate-(?:in|out)\b/.test(readFileSync2(p, "utf8"))) return true;
|
|
2444
2677
|
}
|
|
2445
|
-
return found;
|
|
2446
2678
|
}
|
|
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
2679
|
}
|
|
2453
|
-
return
|
|
2454
|
-
}
|
|
2455
|
-
var TAILWIND_CONFIG_FILES = [
|
|
2456
|
-
"tailwind.config.ts",
|
|
2457
|
-
"tailwind.config.js",
|
|
2458
|
-
"tailwind.config.mjs",
|
|
2459
|
-
"tailwind.config.cjs"
|
|
2460
|
-
];
|
|
2461
|
-
var TAILWIND_CSS_CANDIDATES = [
|
|
2462
|
-
"globals.css",
|
|
2463
|
-
"app/globals.css",
|
|
2464
|
-
"src/app/globals.css",
|
|
2465
|
-
"src/globals.css",
|
|
2466
|
-
"styles/globals.css"
|
|
2467
|
-
];
|
|
2468
|
-
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2469
|
-
function stripCssComments(css) {
|
|
2470
|
-
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2471
|
-
}
|
|
2472
|
-
function hasTailwindImport(css) {
|
|
2473
|
-
return TAILWIND_IMPORT.test(stripCssComments(css));
|
|
2474
|
-
}
|
|
2475
|
-
var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
|
|
2476
|
-
var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
|
|
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));
|
|
2680
|
+
return false;
|
|
2480
2681
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2682
|
+
function checkAnimationPlugin(baseDirInput) {
|
|
2683
|
+
const baseDir = resolve(baseDirInput);
|
|
2684
|
+
const pkg = readPackageJson(baseDir);
|
|
2685
|
+
const config = readAxisConfigLike(baseDir);
|
|
2686
|
+
const declared = pkg !== void 0 && hasDependency2(pkg, "@axis-ds/ui-react") !== void 0;
|
|
2687
|
+
const copied = typeof config?.componentsDir === "string" && componentsUseAnimation(baseDir, config.componentsDir);
|
|
2688
|
+
if (!declared && !copied) return null;
|
|
2689
|
+
const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
|
|
2690
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2691
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2692
|
+
const file = TAILWIND_CSS_CANDIDATES.find((c) => existsSync2(join(baseDir, c)));
|
|
2693
|
+
const css = file !== void 0 ? stripCssComments(readFileSync2(join(baseDir, file), "utf8")) : "";
|
|
2694
|
+
const ok = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`).test(css) || new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`).test(css);
|
|
2695
|
+
return ok ? { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4` } : {
|
|
2696
|
+
name: "animation",
|
|
2697
|
+
severity: "warn",
|
|
2698
|
+
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}";`
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2701
|
+
const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
|
|
2702
|
+
const source = configFile !== void 0 ? stripJsComments(readFileSync2(join(baseDir, configFile), "utf8")) : "";
|
|
2703
|
+
const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
|
|
2704
|
+
const pluginDeclared = pkg !== void 0 && hasDependency2(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0;
|
|
2705
|
+
const pluginInstalled = pluginDeclared && (isPnpProject(baseDir) || findInstalledPackage(baseDir, ANIMATION_PLUGIN_TAILWIND3) !== void 0);
|
|
2706
|
+
if (plugins === "found" && pluginDeclared && pluginInstalled) {
|
|
2707
|
+
return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
2708
|
+
}
|
|
2709
|
+
const cfg = configFile ?? "tailwind.config";
|
|
2710
|
+
const reasons = [];
|
|
2711
|
+
if (!pluginDeclared) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uC120\uC5B8 \uC5C6\uC74C`);
|
|
2712
|
+
else if (!pluginInstalled) reasons.push(`${ANIMATION_PLUGIN_TAILWIND3} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`);
|
|
2713
|
+
if (plugins === "dynamic") reasons.push(`${cfg} plugins \uB97C \uC815\uC801\uC73C\uB85C \uB2E4 \uC77D\uC9C0 \uBABB\uD574 \uD655\uC778\uD558\uC9C0 \uBABB\uD568`);
|
|
2714
|
+
else if (plugins !== "found") reasons.push(`${cfg} plugins \uC5D0 \uC5C6\uC74C`);
|
|
2715
|
+
return {
|
|
2716
|
+
name: "animation",
|
|
2717
|
+
severity: "warn",
|
|
2718
|
+
message: `\uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(${by}, ${reasons.join(" \xB7 ")}): 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}")`
|
|
2719
|
+
};
|
|
2484
2720
|
}
|
|
2485
|
-
function
|
|
2486
|
-
const
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2721
|
+
function readAnimationPluginUse(source) {
|
|
2722
|
+
const name = escapeRegExp(ANIMATION_PLUGIN_TAILWIND3);
|
|
2723
|
+
const idents = /* @__PURE__ */ new Set();
|
|
2724
|
+
for (const m of source.matchAll(new RegExp(`\\bimport\\s+([A-Za-z_$][\\w$]*)\\s+from\\s*(["'])${name}\\2`, "g"))) idents.add(m[1]);
|
|
2725
|
+
for (const m of source.matchAll(
|
|
2726
|
+
new RegExp(`\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*require\\s*\\(\\s*(["'])${name}\\2\\s*\\)`, "g")
|
|
2727
|
+
)) {
|
|
2728
|
+
idents.add(m[1]);
|
|
2729
|
+
}
|
|
2730
|
+
const requireCall = new RegExp(`^require\\s*\\(\\s*(["'])${name}\\1\\s*\\)(?:\\s*\\.\\s*default)?$`);
|
|
2731
|
+
let sawDynamic = false;
|
|
2732
|
+
for (const m of source.matchAll(/\bplugins\b\s*(:)?\s*/g)) {
|
|
2733
|
+
if (m[1] === void 0) {
|
|
2734
|
+
const before = source.slice(Math.max(0, (m.index ?? 0) - 1), m.index ?? 0);
|
|
2735
|
+
if (/[{,\s]/.test(before) || before === "") sawDynamic = true;
|
|
2736
|
+
continue;
|
|
2493
2737
|
}
|
|
2494
|
-
const
|
|
2495
|
-
if (
|
|
2496
|
-
|
|
2738
|
+
const at = (m.index ?? 0) + m[0].length;
|
|
2739
|
+
if (source[at] !== "[") {
|
|
2740
|
+
sawDynamic = true;
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
const block = balancedSlice(source, at);
|
|
2744
|
+
if (block === void 0) {
|
|
2745
|
+
sawDynamic = true;
|
|
2746
|
+
continue;
|
|
2747
|
+
}
|
|
2748
|
+
const elements = splitTopLevel(block.slice(1, -1));
|
|
2749
|
+
for (const el of elements) {
|
|
2750
|
+
const e = el.trim();
|
|
2751
|
+
if (e === "") continue;
|
|
2752
|
+
if (requireCall.test(e) || idents.has(e) || idents.has(e.replace(/\(\s*\)$/, ""))) return "found";
|
|
2753
|
+
if (/^require\s*\(\s*(["'])[^"']+\1\s*\)(?:\s*\.\s*default)?$/.test(e)) continue;
|
|
2754
|
+
sawDynamic = true;
|
|
2497
2755
|
}
|
|
2498
|
-
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
2499
2756
|
}
|
|
2500
|
-
return
|
|
2757
|
+
return sawDynamic ? "dynamic" : "absent";
|
|
2501
2758
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2759
|
+
function splitTopLevel(body) {
|
|
2760
|
+
const out = [];
|
|
2761
|
+
let depth = 0;
|
|
2762
|
+
let start = 0;
|
|
2763
|
+
for (let i = 0; i < body.length; i++) {
|
|
2764
|
+
const c = body[i];
|
|
2765
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2766
|
+
let j = i + 1;
|
|
2767
|
+
while (j < body.length && body[j] !== c) j += body[j] === "\\" ? 2 : 1;
|
|
2768
|
+
i = j;
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
2772
|
+
else if (c === ")" || c === "]" || c === "}") depth--;
|
|
2773
|
+
else if (c === "," && depth === 0) {
|
|
2774
|
+
out.push(body.slice(start, i));
|
|
2775
|
+
start = i + 1;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
out.push(body.slice(start));
|
|
2779
|
+
return out;
|
|
2510
2780
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2781
|
+
|
|
2782
|
+
// src/template/template-apply.ts
|
|
2783
|
+
async function templateApplyWarnings(baseDir, detail) {
|
|
2784
|
+
const warnings = [];
|
|
2785
|
+
const pkgPath = path9.join(baseDir, "package.json");
|
|
2786
|
+
const templateRange = detail.devDependencies?.tailwindcss ?? detail.dependencies?.tailwindcss;
|
|
2787
|
+
const templateMajor = templateRange !== void 0 ? tailwindMajorFromRange(templateRange) : void 0;
|
|
2788
|
+
if (templateMajor !== void 0 && await fs8.pathExists(pkgPath)) {
|
|
2789
|
+
let pkg;
|
|
2790
|
+
try {
|
|
2791
|
+
pkg = await fs8.readJSON(pkgPath);
|
|
2792
|
+
} catch {
|
|
2793
|
+
pkg = void 0;
|
|
2794
|
+
}
|
|
2795
|
+
const project = detectTailwind(baseDir, pkg);
|
|
2796
|
+
if (project.major !== void 0 && project.major !== templateMajor) {
|
|
2797
|
+
warnings.push(
|
|
2798
|
+
`\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.`
|
|
2799
|
+
);
|
|
2800
|
+
}
|
|
2514
2801
|
}
|
|
2515
|
-
|
|
2802
|
+
const usesRootApp = detail.files.some((f) => f.path.startsWith("app/"));
|
|
2803
|
+
if (usesRootApp && await fs8.pathExists(path9.join(baseDir, "src", "app"))) {
|
|
2804
|
+
warnings.push(
|
|
2805
|
+
"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."
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
return warnings;
|
|
2516
2809
|
}
|
|
2517
|
-
function
|
|
2518
|
-
const
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2810
|
+
async function applyTemplate(slug, options) {
|
|
2811
|
+
const spinner = ora3(`'${slug}' \uD15C\uD50C\uB9BF \uAC00\uC838\uC624\uB294 \uC911...`).start();
|
|
2812
|
+
let detail;
|
|
2813
|
+
try {
|
|
2814
|
+
detail = await fetchTemplateDetail(slug);
|
|
2815
|
+
spinner.succeed(`'${detail.name}' \uD15C\uD50C\uB9BF \uB85C\uB4DC \uC644\uB8CC (${detail.files.length}\uAC1C \uD30C\uC77C)`);
|
|
2816
|
+
} catch (err) {
|
|
2817
|
+
spinner.fail(err.message);
|
|
2818
|
+
process.exit(1);
|
|
2525
2819
|
}
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
const
|
|
2533
|
-
if (
|
|
2534
|
-
|
|
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 };
|
|
2820
|
+
const baseDir = path9.resolve(options.dir || ".");
|
|
2821
|
+
for (const w of await templateApplyWarnings(baseDir, detail)) {
|
|
2822
|
+
console.log(chalk5.yellow(`! ${w}`));
|
|
2823
|
+
}
|
|
2824
|
+
const conflicts = [];
|
|
2825
|
+
for (const file of detail.files) {
|
|
2826
|
+
const dest = path9.join(baseDir, file.path);
|
|
2827
|
+
if (await fs8.pathExists(dest)) {
|
|
2828
|
+
conflicts.push(file.path);
|
|
2540
2829
|
}
|
|
2541
|
-
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2542
2830
|
}
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2831
|
+
if (conflicts.length > 0 && !options.yes && !options.dryRun) {
|
|
2832
|
+
console.log(chalk5.yellow(`
|
|
2833
|
+
\uAE30\uC874 \uD30C\uC77C\uACFC \uCDA9\uB3CC\uD558\uB294 ${conflicts.length}\uAC1C \uD30C\uC77C:`));
|
|
2834
|
+
for (const c of conflicts) {
|
|
2835
|
+
console.log(chalk5.gray(` - ${c}`));
|
|
2836
|
+
}
|
|
2837
|
+
const { proceed } = await prompts({
|
|
2838
|
+
type: "confirm",
|
|
2839
|
+
name: "proceed",
|
|
2840
|
+
message: "\uCDA9\uB3CC \uD30C\uC77C\uC744 \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
2841
|
+
initial: false
|
|
2842
|
+
});
|
|
2843
|
+
if (!proceed) {
|
|
2844
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2845
|
+
return;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
if (options.dryRun) {
|
|
2849
|
+
console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] \uC0DD\uC131\uB420 \uD30C\uC77C:"));
|
|
2850
|
+
for (const file of detail.files) {
|
|
2851
|
+
const dest = path9.join(baseDir, file.path);
|
|
2852
|
+
const exists = conflicts.includes(file.path);
|
|
2853
|
+
const label = exists ? chalk5.yellow("\uB36E\uC5B4\uC4F0\uAE30") : chalk5.green("\uC0DD\uC131");
|
|
2854
|
+
console.log(` ${label} ${dest}`);
|
|
2855
|
+
}
|
|
2856
|
+
if (detail.postInstall?.length) {
|
|
2857
|
+
console.log(chalk5.blue("\n[\uBBF8\uB9AC\uBCF4\uAE30] postInstall \uD328\uCE58:"));
|
|
2858
|
+
for (const p of detail.postInstall) {
|
|
2859
|
+
console.log(chalk5.gray(` ${p.type}: ${p.file}`));
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
const writeSpinner = ora3("\uD30C\uC77C \uC0DD\uC131 \uC911...").start();
|
|
2865
|
+
for (const file of detail.files) {
|
|
2866
|
+
const dest = path9.join(baseDir, file.path);
|
|
2867
|
+
await fs8.ensureDir(path9.dirname(dest));
|
|
2868
|
+
await fs8.writeFile(dest, file.content);
|
|
2869
|
+
}
|
|
2870
|
+
writeSpinner.succeed(`${detail.files.length}\uAC1C \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC`);
|
|
2871
|
+
if (detail.postInstall?.length) {
|
|
2872
|
+
console.log(chalk5.blue("\npostInstall \uD328\uCE58 \uC2E4\uD589 \uC911..."));
|
|
2873
|
+
await runPostInstall(detail.postInstall, baseDir);
|
|
2874
|
+
}
|
|
2875
|
+
if (!options.skipDeps) {
|
|
2876
|
+
const allDeps = { ...detail.dependencies, ...detail.devDependencies };
|
|
2877
|
+
const depList = Object.entries(allDeps);
|
|
2878
|
+
if (depList.length > 0) {
|
|
2879
|
+
console.log(chalk5.yellow("\n\uD544\uC694\uD55C \uC758\uC874\uC131:"));
|
|
2880
|
+
const deps = Object.entries(detail.dependencies || {}).map(([k, v]) => `${k}@${v}`).join(" ");
|
|
2881
|
+
const devDeps = Object.entries(detail.devDependencies || {}).map(([k, v]) => `${k}@${v}`).join(" ");
|
|
2882
|
+
if (deps) {
|
|
2883
|
+
console.log(chalk5.cyan(` pnpm add ${deps}`));
|
|
2884
|
+
}
|
|
2885
|
+
if (devDeps) {
|
|
2886
|
+
console.log(chalk5.cyan(` pnpm add -D ${devDeps}`));
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
console.log(chalk5.green(`
|
|
2891
|
+
'${detail.name}' \uD15C\uD50C\uB9BF \uC801\uC6A9 \uC644\uB8CC!`));
|
|
2892
|
+
}
|
|
2893
|
+
async function initTemplate(slug, options) {
|
|
2894
|
+
let selectedSlug = slug;
|
|
2895
|
+
if (!selectedSlug) {
|
|
2896
|
+
const { fetchTemplateIndex: fetchTemplateIndex2 } = await import("./registry-client-6WSGKPF2.js");
|
|
2897
|
+
const index = await fetchTemplateIndex2();
|
|
2898
|
+
const { choice } = await prompts({
|
|
2899
|
+
type: "select",
|
|
2900
|
+
name: "choice",
|
|
2901
|
+
message: "\uC0AC\uC6A9\uD560 \uD15C\uD50C\uB9BF\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
2902
|
+
choices: index.templates.map((t) => ({
|
|
2903
|
+
title: `${t.name} (${t.category})`,
|
|
2904
|
+
description: t.description,
|
|
2905
|
+
value: t.slug
|
|
2906
|
+
}))
|
|
2907
|
+
});
|
|
2908
|
+
if (!choice) {
|
|
2909
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2912
|
+
selectedSlug = choice;
|
|
2913
|
+
}
|
|
2914
|
+
let targetDir = options.dir;
|
|
2915
|
+
if (!targetDir) {
|
|
2916
|
+
const { dir } = await prompts({
|
|
2917
|
+
type: "text",
|
|
2918
|
+
name: "dir",
|
|
2919
|
+
message: "\uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
|
|
2920
|
+
initial: selectedSlug
|
|
2921
|
+
});
|
|
2922
|
+
if (!dir) {
|
|
2923
|
+
console.log(chalk5.gray("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
targetDir = dir;
|
|
2927
|
+
}
|
|
2928
|
+
const resolved = path9.resolve(targetDir);
|
|
2929
|
+
if (await fs8.pathExists(resolved)) {
|
|
2930
|
+
const entries = await fs8.readdir(resolved);
|
|
2931
|
+
if (entries.length > 0) {
|
|
2932
|
+
const { proceed } = await prompts({
|
|
2933
|
+
type: "confirm",
|
|
2934
|
+
name: "proceed",
|
|
2935
|
+
message: `'${targetDir}'\uC5D0 \uC774\uBBF8 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uACC4\uC18D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`,
|
|
2936
|
+
initial: false
|
|
2937
|
+
});
|
|
2938
|
+
if (!proceed) return;
|
|
2939
|
+
}
|
|
2940
|
+
} else {
|
|
2941
|
+
await fs8.ensureDir(resolved);
|
|
2942
|
+
}
|
|
2943
|
+
await applyTemplate(selectedSlug, { dir: targetDir, yes: true });
|
|
2944
|
+
const configPath = path9.join(resolved, "axis.config.json");
|
|
2945
|
+
if (!await fs8.pathExists(configPath)) {
|
|
2946
|
+
const axisConfig = createTemplateConfig(selectedSlug);
|
|
2947
|
+
await fs8.writeJSON(configPath, axisConfig, { spaces: 2 });
|
|
2948
|
+
console.log(chalk5.green("axis.config.json \uC0DD\uC131 \uC644\uB8CC"));
|
|
2949
|
+
}
|
|
2950
|
+
console.log(chalk5.blue(`
|
|
2951
|
+
\uB2E4\uC74C \uB2E8\uACC4:`));
|
|
2952
|
+
console.log(chalk5.cyan(` cd ${targetDir}`));
|
|
2953
|
+
console.log(chalk5.cyan(` pnpm install`));
|
|
2954
|
+
console.log(chalk5.cyan(` pnpm dev`));
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
// src/template/template-diff.ts
|
|
2958
|
+
import fs9 from "fs-extra";
|
|
2959
|
+
import path10 from "path";
|
|
2960
|
+
import chalk6 from "chalk";
|
|
2961
|
+
import ora4 from "ora";
|
|
2962
|
+
async function diffTemplate(slug, options) {
|
|
2963
|
+
const spinner = ora4(`'${slug}' \uD15C\uD50C\uB9BF \uAC00\uC838\uC624\uB294 \uC911...`).start();
|
|
2964
|
+
let detail;
|
|
2965
|
+
try {
|
|
2966
|
+
detail = await fetchTemplateDetail(slug);
|
|
2967
|
+
spinner.succeed(`'${detail.name}' \uB85C\uB4DC \uC644\uB8CC`);
|
|
2968
|
+
} catch (err) {
|
|
2969
|
+
spinner.fail(err.message);
|
|
2970
|
+
process.exit(1);
|
|
2971
|
+
}
|
|
2972
|
+
const baseDir = path10.resolve(options.dir || ".");
|
|
2973
|
+
const entries = [];
|
|
2974
|
+
for (const file of detail.files) {
|
|
2975
|
+
const localPath = path10.join(baseDir, file.path);
|
|
2976
|
+
if (!await fs9.pathExists(localPath)) {
|
|
2977
|
+
entries.push({ path: file.path, status: "added" });
|
|
2978
|
+
continue;
|
|
2979
|
+
}
|
|
2980
|
+
const localContent = await fs9.readFile(localPath, "utf-8");
|
|
2981
|
+
if (localContent === file.content) {
|
|
2982
|
+
entries.push({ path: file.path, status: "unchanged" });
|
|
2983
|
+
} else {
|
|
2984
|
+
entries.push({
|
|
2985
|
+
path: file.path,
|
|
2986
|
+
status: "modified",
|
|
2987
|
+
localLines: localContent.split("\n").length,
|
|
2988
|
+
remoteLines: file.content.split("\n").length
|
|
2989
|
+
});
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
if (options.verbose) {
|
|
2993
|
+
const templatePaths = new Set(detail.files.map((f) => f.path));
|
|
2994
|
+
const localFiles = await collectLocalFiles(baseDir);
|
|
2995
|
+
for (const lf of localFiles) {
|
|
2996
|
+
if (!templatePaths.has(lf)) {
|
|
2997
|
+
entries.push({ path: lf, status: "extra" });
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
console.log(chalk6.blue(`
|
|
3002
|
+
'${detail.name}' \uD15C\uD50C\uB9BF diff \uACB0\uACFC:
|
|
3003
|
+
`));
|
|
3004
|
+
const statusIcon = {
|
|
3005
|
+
added: chalk6.green("+ \uCD94\uAC00 \uD544\uC694"),
|
|
3006
|
+
modified: chalk6.yellow("~ \uBCC0\uACBD\uB428"),
|
|
3007
|
+
unchanged: chalk6.gray("= \uB3D9\uC77C"),
|
|
3008
|
+
extra: chalk6.cyan("? \uB85C\uCEEC \uC804\uC6A9")
|
|
3009
|
+
};
|
|
3010
|
+
let added = 0;
|
|
3011
|
+
let modified = 0;
|
|
3012
|
+
let unchanged = 0;
|
|
3013
|
+
let extra = 0;
|
|
3014
|
+
for (const entry of entries) {
|
|
3015
|
+
const icon = statusIcon[entry.status];
|
|
3016
|
+
console.log(` ${icon.padEnd(28)} ${entry.path}`);
|
|
3017
|
+
if (entry.status === "modified" && options.verbose) {
|
|
3018
|
+
console.log(
|
|
3019
|
+
chalk6.gray(
|
|
3020
|
+
` \uB85C\uCEEC ${entry.localLines}\uC904 / \uC6D0\uBCF8 ${entry.remoteLines}\uC904`
|
|
3021
|
+
)
|
|
3022
|
+
);
|
|
3023
|
+
}
|
|
3024
|
+
switch (entry.status) {
|
|
3025
|
+
case "added":
|
|
3026
|
+
added++;
|
|
3027
|
+
break;
|
|
3028
|
+
case "modified":
|
|
3029
|
+
modified++;
|
|
3030
|
+
break;
|
|
3031
|
+
case "unchanged":
|
|
3032
|
+
unchanged++;
|
|
3033
|
+
break;
|
|
3034
|
+
case "extra":
|
|
3035
|
+
extra++;
|
|
3036
|
+
break;
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
console.log(chalk6.blue("\n\uC694\uC57D:"));
|
|
3040
|
+
console.log(
|
|
3041
|
+
` \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))}` : ""}`
|
|
3042
|
+
);
|
|
3043
|
+
}
|
|
3044
|
+
async function collectLocalFiles(dir, base) {
|
|
3045
|
+
const root = base || dir;
|
|
3046
|
+
const ignore = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", "dist"]);
|
|
3047
|
+
const results = [];
|
|
3048
|
+
let entries;
|
|
3049
|
+
try {
|
|
3050
|
+
entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
3051
|
+
} catch {
|
|
3052
|
+
return results;
|
|
3053
|
+
}
|
|
3054
|
+
for (const entry of entries) {
|
|
3055
|
+
if (ignore.has(entry.name)) continue;
|
|
3056
|
+
const fullPath = path10.join(dir, entry.name);
|
|
3057
|
+
if (entry.isDirectory()) {
|
|
3058
|
+
const nested = await collectLocalFiles(fullPath, root);
|
|
3059
|
+
results.push(...nested);
|
|
3060
|
+
} else {
|
|
3061
|
+
results.push(path10.relative(root, fullPath).replace(/\\/g, "/"));
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
return results;
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
// src/template/template-check.ts
|
|
3068
|
+
import fs10 from "fs-extra";
|
|
3069
|
+
import path11 from "path";
|
|
3070
|
+
import chalk7 from "chalk";
|
|
3071
|
+
|
|
3072
|
+
// src/theme/brand-core.ts
|
|
3073
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
3074
|
+
import { createRequire } from "module";
|
|
3075
|
+
import { dirname, join as join2, relative, resolve as resolve2, sep } from "path";
|
|
3076
|
+
var TOKENS_PACKAGE = "@axis-ds/tokens";
|
|
3077
|
+
var BRAND_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
3078
|
+
var MIN_BRAND_TOKENS_VERSION = "1.3.0";
|
|
3079
|
+
var TOKENS_DEPENDENCY_MIN_VERSION = "1.6.0";
|
|
3080
|
+
var KEY_TOKENS = [
|
|
3081
|
+
"--primary",
|
|
3082
|
+
"--primary-foreground",
|
|
3083
|
+
"--background",
|
|
3084
|
+
"--foreground",
|
|
3085
|
+
"--ring",
|
|
3086
|
+
"--radius",
|
|
3087
|
+
"--axis-surface-default",
|
|
3088
|
+
"--axis-text-primary",
|
|
3089
|
+
"--axis-text-brand",
|
|
3090
|
+
"--axis-button-bg-default",
|
|
3091
|
+
"--axis-border-focus",
|
|
3092
|
+
"--axis-font-family-sans"
|
|
3093
|
+
];
|
|
3094
|
+
var BRAND_ADJUSTMENT_REFERENCE = "WI-0025 PRD \uBD80\uB85D B (docs/workitems/WI-0025-brand-theme/prd.md)";
|
|
3095
|
+
function readJsonFile(file) {
|
|
3096
|
+
return JSON.parse(readFileSync3(file, "utf8"));
|
|
3097
|
+
}
|
|
3098
|
+
function errorCode(err) {
|
|
3099
|
+
return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
|
|
3100
|
+
}
|
|
3101
|
+
function findTokensPackageJson(baseDir) {
|
|
3102
|
+
let dir = resolve2(baseDir);
|
|
3103
|
+
for (; ; ) {
|
|
3104
|
+
const candidate = join2(dir, "node_modules", TOKENS_PACKAGE, "package.json");
|
|
3105
|
+
if (existsSync3(candidate)) return candidate;
|
|
3106
|
+
const parent = dirname(dir);
|
|
3107
|
+
if (parent === dir) return void 0;
|
|
3108
|
+
dir = parent;
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
function projectRequire(baseDir) {
|
|
3112
|
+
return createRequire(join2(resolve2(baseDir), "package.json"));
|
|
3113
|
+
}
|
|
3114
|
+
function tokensSpecifier(subpath) {
|
|
3115
|
+
return `${TOKENS_PACKAGE}/${subpath.replace(/^\.\//, "")}`;
|
|
3116
|
+
}
|
|
3117
|
+
function resolveTokens(baseDir) {
|
|
3118
|
+
const pkgJson = findTokensPackageJson(baseDir);
|
|
3119
|
+
if (!pkgJson) return { status: "not-installed" };
|
|
3120
|
+
const pkg = readJsonFile(pkgJson);
|
|
3121
|
+
const version = typeof pkg.version === "string" ? pkg.version : void 0;
|
|
3122
|
+
try {
|
|
3123
|
+
const indexPath = projectRequire(baseDir).resolve(tokensSpecifier("./brands"));
|
|
3124
|
+
return { status: "ok", version, indexPath };
|
|
3125
|
+
} catch (err) {
|
|
3126
|
+
const code = errorCode(err);
|
|
3127
|
+
if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED") return { status: "unsupported", version };
|
|
3128
|
+
if (code === "MODULE_NOT_FOUND") return { status: "not-built", version };
|
|
3129
|
+
throw err;
|
|
3130
|
+
}
|
|
2550
3131
|
}
|
|
2551
|
-
function
|
|
2552
|
-
|
|
2553
|
-
const v = version.trim();
|
|
2554
|
-
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2555
|
-
return v;
|
|
3132
|
+
function brandImportPath(entry) {
|
|
3133
|
+
return tokensSpecifier(entry.css);
|
|
2556
3134
|
}
|
|
2557
|
-
function
|
|
3135
|
+
function isFile2(file) {
|
|
2558
3136
|
try {
|
|
2559
|
-
|
|
2560
|
-
return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
|
|
3137
|
+
return statSync2(file).isFile();
|
|
2561
3138
|
} catch {
|
|
2562
|
-
return
|
|
3139
|
+
return false;
|
|
2563
3140
|
}
|
|
2564
3141
|
}
|
|
2565
|
-
function
|
|
2566
|
-
|
|
2567
|
-
const
|
|
2568
|
-
const
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
3142
|
+
function findGlobalCss(baseDir, config) {
|
|
3143
|
+
const root = resolve2(baseDir);
|
|
3144
|
+
const result = {};
|
|
3145
|
+
const configured = config?.globalCss;
|
|
3146
|
+
if (typeof configured === "string" && configured.trim() !== "") {
|
|
3147
|
+
const file = resolve2(root, configured);
|
|
3148
|
+
if (isFile2(file)) return { path: file };
|
|
3149
|
+
result.configuredMissing = configured;
|
|
3150
|
+
}
|
|
3151
|
+
for (const candidate of GLOBAL_CSS_CANDIDATES) {
|
|
3152
|
+
const file = join2(root, candidate);
|
|
3153
|
+
if (isFile2(file)) {
|
|
3154
|
+
result.path = file;
|
|
3155
|
+
break;
|
|
2578
3156
|
}
|
|
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
3157
|
}
|
|
2583
|
-
return
|
|
3158
|
+
return result;
|
|
2584
3159
|
}
|
|
2585
|
-
function
|
|
2586
|
-
|
|
3160
|
+
function findBrandImports(css) {
|
|
3161
|
+
const names = [];
|
|
3162
|
+
const pattern = /@import\s+(?:url\(\s*)?["']?@axis-ds\/tokens\/css\/brands\/([a-z][a-z0-9-]*)(?:\.css)?["']?\s*\)?\s*(?=[;\s]|$)/g;
|
|
3163
|
+
for (const m of stripComments(css).matchAll(pattern)) {
|
|
3164
|
+
names.push(m[1]);
|
|
3165
|
+
}
|
|
3166
|
+
return names;
|
|
2587
3167
|
}
|
|
2588
|
-
var
|
|
2589
|
-
function
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
3168
|
+
var AXIS_CONFIG_FILE_NAME = "axis.config.json";
|
|
3169
|
+
function readBrandConfig(baseDir) {
|
|
3170
|
+
let parsed;
|
|
3171
|
+
try {
|
|
3172
|
+
parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), AXIS_CONFIG_FILE_NAME), "utf8"));
|
|
3173
|
+
} catch {
|
|
3174
|
+
return null;
|
|
3175
|
+
}
|
|
3176
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
3177
|
+
return parsed;
|
|
2596
3178
|
}
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
3179
|
+
function inspectBrandImport(baseDir) {
|
|
3180
|
+
const config = readBrandConfig(baseDir);
|
|
3181
|
+
const brand = config?.brand;
|
|
3182
|
+
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
3183
|
+
const root = resolve2(baseDir);
|
|
3184
|
+
const location = findGlobalCss(root, config);
|
|
3185
|
+
const base = { brand };
|
|
3186
|
+
if (location.configuredMissing !== void 0) base.configuredMissing = location.configuredMissing;
|
|
3187
|
+
if (!location.path) {
|
|
3188
|
+
return { ...base, state: "css-missing", imports: [] };
|
|
3189
|
+
}
|
|
3190
|
+
const cssFile = relative(root, location.path).split(sep).join("/");
|
|
3191
|
+
const imports = [...new Set(findBrandImports(readFileSync3(location.path, "utf8")))];
|
|
3192
|
+
let state;
|
|
3193
|
+
if (imports.includes(brand)) state = "match";
|
|
3194
|
+
else if (imports.length === 0) state = "import-missing";
|
|
3195
|
+
else state = "other-brand";
|
|
3196
|
+
return { ...base, state, cssFile, imports };
|
|
2600
3197
|
}
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
return re.test(stripCssComments(css));
|
|
3198
|
+
function isMissingBuildFile(err) {
|
|
3199
|
+
const code = errorCode(err);
|
|
3200
|
+
return code === "MODULE_NOT_FOUND" || code === "ENOENT";
|
|
2605
3201
|
}
|
|
2606
|
-
function
|
|
2607
|
-
const
|
|
2608
|
-
|
|
3202
|
+
function readBrandIndex(indexPath) {
|
|
3203
|
+
const data = readJsonFile(indexPath);
|
|
3204
|
+
if (!Array.isArray(data.brands)) {
|
|
3205
|
+
throw new Error(`${indexPath}: "brands" \uBC30\uC5F4\uC774 \uC5C6\uC2B5\uB2C8\uB2E4`);
|
|
3206
|
+
}
|
|
3207
|
+
return data.brands;
|
|
2609
3208
|
}
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
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]})`
|
|
3209
|
+
function readSummary(baseDir, entry) {
|
|
3210
|
+
const metaPath = projectRequire(baseDir).resolve(tokensSpecifier(entry.meta));
|
|
3211
|
+
const meta = readJsonFile(metaPath);
|
|
3212
|
+
return {
|
|
3213
|
+
name: entry.name,
|
|
3214
|
+
description: typeof meta.description === "string" ? meta.description : "",
|
|
3215
|
+
themes: Array.isArray(meta.themes) ? meta.themes.map(String) : [],
|
|
3216
|
+
a11y: typeof meta.a11y === "object" && meta.a11y !== null ? meta.a11y : {},
|
|
3217
|
+
importPath: brandImportPath(entry)
|
|
3218
|
+
};
|
|
3219
|
+
}
|
|
3220
|
+
function listBrands(baseDir) {
|
|
3221
|
+
const tokens = resolveTokens(baseDir);
|
|
3222
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
3223
|
+
return { status: tokens.status, version: tokens.version, brands: [] };
|
|
2630
3224
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
const item = d.item(m);
|
|
2639
|
-
if (!items.includes(item)) items.push(item);
|
|
2640
|
-
}
|
|
2641
|
-
if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
|
|
3225
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
3226
|
+
let brands;
|
|
3227
|
+
try {
|
|
3228
|
+
brands = entries.map((entry) => readSummary(baseDir, entry));
|
|
3229
|
+
} catch (err) {
|
|
3230
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brands: [] };
|
|
3231
|
+
throw err;
|
|
2642
3232
|
}
|
|
2643
|
-
return
|
|
3233
|
+
return { status: "ok", version: tokens.version, brands };
|
|
2644
3234
|
}
|
|
2645
|
-
function
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
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++;
|
|
3235
|
+
function stripComments(css) {
|
|
3236
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
3237
|
+
}
|
|
3238
|
+
function parseDeclarations(body) {
|
|
3239
|
+
const out = {};
|
|
3240
|
+
for (const m of body.matchAll(/(--[A-Za-z0-9_-]+)\s*:\s*([^;]+);/g)) {
|
|
3241
|
+
out[m[1]] = m[2].trim();
|
|
2676
3242
|
}
|
|
2677
3243
|
return out;
|
|
2678
3244
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
function hasTokensPresetReference(source) {
|
|
2682
|
-
return PRESET_REFERENCE.test(stripJsComments(source));
|
|
2683
|
-
}
|
|
2684
|
-
var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
|
|
2685
|
-
function readPackageJson(baseDir) {
|
|
2686
|
-
try {
|
|
2687
|
-
const parsed = JSON.parse(readFileSync2(join2(baseDir, "package.json"), "utf8"));
|
|
2688
|
-
return isPlainObject(parsed) ? parsed : void 0;
|
|
2689
|
-
} catch {
|
|
2690
|
-
return void 0;
|
|
2691
|
-
}
|
|
3245
|
+
function isDarkSelector(selector) {
|
|
3246
|
+
return /\.dark\b/.test(selector) || /\[data-theme=["']?dark["']?\]/.test(selector);
|
|
2692
3247
|
}
|
|
2693
|
-
function
|
|
2694
|
-
const
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
const
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
if (
|
|
2707
|
-
|
|
3248
|
+
function parseBrandCss(css, name) {
|
|
3249
|
+
const result = { light: {}, dark: {} };
|
|
3250
|
+
let lightFound = false;
|
|
3251
|
+
let darkFound = false;
|
|
3252
|
+
const brandAttr = new RegExp(`\\[data-brand=["']?${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']?\\]`);
|
|
3253
|
+
for (const m of stripComments(css).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
3254
|
+
const selectors = m[1].split(",").map((s) => s.trim());
|
|
3255
|
+
if (!selectors.some((s) => brandAttr.test(s))) continue;
|
|
3256
|
+
if (selectors.some(isDarkSelector)) {
|
|
3257
|
+
if (!darkFound) {
|
|
3258
|
+
result.dark = parseDeclarations(m[2]);
|
|
3259
|
+
darkFound = true;
|
|
3260
|
+
}
|
|
3261
|
+
} else if (!lightFound) {
|
|
3262
|
+
result.light = parseDeclarations(m[2]);
|
|
3263
|
+
lightFound = true;
|
|
2708
3264
|
}
|
|
2709
3265
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
3266
|
+
return result;
|
|
3267
|
+
}
|
|
3268
|
+
function pickKeyTokens(decls) {
|
|
3269
|
+
const out = {};
|
|
3270
|
+
for (const key of KEY_TOKENS) {
|
|
3271
|
+
if (Object.prototype.hasOwnProperty.call(decls, key)) out[key] = decls[key];
|
|
2714
3272
|
}
|
|
2715
|
-
return
|
|
3273
|
+
return out;
|
|
3274
|
+
}
|
|
3275
|
+
var THEME_MARKUP_BRAND_MIN_VERSION = "1.7.0";
|
|
3276
|
+
function providerExample(name) {
|
|
3277
|
+
return [
|
|
3278
|
+
"// 1) \uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx)\uC758 <html> \uC5D0 \uBD99\uC785\uB2C8\uB2E4(\uCCAB \uD654\uBA74\uBD80\uD130 \uC801\uC6A9)",
|
|
3279
|
+
`// ThemeProvider \uB97C \uD568\uAED8 \uC4F0\uBA74 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC774 \uD544\uC694\uD569\uB2C8\uB2E4(\uADF8 \uC544\uB798\uB294 \uB9C8\uC6B4\uD2B8 \uB54C \uC18D\uC131\uC744 \uC9C0\uC6C0)`,
|
|
3280
|
+
`<html lang="ko" data-brand="${name}">`,
|
|
3281
|
+
"",
|
|
3282
|
+
`// 2) \uC0AC\uC6A9\uC790\uAC00 \uACE0\uB974\uAC8C \uD558\uB824\uBA74 setBrand \uB85C \uCF1C\uACE0 \uB055\uB2C8\uB2E4(\uC800\uC7A5\uB3FC \uC720\uC9C0, setBrand(undefined) \uB85C \uB048 \uC0C1\uD0DC \uC720\uC9C0\uB294 ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1)`,
|
|
3283
|
+
'import { useTheme } from "@axis-ds/theme";',
|
|
3284
|
+
"const { setBrand } = useTheme();",
|
|
3285
|
+
`setBrand("${name}");`
|
|
3286
|
+
].join("\n");
|
|
2716
3287
|
}
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
3288
|
+
var BRAND_ACTIVATION_FILES = ROOT_LAYOUT_FILES;
|
|
3289
|
+
var BRAND_ACTIVATION_PATTERN = /data-brand|setBrand\s*\(|defaultBrand\s*=/;
|
|
3290
|
+
var PROVIDER_ACTIVATION_PATTERN = /setBrand\s*\(|defaultBrand\s*=/;
|
|
3291
|
+
var THEME_PROVIDER_PATTERN = /<ThemeProvider\b/;
|
|
3292
|
+
function stripJsLikeComments(src) {
|
|
3293
|
+
return src.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:"'`])\/\/[^\n]*/g, "$1");
|
|
3294
|
+
}
|
|
3295
|
+
function findBrandActivation(baseDir) {
|
|
3296
|
+
const root = resolve2(baseDir);
|
|
3297
|
+
const layoutFiles = [];
|
|
3298
|
+
for (const candidate of BRAND_ACTIVATION_FILES) {
|
|
3299
|
+
const file = join2(root, candidate);
|
|
3300
|
+
if (!isFile2(file)) continue;
|
|
3301
|
+
layoutFiles.push(candidate);
|
|
3302
|
+
const text = stripJsLikeComments(readFileSync3(file, "utf8"));
|
|
3303
|
+
const providerTexts = [];
|
|
3304
|
+
for (const m of text.matchAll(/from\s+["']\.\/(providers?)["']/g)) {
|
|
3305
|
+
for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
|
|
3306
|
+
const rel3 = `${dirname(candidate)}/${m[1]}${ext}`;
|
|
3307
|
+
const p = join2(root, rel3);
|
|
3308
|
+
if (isFile2(p)) providerTexts.push({ rel: rel3, text: stripJsLikeComments(readFileSync3(p, "utf8")) });
|
|
2733
3309
|
}
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3310
|
+
}
|
|
3311
|
+
const all = [text, ...providerTexts.map((x) => x.text)];
|
|
3312
|
+
const markupWithProvider = !all.some((t) => PROVIDER_ACTIVATION_PATTERN.test(t)) && all.some((t) => THEME_PROVIDER_PATTERN.test(t));
|
|
3313
|
+
if (BRAND_ACTIVATION_PATTERN.test(text)) {
|
|
3314
|
+
return markupWithProvider ? { found: candidate, layoutFiles, markupWithProvider } : { found: candidate, layoutFiles };
|
|
3315
|
+
}
|
|
3316
|
+
for (const x of providerTexts) {
|
|
3317
|
+
if (BRAND_ACTIVATION_PATTERN.test(x.text)) {
|
|
3318
|
+
return markupWithProvider ? { found: x.rel, layoutFiles, markupWithProvider } : { found: x.rel, layoutFiles };
|
|
2742
3319
|
}
|
|
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
3320
|
}
|
|
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
3321
|
}
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
3322
|
+
return { layoutFiles };
|
|
3323
|
+
}
|
|
3324
|
+
function inspectBrandActivation(baseDir) {
|
|
3325
|
+
const config = readBrandConfig(baseDir);
|
|
3326
|
+
const brand = config?.brand;
|
|
3327
|
+
if (typeof brand !== "string" || brand.trim() === "") return null;
|
|
3328
|
+
const location = findBrandActivation(baseDir);
|
|
3329
|
+
if (!location.markupWithProvider) return { brand, ...location };
|
|
3330
|
+
return { brand, ...location, theme: packageVersionGate(baseDir, readProjectPackageJson(baseDir), THEME_PACKAGE, THEME_MARKUP_BRAND_MIN_VERSION) };
|
|
3331
|
+
}
|
|
3332
|
+
var THEME_PACKAGE = "@axis-ds/theme";
|
|
3333
|
+
function readProjectPackageJson(baseDir) {
|
|
3334
|
+
try {
|
|
3335
|
+
const parsed = JSON.parse(readFileSync3(join2(resolve2(baseDir), "package.json"), "utf8"));
|
|
3336
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
|
|
3337
|
+
} catch {
|
|
3338
|
+
return void 0;
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
function getBrand(baseDir, name) {
|
|
3342
|
+
const tokens = resolveTokens(baseDir);
|
|
3343
|
+
if (tokens.status !== "ok" || !tokens.indexPath) {
|
|
3344
|
+
return { status: tokens.status, version: tokens.version, brand: null, available: [] };
|
|
3345
|
+
}
|
|
3346
|
+
const entries = readBrandIndex(tokens.indexPath);
|
|
3347
|
+
const available = entries.map((e) => e.name);
|
|
3348
|
+
const entry = entries.find((e) => e.name === name);
|
|
3349
|
+
if (!entry) {
|
|
3350
|
+
return { status: "ok", version: tokens.version, brand: null, available };
|
|
3351
|
+
}
|
|
3352
|
+
let summary;
|
|
3353
|
+
let parsed;
|
|
3354
|
+
try {
|
|
3355
|
+
summary = readSummary(baseDir, entry);
|
|
3356
|
+
const cssPath = projectRequire(baseDir).resolve(summary.importPath);
|
|
3357
|
+
parsed = parseBrandCss(readFileSync3(cssPath, "utf8"), name);
|
|
3358
|
+
} catch (err) {
|
|
3359
|
+
if (isMissingBuildFile(err)) return { status: "not-built", version: tokens.version, brand: null, available: [] };
|
|
3360
|
+
throw err;
|
|
3361
|
+
}
|
|
3362
|
+
return {
|
|
3363
|
+
status: "ok",
|
|
3364
|
+
version: tokens.version,
|
|
3365
|
+
available,
|
|
3366
|
+
brand: {
|
|
3367
|
+
...summary,
|
|
3368
|
+
tokens: { light: pickKeyTokens(parsed.light), dark: pickKeyTokens(parsed.dark) },
|
|
3369
|
+
providerExample: providerExample(name),
|
|
3370
|
+
adjustments: { a11y: summary.a11y, reference: BRAND_ADJUSTMENT_REFERENCE }
|
|
2765
3371
|
}
|
|
2766
|
-
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
// ../axis-registry-core/src/template/dependencies-core.ts
|
|
3376
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
3377
|
+
import { join as join3, resolve as resolve3 } from "path";
|
|
3378
|
+
var REQUIRED_DEPENDENCIES = ["tailwindcss"];
|
|
3379
|
+
var RECOMMENDED_DEPENDENCIES = ["clsx", "tailwind-merge"];
|
|
3380
|
+
function declaredAxisPackages(pkg) {
|
|
3381
|
+
const out = [];
|
|
3382
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
3383
|
+
const deps = pkg[field];
|
|
3384
|
+
if (!isPlainObject(deps)) continue;
|
|
3385
|
+
for (const name of Object.keys(deps)) if (name.startsWith("@axis-ds/") && !out.includes(name)) out.push(name);
|
|
2767
3386
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
3387
|
+
return out;
|
|
3388
|
+
}
|
|
3389
|
+
function checkDependencies(baseDirInput) {
|
|
3390
|
+
const baseDir = resolve3(baseDirInput);
|
|
3391
|
+
let pkg;
|
|
3392
|
+
try {
|
|
3393
|
+
const parsed = JSON.parse(readFileSync4(join3(baseDir, "package.json"), "utf8"));
|
|
3394
|
+
if (!isPlainObject(parsed)) throw new Error("not object");
|
|
3395
|
+
pkg = parsed;
|
|
3396
|
+
} catch (err) {
|
|
3397
|
+
if (err?.code === "ENOENT") {
|
|
3398
|
+
return { name: "dependencies", severity: "fail", message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2775
3399
|
}
|
|
3400
|
+
return { name: "dependencies", severity: "fail", message: "package.json \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(JSON \uD655\uC778)" };
|
|
2776
3401
|
}
|
|
2777
|
-
|
|
3402
|
+
const missingRequired = REQUIRED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
|
|
3403
|
+
if (missingRequired.length > 0) {
|
|
3404
|
+
return { name: "dependencies", severity: "fail", message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}` };
|
|
3405
|
+
}
|
|
3406
|
+
const missingRecommended = RECOMMENDED_DEPENDENCIES.filter((d) => !hasDependency(pkg, d));
|
|
3407
|
+
const targets = [
|
|
3408
|
+
...[...REQUIRED_DEPENDENCIES, ...RECOMMENDED_DEPENDENCIES].filter((d) => hasDependency(pkg, d) !== void 0),
|
|
3409
|
+
...declaredAxisPackages(pkg)
|
|
3410
|
+
];
|
|
3411
|
+
const pnp = isPnpProject(baseDir);
|
|
3412
|
+
const notInstalled = pnp ? [] : targets.filter((d) => findInstalledPackage(baseDir, d) === void 0);
|
|
3413
|
+
const problems = [];
|
|
3414
|
+
if (missingRecommended.length > 0) problems.push(`\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`);
|
|
3415
|
+
if (notInstalled.length > 0) {
|
|
3416
|
+
problems.push(`\uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC740 \uC758\uC874\uC131: ${notInstalled.join(", ")} \u2192 ${detectInstallCommand(baseDir)}`);
|
|
3417
|
+
}
|
|
3418
|
+
if (problems.length > 0) return { name: "dependencies", severity: "warn", message: problems.join(" / ") };
|
|
3419
|
+
return {
|
|
3420
|
+
name: "dependencies",
|
|
3421
|
+
severity: "pass",
|
|
3422
|
+
message: pnp ? `\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uC120\uC5B8\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (Plug'n'Play \uB77C \uC124\uCE58\uBCF8\uC740 \uD655\uC778\uD558\uC9C0 \uC54A\uC74C, ${targets.length}\uAC1C)` : `\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uC120\uC5B8 \xB7 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${targets.length}\uAC1C \uD655\uC778)`
|
|
3423
|
+
};
|
|
2778
3424
|
}
|
|
2779
3425
|
|
|
2780
3426
|
// src/template/template-check.ts
|
|
@@ -2784,15 +3430,21 @@ var SEVERITY_ICON = {
|
|
|
2784
3430
|
fail: chalk7.red("FAIL")
|
|
2785
3431
|
};
|
|
2786
3432
|
async function collectCheckResults(dir) {
|
|
2787
|
-
const baseDir =
|
|
3433
|
+
const baseDir = path11.resolve(dir || ".");
|
|
2788
3434
|
const results = [];
|
|
2789
3435
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
2790
3436
|
results.push(checkTailwindSetup(baseDir));
|
|
2791
3437
|
results.push(checkGlobalsCss(baseDir));
|
|
2792
3438
|
results.push(await checkUtils(baseDir));
|
|
2793
|
-
results.push(
|
|
3439
|
+
results.push(checkDependencies(baseDir));
|
|
2794
3440
|
const brand = checkBrand(baseDir);
|
|
2795
3441
|
if (brand) results.push(brand);
|
|
3442
|
+
const activation = inspectBrandActivation(baseDir);
|
|
3443
|
+
if (activation) results.push(brandActivationResult(activation));
|
|
3444
|
+
const content = checkTailwindContent(baseDir);
|
|
3445
|
+
if (content) results.push(content);
|
|
3446
|
+
const animation = checkAnimationPlugin(baseDir);
|
|
3447
|
+
if (animation) results.push(animation);
|
|
2796
3448
|
return results;
|
|
2797
3449
|
}
|
|
2798
3450
|
async function runCheck(dir) {
|
|
@@ -2829,7 +3481,7 @@ async function runCheck(dir) {
|
|
|
2829
3481
|
return { pass: passCount, warn: warnCount, fail: failCount };
|
|
2830
3482
|
}
|
|
2831
3483
|
async function checkFileExists(baseDir, fileName, label) {
|
|
2832
|
-
const exists = await fs10.pathExists(
|
|
3484
|
+
const exists = await fs10.pathExists(path11.join(baseDir, fileName));
|
|
2833
3485
|
return {
|
|
2834
3486
|
name: label,
|
|
2835
3487
|
severity: exists ? "pass" : "fail",
|
|
@@ -2845,7 +3497,7 @@ async function checkUtils(baseDir) {
|
|
|
2845
3497
|
"utils.ts"
|
|
2846
3498
|
];
|
|
2847
3499
|
for (const candidate of candidates) {
|
|
2848
|
-
const fullPath =
|
|
3500
|
+
const fullPath = path11.join(baseDir, candidate);
|
|
2849
3501
|
if (await fs10.pathExists(fullPath)) {
|
|
2850
3502
|
const content = await fs10.readFile(fullPath, "utf-8");
|
|
2851
3503
|
const hasCn = content.includes("function cn");
|
|
@@ -2862,41 +3514,6 @@ async function checkUtils(baseDir) {
|
|
|
2862
3514
|
message: "utils.ts\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC2DC \uD544\uC694)"
|
|
2863
3515
|
};
|
|
2864
3516
|
}
|
|
2865
|
-
async function checkDependencies(baseDir) {
|
|
2866
|
-
const pkgPath = path10.join(baseDir, "package.json");
|
|
2867
|
-
if (!await fs10.pathExists(pkgPath)) {
|
|
2868
|
-
return {
|
|
2869
|
-
name: "package.json",
|
|
2870
|
-
severity: "fail",
|
|
2871
|
-
message: "package.json \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2872
|
-
};
|
|
2873
|
-
}
|
|
2874
|
-
const pkg = await fs10.readJSON(pkgPath);
|
|
2875
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2876
|
-
const required = ["tailwindcss"];
|
|
2877
|
-
const recommended = ["clsx", "tailwind-merge"];
|
|
2878
|
-
const missingRequired = required.filter((d) => !allDeps[d]);
|
|
2879
|
-
const missingRecommended = recommended.filter((d) => !allDeps[d]);
|
|
2880
|
-
if (missingRequired.length > 0) {
|
|
2881
|
-
return {
|
|
2882
|
-
name: "dependencies",
|
|
2883
|
-
severity: "fail",
|
|
2884
|
-
message: `\uD544\uC218 \uC758\uC874\uC131 \uB204\uB77D: ${missingRequired.join(", ")}`
|
|
2885
|
-
};
|
|
2886
|
-
}
|
|
2887
|
-
if (missingRecommended.length > 0) {
|
|
2888
|
-
return {
|
|
2889
|
-
name: "dependencies",
|
|
2890
|
-
severity: "warn",
|
|
2891
|
-
message: `\uAD8C\uC7A5 \uC758\uC874\uC131 \uB204\uB77D: ${missingRecommended.join(", ")}`
|
|
2892
|
-
};
|
|
2893
|
-
}
|
|
2894
|
-
return {
|
|
2895
|
-
name: "dependencies",
|
|
2896
|
-
severity: "pass",
|
|
2897
|
-
message: "\uD544\uC218 \uBC0F \uAD8C\uC7A5 \uC758\uC874\uC131\uC774 \uBAA8\uB450 \uC124\uCE58\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4"
|
|
2898
|
-
};
|
|
2899
|
-
}
|
|
2900
3517
|
function checkBrand(baseDir) {
|
|
2901
3518
|
const check = inspectBrandImport(baseDir);
|
|
2902
3519
|
return check ? brandCheckResult(check) : null;
|
|
@@ -2931,6 +3548,30 @@ function brandCheckResult(check) {
|
|
|
2931
3548
|
};
|
|
2932
3549
|
}
|
|
2933
3550
|
}
|
|
3551
|
+
function brandActivationResult(check) {
|
|
3552
|
+
if (check.found && check.theme && check.theme.status !== "ok") {
|
|
3553
|
+
const label = versionGateLabel(check.theme);
|
|
3554
|
+
const why = check.theme.status === "below" ? `@axis-ds/theme ${label} \uC758 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4` : `@axis-ds/theme \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${label}). ${THEME_MARKUP_BRAND_MIN_VERSION} \uBBF8\uB9CC\uC774\uBA74 ThemeProvider \uAC00 \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6C1\uB2C8\uB2E4`;
|
|
3555
|
+
return {
|
|
3556
|
+
name: "brand.activation",
|
|
3557
|
+
severity: "warn",
|
|
3558
|
+
message: `${check.found}\uC758 <html data-brand> \uB97C ${why} \u2192 @axis-ds/theme ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9AC\uAC70\uB098 setBrand("${check.brand}")`
|
|
3559
|
+
};
|
|
3560
|
+
}
|
|
3561
|
+
if (check.found) {
|
|
3562
|
+
return {
|
|
3563
|
+
name: "brand.activation",
|
|
3564
|
+
severity: "pass",
|
|
3565
|
+
message: `${check.found}\uC5D0 \uBE0C\uB79C\uB4DC\uB97C \uCF1C\uB294 \uCF54\uB4DC(data-brand \xB7 setBrand \uB4F1)\uAC00 \uC788\uC2B5\uB2C8\uB2E4`
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
const where = check.layoutFiles.length > 0 ? check.layoutFiles.join(" \xB7 ") : "\uB8E8\uD2B8 \uB808\uC774\uC544\uC6C3(app/layout.tsx \uB4F1)";
|
|
3569
|
+
return {
|
|
3570
|
+
name: "brand.activation",
|
|
3571
|
+
severity: "warn",
|
|
3572
|
+
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}")`
|
|
3573
|
+
};
|
|
3574
|
+
}
|
|
2934
3575
|
|
|
2935
3576
|
// src/template/index.ts
|
|
2936
3577
|
function registerTemplateCommand(program2) {
|
|
@@ -3040,36 +3681,13 @@ import chalk9 from "chalk";
|
|
|
3040
3681
|
import path13 from "path";
|
|
3041
3682
|
|
|
3042
3683
|
// src/theme/theme-add.ts
|
|
3043
|
-
import { accessSync, constants, existsSync as existsSync4, readFileSync as
|
|
3684
|
+
import { accessSync, constants, existsSync as existsSync4, readFileSync as readFileSync5, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
3044
3685
|
import path12 from "path";
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
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}`;
|
|
3070
|
-
var THEME_PACKAGE = "@axis-ds/theme";
|
|
3686
|
+
var TOKENS_DEPENDENCY_RANGE = `^${TOKENS_DEPENDENCY_MIN_VERSION}`;
|
|
3687
|
+
var TAILWIND3_BASE_IMPORTS = [`${TOKENS_PACKAGE}/css`, `${TOKENS_PACKAGE}/css/shadcn`];
|
|
3688
|
+
var THEME_MIN_VERSION = "1.3.0";
|
|
3071
3689
|
function readText(file) {
|
|
3072
|
-
return existsSync4(file) ?
|
|
3690
|
+
return existsSync4(file) ? readFileSync5(file, "utf8") : null;
|
|
3073
3691
|
}
|
|
3074
3692
|
function eolOf(text) {
|
|
3075
3693
|
return text.includes("\r\n") ? "\r\n" : "\n";
|
|
@@ -3120,6 +3738,31 @@ function insertImportLine(css, line) {
|
|
|
3120
3738
|
lines.splice(insertAt, 0, line);
|
|
3121
3739
|
return bom + lines.join(eol);
|
|
3122
3740
|
}
|
|
3741
|
+
function insertImportLines(css, lines) {
|
|
3742
|
+
if (lines.length === 0) return css;
|
|
3743
|
+
const body = css.startsWith("\uFEFF") ? css.slice(1) : css;
|
|
3744
|
+
return insertImportLine(css, lines.join(eolOf(body)));
|
|
3745
|
+
}
|
|
3746
|
+
function findLateImports(css) {
|
|
3747
|
+
const body = css.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
|
|
3748
|
+
const lines = body.split(/\r?\n/);
|
|
3749
|
+
let rulesStarted = false;
|
|
3750
|
+
const late = [];
|
|
3751
|
+
for (const raw of lines) {
|
|
3752
|
+
const line = raw.trim();
|
|
3753
|
+
if (line === "") continue;
|
|
3754
|
+
if (/^@(charset|import)\b/i.test(line)) {
|
|
3755
|
+
if (rulesStarted && /^@import\b/i.test(line)) late.push(line);
|
|
3756
|
+
continue;
|
|
3757
|
+
}
|
|
3758
|
+
rulesStarted = true;
|
|
3759
|
+
}
|
|
3760
|
+
return late;
|
|
3761
|
+
}
|
|
3762
|
+
function hasCssImport(css, specifier) {
|
|
3763
|
+
const esc = specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3764
|
+
return new RegExp(`@import\\s+(?:url\\(\\s*)?["']${esc}(?:\\.css)?["']`).test(css.replace(/\/\*[\s\S]*?\*\//g, ""));
|
|
3765
|
+
}
|
|
3123
3766
|
function compareVersions(a, b) {
|
|
3124
3767
|
const parse = (v) => {
|
|
3125
3768
|
const m = /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(v.trim());
|
|
@@ -3166,7 +3809,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3166
3809
|
let config;
|
|
3167
3810
|
try {
|
|
3168
3811
|
const parsed = JSON.parse(configText);
|
|
3169
|
-
if (!
|
|
3812
|
+
if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3170
3813
|
config = parsed;
|
|
3171
3814
|
} catch (err) {
|
|
3172
3815
|
plan.errors.push({ kind: "invalid-config", message: err.message });
|
|
@@ -3178,7 +3821,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3178
3821
|
}
|
|
3179
3822
|
plan.tokens = resolveTokens(baseDir);
|
|
3180
3823
|
if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
|
|
3181
|
-
const data = JSON.parse(
|
|
3824
|
+
const data = JSON.parse(readFileSync5(plan.tokens.indexPath, "utf8"));
|
|
3182
3825
|
const entries = Array.isArray(data.brands) ? data.brands : [];
|
|
3183
3826
|
const entry = entries.find((e) => e.name === brand);
|
|
3184
3827
|
if (!entry) {
|
|
@@ -3194,6 +3837,28 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3194
3837
|
} else {
|
|
3195
3838
|
plan.unverifiedBrand = true;
|
|
3196
3839
|
}
|
|
3840
|
+
const pkgFile = path12.join(baseDir, "package.json");
|
|
3841
|
+
const pkgText = readText(pkgFile);
|
|
3842
|
+
let pkg;
|
|
3843
|
+
if (pkgText !== null) {
|
|
3844
|
+
try {
|
|
3845
|
+
const parsed = JSON.parse(pkgText);
|
|
3846
|
+
if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3847
|
+
pkg = parsed;
|
|
3848
|
+
} catch (err) {
|
|
3849
|
+
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
3850
|
+
plan.writes = [];
|
|
3851
|
+
return plan;
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
3855
|
+
const tailwind4 = tailwind.major !== void 0 && tailwind.major >= 4;
|
|
3856
|
+
const requiredBaseImports = tailwind4 ? [
|
|
3857
|
+
TOKENS_TAILWIND4_ENTRY,
|
|
3858
|
+
...TAILWIND4_COMPONENT_PACKAGES.filter((n) => pkg !== void 0 && hasDependency(pkg, n) !== void 0).map(
|
|
3859
|
+
(n) => `${n}/tailwind.css`
|
|
3860
|
+
)
|
|
3861
|
+
] : [...TAILWIND3_BASE_IMPORTS];
|
|
3197
3862
|
const location = findGlobalCss(baseDir, config);
|
|
3198
3863
|
if (location.path) {
|
|
3199
3864
|
const where = realPathInside(baseDir, location.path);
|
|
@@ -3207,48 +3872,65 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
3207
3872
|
plan.writes = [];
|
|
3208
3873
|
return plan;
|
|
3209
3874
|
}
|
|
3210
|
-
const before =
|
|
3875
|
+
const before = readFileSync5(location.path, "utf8");
|
|
3211
3876
|
const imported = findBrandImports(before);
|
|
3212
3877
|
const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
}
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3878
|
+
const brandAdded = !imported.includes(brand);
|
|
3879
|
+
const baseImports = requiredBaseImports.filter((spec) => !hasCssImport(before, spec));
|
|
3880
|
+
const lines = [...baseImports.map((spec) => `@import "${spec}";`), ...brandAdded ? [`@import "${plan.importPath}";`] : []];
|
|
3881
|
+
plan.css = {
|
|
3882
|
+
file: location.path,
|
|
3883
|
+
configuredMissing: location.configuredMissing,
|
|
3884
|
+
action: lines.length > 0 ? "add" : "exists",
|
|
3885
|
+
otherBrands,
|
|
3886
|
+
brandAdded,
|
|
3887
|
+
baseImports,
|
|
3888
|
+
requiredBaseImports,
|
|
3889
|
+
lateImports: findLateImports(before),
|
|
3890
|
+
tailwind4
|
|
3891
|
+
};
|
|
3892
|
+
if (lines.length > 0) {
|
|
3893
|
+
plan.writes.push({ file: location.path, before, after: insertImportLines(before, lines) });
|
|
3222
3894
|
}
|
|
3223
3895
|
} else {
|
|
3224
|
-
plan.css = {
|
|
3896
|
+
plan.css = {
|
|
3897
|
+
configuredMissing: location.configuredMissing,
|
|
3898
|
+
action: "manual",
|
|
3899
|
+
otherBrands: [],
|
|
3900
|
+
brandAdded: true,
|
|
3901
|
+
baseImports: requiredBaseImports,
|
|
3902
|
+
requiredBaseImports,
|
|
3903
|
+
lateImports: [],
|
|
3904
|
+
tailwind4
|
|
3905
|
+
};
|
|
3225
3906
|
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3907
|
+
if (!tailwind4) {
|
|
3908
|
+
const configFile2 = TAILWIND_CONFIG_FILES.find((f) => existsSync4(path12.join(baseDir, f)));
|
|
3909
|
+
const content = inspectTailwindContent(baseDir);
|
|
3910
|
+
plan.tailwindConfig = {
|
|
3911
|
+
configFile: configFile2,
|
|
3912
|
+
presetMissing: configFile2 === void 0 || !hasTokensPresetReference(readFileSync5(path12.join(baseDir, configFile2), "utf8")),
|
|
3913
|
+
contentMissing: content?.targets.filter((t) => !t.covered) ?? [],
|
|
3914
|
+
contentUnknown: content !== null && (content.unreadable || content.dynamic)
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
plan.activation = findBrandActivation(baseDir);
|
|
3228
3918
|
const installed = plan.tokens.version;
|
|
3229
3919
|
const upgrade = installed !== void 0 && (compareVersions(installed, MIN_BRAND_TOKENS_VERSION) ?? 0) < 0;
|
|
3230
|
-
|
|
3231
|
-
|
|
3920
|
+
const tokensAddCommand = addCommandFor(plan.installCommand, { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
3921
|
+
const themeAddCommand = addCommandFor(plan.installCommand, { [THEME_PACKAGE]: `^${THEME_MIN_VERSION}` });
|
|
3922
|
+
if (pkgText === null || pkg === void 0) {
|
|
3923
|
+
plan.dependency = { action: "no-package-json", upgrade, themeMissing: false, tokensAddCommand, themeAddCommand };
|
|
3232
3924
|
} else {
|
|
3233
|
-
|
|
3234
|
-
|
|
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
|
-
const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
|
|
3244
|
-
const declared = hasDependency2(pkg, TOKENS_PACKAGE);
|
|
3925
|
+
const themeMissing = hasDependency(pkg, THEME_PACKAGE) === void 0;
|
|
3926
|
+
const declared = hasDependency(pkg, TOKENS_PACKAGE);
|
|
3245
3927
|
if (declared !== void 0) {
|
|
3246
|
-
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
|
|
3928
|
+
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing, tokensAddCommand, themeAddCommand };
|
|
3247
3929
|
} else {
|
|
3248
|
-
const deps =
|
|
3930
|
+
const deps = isPlainObject(pkg.dependencies) ? { ...pkg.dependencies } : {};
|
|
3249
3931
|
deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
|
|
3250
3932
|
const next = { ...pkg, dependencies: deps };
|
|
3251
|
-
plan.dependency = { action: "add", upgrade, themeMissing };
|
|
3933
|
+
plan.dependency = { action: "add", upgrade, themeMissing, tokensAddCommand, themeAddCommand };
|
|
3252
3934
|
plan.writes.push({ file: pkgFile, before: pkgText, after: formatJsonLike(pkgText, next) });
|
|
3253
3935
|
}
|
|
3254
3936
|
}
|
|
@@ -3330,33 +4012,55 @@ function applyThemeAdd(plan) {
|
|
|
3330
4012
|
}
|
|
3331
4013
|
|
|
3332
4014
|
// src/theme/index.ts
|
|
3333
|
-
|
|
3334
|
-
|
|
4015
|
+
function importOffset(css, spec) {
|
|
4016
|
+
const escaped = spec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4017
|
+
const m = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escaped}["']`).exec(css);
|
|
4018
|
+
return m ? m.index : -1;
|
|
4019
|
+
}
|
|
4020
|
+
function baseImportLines(after, spec, brandImportPath2, file) {
|
|
4021
|
+
if (spec.endsWith("/tailwind.css")) {
|
|
4022
|
+
return [` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C, \uC704\uCE58 \uBB34\uAD00)`];
|
|
4023
|
+
}
|
|
4024
|
+
const at = importOffset(after, spec);
|
|
4025
|
+
const brandAt = importOffset(after, brandImportPath2);
|
|
4026
|
+
if (brandAt === -1 || at !== -1 && at < brandAt) {
|
|
4027
|
+
return [` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS, \uBE0C\uB79C\uB4DC \uC55E)`];
|
|
4028
|
+
}
|
|
4029
|
+
return [
|
|
4030
|
+
` ${chalk9.green("\u2713")} ${file}: @import "${spec}"; \uCD94\uAC00(\uAE30\uBCF8 \uD1A0\uD070 CSS)`,
|
|
4031
|
+
chalk9.yellow(` ! \uC774 \uC904\uC774 \uBE0C\uB79C\uB4DC import \uB4A4\uC5D0 \uB4E4\uC5B4\uAC14\uC2B5\uB2C8\uB2E4. \uBE0C\uB79C\uB4DC \uAC12\uC774 \uAE30\uBCF8 \uD1A0\uD070\uC5D0 \uB36E\uC774\uBBC0\uB85C @import "${brandImportPath2}"; \uC55E\uC73C\uB85C \uC62E\uAE30\uC138\uC694`)
|
|
4032
|
+
];
|
|
4033
|
+
}
|
|
4034
|
+
function tokensInstallCommand(baseDir) {
|
|
4035
|
+
return addCommandFor(detectInstallCommand(baseDir), { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
4036
|
+
}
|
|
4037
|
+
var TOKENS_INSTALL_COMMAND = addCommandFor("pnpm install", { [TOKENS_PACKAGE]: TOKENS_DEPENDENCY_RANGE });
|
|
4038
|
+
function tokensStatusGuide(status, version, installCommand = TOKENS_INSTALL_COMMAND) {
|
|
3335
4039
|
switch (status) {
|
|
3336
4040
|
case "not-installed":
|
|
3337
4041
|
return [
|
|
3338
4042
|
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(
|
|
4043
|
+
` \uC124\uCE58: ${chalk9.cyan(installCommand)}`
|
|
3340
4044
|
];
|
|
3341
4045
|
case "unsupported":
|
|
3342
4046
|
return [
|
|
3343
4047
|
chalk9.yellow(
|
|
3344
4048
|
`${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
4049
|
),
|
|
3346
|
-
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(
|
|
4050
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(installCommand)}`
|
|
3347
4051
|
];
|
|
3348
4052
|
case "not-built":
|
|
3349
4053
|
return [
|
|
3350
4054
|
chalk9.yellow(
|
|
3351
4055
|
`${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
4056
|
),
|
|
3353
|
-
` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk9.cyan(
|
|
4057
|
+
` \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uBA74 ${chalk9.cyan(`pnpm --filter ${TOKENS_PACKAGE} build`)}, \uC544\uB2C8\uBA74 \uC7AC\uC124\uCE58: ${chalk9.cyan(installCommand)}`
|
|
3354
4058
|
];
|
|
3355
4059
|
}
|
|
3356
4060
|
}
|
|
3357
|
-
function renderThemeList(result) {
|
|
4061
|
+
function renderThemeList(result, installCommand) {
|
|
3358
4062
|
if (result.status !== "ok") {
|
|
3359
|
-
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
4063
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version, installCommand), ""], exitCode: 1 };
|
|
3360
4064
|
}
|
|
3361
4065
|
if (result.brands.length === 0) {
|
|
3362
4066
|
return {
|
|
@@ -3401,9 +4105,9 @@ function tokenTable(brand) {
|
|
|
3401
4105
|
}
|
|
3402
4106
|
return lines;
|
|
3403
4107
|
}
|
|
3404
|
-
function renderThemeInfo(result, name) {
|
|
4108
|
+
function renderThemeInfo(result, name, installCommand) {
|
|
3405
4109
|
if (result.status !== "ok") {
|
|
3406
|
-
return { lines: ["", ...tokensStatusGuide(result.status, result.version), ""], exitCode: 1 };
|
|
4110
|
+
return { lines: ["", ...tokensStatusGuide(result.status, result.version, installCommand), ""], exitCode: 1 };
|
|
3407
4111
|
}
|
|
3408
4112
|
const brand = result.brand;
|
|
3409
4113
|
if (!brand) {
|
|
@@ -3427,7 +4131,7 @@ function renderThemeInfo(result, name) {
|
|
|
3427
4131
|
chalk9.bold("Import (globals.css, @charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)"),
|
|
3428
4132
|
` @import "${brand.importPath}";`,
|
|
3429
4133
|
"",
|
|
3430
|
-
chalk9.bold("
|
|
4134
|
+
chalk9.bold("\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 @axis-ds/theme 1.3.0 \uC774\uC0C1)"),
|
|
3431
4135
|
...brand.providerExample.split("\n").map((l) => l ? ` ${l}` : ""),
|
|
3432
4136
|
chalk9.gray(
|
|
3433
4137
|
` 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 +4216,32 @@ function renderThemeAdd(plan, written) {
|
|
|
3512
4216
|
)
|
|
3513
4217
|
);
|
|
3514
4218
|
}
|
|
4219
|
+
const brandLine = `@import "${plan.importPath}";`;
|
|
3515
4220
|
if (css?.action === "add" && css.file) {
|
|
3516
|
-
|
|
4221
|
+
const after = plan.writes.find((w) => w.file === css.file)?.after ?? "";
|
|
4222
|
+
for (const spec of css.baseImports) {
|
|
4223
|
+
lines.push(...baseImportLines(after, spec, plan.importPath, rel(plan, css.file)));
|
|
4224
|
+
}
|
|
4225
|
+
if (css.brandAdded) lines.push(` ${chalk9.green("\u2713")} ${rel(plan, css.file)}: ${brandLine} \uCD94\uAC00`);
|
|
4226
|
+
else lines.push(` ${chalk9.gray("-")} ${rel(plan, css.file)}: \uBE0C\uB79C\uB4DC import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
|
|
3517
4227
|
} else if (css?.action === "exists" && css.file) {
|
|
3518
4228
|
lines.push(` ${chalk9.gray("-")} ${rel(plan, css.file)}: import \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uAC74\uB108\uB700`);
|
|
3519
4229
|
} else {
|
|
3520
4230
|
lines.push(
|
|
3521
|
-
chalk9.yellow(
|
|
3522
|
-
|
|
4231
|
+
chalk9.yellow(
|
|
4232
|
+
" ! 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."
|
|
4233
|
+
),
|
|
4234
|
+
` \uC804\uC5ED CSS \uB9E8 \uC55E(@charset \xB7 \uB2E4\uB978 @import \uB2E4\uC74C)\uC5D0 \uC774 \uC21C\uC11C\uB85C \uC9C1\uC811 \uB123\uC73C\uC138\uC694: ${[
|
|
4235
|
+
...(css?.requiredBaseImports ?? []).map((spec) => `@import "${spec}";`),
|
|
4236
|
+
brandLine
|
|
4237
|
+
].join(" ")}`
|
|
4238
|
+
);
|
|
4239
|
+
}
|
|
4240
|
+
if (css && css.lateImports.length > 0) {
|
|
4241
|
+
lines.push(
|
|
4242
|
+
chalk9.yellow(
|
|
4243
|
+
` ! \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(" ")}`
|
|
4244
|
+
)
|
|
3523
4245
|
);
|
|
3524
4246
|
}
|
|
3525
4247
|
if (css && css.otherBrands.length > 0) {
|
|
@@ -3538,16 +4260,14 @@ function renderThemeAdd(plan, written) {
|
|
|
3538
4260
|
} else if (dep?.action === "present") {
|
|
3539
4261
|
lines.push(` ${chalk9.gray("-")} package.json: ${TOKENS_PACKAGE} ${dep.declaredRange} \uAC00 \uC774\uBBF8 \uC788\uC5B4 \uBC94\uC704\uB97C \uBC14\uAFB8\uC9C0 \uC54A\uC74C`);
|
|
3540
4262
|
} 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
|
-
);
|
|
4263
|
+
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
4264
|
}
|
|
3545
4265
|
if (dep?.upgrade) {
|
|
3546
4266
|
lines.push(
|
|
3547
4267
|
chalk9.yellow(
|
|
3548
4268
|
` ! \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
4269
|
),
|
|
3550
|
-
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(
|
|
4270
|
+
` \uC5C5\uADF8\uB808\uC774\uB4DC: ${chalk9.cyan(dep.tokensAddCommand)}`
|
|
3551
4271
|
);
|
|
3552
4272
|
}
|
|
3553
4273
|
if (plan.configChanged) {
|
|
@@ -3555,16 +4275,44 @@ function renderThemeAdd(plan, written) {
|
|
|
3555
4275
|
} else {
|
|
3556
4276
|
lines.push(` ${chalk9.gray("-")} axis.config.json: brand \uAC00 \uC774\uBBF8 "${plan.brand}"`);
|
|
3557
4277
|
}
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
chalk9.bold(`
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
4278
|
+
const tw = plan.tailwindConfig;
|
|
4279
|
+
if (tw && (tw.presetMissing || tw.contentMissing.length > 0)) {
|
|
4280
|
+
lines.push("", chalk9.bold(`Tailwind \uC124\uC815 (${tw.configFile ?? "tailwind.config"}, \uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4)`));
|
|
4281
|
+
if (tw.presetMissing) {
|
|
4282
|
+
lines.push(
|
|
4283
|
+
// WI-0072: CommonJS 는 모든 tokens 버전에서 동작하는 `.default` 형태로 안내합니다(1.6.2 이하의 bare require 는 preset 이 빠짐)
|
|
4284
|
+
chalk9.yellow(` ! AXIS preset \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. presets \uC5D0 \uB123\uC73C\uC138\uC694: presets: [${TOKENS_TAILWIND3_CJS_REQUIRE}]`) + chalk9.gray(` (ESM \xB7 TypeScript \uC774\uBA74 import axisPreset from "${TOKENS_TAILWIND3_PRESET}" \uB4A4 presets: [axisPreset])`)
|
|
4285
|
+
);
|
|
4286
|
+
}
|
|
4287
|
+
for (const t of tw.contentMissing) {
|
|
4288
|
+
lines.push(
|
|
4289
|
+
chalk9.yellow(
|
|
4290
|
+
` ! 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}"`
|
|
4291
|
+
)
|
|
4292
|
+
);
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
const act = plan.activation;
|
|
4296
|
+
lines.push("", chalk9.bold(`\uBE0C\uB79C\uB4DC \uCF1C\uAE30 (ThemeProvider \uB294 ${THEME_PACKAGE} ${THEME_MIN_VERSION} \uC774\uC0C1)`));
|
|
4297
|
+
if (act?.found) {
|
|
4298
|
+
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.`);
|
|
4299
|
+
if (act.markupWithProvider) {
|
|
4300
|
+
lines.push(
|
|
4301
|
+
chalk9.yellow(
|
|
4302
|
+
` ! <html data-brand> \uC640 ThemeProvider \uB97C \uD568\uAED8 \uC4F0\uBA74 ${THEME_PACKAGE} ${THEME_MARKUP_BRAND_MIN_VERSION} \uC774\uC0C1\uC774\uC5B4\uC57C \uB9C8\uC6B4\uD2B8 \uB54C \uC9C0\uC6CC\uC9C0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8 \uD655\uC778: axis check`
|
|
4303
|
+
)
|
|
4304
|
+
);
|
|
4305
|
+
}
|
|
4306
|
+
} else {
|
|
4307
|
+
lines.push(
|
|
4308
|
+
...providerExample(plan.brand).split("\n").map((l) => l ? ` ${l}` : ""),
|
|
4309
|
+
chalk9.yellow(
|
|
4310
|
+
` ! ${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.`
|
|
4311
|
+
)
|
|
4312
|
+
);
|
|
4313
|
+
}
|
|
3566
4314
|
if (dep?.themeMissing) {
|
|
3567
|
-
lines.push(` ${THEME_PACKAGE} \uC124\uCE58: ${chalk9.cyan(
|
|
4315
|
+
lines.push(` ThemeProvider \uB97C \uC4F0\uBA74 ${THEME_PACKAGE} \uC124\uCE58: ${chalk9.cyan(dep.themeAddCommand)}`);
|
|
3568
4316
|
}
|
|
3569
4317
|
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
4318
|
return { lines, exitCode: 0 };
|
|
@@ -3598,11 +4346,11 @@ function registerThemeCommand(program2) {
|
|
|
3598
4346
|
const themeCmd = program2.command("theme").description("\uBE0C\uB79C\uB4DC \uD14C\uB9C8 (@axis-ds/tokens \uBE0C\uB79C\uB4DC)");
|
|
3599
4347
|
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
4348
|
const baseDir = path13.resolve(options.dir || ".");
|
|
3601
|
-
print(renderThemeList(listBrands(baseDir)));
|
|
4349
|
+
print(renderThemeList(listBrands(baseDir), tokensInstallCommand(baseDir)));
|
|
3602
4350
|
});
|
|
3603
4351
|
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
4352
|
const baseDir = path13.resolve(options.dir || ".");
|
|
3605
|
-
print(renderThemeInfo(getBrand(baseDir, name), name));
|
|
4353
|
+
print(renderThemeInfo(getBrand(baseDir, name), name, tokensInstallCommand(baseDir)));
|
|
3606
4354
|
});
|
|
3607
4355
|
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
4356
|
const baseDir = path13.resolve(options.dir || ".");
|
|
@@ -3925,13 +4673,13 @@ async function fetchRegistryJson(url, options = {}) {
|
|
|
3925
4673
|
}
|
|
3926
4674
|
|
|
3927
4675
|
// src/init/init.ts
|
|
3928
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as
|
|
4676
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync6, realpathSync as realpathSync3, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
3929
4677
|
import path15 from "path";
|
|
3930
4678
|
import chalk10 from "chalk";
|
|
3931
4679
|
import fs12 from "fs-extra";
|
|
3932
4680
|
|
|
3933
4681
|
// ../axis-registry-core/src/add/safe-write.ts
|
|
3934
|
-
import { constants as fsConstants, existsSync as existsSync5, lstatSync, realpathSync as realpathSync2, statSync as
|
|
4682
|
+
import { constants as fsConstants, existsSync as existsSync5, lstatSync as lstatSync2, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
|
|
3935
4683
|
import path14 from "path";
|
|
3936
4684
|
import fs11 from "fs-extra";
|
|
3937
4685
|
var NEW_FILE_FLAGS = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | (fsConstants.O_NOFOLLOW ?? 0);
|
|
@@ -3969,7 +4717,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
3969
4717
|
}
|
|
3970
4718
|
let st = null;
|
|
3971
4719
|
try {
|
|
3972
|
-
st =
|
|
4720
|
+
st = lstatSync2(target);
|
|
3973
4721
|
} catch {
|
|
3974
4722
|
st = null;
|
|
3975
4723
|
}
|
|
@@ -3987,7 +4735,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
3987
4735
|
}
|
|
3988
4736
|
let followed;
|
|
3989
4737
|
try {
|
|
3990
|
-
followed =
|
|
4738
|
+
followed = statSync3(realTarget);
|
|
3991
4739
|
} catch {
|
|
3992
4740
|
return `\uAE30\uC874 \uD30C\uC77C \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${target})`;
|
|
3993
4741
|
}
|
|
@@ -4003,7 +4751,7 @@ function escapeReason(root, target, options = {}) {
|
|
|
4003
4751
|
}
|
|
4004
4752
|
function isSymlink(p) {
|
|
4005
4753
|
try {
|
|
4006
|
-
return
|
|
4754
|
+
return lstatSync2(p).isSymbolicLink();
|
|
4007
4755
|
} catch {
|
|
4008
4756
|
return false;
|
|
4009
4757
|
}
|
|
@@ -4019,7 +4767,7 @@ function outsideLinkTarget(root, target) {
|
|
|
4019
4767
|
}
|
|
4020
4768
|
function hardLinkCount(target) {
|
|
4021
4769
|
try {
|
|
4022
|
-
const st =
|
|
4770
|
+
const st = lstatSync2(target);
|
|
4023
4771
|
return st.isFile() && st.nlink >= 2 ? st.nlink : null;
|
|
4024
4772
|
} catch {
|
|
4025
4773
|
return null;
|
|
@@ -4150,11 +4898,45 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
4150
4898
|
return twMerge(clsx(inputs));
|
|
4151
4899
|
}
|
|
4152
4900
|
`;
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4901
|
+
async function resolveInitAnswers(baseDirInput, tailwind4) {
|
|
4902
|
+
const baseDir = path15.resolve(baseDirInput);
|
|
4903
|
+
const tw4 = tailwind4 ?? isTailwind4(planUtilsDependencies(baseDir).tailwind);
|
|
4904
|
+
const current = await existingConfig(baseDir);
|
|
4905
|
+
const found = detectProjectPaths(baseDir);
|
|
4906
|
+
const notes = [];
|
|
4907
|
+
const currentComponents = nonEmptyString(current?.componentsDir);
|
|
4908
|
+
const componentsDir = currentComponents ?? found.componentsDir;
|
|
4909
|
+
const pickFile = (key, value, source, label) => {
|
|
4910
|
+
const existing = nonEmptyString(current?.[key]);
|
|
4911
|
+
if (existing !== void 0 && projectFileExists(baseDir, existing)) return existing;
|
|
4912
|
+
if (existing !== void 0) {
|
|
4913
|
+
if (source === "found") {
|
|
4914
|
+
notes.push(`! \uAE30\uC874 ${key}(${existing})\uAC00 \uC5C6\uC5B4 \uCC3E\uC740 \uD30C\uC77C ${value} \uB85C \uBC14\uAFC9\uB2C8\uB2E4.`);
|
|
4915
|
+
return value;
|
|
4916
|
+
}
|
|
4917
|
+
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.`);
|
|
4918
|
+
return existing;
|
|
4919
|
+
} else if (source === "default") {
|
|
4920
|
+
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.`);
|
|
4921
|
+
}
|
|
4922
|
+
return value;
|
|
4923
|
+
};
|
|
4924
|
+
const globalCss = pickFile("globalCss", found.globalCss, found.globalCssSource, "\uC804\uC5ED CSS");
|
|
4925
|
+
const answers = { componentsDir, globalCss };
|
|
4926
|
+
if (!tw4) {
|
|
4927
|
+
answers.tailwindConfig = pickFile("tailwindConfig", found.tailwindConfig, found.tailwindConfigSource, "Tailwind \uC124\uC815");
|
|
4928
|
+
}
|
|
4929
|
+
return { answers, notes };
|
|
4930
|
+
}
|
|
4931
|
+
function animationGuideLine(pkg, tailwind4, installCommand) {
|
|
4932
|
+
const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
|
|
4933
|
+
if (pkg !== void 0 && (hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND3) !== void 0 || hasDependency(pkg, ANIMATION_PLUGIN_TAILWIND4) !== void 0)) {
|
|
4934
|
+
return void 0;
|
|
4935
|
+
}
|
|
4936
|
+
const add = `${addCommandFor(installCommand, {}).trimEnd()} ${name}`;
|
|
4937
|
+
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`;
|
|
4938
|
+
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}.`;
|
|
4939
|
+
}
|
|
4158
4940
|
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
4159
4941
|
function isTailwind4(tailwind) {
|
|
4160
4942
|
return tailwind.major !== void 0 && tailwind.major >= 4;
|
|
@@ -4163,15 +4945,15 @@ var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
|
|
|
4163
4945
|
var TAILWIND4_CONFLICT_LINE = " ! create-next-app \uAE30\uBCF8 globals.css \uC758 :root \xB7 @theme inline \xB7 @media (prefers-color-scheme: dark) \xB7 body \uBE14\uB85D\uC740 AXIS \uC640 \uAC19\uC740 \uC774\uB984(--background \xB7 --foreground \xB7 --color-background \xB7 --font-sans \xB7 --font-mono)\uC744 \uB2E4\uB978 \uAC12\uC73C\uB85C \uC815\uC758\uD569\uB2C8\uB2E4. \uC774 \uBE14\uB85D\uB4E4\uC744 \uC9C0\uC6B0\uC138\uC694.";
|
|
4164
4946
|
function readPackageJsonSafe(baseDir) {
|
|
4165
4947
|
try {
|
|
4166
|
-
const text =
|
|
4948
|
+
const text = readFileSync6(path15.join(baseDir, "package.json"), "utf8");
|
|
4167
4949
|
const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
|
|
4168
|
-
return
|
|
4950
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
4169
4951
|
} catch {
|
|
4170
4952
|
return void 0;
|
|
4171
4953
|
}
|
|
4172
4954
|
}
|
|
4173
4955
|
function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
4174
|
-
const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 &&
|
|
4956
|
+
const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0);
|
|
4175
4957
|
const lines = [
|
|
4176
4958
|
`Tailwind 4: \uC804\uC5ED CSS(${globalCss}) \uB9E8 \uC704\uC5D0 \uB2E4\uC74C \uC904\uC744 \uB123\uC73C\uC138\uC694(\uD30C\uC77C\uC740 \uACE0\uCE58\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4).`,
|
|
4177
4959
|
' @import "tailwindcss";',
|
|
@@ -4184,7 +4966,7 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
|
4184
4966
|
);
|
|
4185
4967
|
}
|
|
4186
4968
|
lines.push(TAILWIND4_CONFLICT_LINE);
|
|
4187
|
-
if (pkg === void 0 ||
|
|
4969
|
+
if (pkg === void 0 || hasDependency(pkg, TOKENS_PACKAGE) === void 0) {
|
|
4188
4970
|
const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
|
|
4189
4971
|
lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
|
|
4190
4972
|
}
|
|
@@ -4221,12 +5003,6 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
|
4221
5003
|
return lines;
|
|
4222
5004
|
}
|
|
4223
5005
|
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
5006
|
function planUtilsDependencies(baseDirInput) {
|
|
4231
5007
|
const baseDir = path15.resolve(baseDirInput);
|
|
4232
5008
|
const installCommand = detectInstallCommand(baseDir);
|
|
@@ -4253,7 +5029,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
4253
5029
|
if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
|
|
4254
5030
|
let text;
|
|
4255
5031
|
try {
|
|
4256
|
-
text =
|
|
5032
|
+
text = readFileSync6(pkgFile, "utf8");
|
|
4257
5033
|
} catch (err) {
|
|
4258
5034
|
return unwritable(err.message);
|
|
4259
5035
|
}
|
|
@@ -4262,7 +5038,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
4262
5038
|
let pkg;
|
|
4263
5039
|
try {
|
|
4264
5040
|
const parsed = JSON.parse(body);
|
|
4265
|
-
if (!
|
|
5041
|
+
if (!isPlainObject(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
4266
5042
|
pkg = parsed;
|
|
4267
5043
|
} catch (err) {
|
|
4268
5044
|
return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
|
|
@@ -4272,14 +5048,14 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
4272
5048
|
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
4273
5049
|
const missing = {};
|
|
4274
5050
|
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
4275
|
-
const declared =
|
|
5051
|
+
const declared = hasDependency(pkg, name);
|
|
4276
5052
|
if (declared !== void 0) plan.present.push({ name, range: declared });
|
|
4277
5053
|
else missing[name] = range;
|
|
4278
5054
|
}
|
|
4279
5055
|
plan.added = Object.keys(missing);
|
|
4280
5056
|
plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
|
|
4281
5057
|
if (plan.added.length === 0) return { ...plan, action: "present" };
|
|
4282
|
-
if (pkg.dependencies !== void 0 && !
|
|
5058
|
+
if (pkg.dependencies !== void 0 && !isPlainObject(pkg.dependencies)) {
|
|
4283
5059
|
return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
4284
5060
|
}
|
|
4285
5061
|
try {
|
|
@@ -4296,7 +5072,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
4296
5072
|
const w = plan.write;
|
|
4297
5073
|
if (plan.action !== "add" || !w) return false;
|
|
4298
5074
|
const baseDir = path15.resolve(baseDirInput);
|
|
4299
|
-
const current = existsSync6(w.file) ?
|
|
5075
|
+
const current = existsSync6(w.file) ? readFileSync6(w.file, "utf8") : null;
|
|
4300
5076
|
if (current !== w.before) {
|
|
4301
5077
|
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
4302
5078
|
}
|
|
@@ -4312,7 +5088,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
4312
5088
|
let restored;
|
|
4313
5089
|
try {
|
|
4314
5090
|
writeFile(w.file, w.before);
|
|
4315
|
-
if (
|
|
5091
|
+
if (readFileSync6(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
|
|
4316
5092
|
restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
|
|
4317
5093
|
} catch (restoreErr) {
|
|
4318
5094
|
restored = `\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB9AC\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${restoreErr.message}). \uD30C\uC77C\uC774 \uC798\uB838\uAC70\uB098 \uBE44\uC5C8\uC744 \uC218 \uC788\uC73C\uB2C8 \uBC84\uC804 \uAD00\uB9AC \uB3C4\uAD6C \uB4F1\uC73C\uB85C \uBCF5\uAD6C\uD558\uC138\uC694`;
|
|
@@ -4349,11 +5125,36 @@ function reportDependencies(plan, log) {
|
|
|
4349
5125
|
}
|
|
4350
5126
|
async function existingConfig(baseDir) {
|
|
4351
5127
|
try {
|
|
4352
|
-
|
|
5128
|
+
const parsed = await readAxisConfig(baseDir);
|
|
5129
|
+
return isPlainObject(parsed) ? parsed : null;
|
|
4353
5130
|
} catch {
|
|
4354
5131
|
return null;
|
|
4355
5132
|
}
|
|
4356
5133
|
}
|
|
5134
|
+
var INIT_MANAGED_KEYS = ["$schema", "componentsDir", "tailwindConfig", "globalCss", "registry"];
|
|
5135
|
+
function mergeInitConfig(current, next) {
|
|
5136
|
+
const removed = [];
|
|
5137
|
+
const entries = [];
|
|
5138
|
+
for (const [k, v] of Object.entries(current)) {
|
|
5139
|
+
if (k in next) entries.push([k, next[k]]);
|
|
5140
|
+
else if (INIT_MANAGED_KEYS.includes(k)) removed.push(k);
|
|
5141
|
+
else entries.push([k, v]);
|
|
5142
|
+
}
|
|
5143
|
+
const nextKeys = Object.keys(next);
|
|
5144
|
+
nextKeys.forEach((k, i) => {
|
|
5145
|
+
if (k in current) return;
|
|
5146
|
+
let at = 0;
|
|
5147
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
5148
|
+
const idx = entries.findIndex(([key]) => key === nextKeys[j]);
|
|
5149
|
+
if (idx !== -1) {
|
|
5150
|
+
at = idx + 1;
|
|
5151
|
+
break;
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
5154
|
+
entries.splice(at, 0, [k, next[k]]);
|
|
5155
|
+
});
|
|
5156
|
+
return { merged: Object.fromEntries(entries), removed };
|
|
5157
|
+
}
|
|
4357
5158
|
function configStateNote(state) {
|
|
4358
5159
|
if (state === "created") return "axis.config.json \uC740 \uC774\uBBF8 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
4359
5160
|
if (state === "updated") return "axis.config.json \uC740 \uC774\uBBF8 \uAC31\uC2E0\uD588\uC2B5\uB2C8\uB2E4.";
|
|
@@ -4370,7 +5171,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4370
5171
|
const shown = path15.relative(baseDir, utilsPath).split(path15.sep).join("/") || utilsPath;
|
|
4371
5172
|
let st;
|
|
4372
5173
|
try {
|
|
4373
|
-
st =
|
|
5174
|
+
st = lstatSync3(utilsPath);
|
|
4374
5175
|
} catch (e) {
|
|
4375
5176
|
if (e.code === "ENOENT") return { action: "create" };
|
|
4376
5177
|
return { action: "reject", reason: `${shown} \uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
@@ -4390,7 +5191,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4390
5191
|
}
|
|
4391
5192
|
let target;
|
|
4392
5193
|
try {
|
|
4393
|
-
target =
|
|
5194
|
+
target = statSync4(real);
|
|
4394
5195
|
} catch (e) {
|
|
4395
5196
|
return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC758 \uC815\uBCF4\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4396
5197
|
}
|
|
@@ -4398,7 +5199,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4398
5199
|
if (!target.isFile()) return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4` };
|
|
4399
5200
|
let content2;
|
|
4400
5201
|
try {
|
|
4401
|
-
content2 =
|
|
5202
|
+
content2 = readFileSync6(utilsPath, "utf8");
|
|
4402
5203
|
} catch (e) {
|
|
4403
5204
|
return { action: "reject", reason: `${shown} \uB9C1\uD06C \uB300\uC0C1(${real})\uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4404
5205
|
}
|
|
@@ -4413,7 +5214,7 @@ function planUtilsWrite(baseDirInput, utilsPath) {
|
|
|
4413
5214
|
if (!st.isFile()) return { action: "reject", reason: `${shown} \uC774 \uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uB77C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` };
|
|
4414
5215
|
let content;
|
|
4415
5216
|
try {
|
|
4416
|
-
content =
|
|
5217
|
+
content = readFileSync6(utilsPath, "utf8");
|
|
4417
5218
|
} catch (e) {
|
|
4418
5219
|
return { action: "reject", reason: `\uAE30\uC874 ${shown} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})` };
|
|
4419
5220
|
}
|
|
@@ -4446,8 +5247,6 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4446
5247
|
registry
|
|
4447
5248
|
);
|
|
4448
5249
|
const configPath = path15.join(baseDir, "axis.config.json");
|
|
4449
|
-
const nextText = `${JSON.stringify(axisConfig, null, 2)}
|
|
4450
|
-
`;
|
|
4451
5250
|
const rejects = [];
|
|
4452
5251
|
let previousText = null;
|
|
4453
5252
|
try {
|
|
@@ -4457,9 +5256,18 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4457
5256
|
rejects.push(`\uAE30\uC874 axis.config.json \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${errCode(e)})`);
|
|
4458
5257
|
}
|
|
4459
5258
|
}
|
|
5259
|
+
let removedKeys = [];
|
|
5260
|
+
let nextText = `${JSON.stringify(axisConfig, null, 2)}
|
|
5261
|
+
`;
|
|
5262
|
+
if (previousText !== null && current !== null) {
|
|
5263
|
+
const { merged, removed } = mergeInitConfig(current, axisConfig);
|
|
5264
|
+
removedKeys = removed;
|
|
5265
|
+
const body = previousText.startsWith(BOM) ? previousText.slice(1) : previousText;
|
|
5266
|
+
nextText = (previousText.startsWith(BOM) ? BOM : "") + formatJsonLike(body, merged);
|
|
5267
|
+
}
|
|
4460
5268
|
if (previousText !== null && previousText !== nextText) {
|
|
4461
5269
|
try {
|
|
4462
|
-
const st =
|
|
5270
|
+
const st = statSync4(configPath);
|
|
4463
5271
|
if (st.isFile() && st.nlink >= 2) rejects.push(hardLinkMessage("axis.config.json", st.nlink));
|
|
4464
5272
|
} catch {
|
|
4465
5273
|
}
|
|
@@ -4500,7 +5308,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4500
5308
|
configState = "updated";
|
|
4501
5309
|
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
5310
|
const agenticNote = existingAgenticDir !== void 0 ? ", agenticDir \uB294 \uAE30\uC874 \uAC12 \uC720\uC9C0" : "";
|
|
4503
|
-
|
|
5311
|
+
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";
|
|
5312
|
+
log(chalk10.green(`\u2713 axis.config.json \uAC31\uC2E0(${mergeNote}, ${registryNote}${agenticNote})`));
|
|
4504
5313
|
if (migratedRegistry && existingRegistry !== void 0) {
|
|
4505
5314
|
log(
|
|
4506
5315
|
chalk10.yellow(
|
|
@@ -4508,9 +5317,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4508
5317
|
)
|
|
4509
5318
|
);
|
|
4510
5319
|
}
|
|
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)`));
|
|
5320
|
+
if (removedKeys.length > 0) {
|
|
5321
|
+
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
5322
|
}
|
|
4515
5323
|
}
|
|
4516
5324
|
let utilsStateNote = "utils.ts \uB294 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(\uC774\uBBF8 \uAC19\uC740 \uB0B4\uC6A9).";
|
|
@@ -4552,6 +5360,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
4552
5360
|
return;
|
|
4553
5361
|
}
|
|
4554
5362
|
reportDependencies(plan, log);
|
|
5363
|
+
const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand);
|
|
5364
|
+
if (animation !== void 0) log(chalk10.yellow(` ${animation}`));
|
|
4555
5365
|
if (tailwind4) {
|
|
4556
5366
|
const [head, ...rest] = tailwind4GuideLines(
|
|
4557
5367
|
readPackageJsonSafe(baseDir),
|
|
@@ -4572,28 +5382,31 @@ ${head}`));
|
|
|
4572
5382
|
function registerInitCommand(program2, registryUrl = DEFAULT_REGISTRY_URL) {
|
|
4573
5383
|
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
5384
|
console.log(chalk11.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
|
|
4575
|
-
const
|
|
4576
|
-
const
|
|
5385
|
+
const baseDir = process.cwd();
|
|
5386
|
+
const tailwind4 = isTailwind4(planUtilsDependencies(baseDir).tailwind);
|
|
5387
|
+
const resolved = await resolveInitAnswers(baseDir, tailwind4);
|
|
5388
|
+
for (const note of resolved.notes) console.log(note.startsWith("!") ? chalk11.yellow(note) : chalk11.gray(note));
|
|
5389
|
+
const config = options.yes ? { ...resolved.answers } : await prompts2([
|
|
4577
5390
|
{
|
|
4578
5391
|
type: "text",
|
|
4579
5392
|
name: "componentsDir",
|
|
4580
5393
|
message: "\uCEF4\uD3EC\uB10C\uD2B8 \uB514\uB809\uD1A0\uB9AC:",
|
|
4581
|
-
initial:
|
|
5394
|
+
initial: resolved.answers.componentsDir
|
|
4582
5395
|
},
|
|
4583
5396
|
{
|
|
4584
5397
|
type: tailwind4 ? null : "text",
|
|
4585
5398
|
name: "tailwindConfig",
|
|
4586
5399
|
message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
|
|
4587
|
-
initial:
|
|
5400
|
+
initial: resolved.answers.tailwindConfig
|
|
4588
5401
|
},
|
|
4589
5402
|
{
|
|
4590
5403
|
type: "text",
|
|
4591
5404
|
name: "globalCss",
|
|
4592
5405
|
message: "\uAE00\uB85C\uBC8C CSS \uD30C\uC77C:",
|
|
4593
|
-
initial:
|
|
5406
|
+
initial: resolved.answers.globalCss
|
|
4594
5407
|
}
|
|
4595
5408
|
]);
|
|
4596
|
-
await runInit(
|
|
5409
|
+
await runInit(baseDir, config, registryUrl);
|
|
4597
5410
|
});
|
|
4598
5411
|
}
|
|
4599
5412
|
|
|
@@ -4602,12 +5415,12 @@ import chalk12 from "chalk";
|
|
|
4602
5415
|
import prompts3 from "prompts";
|
|
4603
5416
|
|
|
4604
5417
|
// ../axis-registry-core/src/add/add.ts
|
|
4605
|
-
import { existsSync as existsSync8, readFileSync as
|
|
5418
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
4606
5419
|
import path17 from "path";
|
|
4607
5420
|
import fs13 from "fs-extra";
|
|
4608
5421
|
|
|
4609
5422
|
// ../axis-registry-core/src/registry/bundled.ts
|
|
4610
|
-
import { existsSync as existsSync7, readFileSync as
|
|
5423
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
4611
5424
|
import path16 from "path";
|
|
4612
5425
|
import { fileURLToPath } from "url";
|
|
4613
5426
|
function findBundledRegistryDir(moduleUrl = import.meta.url) {
|
|
@@ -4621,7 +5434,7 @@ function readBundledJson(dir, fileName) {
|
|
|
4621
5434
|
const file = path16.join(dir, fileName);
|
|
4622
5435
|
let text;
|
|
4623
5436
|
try {
|
|
4624
|
-
text =
|
|
5437
|
+
text = readFileSync7(file, "utf8");
|
|
4625
5438
|
} catch {
|
|
4626
5439
|
throw new Error(`\uB3D9\uBD09 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 ${fileName} \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(${dir})`);
|
|
4627
5440
|
}
|
|
@@ -4809,7 +5622,7 @@ function createPinnedFetch(options = {}) {
|
|
|
4809
5622
|
const judge = options.judge ?? blockedAddressReason;
|
|
4810
5623
|
const send = options.request ?? httpsRequest;
|
|
4811
5624
|
const maxBytes = options.maxBytes ?? PINNED_FETCH_MAX_BYTES;
|
|
4812
|
-
return (input, init) => new Promise((
|
|
5625
|
+
return (input, init) => new Promise((resolve4, reject) => {
|
|
4813
5626
|
let url;
|
|
4814
5627
|
try {
|
|
4815
5628
|
url = new URL(input);
|
|
@@ -4850,7 +5663,7 @@ function createPinnedFetch(options = {}) {
|
|
|
4850
5663
|
if (failed) return;
|
|
4851
5664
|
const body = Buffer.concat(chunks).toString("utf8");
|
|
4852
5665
|
const status = res.statusCode ?? 0;
|
|
4853
|
-
|
|
5666
|
+
resolve4({ ok: status >= 200 && status < 300, status, text: async () => body });
|
|
4854
5667
|
});
|
|
4855
5668
|
}
|
|
4856
5669
|
);
|
|
@@ -5261,7 +6074,7 @@ function relativeSpecifierResolves(fromFile, spec) {
|
|
|
5261
6074
|
const base = path17.resolve(path17.dirname(fromFile), spec);
|
|
5262
6075
|
return RESOLVE_EXTS.some((ext) => {
|
|
5263
6076
|
try {
|
|
5264
|
-
return
|
|
6077
|
+
return statSync5(base + ext).isFile();
|
|
5265
6078
|
} catch {
|
|
5266
6079
|
return false;
|
|
5267
6080
|
}
|
|
@@ -5336,9 +6149,9 @@ function missingDependencies(root, items) {
|
|
|
5336
6149
|
const installCommand = detectInstallCommand(root);
|
|
5337
6150
|
let pkg;
|
|
5338
6151
|
try {
|
|
5339
|
-
const text =
|
|
6152
|
+
const text = readFileSync8(path17.join(root, "package.json"), "utf8").replace(/^\uFEFF/, "");
|
|
5340
6153
|
const parsed = JSON.parse(text);
|
|
5341
|
-
pkg =
|
|
6154
|
+
pkg = isPlainObject(parsed) ? parsed : void 0;
|
|
5342
6155
|
} catch {
|
|
5343
6156
|
pkg = void 0;
|
|
5344
6157
|
}
|
|
@@ -5347,7 +6160,7 @@ function missingDependencies(root, items) {
|
|
|
5347
6160
|
for (const item of items) {
|
|
5348
6161
|
for (const dep of item.dependencies) {
|
|
5349
6162
|
const name = dependencyName(dep);
|
|
5350
|
-
if (pkg !== void 0 &&
|
|
6163
|
+
if (pkg !== void 0 && hasDependency(pkg, name) !== void 0) continue;
|
|
5351
6164
|
if (name in specs) continue;
|
|
5352
6165
|
const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
|
|
5353
6166
|
specs[name] = explicit ?? ranges[name];
|
|
@@ -5457,7 +6270,7 @@ async function runAdd(cwd, requested, options, ctx) {
|
|
|
5457
6270
|
continue;
|
|
5458
6271
|
}
|
|
5459
6272
|
try {
|
|
5460
|
-
existing.set(file,
|
|
6273
|
+
existing.set(file, readFileSync8(file.target, "utf8"));
|
|
5461
6274
|
} catch (e) {
|
|
5462
6275
|
readErrors.push(
|
|
5463
6276
|
`${file.item.name}: \uAE30\uC874 \uD30C\uC77C ${rel2(root, file.target)} \uC744 \uC77D\uC9C0 \uBABB\uD574 \uBE44\uAD50\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${e.code ?? e.message})`
|