@axis-ds/cli 1.7.9 → 1.7.10
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 +5 -2
- package/dist/index.js +82 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,17 +38,20 @@ axis list
|
|
|
38
38
|
- 이미 있는 파일: 내용이 같으면 건너뜀, 다르면 대화형에서는 묻고, `-y` 는 건너뛰며 목록을 알려 주고, `--overwrite` 만 덮어씁니다. 터미널이 아닌 곳(CI · 파이프)에서는 묻지 않고 `-y` 와 같이 건너뜁니다. 출력은 새로 만든 파일 `+`, 덮어쓴 파일 `~ … (덮어씀)`, 같은 내용이라 건너뛴 파일 `=` 입니다. `--overwrite` 는 `registryDependencies` 로 끌려온 파일(예: 고친 `utils.ts`)도 덮어쓰니 출력의 `~` 를 확인하세요.
|
|
39
39
|
- 쓰기 전에 실제 경로(심볼릭 링크를 따라간 위치)가 프로젝트 디렉터리 안인지 확인하고, 밖이면 쓰지 않습니다. 기존 대상 파일이 심볼릭 링크여도 내용이 같거나 `-y` 로 건너뛰면 쓰지 않으므로 건너뜁니다(예: 앱 디렉터리 안의 공용 `utils.ts`, 또는 모노레포의 다른 패키지처럼 프로젝트 밖의 `utils.ts` 에 링크해 둔 경우). 밖을 가리키는 링크는 `= <경로> (같은 내용이라 건너뜀, 링크 대상이 프로젝트 밖)` 처럼 그 사실을 함께 알립니다(rc 0). 상위 디렉터리(`componentsDir` 등)가 밖을 가리키는 링크면 경로 이탈로 거부합니다. 설치 대상이 디렉터리(또는 디렉터리를 가리키는 링크)이거나 기존 파일을 읽지 못하면 이유를 알리고 아무것도 쓰지 않고 rc 1 입니다. 링크를 실제로 덮어써야 할 때(`--overwrite` · 대화형 예, 링크가 프로젝트 안 · 밖 어디를 가리켜도)만 아무것도 쓰지 않고 rc 1 로 알립니다. 덮어써야 하는 일반 파일이 다른 경로와 하드링크로 이어져 있으면(링크 수 2 이상) 쓰기 전에 그 경로와 이유를 알리고 아무것도 쓰지 않은 채 rc 1 로 끝내며, 쓰기 직전에도 연 파일로 한 번 더 확인합니다(내용이 같거나 `-y` 로 건너뛰는 파일은 영향 없음). 덮어쓰기를 묻는 동안 새로 설치할 파일과 같은 이름의 파일이 생기면 그 파일을 덮어쓰지 않고 경로를 알린 뒤 rc 1 로 끝냅니다. 검사와 쓰기 사이의 동시 경합은 사후 검사로 감지합니다: 쓴 파일의 실제 위치가 프로젝트 밖이면 그 파일을 지우지 않고 경로를 알린 뒤 rc 1 로 끝냅니다(그 위치의 파일은 사용자 것일 수 있어 CLI 가 지우지 않음).
|
|
40
40
|
- `package.json` 에 없는 의존성은 lockfile 에 맞춘 설치 명령으로 안내만 합니다(설치는 하지 않음). 안내 명령은 복사해 실행하는 셸 명령이라, 레지스트리의 `dependencies` 값이 패키지 이름(선택적 `@범위`) 형태가 아니면(`;` · `$` · 따옴표 등) 그 원격 응답을 형식 불일치로 보고 CLI 포함본을 씁니다.
|
|
41
|
+
- 앱 `package.json` 다음 워크스페이스 루트 `package.json` 의 선언도 「있음」으로 봅니다. 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서는 루트 선언을 「있음」으로 보지 않고 미선언과 같게 안내 명령에 넣습니다(앱이 루트에만 선언한 패키지를 해석하지 못해 컴포넌트의 import 가 실패함, MCP `axis.install_component` 도 같음).
|
|
41
42
|
- `axis.config.json` 의 `componentsDir` · `agenticDir` 에 역슬래시(`src\components\ui`)를 적어도 `/` 로 읽습니다.
|
|
42
43
|
- `axis list` 는 레지스트리 index 의 Core UI · Agentic UI 항목을 보여 줍니다(`--category ui|agentic`).
|
|
43
44
|
|
|
44
45
|
## 프로젝트 초기화 (`axis init`)
|
|
45
46
|
|
|
46
47
|
- `axis.config.json` 과 `cn()` 을 담은 `utils.ts` 를 만들고, `clsx` · `tailwind-merge` 가 `package.json` 에 없으면 `dependencies` 에 더합니다. 설치는 실행하지 않고 명령만 안내합니다.
|
|
48
|
+
- 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서는 워크스페이스 루트 선언을 「이미 있음」으로 보지 않습니다(`axis check` 의 dependencies 항목과 같은 경계). 루트에만 선언한 `clsx` · `tailwind-merge` 는 앱이 해석하지 못해 `utils.ts` 의 import 가 실패하므로, 미선언과 같은 범위로 앱 `package.json` 에 더하고 「clsx, tailwind-merge 는 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다」를 함께 냅니다(종전에는 「이미 있습니다」로 쓰지 않았음). `tailwindcss` 가 루트에만 있으면 「! 필수 의존성 tailwindcss 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언하세요」 한 줄을 냅니다(`tailwindcss` 는 쓰지 않고, Tailwind 3 · 4 분기는 루트 선언으로 정함). PnP 가 아닌 워크스페이스(pnpm · npm · yarn node-modules)는 종전대로 루트 선언을 인정합니다. 종료 코드는 그대로입니다.
|
|
47
49
|
- `axis.config.json` 의 `registry` 는 기본값(`https://axis-design-system.pages.dev/r`)이거나, 이미 있던 config 의 값입니다. 종전 기본값 `https://axis.minu.best/r` 는 Cloudflare 403 이라 바꿨습니다. add · list 는 그 값을 새 기본값으로 바꿔 읽으며 한 줄 알립니다(위 「컴포넌트 추가」, 파일은 고치지 않음). init 을 다시 실행하면 그 값을 새 기본값으로 바꿔 쓰고 「registry 를 새 기본 주소로 갱신」으로 알립니다. 사용자가 지정한 다른 값은 init 도 그대로 둡니다.
|
|
48
50
|
- `utils.ts` 가 이미 있으면 같은 내용이면 「유지(이미 같은 내용)」(다시 쓰지 않음), 다르면 init 의 utils 로 덮어쓰고 「덮어씀」으로 알립니다(터미널이 아닌 곳에서 `-y` 없이 실행하면 덮어쓰지 않고 rc 1, 아래 「터미널이 아닌 곳에서 실행」). `utils.ts` 쓰기는 `axis add` 와 같은 규칙입니다: 심볼릭 링크면 같은 내용일 때 「유지(이미 같은 내용, 링크)」로 두고, 내용이 다른 링크(프로젝트 안 · 밖) · 깨진 링크 · 디렉터리 · 읽을 수 없는 파일 · 다른 경로와 하드링크로 이어진 파일은 쓰지 않고 그 사실을 알린 뒤 rc 1 입니다. 이 판정은 쓰기 전에 하므로 이때는 `axis.config.json` · `package.json` 도 쓰지 않습니다. 다른 경로와 하드링크로 이어진 `axis.config.json` 을 다시 써야 할 때도 같습니다.
|
|
49
51
|
- 경로 기본값(`-y` 값 · 대화형 초기값)은 실제 프로젝트를 보고 정합니다(1.6.0 부터). `componentsDir` 는 `src/` 가 있으면 `./src/components/ui`, 없으면 `./components/ui` 이고 `src/` 를 새로 만들지 않습니다. `globalCss` 는 `app/globals.css` · `src/app/globals.css` · `styles/globals.css` · `src/styles/globals.css` · `globals.css` 가운데 실제로 있는 첫 파일, `tailwindConfig` 는 있는 `tailwind.config.{ts,js,mjs,cjs}` 가운데 첫 파일입니다. 찾지 못하면 기본값을 기록하고 그 사실을 한 줄 알립니다. Tailwind 4 안내 제목도 이 경로를 씁니다.
|
|
50
52
|
- config 가 이미 있으면 출력이 「생성 완료」가 아니라 사실대로 「유지(이미 같은 내용)」 또는 「갱신」입니다. 갱신은 init 이 다루는 키(`$schema` · `componentsDir` · `tailwindConfig` · `globalCss` · `registry`)만 바꾸고, 그 밖의 키(`brand` · `monetDir` · `template` · `agenticDir` 등)는 값과 순서를 그대로 둡니다(1.6.0 부터, 이전에는 빠졌음). 들여쓰기도 기존 파일을 따릅니다. 기존 `componentsDir` 는 그대로 두고, `globalCss` · `tailwindConfig` 는 가리키는 파일이 있으면 그대로, 없으면 찾은 파일로 바꾸고 알립니다(찾지 못하면 그대로 두고 알림). Tailwind 4 이상이면 `tailwindConfig` 를 지우고 알립니다. `registry` 가 종전 기본값이면 위처럼 새 기본값으로 바꿉니다. `AXIS_REGISTRY_URL` 은 config 에 기록하지 않고 add · list 를 실행할 때만 우선합니다.
|
|
51
53
|
- 애니메이션 플러그인(`tailwindcss-animate` · `tw-animate-css`)이 `package.json` 에 없으면, Dialog · Select 등의 열고 닫는 애니메이션에 필요하다는 안내 한 줄을 냅니다(Tailwind 3 은 plugins, Tailwind 4 는 `@import "tw-animate-css";`). 1.7.5 부터 선언은 앱 다음 워크스페이스 루트 `package.json` 까지 보고, 이름은 `axis check` 와 같습니다(Tailwind 3 은 `tailwindcss-animate` 만, Tailwind 4 는 `tw-animate-css` · `tailwindcss-animate` 둘 다). 선언과 설치본이 모두 있으면 안내하지 않고, 선언만 있고 설치본이 없으면 「선언돼 있지만 설치되지 않았습니다」와 설치 명령 · 설정 줄을 냅니다(1.7.8 다음 patch 부터 npm 워크스페이스 루트 선언이면 설치 명령이 「워크스페이스 루트에서 npm install」, `clsx` · `tailwind-merge` 가 루트에 있을 때의 「설치는 실행하지 않았습니다. 설치: …」 줄도 같음). Yarn PnP 는 루트 선언을 인정하지 않고 앱 선언이 있으면 안내하지 않습니다.
|
|
54
|
+
- 1.7.9 다음 patch 부터(WI-0099) Tailwind 4 는 `axis check` 의 animation 항목과 같은 전역 CSS(`globalCss` 다음 후보, 상대 `@import` 하위 파일 포함)를 먼저 읽고 같은 판정을 씁니다. CSS 의 줄마다 그 줄이 가리키는 패키지(`@import "tw-animate-css"` → `tw-animate-css`, `@plugin "tailwindcss-animate"` → `tailwindcss-animate`)가 선언 · 설치돼 있으면 안내하지 않고, 아니면 「<파일>의 애니메이션 줄을 쓸 수 없습니다(<check 와 같은 사유>)」와 설치 명령을 냅니다. 다른 이름의 패키지만 설치돼 있으면(예: 줄은 `tw-animate-css` 인데 `tailwindcss-animate` 만 설치) 줄을 그 패키지로 바꾸는 대안을 함께 냅니다(종전에는 안내하지 않았고 check 만 WARN). CSS 에 줄이 없는데 패키지가 설치돼 있으면 「설치돼 있지만 <파일>에 애니메이션 줄이 없습니다」로 줄을 넣으라고 안내합니다(종전 침묵). 전역 CSS 파일이 없거나 Tailwind 3 이면 위 종전 판정 그대로입니다. 종료 코드와 쓰는 파일은 바뀌지 않습니다. Yarn PnP 에서 줄의 패키지가 워크스페이스 루트에만 선언된 경우는 WI-0099 에서 종전 그대로 두었고, WI-0095 부터 같은 판정으로 「…(tw-animate-css 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다). 설치하세요: yarn add tw-animate-css」입니다.
|
|
52
55
|
- `tailwind-merge` 범위와 아래 안내는 프로젝트의 Tailwind 버전(설치본, 없으면 `package.json` 선언)으로 정합니다. 판정하지 못하면 Tailwind 3 으로 봅니다.
|
|
53
56
|
- Tailwind 4 이상이면 전역 CSS 에 넣을 줄을 안내합니다. CSS 파일은 고치지 않습니다.
|
|
54
57
|
|
|
@@ -58,9 +61,9 @@ axis list
|
|
|
58
61
|
@import "@axis-ds/ui-react/tailwind.css"; /* npm 패키지 컴포넌트를 쓸 때, agentic-ui 도 같은 방식 */
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
- 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다).
|
|
64
|
+
- 컴포넌트 패키지 줄은 `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 만큼 냅니다. 선언이 없으면 예시 한 줄만 냅니다(`axis add` 로 복사한 컴포넌트는 프로젝트 소스라 따로 넣을 필요가 없습니다). 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서 워크스페이스 루트에만 선언한 패키지는 줄 대신 `axis check` 와 같은 「! <패키지> 가 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언한 뒤 @import "<패키지>/tailwind.css";」를 냅니다(종전에는 줄을 그대로 냈고, 넣으면 빌드가 `Can't resolve`).
|
|
62
65
|
- 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」와 같은 내용).
|
|
63
|
-
- `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다.
|
|
66
|
+
- `@axis-ds/tokens` 가 `package.json` 에 없으면 lockfile 에 맞춘 설치 명령(예: `pnpm add "@axis-ds/tokens@^1.4.0"`)을 안내합니다. 토큰 진입점은 1.4.0 부터 있습니다. 1.7.9 다음 patch 부터(WI-0095) Yarn Plug'n'Play 에서 루트에만 선언했으면 같은 명령에 사유를 붙여 「@axis-ds/tokens 설치(워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다): yarn add …」입니다(종전에는 안내하지 않았음).
|
|
64
67
|
- `package.json` 에 선언된 `@axis-ds/tokens` · `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 버전 조건(`axis check` 와 같은 함수 · 같은 판정). 설치본을 먼저 보고, 없으면 선언 범위를 봅니다:
|
|
65
68
|
- 설치본: `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 이상으로 올린 뒤 다시 설치하라는 줄만 냅니다(선언을 덮어쓰지 않음).
|
|
66
69
|
- 설치본이 없을 때 선언 범위의 하한이 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`)는 가장 높은 하한을 봅니다.
|
package/dist/index.js
CHANGED
|
@@ -2137,9 +2137,6 @@ import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep }
|
|
|
2137
2137
|
function declaredRange(baseDir, pkg, name) {
|
|
2138
2138
|
return declaredDependency(baseDir, pkg, name)?.range;
|
|
2139
2139
|
}
|
|
2140
|
-
function declaredRangeForCheck(baseDir, pkg, name) {
|
|
2141
|
-
return declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true })?.range;
|
|
2142
|
-
}
|
|
2143
2140
|
function isPlainObject3(value) {
|
|
2144
2141
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2145
2142
|
}
|
|
@@ -3408,6 +3405,33 @@ function componentsUseAnimation(baseDir, componentsDir) {
|
|
|
3408
3405
|
}
|
|
3409
3406
|
return false;
|
|
3410
3407
|
}
|
|
3408
|
+
function animationPluginProblem(baseDir, pkg, name, pnp) {
|
|
3409
|
+
const declared = declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true });
|
|
3410
|
+
if (declared === void 0) {
|
|
3411
|
+
return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? { name, kind: "pnpRootOnly", why: `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` } : { name, kind: "undeclared", why: `${name} \uC120\uC5B8 \uC5C6\uC74C` };
|
|
3412
|
+
}
|
|
3413
|
+
if (!pnp && findInstalledPackage(baseDir, name) === void 0) {
|
|
3414
|
+
return { name, kind: "notInstalled", why: `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`, root: declared.source === "root" };
|
|
3415
|
+
}
|
|
3416
|
+
return void 0;
|
|
3417
|
+
}
|
|
3418
|
+
function inspectTailwind4Animation(baseDirInput, pkgInput) {
|
|
3419
|
+
const baseDir = resolveBaseDir(baseDirInput);
|
|
3420
|
+
const pkg = pkgInput ?? readPackageJson(baseDir);
|
|
3421
|
+
const pnp = isPnpProject(baseDir);
|
|
3422
|
+
const selection = selectCheckGlobalCss(baseDir);
|
|
3423
|
+
const note = globalCssSelectionNote(selection);
|
|
3424
|
+
const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
|
|
3425
|
+
const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
|
|
3426
|
+
const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
|
|
3427
|
+
const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
|
|
3428
|
+
const lines = [];
|
|
3429
|
+
if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
|
|
3430
|
+
if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
|
|
3431
|
+
const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
|
|
3432
|
+
const problems = lines.map((name) => animationPluginProblem(baseDir, pkg, name, pnp)).filter((p) => p !== void 0);
|
|
3433
|
+
return { selection, file: selection.rel, note, via, lines, problems };
|
|
3434
|
+
}
|
|
3411
3435
|
function checkAnimationPlugin(baseDirInput) {
|
|
3412
3436
|
const baseDir = resolveBaseDir(baseDirInput);
|
|
3413
3437
|
const pkg = readPackageJson(baseDir);
|
|
@@ -3418,25 +3442,8 @@ function checkAnimationPlugin(baseDirInput) {
|
|
|
3418
3442
|
const by = declared ? "@axis-ds/ui-react \uC120\uC5B8" : "componentsDir \uC758 animate-in \uB958 \uD074\uB798\uC2A4";
|
|
3419
3443
|
const tailwind = detectTailwind(baseDir, pkg);
|
|
3420
3444
|
const pnp = isPnpProject(baseDir);
|
|
3421
|
-
const pluginProblem = (name) => {
|
|
3422
|
-
if (declaredRangeForCheck(baseDir, pkg, name) === void 0) {
|
|
3423
|
-
return pnpRootOnlyDependency(baseDir, pkg, name) !== void 0 ? `${name} \uAC00 ${PNP_ROOT_ONLY_NOTE}` : `${name} \uC120\uC5B8 \uC5C6\uC74C`;
|
|
3424
|
-
}
|
|
3425
|
-
if (!pnp && findInstalledPackage(baseDir, name) === void 0) return `${name} \uBBF8\uC124\uCE58(\uC120\uC5B8\uB9CC \uC788\uC74C)`;
|
|
3426
|
-
return void 0;
|
|
3427
|
-
};
|
|
3428
3445
|
if (tailwind.major !== void 0 && tailwind.major >= 4) {
|
|
3429
|
-
const
|
|
3430
|
-
const note = globalCssSelectionNote(selection);
|
|
3431
|
-
const file = selection.rel;
|
|
3432
|
-
const expanded = selection.path !== void 0 && selection.rel !== void 0 ? expandGlobalCss(baseDir, selection.path, selection.rel, outsideCssDir(selection)) : void 0;
|
|
3433
|
-
const css = expanded !== void 0 ? stripCssComments(expanded.evidence) : "";
|
|
3434
|
-
const twAnimate = new RegExp(`@import\\s+(?:url\\(\\s*)?["']${ANIMATION_PLUGIN_TAILWIND4}["']`);
|
|
3435
|
-
const animatePlugin = new RegExp(`@plugin\\s+["']${ANIMATION_PLUGIN_TAILWIND3}["']`);
|
|
3436
|
-
const lines = [];
|
|
3437
|
-
if (twAnimate.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND4);
|
|
3438
|
-
if (animatePlugin.test(css)) lines.push(ANIMATION_PLUGIN_TAILWIND3);
|
|
3439
|
-
const via = expanded !== void 0 ? cssImportViaNote(viaFiles([evidenceOrigin(expanded, (f) => twAnimate.test(f)), evidenceOrigin(expanded, (f) => animatePlugin.test(f))])) : "";
|
|
3446
|
+
const { file, note, via, lines, problems } = inspectTailwind4Animation(baseDir, pkg);
|
|
3440
3447
|
if (lines.length === 0) {
|
|
3441
3448
|
return {
|
|
3442
3449
|
name: "animation",
|
|
@@ -3444,7 +3451,6 @@ function checkAnimationPlugin(baseDirInput) {
|
|
|
3444
3451
|
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}";${note}`
|
|
3445
3452
|
};
|
|
3446
3453
|
}
|
|
3447
|
-
const problems = lines.map((name) => ({ name, why: pluginProblem(name) })).filter((x) => x.why !== void 0);
|
|
3448
3454
|
if (problems.length === 0) return { name: "animation", severity: "pass", message: `${file}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uD50C\uB7EC\uADF8\uC778\uC774 \uC788\uC2B5\uB2C8\uB2E4${via}${note}` };
|
|
3449
3455
|
return {
|
|
3450
3456
|
name: "animation",
|
|
@@ -3455,7 +3461,7 @@ function checkAnimationPlugin(baseDirInput) {
|
|
|
3455
3461
|
const configFile = TAILWIND_CONFIG_FILES.find((f) => existsSync2(join(baseDir, f)));
|
|
3456
3462
|
const source = configFile !== void 0 ? stripJsComments(readFileSync2(join(baseDir, configFile), "utf8")) : "";
|
|
3457
3463
|
const plugins = configFile !== void 0 ? readAnimationPluginUse(source) : "absent";
|
|
3458
|
-
const pluginReason =
|
|
3464
|
+
const pluginReason = animationPluginProblem(baseDir, pkg, ANIMATION_PLUGIN_TAILWIND3, pnp)?.why;
|
|
3459
3465
|
if (plugins === "found" && pluginReason === void 0) {
|
|
3460
3466
|
return { name: "animation", severity: "pass", message: `${configFile}\uC758 plugins \uC5D0 ${ANIMATION_PLUGIN_TAILWIND3} \uAC00 \uC788\uC2B5\uB2C8\uB2E4` };
|
|
3461
3467
|
}
|
|
@@ -6069,6 +6075,7 @@ async function resolveInitAnswers(baseDirInput, tailwind4) {
|
|
|
6069
6075
|
}
|
|
6070
6076
|
function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
|
|
6071
6077
|
const name = tailwind4 ? ANIMATION_PLUGIN_TAILWIND4 : ANIMATION_PLUGIN_TAILWIND3;
|
|
6078
|
+
const setupOf = (candidate) => !tailwind4 ? `tailwind.config \uC758 plugins \uC5D0 require("${candidate}") \uB97C \uB123\uC73C\uC138\uC694` : `\uC804\uC5ED CSS \uC5D0 ${tailwind4AnimationLine(candidate)} \uB97C \uB123\uC73C\uC138\uC694`;
|
|
6072
6079
|
if (baseDir !== void 0) {
|
|
6073
6080
|
const pnp = isPnpProject(baseDir);
|
|
6074
6081
|
const candidates = tailwind4 ? [ANIMATION_PLUGIN_TAILWIND4, ANIMATION_PLUGIN_TAILWIND3] : [ANIMATION_PLUGIN_TAILWIND3];
|
|
@@ -6077,12 +6084,24 @@ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
|
|
|
6077
6084
|
if (pnp) return hasDependency(pkg, n) !== void 0 ? { source: "app" } : void 0;
|
|
6078
6085
|
return declaredDependency(baseDir, pkg, n);
|
|
6079
6086
|
};
|
|
6087
|
+
const usable = (n) => declaredOf(n) !== void 0 && (pnp || findInstalledPackage(baseDir, n) !== void 0);
|
|
6088
|
+
const css = tailwind4 && pkg !== void 0 ? inspectTailwind4Animation(baseDir, pkg) : void 0;
|
|
6089
|
+
const cssFile = css?.file !== void 0 ? `${css.file}${css.via}` : void 0;
|
|
6090
|
+
if (css !== void 0 && cssFile !== void 0 && css.lines.length > 0) {
|
|
6091
|
+
if (css.problems.length === 0) return void 0;
|
|
6092
|
+
return tailwind4AnimationProblemLine(cssFile, css.lines, css.problems, installCommand, candidates.filter(usable));
|
|
6093
|
+
}
|
|
6080
6094
|
for (const candidate of candidates) {
|
|
6081
6095
|
const declared = declaredOf(candidate);
|
|
6082
6096
|
if (declared === void 0) continue;
|
|
6083
|
-
if (pnp || findInstalledPackage(baseDir, candidate) !== void 0)
|
|
6097
|
+
if (pnp || findInstalledPackage(baseDir, candidate) !== void 0) {
|
|
6098
|
+
if (css !== void 0 && cssFile !== void 0 && css.lines.length === 0) {
|
|
6099
|
+
return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${pnp ? "\uC120\uC5B8" : "\uC124\uCE58"}\uB3FC \uC788\uC9C0\uB9CC ${cssFile}\uC5D0 \uC560\uB2C8\uBA54\uC774\uC158 \uC904\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. ${setupOf(candidate)}.`;
|
|
6100
|
+
}
|
|
6101
|
+
return void 0;
|
|
6102
|
+
}
|
|
6084
6103
|
const declaredWhere = declared.source === "root" ? "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 " : "";
|
|
6085
|
-
const setup =
|
|
6104
|
+
const setup = setupOf(candidate);
|
|
6086
6105
|
const install = installCommandPhrase(installCommand, declared.source === "root");
|
|
6087
6106
|
return `\uC560\uB2C8\uBA54\uC774\uC158: ${candidate} \uB294 ${declaredWhere}\uC120\uC5B8\uB3FC \uC788\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${install} \uB4A4 ${setup}.`;
|
|
6088
6107
|
}
|
|
@@ -6093,6 +6112,25 @@ function animationGuideLine(pkg, tailwind4, installCommand, baseDir) {
|
|
|
6093
6112
|
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`;
|
|
6094
6113
|
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}.`;
|
|
6095
6114
|
}
|
|
6115
|
+
function pnpRootOnlyTailwindLine(baseDir, pkg) {
|
|
6116
|
+
return pnpRootOnlyDependency(baseDir, pkg, "tailwindcss") !== void 0 ? `! \uD544\uC218 \uC758\uC874\uC131 tailwindcss \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD558\uC138\uC694` : void 0;
|
|
6117
|
+
}
|
|
6118
|
+
function tailwind4AnimationLine(name) {
|
|
6119
|
+
return name === ANIMATION_PLUGIN_TAILWIND4 ? `@import "${name}";` : `@plugin "${name}";`;
|
|
6120
|
+
}
|
|
6121
|
+
function tailwind4AnimationProblemLine(cssFile, lines, problems, installCommand, usable) {
|
|
6122
|
+
const commands = [];
|
|
6123
|
+
const undeclared = problems.filter((p) => p.kind !== "notInstalled").map((p) => p.name);
|
|
6124
|
+
if (undeclared.length > 0) commands.push(`${addCommandFor(installCommand, {}).trimEnd()} ${undeclared.join(" ")}`);
|
|
6125
|
+
const notInstalled = problems.filter((p) => p.kind === "notInstalled");
|
|
6126
|
+
if (notInstalled.length > 0) commands.push(installCommandPhrase(installCommand, notInstalled.some((p) => p.root === true)));
|
|
6127
|
+
const why = problems.map((p) => p.why).join(" \xB7 ");
|
|
6128
|
+
const problemLines = problems.map((p) => tailwind4AnimationLine(p.name)).join(" \xB7 ");
|
|
6129
|
+
const other = usable.find((n) => !problems.some((p) => p.name === n));
|
|
6130
|
+
const install = `\uC124\uCE58\uD558\uC138\uC694: ${commands.join(" \xB7 ")}`;
|
|
6131
|
+
const action = other === void 0 ? install : lines.includes(other) ? `\uC774\uBBF8 \uC124\uCE58\uB41C ${other} \uB9CC \uC4F0\uB824\uBA74 ${problemLines} \uC904\uC744 \uC9C0\uC6B0\uACE0, \uC544\uB2C8\uBA74 ${install}` : `\uC774\uBBF8 \uC124\uCE58\uB41C ${other} \uB97C \uC4F0\uB824\uBA74 ${problemLines} \uC904\uC744 ${tailwind4AnimationLine(other)} \uB85C \uBC14\uAFB8\uACE0, \uC544\uB2C8\uBA74 ${install}`;
|
|
6132
|
+
return `\uC560\uB2C8\uBA54\uC774\uC158: ${cssFile}\uC758 \uC560\uB2C8\uBA54\uC774\uC158 \uC904\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(${why}). ${action}`;
|
|
6133
|
+
}
|
|
6096
6134
|
var INIT_NEXT_STEP_COMMAND = "npx @axis-ds/cli add button";
|
|
6097
6135
|
function isTailwind4(tailwind) {
|
|
6098
6136
|
return tailwind.major !== void 0 && tailwind.major >= 4;
|
|
@@ -6109,15 +6147,20 @@ function readPackageJsonSafe(baseDir) {
|
|
|
6109
6147
|
}
|
|
6110
6148
|
}
|
|
6111
6149
|
function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
6112
|
-
const declared = (name) => pkg !== void 0 && (baseDir !== void 0 ? declaredDependency(baseDir, pkg, name) : hasDependency(pkg, name)) !== void 0;
|
|
6150
|
+
const declared = (name) => pkg !== void 0 && (baseDir !== void 0 ? declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true }) : hasDependency(pkg, name)) !== void 0;
|
|
6151
|
+
const pnpRootOnly = (name) => baseDir !== void 0 && pnpRootOnlyDependency(baseDir, pkg, name) !== void 0;
|
|
6113
6152
|
const used = TAILWIND4_COMPONENT_PACKAGES.filter((name) => declared(name));
|
|
6153
|
+
const rootOnlyComponents = TAILWIND4_COMPONENT_PACKAGES.filter((name) => pnpRootOnly(name));
|
|
6114
6154
|
const lines = [
|
|
6115
6155
|
`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).`,
|
|
6116
6156
|
' @import "tailwindcss";',
|
|
6117
6157
|
` ${TOKENS_TAILWIND4_IMPORT_LINE}`,
|
|
6118
6158
|
...used.map((name) => ` ${componentTailwindImportLine(name)}`)
|
|
6119
6159
|
];
|
|
6120
|
-
|
|
6160
|
+
for (const name of rootOnlyComponents) {
|
|
6161
|
+
lines.push(` ! ${name} \uAC00 ${PNP_ROOT_ONLY_NOTE} \u2192 \uC571 package.json \uC5D0 \uC120\uC5B8\uD55C \uB4A4 ${componentTailwindImportLine(name)}`);
|
|
6162
|
+
}
|
|
6163
|
+
if (used.length === 0 && rootOnlyComponents.length === 0) {
|
|
6121
6164
|
lines.push(
|
|
6122
6165
|
` 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";).`
|
|
6123
6166
|
);
|
|
@@ -6125,7 +6168,8 @@ function tailwind4GuideLines(pkg, installCommand, globalCss, baseDir) {
|
|
|
6125
6168
|
lines.push(TAILWIND4_CONFLICT_LINE);
|
|
6126
6169
|
if (!declared(TOKENS_PACKAGE)) {
|
|
6127
6170
|
const add = addCommandFor(installCommand, { [TOKENS_PACKAGE]: `^${TAILWIND4_TOKENS_VERSION}` });
|
|
6128
|
-
|
|
6171
|
+
const why = pnpRootOnly(TOKENS_PACKAGE) ? `(${PNP_ROOT_ONLY_NOTE})` : "";
|
|
6172
|
+
lines.push(` ${TOKENS_PACKAGE} \uC124\uCE58${why}: ${add}`);
|
|
6129
6173
|
}
|
|
6130
6174
|
const versions = axisPackagesBelowTailwind4(pkg, baseDir);
|
|
6131
6175
|
const unknown = versions.filter((v) => v.status === "unknown");
|
|
@@ -6169,6 +6213,7 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
6169
6213
|
action: "no-package-json",
|
|
6170
6214
|
added: [],
|
|
6171
6215
|
present: [],
|
|
6216
|
+
pnpRootOnly: [],
|
|
6172
6217
|
ranges: ranges0,
|
|
6173
6218
|
tailwind: tailwind0,
|
|
6174
6219
|
installCommand,
|
|
@@ -6205,9 +6250,12 @@ function planUtilsDependencies(baseDirInput) {
|
|
|
6205
6250
|
plan.addCommand = addCommandFor(installCommand, plan.ranges);
|
|
6206
6251
|
const missing = {};
|
|
6207
6252
|
for (const [name, range] of Object.entries(plan.ranges)) {
|
|
6208
|
-
const declared = declaredDependency(baseDir, pkg, name);
|
|
6253
|
+
const declared = declaredDependency(baseDir, pkg, name, void 0, { appOnlyInPnp: true });
|
|
6209
6254
|
if (declared !== void 0) plan.present.push({ name, range: declared.range, source: declared.source });
|
|
6210
|
-
else
|
|
6255
|
+
else {
|
|
6256
|
+
missing[name] = range;
|
|
6257
|
+
if (pnpRootOnlyDependency(baseDir, pkg, name) !== void 0) plan.pnpRootOnly.push(name);
|
|
6258
|
+
}
|
|
6211
6259
|
}
|
|
6212
6260
|
plan.added = Object.keys(missing);
|
|
6213
6261
|
plan.addCommand = addCommandFor(installCommand, plan.added.length > 0 ? missing : plan.ranges);
|
|
@@ -6268,6 +6316,7 @@ function reportDependencies(plan, log) {
|
|
|
6268
6316
|
if (plan.action === "add") {
|
|
6269
6317
|
const addedText = plan.added.map((n) => `${n}@${plan.ranges[n]}`).join(", ");
|
|
6270
6318
|
log(chalk10.green(`\u2713 package.json dependencies \uC5D0 \uCD94\uAC00: ${addedText}`));
|
|
6319
|
+
if (plan.pnpRootOnly.length > 0) log(chalk10.gray(` ${plan.pnpRootOnly.join(", ")} \uB294 ${PNP_ROOT_ONLY_NOTE}`));
|
|
6271
6320
|
if (plan.present.length > 0) log(chalk10.gray(` \uC774\uBBF8 \uC788\uC74C(\uBC84\uC804 \uC720\uC9C0): ${presentText}${rootNote}`));
|
|
6272
6321
|
if (plan.added.includes("tailwind-merge")) logBasis();
|
|
6273
6322
|
log(chalk10.yellow(` \uC124\uCE58\uB294 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58: ${installText}`));
|
|
@@ -6527,6 +6576,8 @@ async function runInit(baseDirInput, answers, registryUrl, log = console.log, op
|
|
|
6527
6576
|
return;
|
|
6528
6577
|
}
|
|
6529
6578
|
reportDependencies(plan, log);
|
|
6579
|
+
const tailwindRootOnly = pnpRootOnlyTailwindLine(baseDir, readPackageJsonSafe(baseDir));
|
|
6580
|
+
if (tailwindRootOnly !== void 0) log(chalk10.yellow(` ${tailwindRootOnly}`));
|
|
6530
6581
|
const animation = animationGuideLine(readPackageJsonSafe(baseDir), tailwind4, plan.installCommand, baseDir);
|
|
6531
6582
|
if (animation !== void 0) log(chalk10.yellow(` ${animation}`));
|
|
6532
6583
|
if (tailwind4) {
|
|
@@ -7333,7 +7384,7 @@ function missingDependencies(root, items) {
|
|
|
7333
7384
|
for (const item of items) {
|
|
7334
7385
|
for (const dep of item.dependencies) {
|
|
7335
7386
|
const name = dependencyName(dep);
|
|
7336
|
-
if (declaredDependency(root, pkg, name, rootPkg) !== void 0) continue;
|
|
7387
|
+
if (declaredDependency(root, pkg, name, rootPkg, { appOnlyInPnp: true }) !== void 0) continue;
|
|
7337
7388
|
if (name in specs) continue;
|
|
7338
7389
|
const explicit = dep.length > name.length ? dep.slice(name.length + 1) : void 0;
|
|
7339
7390
|
specs[name] = explicit ?? ranges[name];
|