@axis-ds/cli 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/index.js +540 -172
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,28 @@ axis add button
|
|
|
23
23
|
axis list
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## 프로젝트 초기화 (`axis init`)
|
|
27
|
+
|
|
28
|
+
- `axis.config.json` 과 `cn()` 을 담은 `utils.ts` 를 만들고, `clsx` · `tailwind-merge` 가 `package.json` 에 없으면 `dependencies` 에 더합니다. 설치는 실행하지 않고 명령만 안내합니다.
|
|
29
|
+
- `tailwind-merge` 범위와 아래 안내는 프로젝트의 Tailwind 버전(설치본, 없으면 `package.json` 선언)으로 정합니다. 판정하지 못하면 Tailwind 3 으로 봅니다.
|
|
30
|
+
- Tailwind 4 이상이면 전역 CSS 에 넣을 줄을 안내합니다. CSS 파일은 고치지 않습니다.
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@import "tailwindcss";
|
|
34
|
+
@import "@axis-ds/tokens/css/tailwind4";
|
|
35
|
+
@import "@axis-ds/ui-react/tailwind.css"; /* npm 패키지 컴포넌트를 쓸 때, agentic-ui 도 같은 방식 */
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다).
|
|
39
|
+
- create-next-app 기본 `globals.css` 의 `:root` · `@theme inline` · `@media (prefers-color-scheme: dark)` · `body` 블록이 AXIS 와 같은 이름(`--background` · `--foreground` · `--color-background` · `--font-sans` · `--font-mono`)을 다른 값으로 정의하니 지우라는 주의를 함께 냅니다(Quick Start 가이드 「Tailwind CSS 4」와 같은 내용).
|
|
40
|
+
- `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다.
|
|
41
|
+
- `package.json` 에 선언된 `@axis-ds/tokens` · `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 버전 조건(`axis check` 와 같은 함수 · 같은 판정). 설치본을 먼저 보고, 없으면 선언 범위를 봅니다:
|
|
42
|
+
- 설치본: `node_modules/<패키지>/package.json` 의 `version` 이 정확한 버전이면 그것으로 판정합니다. 1.4.0 이상이면 선언이 `^1.3.0` · `1.x` · `catalog:` 여도 안내하지 않고, 미만이면(`1.4.0-beta.1` 포함) 설치본 버전을 보여 주며 `^1.4.0` 으로 올리는 명령을 냅니다(예: `설치본(@axis-ds/tokens 1.3.0, 선언 ^1.4.0)을 올리세요: pnpm add "@axis-ds/tokens@^1.4.0"`). 다만 설치본이 미만이어도 선언 하한을 읽을 수 없으면(`catalog:` · `npm:` · `latest` · `||` 등) 명령을 내지 않고 선언이 가리키는 버전을 1.4.0 이상으로 올린 뒤 다시 설치하라는 줄만 냅니다(선언을 덮어쓰지 않음).
|
|
43
|
+
- 설치본이 없을 때 선언 범위의 하한이 1.4.0 미만이면(예: `^1.3.0` · `1.x` · `1.3.0 - 1.5.0` · `^1.4.0-beta.1`) 그 패키지들을 `^1.4.0` 으로 올리는 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 냅니다. 하이픈 범위는 왼쪽 버전을, 비교자 여러 개(`>=1.2 >=1.4`)는 가장 높은 하한을 봅니다.
|
|
44
|
+
- 하한을 읽을 수 없으면(`catalog:` · `latest` · `||` · `<2` · `*` 등) 선언을 덮어쓰는 명령 대신 「설치된 버전이 1.4.0 이상인지 확인하세요」를 냅니다.
|
|
45
|
+
- `workspace:` 프로토콜은 모노레포 링크라 설치본과 관계없이 안내하지 않습니다(링크된 패키지의 `version` 은 배포 전 소스의 값이라 1.4.0 미만이어도 진입점이 없다는 근거가 아닙니다).
|
|
46
|
+
- Tailwind 4 에는 설정 파일이 없으므로 `axis.config.json` 에 `tailwindConfig` 를 적지 않고, 대화형 실행에서도 묻지 않습니다. Tailwind 3 은 종전과 같습니다.
|
|
47
|
+
|
|
26
48
|
## 브랜드 테마 (`axis theme`)
|
|
27
49
|
|
|
28
50
|
프로젝트에 설치된 `@axis-ds/tokens`(1.3.0 이상)의 브랜드를 조회하고 적용합니다. 세 명령 모두 `-d, --dir <path>` 로 대상 디렉터리를 받습니다(기본: 현재 디렉터리).
|
|
@@ -44,6 +66,22 @@ axis theme add ontology
|
|
|
44
66
|
- `@axis-ds/tokens` 가 없거나 1.3.0 미만이면 목록 대신 설치 · 업그레이드 안내를 내고 종료 코드 1 로 끝납니다.
|
|
45
67
|
- `axis check` 는 `axis.config.json` 의 `brand` 와 CSS 의 브랜드 import 가 맞는지도 봅니다.
|
|
46
68
|
|
|
69
|
+
## 프로젝트 검증 (`axis check`)
|
|
70
|
+
|
|
71
|
+
- Tailwind 구성 항목: Tailwind 4 이상(설치본, 없으면 `package.json` 선언으로 판정)은 설정 파일 대신 전역 CSS(`globals.css` · `app/globals.css` · `src/app/globals.css` · `src/globals.css` · `styles/globals.css` 순으로 처음 찾은 파일 하나)를 봅니다. Tailwind 3 이하는 `tailwind.config.ts` · `.js` · `.mjs` · `.cjs` 를 찾습니다.
|
|
72
|
+
- Tailwind 4: `@import "tailwindcss"` 가 있는 CSS 에서 아래 문제가 하나도 없으면 PASS 이고, 하나라도 있으면 WARN 입니다(블록 주석 안은 없는 것으로 봅니다). `@import "tailwindcss"` 가 없으면 그 WARN 하나만 냅니다.
|
|
73
|
+
1. 토큰 진입점 `@import "@axis-ds/tokens/css/tailwind4";` 이 없음 → 문구에 넣을 import 줄. 진입점이 없으면 `bg-primary` · `rounded-md` 같은 AXIS 매핑이 만들어지지 않습니다. `@axis-ds/tokens/css` · `css/shadcn` · `tailwind`(Tailwind 3 preset)는 진입점으로 치지 않습니다.
|
|
74
|
+
2. `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` import 가 없음 → 빠진 import 줄. 선언이 없으면(복사 설치) 요구하지 않습니다. `tailwind.css` 대신 그 패키지를 가리키는 `@source` 를 같은 CSS 에 직접 썼으면(예: `@source "../node_modules/@axis-ds/ui-react/dist";`, 작은따옴표 · 다른 상대 경로 포함) 스캔 경로가 있는 것으로 봅니다. 경로 문자열에 `@axis-ds/<패키지>` 가 들어 있고 그 바로 뒤가 경로 끝 · `/` · `\` 이면(`@axis-ds/ui-react-extra` 같은 다른 이름은 아님) 그 패키지를 가리킨다고 판정합니다(경로가 실제로 있는지는 보지 않음). 주석 안 · `@source not` · `@source inline()` 은 인정하지 않고, brace 확장(`@source "{…/@axis-ds/ui-react,…}/dist"`) · `@import "…" source("…")` 형태도 인정하지 않습니다(WARN 쪽으로 판정).
|
|
75
|
+
3. 진입점이 있는데 create-next-app 기본 정의가 남음 → 실제로 남은 정의 이름(예: `--font-sans` 만 남았으면 `@theme --font-sans: var(--font-geist-sans)` 만 표시). `--background` · `--foreground` 를 색값(`#ffffff` · `rgb()` · `oklch()` 등)으로 정의, `--color-background: var(--background)` 류, `--font-sans` · `--font-mono: var(--font-geist-*)`, `background` · `color: var(--background)` 류 직접 사용을 봅니다(create-next-app 15.5.28 기본 `globals.css` 실물 기준). AXIS 의 HSL 삼중값(`0 0% 100%`) 재정의나 `hsl(var(--background))` 는 걸리지 않습니다. 표시 앞머리(`:root 색값` · `@theme` · `body`)는 create-next-app 기본 블록 이름이라, 같은 선언이 다른 선택자에 있어도 그 이름으로 표시됩니다.
|
|
76
|
+
4. 진입점이 있는데 `@axis-ds/tokens` 가 아래 버전 조건에 걸림.
|
|
77
|
+
5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다.
|
|
78
|
+
- 문제가 여럿이면 위 순서대로 ` / ` 로 이어 한 항목에 냅니다. 끝에는 `package.json` 에 선언된 세 AXIS 패키지 가운데 1.4.0 미만인 것을 `(1.4.0 이상 필요: @axis-ds/tokens ^1.3.0)`, 판정할 수 없는 것을 `(설치된 버전이 1.4.0 이상인지 확인하세요: @axis-ds/agentic-ui catalog:)` 로 한 번 덧붙입니다. 버전은 `axis init` 과 같은 함수로 판정합니다: 설치본(`node_modules/<패키지>/package.json` 의 정확한 `version`)이 있으면 그것으로 보고(`(1.4.0 이상 필요: @axis-ds/ui-react 설치본 1.3.0)`, 1.4.0 이상이면 선언과 관계없이 넣지 않음), 없으면 선언 범위의 하한, 하한도 읽을 수 없으면(`catalog:` · `latest` · `||` 등) 판정 불가입니다. `workspace:` 는 넣지 않습니다.
|
|
79
|
+
- 문구 예: `Tailwind 4: globals.css에 AXIS 토큰 진입점이 없습니다 → @import "@axis-ds/tokens/css/tailwind4"; / 컴포넌트 스캔 경로(tailwind.css)가 없습니다 → @import "@axis-ds/ui-react/tailwind.css"; (1.4.0 이상 필요: @axis-ds/tokens ^1.3.0 · @axis-ds/ui-react ^1.3.0)`
|
|
80
|
+
- Tailwind 3: `tailwind.config.ts` 에 `--background` · `hsl(var(` 가 있으면 종전 문구로 PASS 입니다. 그렇지 않아도 설정 파일(`.ts` · `.js` · `.mjs` · `.cjs`)이 `@axis-ds/tokens/tailwind` preset 을 `require` · `import` 하면(주석 밖) `tailwind.config.mjs에 AXIS 토큰이 설정되어 있습니다 (@axis-ds/tokens/tailwind preset)` 처럼 PASS 입니다. 1.3.0 에서는 preset 만 쓰는 `.ts` 가 WARN(`AXIS 토큰 설정이 없습니다`), `.js` · `.mjs` · `.cjs` 가 WARN(`TypeScript 권장`)이었습니다.
|
|
81
|
+
- globals.css 항목: 같은 후보에서 처음 찾은 CSS 하나를 봅니다. `--background` 와 `--primary` 를 직접 정의하거나, `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn` · `@axis-ds/tokens/css/tailwind4` 를 import 하면(블록 주석 밖, 작은따옴표 · `url()` · `layer()` 표기 포함) PASS 입니다. import 로 인정한 경우 문구 끝에 `(@axis-ds/tokens/css/tailwind4 import)` 처럼 경로가 붙습니다. 1.4.0 부터이고, 이전에는 import 만 있으면 WARN 이었습니다.
|
|
82
|
+
- FAIL 이 하나라도 있으면 종료 코드 1 로 끝납니다. WARN 만 있으면 0 입니다(1.3.0 부터, 이전에는 결과와 관계없이 0).
|
|
83
|
+
- MCP `axis.check_project` 도 같은 항목 · 문구를 냅니다.
|
|
84
|
+
|
|
47
85
|
## 문서
|
|
48
86
|
|
|
49
87
|
자세한 사용법은 [AXIS Design System 문서](https://axis.minu.best)를 참고하세요.
|
package/dist/index.js
CHANGED
|
@@ -1580,7 +1580,7 @@ function createInitConfig(answers, registry) {
|
|
|
1580
1580
|
return {
|
|
1581
1581
|
$schema: AXIS_CONFIG_SCHEMA_URL,
|
|
1582
1582
|
componentsDir: answers.componentsDir,
|
|
1583
|
-
tailwindConfig: answers.tailwindConfig,
|
|
1583
|
+
...answers.tailwindConfig !== void 0 ? { tailwindConfig: answers.tailwindConfig } : {},
|
|
1584
1584
|
globalCss: answers.globalCss,
|
|
1585
1585
|
registry
|
|
1586
1586
|
};
|
|
@@ -2099,6 +2099,438 @@ function getBrand(baseDir, name) {
|
|
|
2099
2099
|
};
|
|
2100
2100
|
}
|
|
2101
2101
|
|
|
2102
|
+
// src/template/tailwind-core.ts
|
|
2103
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
2104
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
2105
|
+
function hasDependency(pkg, name) {
|
|
2106
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
2107
|
+
const deps = pkg[field];
|
|
2108
|
+
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
2109
|
+
return String(deps[name]);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
return void 0;
|
|
2113
|
+
}
|
|
2114
|
+
function isPlainObject(value) {
|
|
2115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2116
|
+
}
|
|
2117
|
+
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
2118
|
+
function versionParts(token) {
|
|
2119
|
+
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
2120
|
+
if (!m) return void 0;
|
|
2121
|
+
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
2122
|
+
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
2123
|
+
}
|
|
2124
|
+
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
2125
|
+
function comparatorBounds(op, v) {
|
|
2126
|
+
switch (op) {
|
|
2127
|
+
case ">=":
|
|
2128
|
+
return { lower: v.major };
|
|
2129
|
+
case ">":
|
|
2130
|
+
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
2131
|
+
case "<=":
|
|
2132
|
+
return { upper: v.major };
|
|
2133
|
+
case "<": {
|
|
2134
|
+
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
2135
|
+
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
2136
|
+
}
|
|
2137
|
+
default:
|
|
2138
|
+
return { lower: v.major, upper: v.major };
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
function tailwindMajorBounds(range) {
|
|
2142
|
+
const r = range.trim();
|
|
2143
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2144
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2145
|
+
if (simple) {
|
|
2146
|
+
const v = versionParts(simple[1]);
|
|
2147
|
+
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
2148
|
+
}
|
|
2149
|
+
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
2150
|
+
if (hyphen) {
|
|
2151
|
+
const tokens2 = r.split(/\s+-\s+/);
|
|
2152
|
+
const a = versionParts(tokens2[0]);
|
|
2153
|
+
const b = versionParts(tokens2[1]);
|
|
2154
|
+
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
2155
|
+
}
|
|
2156
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2157
|
+
const lowers = [];
|
|
2158
|
+
const uppers = [];
|
|
2159
|
+
for (const t of tokens) {
|
|
2160
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2161
|
+
if (!c) return void 0;
|
|
2162
|
+
const v = versionParts(c[2]);
|
|
2163
|
+
if (v === void 0) return void 0;
|
|
2164
|
+
const b = comparatorBounds(c[1], v);
|
|
2165
|
+
if (b.lower !== void 0) lowers.push(b.lower);
|
|
2166
|
+
if (b.upper !== void 0) uppers.push(b.upper);
|
|
2167
|
+
}
|
|
2168
|
+
if (lowers.length === 0) return void 0;
|
|
2169
|
+
const lower = Math.max(...lowers);
|
|
2170
|
+
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
2171
|
+
if (upper !== void 0 && upper < lower) return void 0;
|
|
2172
|
+
return upper !== void 0 ? { lower, upper } : { lower };
|
|
2173
|
+
}
|
|
2174
|
+
function majorWithin(major, bounds) {
|
|
2175
|
+
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
2176
|
+
}
|
|
2177
|
+
function majorFromVersion(version) {
|
|
2178
|
+
if (typeof version !== "string") return void 0;
|
|
2179
|
+
const v = version.trim();
|
|
2180
|
+
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
2181
|
+
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2182
|
+
return Number(m[1]);
|
|
2183
|
+
}
|
|
2184
|
+
function detectTailwind(baseDirInput, pkg) {
|
|
2185
|
+
const baseDir = resolve2(baseDirInput);
|
|
2186
|
+
const installedFile = join2(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
2187
|
+
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
2188
|
+
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
2189
|
+
const declaredMajor = bounds?.lower;
|
|
2190
|
+
try {
|
|
2191
|
+
const installed = JSON.parse(readFileSync2(installedFile, "utf8"));
|
|
2192
|
+
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
2193
|
+
const major = majorFromVersion(version);
|
|
2194
|
+
if (major !== void 0) {
|
|
2195
|
+
const found = { major, source: "installed", value: String(version) };
|
|
2196
|
+
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
2197
|
+
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
2198
|
+
}
|
|
2199
|
+
return found;
|
|
2200
|
+
}
|
|
2201
|
+
} catch {
|
|
2202
|
+
}
|
|
2203
|
+
if (declared !== void 0) {
|
|
2204
|
+
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
2205
|
+
return { source: "none", value: declared };
|
|
2206
|
+
}
|
|
2207
|
+
return { source: "none" };
|
|
2208
|
+
}
|
|
2209
|
+
var TAILWIND_CONFIG_FILES = [
|
|
2210
|
+
"tailwind.config.ts",
|
|
2211
|
+
"tailwind.config.js",
|
|
2212
|
+
"tailwind.config.mjs",
|
|
2213
|
+
"tailwind.config.cjs"
|
|
2214
|
+
];
|
|
2215
|
+
var TAILWIND_CSS_CANDIDATES = [
|
|
2216
|
+
"globals.css",
|
|
2217
|
+
"app/globals.css",
|
|
2218
|
+
"src/app/globals.css",
|
|
2219
|
+
"src/globals.css",
|
|
2220
|
+
"styles/globals.css"
|
|
2221
|
+
];
|
|
2222
|
+
var TAILWIND_IMPORT = /@import\s+(?:url\(\s*)?["']tailwindcss["']/;
|
|
2223
|
+
function stripCssComments(css) {
|
|
2224
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2225
|
+
}
|
|
2226
|
+
function hasTailwindImport(css) {
|
|
2227
|
+
return TAILWIND_IMPORT.test(stripCssComments(css));
|
|
2228
|
+
}
|
|
2229
|
+
var TOKENS_TAILWIND4_ENTRY = "@axis-ds/tokens/css/tailwind4";
|
|
2230
|
+
var TOKENS_TAILWIND4_IMPORT_LINE = `@import "${TOKENS_TAILWIND4_ENTRY}";`;
|
|
2231
|
+
var TOKENS_TAILWIND4_IMPORT = /@import\s+(?:url\(\s*)?["']@axis-ds\/tokens\/css\/tailwind4["']/;
|
|
2232
|
+
function hasTokensTailwind4Import(css) {
|
|
2233
|
+
return TOKENS_TAILWIND4_IMPORT.test(stripCssComments(css));
|
|
2234
|
+
}
|
|
2235
|
+
var TOKENS_CSS_IMPORT = /@import\s+(?:url\(\s*)?["'](@axis-ds\/tokens\/css(?:\/shadcn|\/tailwind4)?)["']/;
|
|
2236
|
+
function findTokensCssImport(css) {
|
|
2237
|
+
return TOKENS_CSS_IMPORT.exec(stripCssComments(css))?.[1];
|
|
2238
|
+
}
|
|
2239
|
+
function checkGlobalsCss(baseDirInput) {
|
|
2240
|
+
const baseDir = resolve2(baseDirInput);
|
|
2241
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2242
|
+
const file = join2(baseDir, candidate);
|
|
2243
|
+
if (!existsSync2(file)) continue;
|
|
2244
|
+
const content = readFileSync2(file, "utf8");
|
|
2245
|
+
if (content.includes("--background") && content.includes("--primary")) {
|
|
2246
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
2247
|
+
}
|
|
2248
|
+
const imported = findTokensCssImport(content);
|
|
2249
|
+
if (imported !== void 0) {
|
|
2250
|
+
return { name: "globals.css", severity: "pass", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${imported} import)` };
|
|
2251
|
+
}
|
|
2252
|
+
return { name: "globals.css", severity: "warn", message: `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4` };
|
|
2253
|
+
}
|
|
2254
|
+
return { name: "globals.css", severity: "fail", message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2255
|
+
}
|
|
2256
|
+
var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
|
|
2257
|
+
var TAILWIND4_AXIS_PACKAGES = ["@axis-ds/tokens", "@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2258
|
+
function lowerOf(token) {
|
|
2259
|
+
const v = versionParts(token);
|
|
2260
|
+
if (!v) return void 0;
|
|
2261
|
+
const num = (part) => isWild(part) ? 0 : Number(part);
|
|
2262
|
+
const pre = /^v?\d+(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?-/.test(token);
|
|
2263
|
+
return { core: [v.major, num(v.minor), num(v.patch)], pre };
|
|
2264
|
+
}
|
|
2265
|
+
function compareLower(a, b) {
|
|
2266
|
+
for (let i = 0; i < 3; i++) {
|
|
2267
|
+
if (a.core[i] !== b.core[i]) return a.core[i] - b.core[i];
|
|
2268
|
+
}
|
|
2269
|
+
return Number(b.pre) - Number(a.pre);
|
|
2270
|
+
}
|
|
2271
|
+
function rangeLowerVersion(range) {
|
|
2272
|
+
const r = range.trim();
|
|
2273
|
+
if (r === "" || r.includes("||")) return void 0;
|
|
2274
|
+
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
2275
|
+
if (simple) return lowerOf(simple[1]);
|
|
2276
|
+
if (new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).test(r)) {
|
|
2277
|
+
const [a, b] = r.split(/\s+-\s+/);
|
|
2278
|
+
return lowerOf(b) ? lowerOf(a) : void 0;
|
|
2279
|
+
}
|
|
2280
|
+
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
2281
|
+
let lower;
|
|
2282
|
+
for (const t of tokens) {
|
|
2283
|
+
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
2284
|
+
if (!c) return void 0;
|
|
2285
|
+
const v = versionParts(c[2]);
|
|
2286
|
+
const low = lowerOf(c[2]);
|
|
2287
|
+
if (!v || !low) return void 0;
|
|
2288
|
+
let candidate;
|
|
2289
|
+
if (c[1] === ">=" || c[1] === "=") candidate = low;
|
|
2290
|
+
else if (c[1] === ">") {
|
|
2291
|
+
if (isWild(v.minor)) candidate = { core: [v.major + 1, 0, 0], pre: false };
|
|
2292
|
+
else if (isWild(v.patch)) candidate = { core: [v.major, Number(v.minor) + 1, 0], pre: false };
|
|
2293
|
+
else candidate = { core: [v.major, Number(v.minor), Number(v.patch) + 1], pre: false };
|
|
2294
|
+
}
|
|
2295
|
+
if (candidate && (!lower || compareLower(candidate, lower) > 0)) lower = candidate;
|
|
2296
|
+
}
|
|
2297
|
+
return lower;
|
|
2298
|
+
}
|
|
2299
|
+
function rangeLowerAtLeast(range, min) {
|
|
2300
|
+
const lower = rangeLowerVersion(range);
|
|
2301
|
+
const target = lowerOf(min);
|
|
2302
|
+
if (!lower || !target) return void 0;
|
|
2303
|
+
return compareLower(lower, target) >= 0;
|
|
2304
|
+
}
|
|
2305
|
+
function exactVersion(version) {
|
|
2306
|
+
if (typeof version !== "string") return void 0;
|
|
2307
|
+
const v = version.trim();
|
|
2308
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(v) || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
2309
|
+
return v;
|
|
2310
|
+
}
|
|
2311
|
+
function installedVersion(baseDir, name) {
|
|
2312
|
+
try {
|
|
2313
|
+
const parsed = JSON.parse(readFileSync2(join2(baseDir, "node_modules", ...name.split("/"), "package.json"), "utf8"));
|
|
2314
|
+
return isPlainObject(parsed) ? exactVersion(parsed.version) : void 0;
|
|
2315
|
+
} catch {
|
|
2316
|
+
return void 0;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
function axisPackagesBelowTailwind4(pkg, baseDirInput) {
|
|
2320
|
+
if (!pkg) return [];
|
|
2321
|
+
const baseDir = baseDirInput !== void 0 ? resolve2(baseDirInput) : void 0;
|
|
2322
|
+
const out = [];
|
|
2323
|
+
const min = lowerOf(TAILWIND4_MIN_AXIS_VERSION);
|
|
2324
|
+
for (const name of TAILWIND4_AXIS_PACKAGES) {
|
|
2325
|
+
const range = hasDependency(pkg, name);
|
|
2326
|
+
if (range === void 0 || range.trim().startsWith("workspace:")) continue;
|
|
2327
|
+
const installed = baseDir !== void 0 ? installedVersion(baseDir, name) : void 0;
|
|
2328
|
+
const installedLower = installed !== void 0 ? lowerOf(installed) : void 0;
|
|
2329
|
+
if (installed !== void 0 && installedLower !== void 0) {
|
|
2330
|
+
if (compareLower(installedLower, min) < 0) out.push({ name, range, status: "below", source: "installed", installed });
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
2333
|
+
const atLeast = rangeLowerAtLeast(range, TAILWIND4_MIN_AXIS_VERSION);
|
|
2334
|
+
if (atLeast === false) out.push({ name, range, status: "below", source: "declared" });
|
|
2335
|
+
else if (atLeast === void 0) out.push({ name, range, status: "unknown", source: "declared" });
|
|
2336
|
+
}
|
|
2337
|
+
return out;
|
|
2338
|
+
}
|
|
2339
|
+
function axisPackageVersionLabel(issue) {
|
|
2340
|
+
return issue.source === "installed" ? `${issue.name} \uC124\uCE58\uBCF8 ${issue.installed}` : `${issue.name} ${issue.range}`;
|
|
2341
|
+
}
|
|
2342
|
+
var declaredList = (issues) => issues.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
2343
|
+
function tailwind4VersionNote(issues) {
|
|
2344
|
+
const below = issues.filter((i) => i.status === "below");
|
|
2345
|
+
const unknown = issues.filter((i) => i.status === "unknown");
|
|
2346
|
+
let note = "";
|
|
2347
|
+
if (below.length > 0) note += ` (${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1 \uD544\uC694: ${declaredList(below)})`;
|
|
2348
|
+
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)})`;
|
|
2349
|
+
return note;
|
|
2350
|
+
}
|
|
2351
|
+
var TAILWIND4_COMPONENT_PACKAGES = ["@axis-ds/ui-react", "@axis-ds/agentic-ui"];
|
|
2352
|
+
function componentTailwindImportLine(name) {
|
|
2353
|
+
return `@import "${name}/tailwind.css";`;
|
|
2354
|
+
}
|
|
2355
|
+
var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2356
|
+
function hasComponentTailwindImport(css, name) {
|
|
2357
|
+
const re = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${escapeRegExp(name)}/tailwind\\.css["']`);
|
|
2358
|
+
return re.test(stripCssComments(css));
|
|
2359
|
+
}
|
|
2360
|
+
function hasComponentSource(css, name) {
|
|
2361
|
+
const re = new RegExp(`@source\\s+(["'])(?!@axis-ds/)[^"'\\n]*${escapeRegExp(name)}(?:[/\\\\][^"'\\n]*)?\\1`);
|
|
2362
|
+
return re.test(stripCssComments(css));
|
|
2363
|
+
}
|
|
2364
|
+
var CREATE_NEXT_APP_DEFAULTS = [
|
|
2365
|
+
{
|
|
2366
|
+
prefix: ":root \uC0C9\uAC12",
|
|
2367
|
+
pattern: /(?<![\w-])(--(?:background|foreground))\s*:\s*(?:#[0-9a-fA-F]{3,8}\b|(?:rgba?|hsla?|hwb|oklch|oklab|lab|lch|color)\()/g,
|
|
2368
|
+
item: (m) => m[1]
|
|
2369
|
+
},
|
|
2370
|
+
{
|
|
2371
|
+
prefix: "@theme",
|
|
2372
|
+
pattern: /(?<![\w-])(--color-(?:background|foreground))\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2373
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
prefix: "@theme",
|
|
2377
|
+
pattern: /(?<![\w-])(--font-(?:sans|mono))\s*:\s*var\(\s*(--font-geist-(?:sans|mono))\s*\)/g,
|
|
2378
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2379
|
+
},
|
|
2380
|
+
{
|
|
2381
|
+
prefix: "body",
|
|
2382
|
+
pattern: /(?<![\w-])(background|background-color|color)\s*:\s*var\(\s*(--(?:background|foreground))\s*\)/g,
|
|
2383
|
+
item: (m) => `${m[1]}: var(${m[2]})`
|
|
2384
|
+
}
|
|
2385
|
+
];
|
|
2386
|
+
function findCreateNextAppDefaults(css) {
|
|
2387
|
+
const body = stripCssComments(css);
|
|
2388
|
+
const labels = [];
|
|
2389
|
+
for (const d of CREATE_NEXT_APP_DEFAULTS) {
|
|
2390
|
+
const items = [];
|
|
2391
|
+
for (const m of body.matchAll(d.pattern)) {
|
|
2392
|
+
const item = d.item(m);
|
|
2393
|
+
if (!items.includes(item)) items.push(item);
|
|
2394
|
+
}
|
|
2395
|
+
if (items.length > 0) labels.push(`${d.prefix} ${items.join(", ")}`);
|
|
2396
|
+
}
|
|
2397
|
+
return labels;
|
|
2398
|
+
}
|
|
2399
|
+
function stripJsComments(src) {
|
|
2400
|
+
let out = "";
|
|
2401
|
+
let i = 0;
|
|
2402
|
+
const n = src.length;
|
|
2403
|
+
while (i < n) {
|
|
2404
|
+
const c = src[i];
|
|
2405
|
+
const d = src[i + 1];
|
|
2406
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2407
|
+
let j = i + 1;
|
|
2408
|
+
while (j < n && src[j] !== c) {
|
|
2409
|
+
if (src[j] === "\\") j++;
|
|
2410
|
+
else if (c !== "`" && src[j] === "\n") break;
|
|
2411
|
+
j++;
|
|
2412
|
+
}
|
|
2413
|
+
out += src.slice(i, j + 1);
|
|
2414
|
+
i = j + 1;
|
|
2415
|
+
continue;
|
|
2416
|
+
}
|
|
2417
|
+
if (c === "/" && d === "/") {
|
|
2418
|
+
const end = src.indexOf("\n", i);
|
|
2419
|
+
i = end === -1 ? n : end;
|
|
2420
|
+
continue;
|
|
2421
|
+
}
|
|
2422
|
+
if (c === "/" && d === "*") {
|
|
2423
|
+
const end = src.indexOf("*/", i + 2);
|
|
2424
|
+
i = end === -1 ? n : end + 2;
|
|
2425
|
+
out += " ";
|
|
2426
|
+
continue;
|
|
2427
|
+
}
|
|
2428
|
+
out += c;
|
|
2429
|
+
i++;
|
|
2430
|
+
}
|
|
2431
|
+
return out;
|
|
2432
|
+
}
|
|
2433
|
+
var TOKENS_TAILWIND3_PRESET = "@axis-ds/tokens/tailwind";
|
|
2434
|
+
var PRESET_REFERENCE = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s*|\bimport\s+)(["'])@axis-ds\/tokens\/tailwind\1/;
|
|
2435
|
+
function hasTokensPresetReference(source) {
|
|
2436
|
+
return PRESET_REFERENCE.test(stripJsComments(source));
|
|
2437
|
+
}
|
|
2438
|
+
var PRESET_PASS_SUFFIX = `\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 (${TOKENS_TAILWIND3_PRESET} preset)`;
|
|
2439
|
+
function readPackageJson(baseDir) {
|
|
2440
|
+
try {
|
|
2441
|
+
const parsed = JSON.parse(readFileSync2(join2(baseDir, "package.json"), "utf8"));
|
|
2442
|
+
return isPlainObject(parsed) ? parsed : void 0;
|
|
2443
|
+
} catch {
|
|
2444
|
+
return void 0;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
function tailwind4Issues(css, pkg, versions) {
|
|
2448
|
+
const issues = [];
|
|
2449
|
+
const hasEntry = hasTokensTailwind4Import(css);
|
|
2450
|
+
if (!hasEntry) issues.push(`AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${TOKENS_TAILWIND4_IMPORT_LINE}`);
|
|
2451
|
+
const missing = TAILWIND4_COMPONENT_PACKAGES.filter(
|
|
2452
|
+
(name) => pkg !== void 0 && hasDependency(pkg, name) !== void 0 && !hasComponentTailwindImport(css, name) && !hasComponentSource(css, name)
|
|
2453
|
+
);
|
|
2454
|
+
if (missing.length > 0) {
|
|
2455
|
+
issues.push(`\uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCE94 \uACBD\uB85C(tailwind.css)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 ${missing.map(componentTailwindImportLine).join(" ")}`);
|
|
2456
|
+
}
|
|
2457
|
+
if (hasEntry) {
|
|
2458
|
+
const defaults = findCreateNextAppDefaults(css);
|
|
2459
|
+
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`);
|
|
2460
|
+
if (versions.some((v) => v.name === TAILWIND4_AXIS_PACKAGES[0])) {
|
|
2461
|
+
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`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
for (const name of TAILWIND4_COMPONENT_PACKAGES) {
|
|
2465
|
+
if (hasComponentTailwindImport(css, name) && versions.some((v) => v.name === name)) {
|
|
2466
|
+
issues.push(`${name}/tailwind.css import \uAC00 \uC788\uC9C0\uB9CC ${name} \uBC84\uC804 \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
return issues;
|
|
2470
|
+
}
|
|
2471
|
+
function checkTailwindSetup(baseDirInput) {
|
|
2472
|
+
const baseDir = resolve2(baseDirInput);
|
|
2473
|
+
const pkg = readPackageJson(baseDir);
|
|
2474
|
+
const tailwind = detectTailwind(baseDir, pkg);
|
|
2475
|
+
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
2476
|
+
const label = `Tailwind ${tailwind.major}`;
|
|
2477
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2478
|
+
const file = join2(baseDir, candidate);
|
|
2479
|
+
if (!existsSync2(file)) continue;
|
|
2480
|
+
const css = readFileSync2(file, "utf8");
|
|
2481
|
+
if (!hasTailwindImport(css)) {
|
|
2482
|
+
return {
|
|
2483
|
+
name: "tailwind.config",
|
|
2484
|
+
severity: "warn",
|
|
2485
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
2489
|
+
const issues = tailwind4Issues(css, pkg, versions);
|
|
2490
|
+
if (issues.length > 0) {
|
|
2491
|
+
return {
|
|
2492
|
+
name: "tailwind.config",
|
|
2493
|
+
severity: "warn",
|
|
2494
|
+
message: `${label}: ${candidate}\uC5D0 ${issues.join(" / ")}${tailwind4VersionNote(versions)}`
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
return {
|
|
2498
|
+
name: "tailwind.config",
|
|
2499
|
+
severity: "pass",
|
|
2500
|
+
message: `${label}: ${candidate}\uC5D0 @import "tailwindcss" \uC640 AXIS \uD1A0\uD070 \uC9C4\uC785\uC810\uC774 \uC788\uC2B5\uB2C8\uB2E4`
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
return {
|
|
2504
|
+
name: "tailwind.config",
|
|
2505
|
+
severity: "warn",
|
|
2506
|
+
message: `${label}: @import "tailwindcss" \uB97C \uD655\uC778\uD560 CSS \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4`
|
|
2507
|
+
};
|
|
2508
|
+
}
|
|
2509
|
+
const [tsFile, ...otherFiles] = TAILWIND_CONFIG_FILES;
|
|
2510
|
+
const tsPath = join2(baseDir, tsFile);
|
|
2511
|
+
if (existsSync2(tsPath)) {
|
|
2512
|
+
const content = readFileSync2(tsPath, "utf8");
|
|
2513
|
+
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
2514
|
+
if (hasTokens) {
|
|
2515
|
+
return { name: "tailwind.config", severity: "pass", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" };
|
|
2516
|
+
}
|
|
2517
|
+
if (hasTokensPresetReference(content)) {
|
|
2518
|
+
return { name: "tailwind.config", severity: "pass", message: `tailwind.config.ts${PRESET_PASS_SUFFIX}` };
|
|
2519
|
+
}
|
|
2520
|
+
return { name: "tailwind.config", severity: "warn", message: "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2521
|
+
}
|
|
2522
|
+
for (const file of otherFiles) {
|
|
2523
|
+
const path13 = join2(baseDir, file);
|
|
2524
|
+
if (existsSync2(path13)) {
|
|
2525
|
+
if (hasTokensPresetReference(readFileSync2(path13, "utf8"))) {
|
|
2526
|
+
return { name: "tailwind.config", severity: "pass", message: `${file}${PRESET_PASS_SUFFIX}` };
|
|
2527
|
+
}
|
|
2528
|
+
return { name: "tailwind.config", severity: "warn", message: `${file} \uC874\uC7AC (TypeScript \uAD8C\uC7A5)` };
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
return { name: "tailwind.config", severity: "fail", message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" };
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2102
2534
|
// src/template/template-check.ts
|
|
2103
2535
|
var SEVERITY_ICON = {
|
|
2104
2536
|
pass: chalk6.green("PASS"),
|
|
@@ -2109,8 +2541,8 @@ async function collectCheckResults(dir) {
|
|
|
2109
2541
|
const baseDir = path8.resolve(dir || ".");
|
|
2110
2542
|
const results = [];
|
|
2111
2543
|
results.push(await checkFileExists(baseDir, "axis.config.json", "axis.config.json"));
|
|
2112
|
-
results.push(
|
|
2113
|
-
results.push(
|
|
2544
|
+
results.push(checkTailwindSetup(baseDir));
|
|
2545
|
+
results.push(checkGlobalsCss(baseDir));
|
|
2114
2546
|
results.push(await checkUtils(baseDir));
|
|
2115
2547
|
results.push(await checkDependencies(baseDir));
|
|
2116
2548
|
const brand = checkBrand(baseDir);
|
|
@@ -2148,6 +2580,7 @@ async function runCheck(dir) {
|
|
|
2148
2580
|
} else {
|
|
2149
2581
|
console.log(chalk6.green("\n\uBAA8\uB4E0 \uAC80\uC99D\uC744 \uD1B5\uACFC\uD588\uC2B5\uB2C8\uB2E4!"));
|
|
2150
2582
|
}
|
|
2583
|
+
return { pass: passCount, warn: warnCount, fail: failCount };
|
|
2151
2584
|
}
|
|
2152
2585
|
async function checkFileExists(baseDir, fileName, label) {
|
|
2153
2586
|
const exists = await fs9.pathExists(path8.join(baseDir, fileName));
|
|
@@ -2157,57 +2590,6 @@ async function checkFileExists(baseDir, fileName, label) {
|
|
|
2157
2590
|
message: exists ? `${label} \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4` : `${label} \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2192 'axis init'\uC744 \uC2E4\uD589\uD558\uC138\uC694`
|
|
2158
2591
|
};
|
|
2159
2592
|
}
|
|
2160
|
-
async function checkTailwindConfig(baseDir) {
|
|
2161
|
-
const tsPath = path8.join(baseDir, "tailwind.config.ts");
|
|
2162
|
-
const jsPath = path8.join(baseDir, "tailwind.config.js");
|
|
2163
|
-
if (await fs9.pathExists(tsPath)) {
|
|
2164
|
-
const content = await fs9.readFile(tsPath, "utf-8");
|
|
2165
|
-
const hasTokens = content.includes("--background") || content.includes("hsl(var(");
|
|
2166
|
-
return {
|
|
2167
|
-
name: "tailwind.config",
|
|
2168
|
-
severity: hasTokens ? "pass" : "warn",
|
|
2169
|
-
message: hasTokens ? "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070\uC774 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4" : "tailwind.config.ts\uC5D0 AXIS \uD1A0\uD070 \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2170
|
-
};
|
|
2171
|
-
}
|
|
2172
|
-
if (await fs9.pathExists(jsPath)) {
|
|
2173
|
-
return {
|
|
2174
|
-
name: "tailwind.config",
|
|
2175
|
-
severity: "warn",
|
|
2176
|
-
message: "tailwind.config.js \uC874\uC7AC (TypeScript \uAD8C\uC7A5)"
|
|
2177
|
-
};
|
|
2178
|
-
}
|
|
2179
|
-
return {
|
|
2180
|
-
name: "tailwind.config",
|
|
2181
|
-
severity: "fail",
|
|
2182
|
-
message: "tailwind.config \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2183
|
-
};
|
|
2184
|
-
}
|
|
2185
|
-
async function checkGlobalsCss(baseDir) {
|
|
2186
|
-
const candidates = [
|
|
2187
|
-
"globals.css",
|
|
2188
|
-
"app/globals.css",
|
|
2189
|
-
"src/app/globals.css",
|
|
2190
|
-
"src/globals.css",
|
|
2191
|
-
"styles/globals.css"
|
|
2192
|
-
];
|
|
2193
|
-
for (const candidate of candidates) {
|
|
2194
|
-
const fullPath = path8.join(baseDir, candidate);
|
|
2195
|
-
if (await fs9.pathExists(fullPath)) {
|
|
2196
|
-
const content = await fs9.readFile(fullPath, "utf-8");
|
|
2197
|
-
const hasTokens = content.includes("--background") && content.includes("--primary");
|
|
2198
|
-
return {
|
|
2199
|
-
name: "globals.css",
|
|
2200
|
-
severity: hasTokens ? "pass" : "warn",
|
|
2201
|
-
message: hasTokens ? `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC815\uC758\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4` : `${candidate}\uC5D0 AXIS CSS \uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4`
|
|
2202
|
-
};
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
return {
|
|
2206
|
-
name: "globals.css",
|
|
2207
|
-
severity: "fail",
|
|
2208
|
-
message: "globals.css \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4"
|
|
2209
|
-
};
|
|
2210
|
-
}
|
|
2211
2593
|
async function checkUtils(baseDir) {
|
|
2212
2594
|
const candidates = [
|
|
2213
2595
|
"lib/utils.ts",
|
|
@@ -2402,7 +2784,8 @@ function registerTemplateCommand(program2) {
|
|
|
2402
2784
|
}
|
|
2403
2785
|
function registerCheckCommand(program2) {
|
|
2404
2786
|
program2.command("check").description("AXIS \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uAC80\uC99D").option("-d, --dir <path>", "\uB300\uC0C1 \uB514\uB809\uD1A0\uB9AC").action(async (options) => {
|
|
2405
|
-
await runCheck(options.dir);
|
|
2787
|
+
const summary = await runCheck(options.dir);
|
|
2788
|
+
if (summary.fail > 0) process.exitCode = 1;
|
|
2406
2789
|
});
|
|
2407
2790
|
}
|
|
2408
2791
|
|
|
@@ -2411,12 +2794,12 @@ import chalk8 from "chalk";
|
|
|
2411
2794
|
import path10 from "path";
|
|
2412
2795
|
|
|
2413
2796
|
// src/theme/theme-add.ts
|
|
2414
|
-
import { accessSync, constants, existsSync as
|
|
2797
|
+
import { accessSync, constants, existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
2415
2798
|
import path9 from "path";
|
|
2416
2799
|
var TOKENS_DEPENDENCY_RANGE = `^${MIN_BRAND_TOKENS_VERSION}`;
|
|
2417
2800
|
var THEME_PACKAGE = "@axis-ds/theme";
|
|
2418
2801
|
function readText(file) {
|
|
2419
|
-
return
|
|
2802
|
+
return existsSync3(file) ? readFileSync3(file, "utf8") : null;
|
|
2420
2803
|
}
|
|
2421
2804
|
function eolOf(text) {
|
|
2422
2805
|
return text.includes("\r\n") ? "\r\n" : "\n";
|
|
@@ -2492,12 +2875,12 @@ function isStylesheet(realPath) {
|
|
|
2492
2875
|
return path9.extname(realPath).toLowerCase() === ".css";
|
|
2493
2876
|
}
|
|
2494
2877
|
function detectInstallCommand(baseDir) {
|
|
2495
|
-
if (
|
|
2496
|
-
if (
|
|
2497
|
-
if (
|
|
2878
|
+
if (existsSync3(path9.join(baseDir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
2879
|
+
if (existsSync3(path9.join(baseDir, "yarn.lock"))) return "yarn install";
|
|
2880
|
+
if (existsSync3(path9.join(baseDir, "package-lock.json"))) return "npm install";
|
|
2498
2881
|
return "pnpm install";
|
|
2499
2882
|
}
|
|
2500
|
-
function
|
|
2883
|
+
function hasDependency2(pkg, name) {
|
|
2501
2884
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
2502
2885
|
const deps = pkg[field];
|
|
2503
2886
|
if (typeof deps === "object" && deps !== null && name in deps) {
|
|
@@ -2506,7 +2889,7 @@ function hasDependency(pkg, name) {
|
|
|
2506
2889
|
}
|
|
2507
2890
|
return void 0;
|
|
2508
2891
|
}
|
|
2509
|
-
function
|
|
2892
|
+
function isPlainObject2(value) {
|
|
2510
2893
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2511
2894
|
}
|
|
2512
2895
|
function planThemeAdd(baseDirInput, brand) {
|
|
@@ -2531,7 +2914,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2531
2914
|
let config;
|
|
2532
2915
|
try {
|
|
2533
2916
|
const parsed = JSON.parse(configText);
|
|
2534
|
-
if (!
|
|
2917
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2535
2918
|
config = parsed;
|
|
2536
2919
|
} catch (err) {
|
|
2537
2920
|
plan.errors.push({ kind: "invalid-config", message: err.message });
|
|
@@ -2543,7 +2926,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2543
2926
|
}
|
|
2544
2927
|
plan.tokens = resolveTokens(baseDir);
|
|
2545
2928
|
if (plan.tokens.status === "ok" && plan.tokens.indexPath) {
|
|
2546
|
-
const data = JSON.parse(
|
|
2929
|
+
const data = JSON.parse(readFileSync3(plan.tokens.indexPath, "utf8"));
|
|
2547
2930
|
const entries = Array.isArray(data.brands) ? data.brands : [];
|
|
2548
2931
|
const entry = entries.find((e) => e.name === brand);
|
|
2549
2932
|
if (!entry) {
|
|
@@ -2572,7 +2955,7 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2572
2955
|
plan.writes = [];
|
|
2573
2956
|
return plan;
|
|
2574
2957
|
}
|
|
2575
|
-
const before =
|
|
2958
|
+
const before = readFileSync3(location.path, "utf8");
|
|
2576
2959
|
const imported = findBrandImports(before);
|
|
2577
2960
|
const otherBrands = [...new Set(imported.filter((n) => n !== brand))];
|
|
2578
2961
|
if (imported.includes(brand)) {
|
|
@@ -2598,19 +2981,19 @@ function planThemeAdd(baseDirInput, brand) {
|
|
|
2598
2981
|
let pkg;
|
|
2599
2982
|
try {
|
|
2600
2983
|
const parsed = JSON.parse(pkgText);
|
|
2601
|
-
if (!
|
|
2984
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
2602
2985
|
pkg = parsed;
|
|
2603
2986
|
} catch (err) {
|
|
2604
2987
|
plan.errors.push({ kind: "invalid-package-json", message: err.message });
|
|
2605
2988
|
plan.writes = [];
|
|
2606
2989
|
return plan;
|
|
2607
2990
|
}
|
|
2608
|
-
const themeMissing =
|
|
2609
|
-
const declared =
|
|
2991
|
+
const themeMissing = hasDependency2(pkg, THEME_PACKAGE) === void 0;
|
|
2992
|
+
const declared = hasDependency2(pkg, TOKENS_PACKAGE);
|
|
2610
2993
|
if (declared !== void 0) {
|
|
2611
2994
|
plan.dependency = { action: "present", declaredRange: declared, upgrade, themeMissing };
|
|
2612
2995
|
} else {
|
|
2613
|
-
const deps =
|
|
2996
|
+
const deps = isPlainObject2(pkg.dependencies) ? { ...pkg.dependencies } : {};
|
|
2614
2997
|
deps[TOKENS_PACKAGE] = TOKENS_DEPENDENCY_RANGE;
|
|
2615
2998
|
const next = { ...pkg, dependencies: deps };
|
|
2616
2999
|
plan.dependency = { action: "add", upgrade, themeMissing };
|
|
@@ -2990,7 +3373,7 @@ import chalk10 from "chalk";
|
|
|
2990
3373
|
import prompts2 from "prompts";
|
|
2991
3374
|
|
|
2992
3375
|
// src/init/init.ts
|
|
2993
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as
|
|
3376
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
2994
3377
|
import path11 from "path";
|
|
2995
3378
|
import chalk9 from "chalk";
|
|
2996
3379
|
import fs10 from "fs-extra";
|
|
@@ -2999,98 +3382,6 @@ var TAILWIND_MERGE_RANGES = {
|
|
|
2999
3382
|
tailwind4: "^3.4.0",
|
|
3000
3383
|
tailwind3: "^2.6.0"
|
|
3001
3384
|
};
|
|
3002
|
-
var VERSION = String.raw`v?(\d+)(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
3003
|
-
function versionParts(token) {
|
|
3004
|
-
const m = new RegExp(`^${VERSION}$`).exec(token);
|
|
3005
|
-
if (!m) return void 0;
|
|
3006
|
-
if (/^v?0\.0\.0-/.test(token)) return void 0;
|
|
3007
|
-
return { major: Number(m[1]), minor: m[2], patch: m[3] };
|
|
3008
|
-
}
|
|
3009
|
-
var isWild = (part) => part === void 0 || /^[xX*]$/.test(part);
|
|
3010
|
-
function comparatorBounds(op, v) {
|
|
3011
|
-
switch (op) {
|
|
3012
|
-
case ">=":
|
|
3013
|
-
return { lower: v.major };
|
|
3014
|
-
case ">":
|
|
3015
|
-
return { lower: isWild(v.minor) ? v.major + 1 : v.major };
|
|
3016
|
-
case "<=":
|
|
3017
|
-
return { upper: v.major };
|
|
3018
|
-
case "<": {
|
|
3019
|
-
const zeroOrWild = (part) => isWild(part) || Number(part) === 0;
|
|
3020
|
-
return { upper: zeroOrWild(v.minor) && zeroOrWild(v.patch) ? v.major - 1 : v.major };
|
|
3021
|
-
}
|
|
3022
|
-
default:
|
|
3023
|
-
return { lower: v.major, upper: v.major };
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
function tailwindMajorBounds(range) {
|
|
3027
|
-
const r = range.trim();
|
|
3028
|
-
if (r === "" || r.includes("||")) return void 0;
|
|
3029
|
-
const simple = new RegExp(`^(?:\\^|~|=)?\\s*(${VERSION})$`).exec(r);
|
|
3030
|
-
if (simple) {
|
|
3031
|
-
const v = versionParts(simple[1]);
|
|
3032
|
-
return v ? { lower: v.major, upper: v.major } : void 0;
|
|
3033
|
-
}
|
|
3034
|
-
const hyphen = new RegExp(`^(${VERSION})\\s+-\\s+(${VERSION})$`).exec(r);
|
|
3035
|
-
if (hyphen) {
|
|
3036
|
-
const tokens2 = r.split(/\s+-\s+/);
|
|
3037
|
-
const a = versionParts(tokens2[0]);
|
|
3038
|
-
const b = versionParts(tokens2[1]);
|
|
3039
|
-
return a && b && a.major <= b.major ? { lower: a.major, upper: b.major } : void 0;
|
|
3040
|
-
}
|
|
3041
|
-
const tokens = r.replace(/(>=|<=|>|<|=)\s+/g, "$1").split(/\s+/);
|
|
3042
|
-
const lowers = [];
|
|
3043
|
-
const uppers = [];
|
|
3044
|
-
for (const t of tokens) {
|
|
3045
|
-
const c = /^(>=|<=|>|<|=)(.+)$/.exec(t);
|
|
3046
|
-
if (!c) return void 0;
|
|
3047
|
-
const v = versionParts(c[2]);
|
|
3048
|
-
if (v === void 0) return void 0;
|
|
3049
|
-
const b = comparatorBounds(c[1], v);
|
|
3050
|
-
if (b.lower !== void 0) lowers.push(b.lower);
|
|
3051
|
-
if (b.upper !== void 0) uppers.push(b.upper);
|
|
3052
|
-
}
|
|
3053
|
-
if (lowers.length === 0) return void 0;
|
|
3054
|
-
const lower = Math.max(...lowers);
|
|
3055
|
-
const upper = uppers.length > 0 ? Math.min(...uppers) : void 0;
|
|
3056
|
-
if (upper !== void 0 && upper < lower) return void 0;
|
|
3057
|
-
return upper !== void 0 ? { lower, upper } : { lower };
|
|
3058
|
-
}
|
|
3059
|
-
function majorWithin(major, bounds) {
|
|
3060
|
-
return major >= bounds.lower && (bounds.upper === void 0 || major <= bounds.upper);
|
|
3061
|
-
}
|
|
3062
|
-
function majorFromVersion(version) {
|
|
3063
|
-
if (typeof version !== "string") return void 0;
|
|
3064
|
-
const v = version.trim();
|
|
3065
|
-
const m = /^v?(\d+)\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?$/.exec(v);
|
|
3066
|
-
if (!m || /^v?0\.0\.0-/.test(v)) return void 0;
|
|
3067
|
-
return Number(m[1]);
|
|
3068
|
-
}
|
|
3069
|
-
function detectTailwind(baseDirInput, pkg) {
|
|
3070
|
-
const baseDir = path11.resolve(baseDirInput);
|
|
3071
|
-
const installedFile = path11.join(baseDir, "node_modules", "tailwindcss", "package.json");
|
|
3072
|
-
const declared = pkg ? hasDependency(pkg, "tailwindcss") : void 0;
|
|
3073
|
-
const bounds = declared !== void 0 ? tailwindMajorBounds(declared) : void 0;
|
|
3074
|
-
const declaredMajor = bounds?.lower;
|
|
3075
|
-
try {
|
|
3076
|
-
const installed = JSON.parse(readFileSync3(installedFile, "utf8"));
|
|
3077
|
-
const version = isPlainObject(installed) ? installed.version : void 0;
|
|
3078
|
-
const major = majorFromVersion(version);
|
|
3079
|
-
if (major !== void 0) {
|
|
3080
|
-
const found = { major, source: "installed", value: String(version) };
|
|
3081
|
-
if (declared !== void 0 && bounds !== void 0 && !majorWithin(major, bounds)) {
|
|
3082
|
-
found.mismatch = { declared, declaredMajor: bounds.lower };
|
|
3083
|
-
}
|
|
3084
|
-
return found;
|
|
3085
|
-
}
|
|
3086
|
-
} catch {
|
|
3087
|
-
}
|
|
3088
|
-
if (declared !== void 0) {
|
|
3089
|
-
if (declaredMajor !== void 0) return { major: declaredMajor, source: "declared", value: declared };
|
|
3090
|
-
return { source: "none", value: declared };
|
|
3091
|
-
}
|
|
3092
|
-
return { source: "none" };
|
|
3093
|
-
}
|
|
3094
3385
|
function selectUtilsDependencies(tailwind) {
|
|
3095
3386
|
return {
|
|
3096
3387
|
clsx: CLSX_RANGE,
|
|
@@ -3132,6 +3423,70 @@ var INIT_DEFAULTS = {
|
|
|
3132
3423
|
globalCss: "./src/app/globals.css"
|
|
3133
3424
|
};
|
|
3134
3425
|
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
3426
|
+
function isTailwind4(tailwind) {
|
|
3427
|
+
return tailwind.major !== void 0 && tailwind.major >= 4;
|
|
3428
|
+
}
|
|
3429
|
+
var TAILWIND4_TOKENS_VERSION = TAILWIND4_MIN_AXIS_VERSION;
|
|
3430
|
+
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.";
|
|
3431
|
+
function readPackageJsonSafe(baseDir) {
|
|
3432
|
+
try {
|
|
3433
|
+
const text = readFileSync4(path11.join(baseDir, "package.json"), "utf8");
|
|
3434
|
+
const parsed = JSON.parse(text.startsWith(BOM) ? text.slice(1) : text);
|
|
3435
|
+
return isPlainObject2(parsed) ? parsed : void 0;
|
|
3436
|
+
} catch {
|
|
3437
|
+
return void 0;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
3441
|
+
const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pkg !== void 0 && hasDependency2(pkg, name) !== void 0);
|
|
3442
|
+
const lines = [
|
|
3443
|
+
`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).`,
|
|
3444
|
+
' @import "tailwindcss";',
|
|
3445
|
+
` ${TOKENS_TAILWIND4_IMPORT_LINE}`,
|
|
3446
|
+
...used.map((name) => ` ${componentTailwindImportLine(name)}`)
|
|
3447
|
+
];
|
|
3448
|
+
if (used.length === 0) {
|
|
3449
|
+
lines.push(
|
|
3450
|
+
` npm \uD328\uD0A4\uC9C0 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC4F0\uBA74 \uADF8 \uD328\uD0A4\uC9C0\uC758 tailwind.css \uB3C4 \uB123\uC73C\uC138\uC694(\uC608: @import "${TAILWIND4_COMPONENT_PACKAGES[0]}/tailwind.css";).`
|
|
3451
|
+
);
|
|
3452
|
+
}
|
|
3453
|
+
lines.push(TAILWIND4_CONFLICT_LINE);
|
|
3454
|
+
if (pkg === void 0 || hasDependency2(pkg, TOKENS_PACKAGE) === void 0) {
|
|
3455
|
+
const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
|
|
3456
|
+
lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58: ${add}`);
|
|
3457
|
+
}
|
|
3458
|
+
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
3459
|
+
const unknown = versions.filter((v) => v.status === "unknown");
|
|
3460
|
+
const declaredOf = (list) => list.map(axisPackageVersionLabel).join(" \xB7 ");
|
|
3461
|
+
const upgradeOf = (list) => addCommandFor(installCommand, Object.fromEntries(list.map((b) => [b.name, `^${TAILWIND4_MIN_AXIS_VERSION}`])));
|
|
3462
|
+
const belowDeclared = versions.filter((v) => v.status === "below" && v.source === "declared");
|
|
3463
|
+
const readableRange = (v) => rangeLowerAtLeast(v.range, TAILWIND4_MIN_AXIS_VERSION) !== void 0;
|
|
3464
|
+
const installedBelow = versions.filter((v) => v.status === "below" && v.source === "installed");
|
|
3465
|
+
const belowInstalled = installedBelow.filter(readableRange);
|
|
3466
|
+
const belowInstalledOpaque = installedBelow.filter((v) => !readableRange(v));
|
|
3467
|
+
const installedOf = (list) => list.map((v) => `${v.name} ${v.installed}, \uC120\uC5B8 ${v.range}`).join(" \xB7 ");
|
|
3468
|
+
if (belowDeclared.length > 0) {
|
|
3469
|
+
lines.push(
|
|
3470
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(belowDeclared)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowDeclared)}`
|
|
3471
|
+
);
|
|
3472
|
+
}
|
|
3473
|
+
if (belowInstalled.length > 0) {
|
|
3474
|
+
lines.push(
|
|
3475
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalled)})\uC744 \uC62C\uB9AC\uC138\uC694: ${upgradeOf(belowInstalled)}`
|
|
3476
|
+
);
|
|
3477
|
+
}
|
|
3478
|
+
if (belowInstalledOpaque.length > 0) {
|
|
3479
|
+
lines.push(
|
|
3480
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uBCF8(${installedOf(belowInstalledOpaque)})\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uBBF8\uB9CC\uC785\uB2C8\uB2E4. \uC120\uC5B8\uC774 \uAC00\uB9AC\uD0A4\uB294 \uBC84\uC804\uC744 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 \uB2E4\uC2DC \uC124\uCE58\uD558\uC138\uC694(\uC120\uC5B8\uC740 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4).`
|
|
3481
|
+
);
|
|
3482
|
+
}
|
|
3483
|
+
if (unknown.length > 0) {
|
|
3484
|
+
lines.push(
|
|
3485
|
+
` ! Tailwind 4 \uC9C4\uC785\uC810\uC740 ${TAILWIND4_MIN_AXIS_VERSION} \uBD80\uD130 \uC788\uC2B5\uB2C8\uB2E4. \uC120\uC5B8(${declaredOf(unknown)})\uC73C\uB85C\uB294 \uBC84\uC804\uC744 \uD310\uC815\uD560 \uC218 \uC5C6\uC73C\uB2C8 \uC124\uCE58\uB41C \uBC84\uC804\uC774 ${TAILWIND4_MIN_AXIS_VERSION} \uC774\uC0C1\uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
|
|
3486
|
+
);
|
|
3487
|
+
}
|
|
3488
|
+
return lines;
|
|
3489
|
+
}
|
|
3135
3490
|
var BOM = "\uFEFF";
|
|
3136
3491
|
function addCommandFor(installCommand, deps) {
|
|
3137
3492
|
const specs = Object.entries(deps).map(([name, range]) => `"${name}@${range}"`).join(" ");
|
|
@@ -3154,7 +3509,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3154
3509
|
addCommand: addCommandFor(installCommand, ranges0)
|
|
3155
3510
|
};
|
|
3156
3511
|
const pkgFile = path11.join(baseDir, "package.json");
|
|
3157
|
-
if (!
|
|
3512
|
+
if (!existsSync4(pkgFile)) return plan;
|
|
3158
3513
|
const unwritable = (reason) => ({ ...plan, action: "unwritable", reason });
|
|
3159
3514
|
let where;
|
|
3160
3515
|
try {
|
|
@@ -3165,7 +3520,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3165
3520
|
if (!where.inside) return unwritable(`\uC2E4\uC81C \uC704\uCE58(${where.realPath})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC \uBC16\uC785\uB2C8\uB2E4`);
|
|
3166
3521
|
let text;
|
|
3167
3522
|
try {
|
|
3168
|
-
text =
|
|
3523
|
+
text = readFileSync4(pkgFile, "utf8");
|
|
3169
3524
|
} catch (err) {
|
|
3170
3525
|
return unwritable(err.message);
|
|
3171
3526
|
}
|
|
@@ -3174,7 +3529,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3174
3529
|
let pkg;
|
|
3175
3530
|
try {
|
|
3176
3531
|
const parsed = JSON.parse(body);
|
|
3177
|
-
if (!
|
|
3532
|
+
if (!isPlainObject2(parsed)) throw new Error("\uCD5C\uC0C1\uC704\uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3178
3533
|
pkg = parsed;
|
|
3179
3534
|
} catch (err) {
|
|
3180
3535
|
return unwritable(`JSON \uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}`);
|
|
@@ -3184,14 +3539,14 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
3184
3539
|
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
3185
3540
|
const missing = {};
|
|
3186
3541
|
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
3187
|
-
const declared =
|
|
3542
|
+
const declared = hasDependency2(pkg, name);
|
|
3188
3543
|
if (declared !== void 0) plan.present.push({ name, range: declared });
|
|
3189
3544
|
else missing[name] = range;
|
|
3190
3545
|
}
|
|
3191
3546
|
plan.added = Object.keys(missing);
|
|
3192
3547
|
plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
|
|
3193
3548
|
if (plan.added.length === 0) return { ...plan, action: "present" };
|
|
3194
|
-
if (pkg.dependencies !== void 0 && !
|
|
3549
|
+
if (pkg.dependencies !== void 0 && !isPlainObject2(pkg.dependencies)) {
|
|
3195
3550
|
return unwritable("dependencies \uAC00 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
3196
3551
|
}
|
|
3197
3552
|
try {
|
|
@@ -3208,7 +3563,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
3208
3563
|
const w = plan.write;
|
|
3209
3564
|
if (plan.action !== "add" || !w) return false;
|
|
3210
3565
|
const baseDir = path11.resolve(baseDirInput);
|
|
3211
|
-
const current =
|
|
3566
|
+
const current = existsSync4(w.file) ? readFileSync4(w.file, "utf8") : null;
|
|
3212
3567
|
if (current !== w.before) {
|
|
3213
3568
|
throw new Error(`${w.file} \uC774 \uACC4\uD68D \uB4A4\uC5D0 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`);
|
|
3214
3569
|
}
|
|
@@ -3224,7 +3579,7 @@ function applyUtilsDependencies(baseDirInput, plan, writeFile = defaultWriteFile
|
|
|
3224
3579
|
let restored;
|
|
3225
3580
|
try {
|
|
3226
3581
|
writeFile(w.file, w.before);
|
|
3227
|
-
if (
|
|
3582
|
+
if (readFileSync4(w.file, "utf8") !== w.before) throw new Error("\uB418\uB3CC\uB9B0 \uB0B4\uC6A9\uC774 \uC6D0\uB798 \uB0B4\uC6A9\uACFC \uB2E4\uB985\uB2C8\uB2E4");
|
|
3228
3583
|
restored = "\uC6D0\uB798 \uB0B4\uC6A9\uC73C\uB85C \uB418\uB3CC\uB838\uC2B5\uB2C8\uB2E4";
|
|
3229
3584
|
} catch (restoreErr) {
|
|
3230
3585
|
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`;
|
|
@@ -3261,10 +3616,12 @@ function reportDependencies(plan, log) {
|
|
|
3261
3616
|
}
|
|
3262
3617
|
async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
3263
3618
|
const baseDir = path11.resolve(baseDirInput);
|
|
3619
|
+
const plan = planUtilsDependencies(baseDir);
|
|
3620
|
+
const tailwind4 = isTailwind4(plan.tailwind);
|
|
3264
3621
|
const axisConfig = createInitConfig(
|
|
3265
3622
|
{
|
|
3266
3623
|
componentsDir: answers.componentsDir,
|
|
3267
|
-
tailwindConfig: answers.tailwindConfig,
|
|
3624
|
+
tailwindConfig: tailwind4 ? void 0 : answers.tailwindConfig,
|
|
3268
3625
|
globalCss: answers.globalCss
|
|
3269
3626
|
},
|
|
3270
3627
|
registryUrl
|
|
@@ -3275,7 +3632,6 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
3275
3632
|
await fs10.ensureDir(path11.dirname(utilsPath));
|
|
3276
3633
|
await fs10.writeFile(utilsPath, UTILS_TS_CONTENT);
|
|
3277
3634
|
log(chalk9.green("\u2713 utils.ts \uC0DD\uC131 \uC644\uB8CC"));
|
|
3278
|
-
const plan = planUtilsDependencies(baseDir);
|
|
3279
3635
|
try {
|
|
3280
3636
|
applyUtilsDependencies(baseDir, plan);
|
|
3281
3637
|
} catch (err) {
|
|
@@ -3286,6 +3642,17 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
3286
3642
|
return;
|
|
3287
3643
|
}
|
|
3288
3644
|
reportDependencies(plan, log);
|
|
3645
|
+
if (tailwind4) {
|
|
3646
|
+
const [head, ...rest] = tailwind4GuideLines(
|
|
3647
|
+
readPackageJsonSafe(baseDir),
|
|
3648
|
+
plan.installCommand,
|
|
3649
|
+
answers.globalCss,
|
|
3650
|
+
baseDir
|
|
3651
|
+
);
|
|
3652
|
+
log(chalk9.blue(`
|
|
3653
|
+
${head}`));
|
|
3654
|
+
for (const line of rest) log(line.startsWith(" !") ? chalk9.yellow(line) : chalk9.cyan(line));
|
|
3655
|
+
}
|
|
3289
3656
|
log(chalk9.blue("\n\uCD08\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C \uB2E4\uC74C \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD558\uC138\uC694:"));
|
|
3290
3657
|
log(chalk9.cyan(` ${INIT_NEXT_STEP_COMMAND}
|
|
3291
3658
|
`));
|
|
@@ -3295,6 +3662,7 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log) {
|
|
|
3295
3662
|
function registerInitCommand(program2, registryUrl) {
|
|
3296
3663
|
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) => {
|
|
3297
3664
|
console.log(chalk10.blue("\n\u{1F3A8} AXIS Design System \uCD08\uAE30\uD654\n"));
|
|
3665
|
+
const tailwind4 = isTailwind4(planUtilsDependencies(process.cwd()).tailwind);
|
|
3298
3666
|
const config = options.yes ? { ...INIT_DEFAULTS } : await prompts2([
|
|
3299
3667
|
{
|
|
3300
3668
|
type: "text",
|
|
@@ -3303,7 +3671,7 @@ function registerInitCommand(program2, registryUrl) {
|
|
|
3303
3671
|
initial: INIT_DEFAULTS.componentsDir
|
|
3304
3672
|
},
|
|
3305
3673
|
{
|
|
3306
|
-
type: "text",
|
|
3674
|
+
type: tailwind4 ? null : "text",
|
|
3307
3675
|
name: "tailwindConfig",
|
|
3308
3676
|
message: "Tailwind \uC124\uC815 \uD30C\uC77C:",
|
|
3309
3677
|
initial: INIT_DEFAULTS.tailwindConfig
|