@axis-ds/cli 1.7.6 → 1.7.8
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 +13 -8
- package/dist/{chunk-I3HWV7Y5.js → chunk-C2T7NVDG.js} +322 -4
- package/dist/index.js +781 -164
- package/dist/monet.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,25 +95,30 @@ axis theme add ontology
|
|
|
95
95
|
|
|
96
96
|
## 프로젝트 검증 (`axis check`)
|
|
97
97
|
|
|
98
|
-
- Tailwind 구성
|
|
98
|
+
- 전역 CSS 선택(1.7.7 부터): 전역 CSS 를 읽는 세 항목(Tailwind 4 의 Tailwind 구성 항목 · globals.css 항목 · Tailwind 4 의 animation 항목)은 같은 파일 하나를 봅니다. `axis.config.json` 의 `globalCss` 가 가리키는 파일이 있고 `.css` 이면 그 파일입니다. 모노레포의 `../shared/globals.css` 처럼 프로젝트 밖 경로도 읽기만 합니다(`axis theme add` 는 종전대로 밖 파일에 쓰지 않습니다). `globalCss` 키가 없거나 그 파일을 쓸 수 없으면 `globals.css` · `app/globals.css` · `src/app/globals.css` · `src/globals.css` · `styles/globals.css` 순으로 처음 찾은 파일이고, 쓸 수 없었던 이유를 항목 문구 끝에 붙입니다. 없는 파일 · 디렉터리면 `(globalCss ./nope.css 없음)`, `.css` 가 아닌 파일이면 `(globalCss ./package.json: .css 파일이 아님)` 입니다. brand 항목도 같은 `globalCss` 규칙과 표기를 쓰지만 후보 목록이 다릅니다(`app/globals.css` → `src/app/globals.css` → `styles/globals.css` → `src/styles/globals.css` → 루트 `globals.css`). 세 항목도 후보 이름과 같은 디렉터리(예: 루트 `globals.css/`)는 건너뜁니다(1.7.6 까지는 check 가 `EISDIR` 로 멈췄습니다). 1.7.6 까지는 세 항목이 `globalCss` 를 보지 않아, CSS 를 후보 밖(`src/styles/globals.css` 등)에 두고 `globalCss` 로 가리킨 프로젝트도 globals.css FAIL(종료 코드 1)이었고, 루트에 다른 `globals.css` 가 있으면 brand 와 다른 파일을 판정했습니다.
|
|
99
|
+
- 상대 `@import` 펼침(1.7.7 부터): 고른 파일이 `@import "./axis.css";` · `@import '../styles/axis.css';` 처럼 따옴표 안 상대 경로(`./` · `../`, 공백 없는 `@import"./axis.css"` · 확장자 없는 `"./axis"` 포함)로 들여온 프로젝트 안 CSS 도 근거 줄(`@import "tailwindcss"` · 토큰 진입점 · tokens CSS import · `--axis-*` 정의 · 컴포넌트 `tailwind.css` · `@source` · `tw-animate-css` · `@plugin "tailwindcss-animate"` · 브랜드 import)을 찾을 때 함께 봅니다. 근거를 하위 파일에서 찾으면 문구 끝(`globalCss` 표기 앞)에 `(app/axis.css 의 import)` 처럼 출처를 붙이고, 하위 파일이 없으면 종전 문구 그대로입니다. 확장자 없는 이름은 적힌 이름의 파일이 먼저이고 없으면 끝에 `.css` 를 붙인 파일을 봅니다(Tailwind 4 와 같음). 하위 파일이 다시 import 한 파일도 진입 파일에서 32단계까지 따라가고, 같은 파일은 한 번만 읽습니다. 프로젝트 밖으로 나가는 경로(`../` · 밖을 가리키는 심볼릭 링크), 없는 파일 · 디렉터리, `url(...)` 형태, `layer()` · `supports()` · media 조건이 붙은 import(조건 안의 토큰 진입점은 Tailwind 4 빌드가 실패함. Tailwind 3 은 조건이 붙은 import 도 펼쳐 빌드하지만 check 는 따라가지 않아 그 파일의 줄을 근거로 보지 않습니다), `./` 없는 이름(`"axis.css"`, 패키지 경로로 풀림)은 따라가지 않습니다. 프로젝트 밖 전역 CSS 가 다시 밖 파일을 import 해도 읽지 않습니다. 상대 import 가 순환하면(a → b → a · 자기 import) 빌드가 실패하므로 globals.css 항목은 진입 파일만으로 판정한 문구 뒤에 ` / ` 로 순환 문구를 붙여 WARN 을 냅니다(예: `app/globals.css에 AXIS CSS 변수가 없습니다 / app/globals.css · app/b.css 이 서로 @import 해 빌드가 순환으로 실패합니다 → 순환하는 @import 를 없애세요`, 자기 자신을 import 하면 `app/globals.css 이 자기 자신을 @import 해 빌드가 순환으로 실패합니다 → 순환하는 @import 를 없애세요`). 진입 파일이 PASS 여도 WARN 이고, 이때는 모든 항목이 진입 파일만 보며 순환 문구는 globals.css 항목에만 붙습니다. 순환은 조건이 붙은 import 까지 넣어 Tailwind 4 의 재귀 한도와 같은 100단계까지 찾습니다(근거는 위와 같이 조건 없는 import · 32단계까지만 봄). 하위 파일의 패키지 경로 줄은 진입 파일에 같은 줄이 있을 때와 같은 해석 판정(아래 Tailwind 구성 항목 2 · 5번 · globals.css 항목)을 그 하위 파일의 디렉터리 기준(그 디렉터리의 중첩 `node_modules` 포함)으로 거치고(1.7.8 부터 Tailwind 4 의 tokens CSS import · 컴포넌트 `tailwind.css` 줄은 아래 「중첩 설치본」 규칙, `@import "tailwindcss"` 줄과 Tailwind 3 은 이 규칙 그대로), 브랜드 import 는 종전대로 그 판정 없이 위치만 봅니다. create-next-app 기본 정의 · `font-family: Arial` 같은 결함은 진입 파일에서만 봅니다. 1.7.6 까지는 하위 파일을 보지 않아, 근거를 하위 파일에 둔 프로젝트도 「없습니다」 WARN 이었습니다(종료 코드는 그대로).
|
|
100
|
+
- Tailwind 구성 항목: Tailwind 4 이상(설치본, 없으면 `package.json` 선언으로 판정)은 설정 파일 대신 위 전역 CSS 선택이 고른 파일 하나(상대 `@import` 로 들여온 하위 파일 포함)를 봅니다. Tailwind 3 이하는 `tailwind.config.ts` · `.js` · `.mjs` · `.cjs` 를 찾습니다.
|
|
99
101
|
- Tailwind 4: `@import "tailwindcss"` 가 있는 CSS 에서 아래 문제가 하나도 없으면 PASS 이고, 하나라도 있으면 WARN 입니다(블록 주석 안은 없는 것으로 봅니다). `@import "tailwindcss"` 가 없으면 그 WARN 하나만 냅니다.
|
|
100
102
|
1. 토큰 진입점 `@import "@axis-ds/tokens/css/tailwind4";` 이 없음 → 문구에 넣을 import 줄. 진입점이 없으면 `bg-primary` · `rounded-md` 같은 AXIS 매핑이 만들어지지 않습니다. `@axis-ds/tokens/css` · `css/shadcn` · `tailwind`(Tailwind 3 preset)는 진입점으로 치지 않습니다.
|
|
101
|
-
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 쪽으로 판정).
|
|
103
|
+
2. `package.json` 에 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 의 `tailwind.css` import 가 없음 → 빠진 import 줄. 선언이 없으면(복사 설치) 요구하지 않습니다. 1.7.7 부터는 그 줄이 이 앱에서 해석될 때만 줄을 바로 안내합니다. 앱 `package.json` 선언과, 설치본에 `tailwind.css` 가 있는 워크스페이스 루트 선언은 종전대로 줄을 안내합니다. 해석되지 않는 루트 선언은 먼저 할 일을 안내합니다: Plug'n'Play 에서 루트에만 선언(→ 앱 `package.json` 에 선언한 뒤 줄), 설치본 없음(→ 설치 뒤 줄), 설치본이 1.4.0 미만이거나 버전을 읽지 못함(→ 1.4.0 이상으로 올린 뒤 줄), 1.4.0 이상인데 `tailwind.css` 가 없음(→ 다시 설치 뒤 줄). 앱 디렉터리에 lockfile 이 있으면 루트 선언을 선언으로 보지 않습니다(`axis theme add` 와 같은 판정). 1.7.6 까지는 선언만 보고 줄을 안내해, 그대로 넣으면 빌드가 `Can't resolve` 로 깨질 수 있었습니다. `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 쪽으로 판정).
|
|
102
104
|
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 기본 블록 이름이라, 같은 선언이 다른 선택자에 있어도 그 이름으로 표시됩니다.
|
|
103
105
|
4. 진입점이 있는데 `@axis-ds/tokens` 가 아래 버전 조건에 걸림.
|
|
104
|
-
5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다.
|
|
106
|
+
5. `@axis-ds/ui-react/tailwind.css` · `@axis-ds/agentic-ui/tailwind.css` 를 import 하는데 그 패키지가 아래 버전 조건에 걸림(`tailwind.css` 는 1.4.0 부터 있음). 직접 `@source` 로 스캔하는 패키지는 `tailwind.css` 가 필요 없으므로 이 문제를 만들지 않습니다. 1.7.7 부터는 줄이 이미 있어도 2번의 해석되지 않는 루트 선언(Plug'n'Play 루트 전용 · 설치본 없음 · 설치본에 `tailwind.css` 없음 · 버전을 읽지 못함)이면 버전 조건 대신 「`<패키지>/tailwind.css` import 가 있지만 … 해석되지 않습니다」 WARN 입니다(1.4.0 미만 설치본은 종전 버전 조건 문구, 1.7.6 까지는 버전 조건만 봐서 PASS 일 수 있었음). 1.7.8 부터는 아래 중첩 설치본 판정도 이 자리에 나옵니다.
|
|
107
|
+
- 프로젝트 밖 전역 CSS(1.7.7 부터): 고른 파일이 앱 밖(`globalCss` 가 `../shared/globals.css` 등)이면 그 파일의 `@import "tailwindcss"` 와 컴포넌트 `tailwind.css` 줄을 그 파일 위치 기준으로도 봅니다. 빌드 도구가 패키지 경로를 그 CSS 파일 위치부터 상위 `node_modules` 로 풀기 때문입니다(설치본이 앱 아래에만 있으면 빌드가 `Can't resolve` 로 실패, 공통 상위로 호이스팅하면 성공). 앱에서는 설치본을 찾는데 그 파일 위치에서는 찾지 못하면 「import 가 있지만 이 파일 위치에서 <패키지> 를 찾지 못해 해석되지 않습니다」 WARN 입니다(`tailwindcss` 줄은 문제 목록 맨 앞, 컴포넌트 줄은 5번 자리). 토큰 진입점 줄은 globals.css 항목이 같은 기준으로 알립니다. Plug'n'Play 이거나 앱 위치에서 설치본을 찾지 못하면 이 판정을 하지 않습니다.
|
|
108
|
+
- 중첩 설치본(그림자, 1.7.8 부터): 앱 안 CSS(진입 파일 · 상대 `@import` 로 들여온 하위 파일)의 tokens CSS import 줄(`@axis-ds/tokens/css` · `css/shadcn` · `css/tailwind4`, globals.css 항목)과 컴포넌트 `tailwind.css` 줄(위 5번 자리)은 그 줄이 있는 파일 위치부터 Tailwind 4 빌드 도구와 같은 순서로 풉니다. 위로 올라가며 `node_modules/<패키지>` 를 찾고, 먼저 잡힌 설치본에 `exports` 가 있으면 그 `exports`(조건 `style` · `default`)로만 풉니다. 그 설치본이 앱 기준 설치본과 실경로가 다르고(예: `app/node_modules` 에 남은 1.3.0) subpath 를 내보내지 않거나 내보낸 파일이 없으면 빌드가 실패하므로 「import 가 있지만 그 줄이 있는 파일 위치에서 먼저 잡히는 app/node_modules/@axis-ds/ui-react(1.3.0)가 ./tailwind.css 를 내보내지 않아 해석되지 않습니다 → 그 중첩 node_modules 의 @axis-ds/ui-react 를 지우거나 1.4.0 이상으로 맞추세요」 같은 WARN 입니다(이미 1.4.0 이상이면 「다시 설치하세요」). `exports` 도 그 파일도 없는 중첩 디렉터리는 빌드 도구처럼 건너뛰고 상위 설치본으로 봅니다. 앱과 워크스페이스 루트에 설치본이 없고, 그 줄이 있는 파일 위치에서는 풀리지 않는데 같은 전역 CSS 의 다른 파일 위치에서만 풀리면 「설치본이 <경로> 에만 있음」 WARN 입니다. 그림자 파일의 내용은 보지 않고, 프로젝트 밖 전역 CSS · `@import "tailwindcss"` 줄 · Tailwind 3 은 종전대로입니다. 1.7.7 까지는 앱 안 진입 파일의 줄은 앱 기준으로만, 하위 파일의 줄은 처음 만난 설치본(tokens 는 디렉터리, 컴포넌트는 `tailwind.css` 파일)만 봐서 빌드가 실패하는 그림자도 PASS 일 수 있었습니다.
|
|
105
109
|
- 문제가 여럿이면 위 순서대로 ` / ` 로 이어 한 항목에 냅니다. 끝에는 `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:` 는 넣지 않습니다.
|
|
106
110
|
- 문구 예: `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)`
|
|
107
|
-
- Tailwind 3: 설정 파일(`.ts` · `.js` · `.mjs` · `.cjs`)이 `@axis-ds/tokens/tailwind` preset 을 `require` · `import` 하면(주석 밖) `tailwind.config.ts에 AXIS 토큰이 설정되어 있습니다 (@axis-ds/tokens/tailwind preset)` 처럼 PASS
|
|
108
|
-
- Tailwind 3 CommonJS(1.6.1 부터): 설정이 `.cjs` 이거나 `module.exports` 를 쓰고 `.default` 없는 `require("@axis-ds/tokens/tailwind")` 가 있으면, 설치본(없으면 선언
|
|
109
|
-
-
|
|
111
|
+
- Tailwind 3: 설정 파일(`.ts` · `.js` · `.mjs` · `.cjs`)이 `@axis-ds/tokens/tailwind` preset 을 `require` · `import` 하면(주석 밖) `tailwind.config.ts에 AXIS 토큰이 설정되어 있습니다 (@axis-ds/tokens/tailwind preset)` 처럼 PASS 이고(1.7.8 부터는 아래 tokens 해석 조건도 맞아야 함), 없으면 WARN 입니다(1.6.0 부터. 이전에는 `--background` · `hsl(var(` 문자열만 있어도 PASS 여서 AXIS 참조가 없는 자체 매핑도 통과했습니다).
|
|
112
|
+
- Tailwind 3 CommonJS(1.6.1 부터): 설정이 `.cjs` 이거나 `module.exports` 를 쓰고 `.default` 없는 `require("@axis-ds/tokens/tailwind")` 가 있으면, 설치본(없으면 선언 하한. 1.7.8 부터 선언 하한으로 가는 것은 아래 tokens 해석 조건을 통과한 경우뿐) `@axis-ds/tokens` 가 1.7.0 미만일 때 WARN 입니다. 1.6.2 이하의 이 형태는 preset 이 아니라 `{ default }` 를 받아 색 · keyframes 가 빠집니다(1.1.0 부터). `.ts` · `.mjs` 의 `export default` 안 `require` 와 `import` 형태는 Tailwind 가 `.default` 를 꺼내 줘서 이 버전 판정을 하지 않습니다.
|
|
113
|
+
- Tailwind 3 preset 의 tokens 해석(1.7.8 부터): 위 두 판정 앞에서, preset 을 어떤 모양(`require` · `.default` · `import` · `.ts`)으로 받든 `@axis-ds/tokens` 가 이 앱에서 해석되는지 봅니다. globals.css 항목과 같은 기준이라, 앱 `package.json` 에 선언했으면 설치 여부와 상관없이 종전 판정(미설치는 dependencies 항목이 알림)이고, 선언이 없거나 워크스페이스 루트에만 선언했으면 설치본 디렉터리가 있을 때만 종전 판정입니다. 설치본이 없으면 「tailwind.config.mjs에 AXIS preset 참조가 있지만 @axis-ds/tokens 가 설치되지 않아 해석되지 않습니다 → 설치(…)」, Plug'n'Play 에서 루트에만 선언했으면 「… 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다(워크스페이스 루트 선언 …) → 앱 package.json 에 @axis-ds/tokens 를 선언하세요」 WARN 입니다(CommonJS bare require 는 바로 위 단락의 종전 문구 「… 1.7.0 이상을 선언하세요」). 1.7.7 까지는 PASS 였고, CommonJS bare require 는 이미 WARN 이었던 경우(미선언 · 미설치, 루트 1.7.0 미만 선언 · 미설치)에 문구만 바뀝니다. 종료 코드는 그대로입니다. 이 레이아웃은 Tailwind 빌드가 `Cannot find module '@axis-ds/tokens/tailwind'` 로 실패합니다. 1.7.0 버전 판정은 종전대로 CommonJS bare require 만 봅니다.
|
|
114
|
+
- globals.css 항목: 위 전역 CSS 선택이 고른 CSS 하나(상대 `@import` 로 들여온 하위 파일 포함, Arial 은 진입 파일만)를 봅니다(Tailwind 3 이하도 같음). 고를 파일이 하나도 없으면 FAIL 입니다. 1.6.1 부터 AXIS 근거가 있을 때만 PASS 입니다: `@axis-ds/tokens/css` · `@axis-ds/tokens/css/shadcn` · `@axis-ds/tokens/css/tailwind4` import(블록 주석 밖, 작은따옴표 · `url()` · `layer()` 표기 포함, 문구 끝에 `(@axis-ds/tokens/css/tailwind4 import)` 처럼 경로), `--axis-*` 변수 정의, 또는 루트 레이아웃(`app/layout.tsx` 등)의 `import "@axis-ds/tokens/css"`. 1.7.7 부터 tokens import(CSS · 루트 레이아웃 JS)는 이 앱에서 해석될 때만 근거로 칩니다. 앱 `package.json` 에 `@axis-ds/tokens` 를 선언했으면 설치 여부와 상관없이 종전대로 PASS 이고(미설치는 dependencies 항목이 알림), 선언이 없거나 워크스페이스 루트에만 선언했으면 설치본 디렉터리(`node_modules/@axis-ds/tokens`, 상위 디렉터리 포함)가 있을 때 PASS 입니다. 설치본이 없으면 「<경로> import 가 있지만 @axis-ds/tokens 가 설치되지 않아 해석되지 않습니다 → 설치(…)」, Plug'n'Play 에서 루트에만 선언했으면 「… 워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다 → 앱 package.json 에 선언하세요」 WARN 입니다(1.7.6 까지는 PASS, 종료 코드는 그대로). 고른 파일이 프로젝트 밖이면 Tailwind 구성 항목과 같이 그 파일 위치에서 설치본이 보이는지도 봅니다. `--axis-*` 변수 정의는 이 판정을 거치지 않습니다. 단, 해석되지 않는 tokens import 가 함께 있으면 import 판정을 따라 WARN 입니다. 자체 `--background` · `--primary` 만 있으면 「자체 CSS 변수만 있고 AXIS 토큰이 없습니다」 WARN 입니다(1.6.0 까지는 PASS). Tailwind 3 에서 create-next-app 기본 `body` 의 `font-family: Arial` 이 남아 있으면 PASS 조건을 채워도 WARN 입니다(Tailwind 4 는 tailwind.config 항목의 create-next-app 기본 정의로 냅니다).
|
|
110
115
|
- dependencies 항목(1.6.1 부터): `tailwindcss` 선언이 없으면 FAIL, `clsx` · `tailwind-merge` 선언이 없으면 WARN(종전과 같음). 여기에 선언된 `tailwindcss` · `clsx` · `tailwind-merge` · `@axis-ds/*` 가 `node_modules` 에 없으면 「선언됐지만 설치되지 않은 의존성」 WARN 과 lockfile 에 맞는 설치 명령을 냅니다. 상위 디렉터리의 `node_modules`(모노레포 호이스팅)도 찾고, Plug'n'Play(`.pnp.cjs`)는 설치본을 읽지 않고 선언 기준입니다. 1.6.0 까지는 선언만 보고 「모두 설치되어 있습니다」였습니다.
|
|
111
116
|
- 1.7.6 부터 워크스페이스 루트 `package.json` 에 선언한 `@axis-ds/*`(앱에 없는 것)도 설치 확인 대상이고, 설치되지 않았으면 「워크스페이스 루트에 선언돼 있지만 설치되지 않았습니다」 WARN 입니다(종료 코드는 그대로, 1.7.5 까지는 앱 선언만 봐서 PASS).
|
|
112
117
|
- 1.7.6 부터 Plug'n'Play 는 워크스페이스 루트 선언을 인정하지 않습니다. 앱이 자기 `package.json` 에 없는 패키지를 해석하지 못하기 때문입니다. 루트에만 있는 `tailwindcss` 는 「워크스페이스 루트에만 선언돼 Plug'n'Play 에서 앱이 해석하지 못합니다」 FAIL, `clsx` · `tailwind-merge` · `@axis-ds/*` 는 같은 문구의 WARN 입니다(1.7.5 까지는 PASS). `.pnp.cjs` 는 `.git` 이 있는 층에서 찾기를 멈춥니다. `pnpFallbackMode: all` 설정은 읽지 않습니다.
|
|
113
118
|
- 해당할 때만 더하는 항목(1.6.0 부터, brand 항목 뒤 이 순서):
|
|
114
119
|
- `brand.activation`: `brand` 가 있을 때 루트 레이아웃(`app/layout.tsx` · `src/app/layout.tsx` · `pages/_app` 등, 그 레이아웃이 import 하는 같은 디렉터리의 `./providers` 한 단계 포함)에 `data-brand` · `setBrand(` · `defaultBrand=` 가 없으면 WARN 입니다(휴리스틱, `ThemeProvider` 단독은 켜는 코드가 아님). 1.6.1 부터 마크업 `data-brand` 와 `ThemeProvider` 만 있고 `setBrand(` · `defaultBrand=` 가 없으면 설치본(없으면 선언) `@axis-ds/theme` 가 1.7.0 미만이거나 판정할 수 없을 때 WARN 입니다(1.6.2 이하는 마운트 때 속성을 지움). 1.7.6 부터 Plug'n'Play 에서 `@axis-ds/theme` 가 워크스페이스 루트에만 선언돼 있으면 「앱이 해석하지 못합니다」 WARN 입니다(Tailwind 3 CommonJS preset 의 `@axis-ds/tokens` 판정도 같음).
|
|
115
|
-
- `tailwind.content`: Tailwind 3 설정 파일이 있고 `componentsDir` 나 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 가 있을 때, `content` 의 문자열 glob 이 그 경로를 덮지 않으면 FAIL 입니다(그 경로의 클래스가 생성되지 않음). `content` 를 정적으로 다 읽지 못하면(변수 · 펼침) WARN 입니다. 패키지 경로는 프로젝트 디렉터리부터 상위로 찾은 설치본 위치 기준이라, npm workspaces · pnpm hoisted 처럼 루트에만 설치된 앱은 `../../node_modules/@axis-ds/ui-react/dist/**/*.{js,mjs}` 를 안내합니다(1.7.1 부터, 설치본이
|
|
116
|
-
- `animation`: `@axis-ds/ui-react` 선언이나 `componentsDir` 의 `animate-in` 류 클래스가 있을 때 애니메이션 플러그인(Tailwind 3 `tailwindcss-animate` 선언 + 설치본 + `plugins` 배열 참조, Tailwind 4 `@import "tw-animate-css"`)이 없으면 WARN 입니다. 1.6.1 부터 Tailwind 3 은 `plugins` 배열 안의 `require("tailwindcss-animate")` 나 그 패키지를 받은 식별자(`import animate from` · `const animate = require(...)`)만 인정합니다(import 만 있거나 다른 곳의 같은 문자열은 아님). 배열을 정적으로 다 읽지 못하면(펼침 · 단축 속성) 「확인하지 못함」 WARN 입니다. 1.7.6 부터 Tailwind 4 는 CSS 의 줄마다 그 줄의 패키지(`tw-animate-css` · `tailwindcss-animate`)가 선언 · 설치돼 있어야 PASS 이고, 줄은 있는데 선언이나 설치본이 없으면 「애니메이션 플러그인을 쓸 수 없습니다」 WARN 입니다(1.7.5 까지는 줄만 보고 PASS, 실제 빌드는 실패). Plug'n'Play 에서는 플러그인 선언을 앱 `package.json` 에서만 봅니다.
|
|
120
|
+
- `tailwind.content`: Tailwind 3 설정 파일이 있고 `componentsDir` 나 선언된 `@axis-ds/ui-react` · `@axis-ds/agentic-ui` 가 있을 때, `content` 의 문자열 glob 이 그 경로를 덮지 않으면 FAIL 입니다(그 경로의 클래스가 생성되지 않음). `content` 를 정적으로 다 읽지 못하면(변수 · 펼침) WARN 입니다. 패키지 경로는 프로젝트 디렉터리부터 상위로 찾은 설치본 위치 기준이라, npm workspaces · pnpm hoisted 처럼 루트에만 설치된 앱은 `../../node_modules/@axis-ds/ui-react/dist/**/*.{js,mjs}` 를 안내합니다(1.7.1 부터, 설치본이 없으면 `./node_modules/...`). `**` 는 `../` 를 넘지 않는 것으로, 절대경로 glob 은 실제 위치와 비교해 판정합니다. 1.7.4 부터 pnpm 기본 레이아웃처럼 앱 설치본이 링크이면 실경로가 같은 상위 설치본(`../../node_modules/...`)과 `.pnpm` 스토어 실경로를 상대 경로로 쓴 glob 도 인정하고, 실경로가 다른 상위 설치본을 가리키면 FAIL 문구에 그 이유를 붙입니다. 상위 경로는 Tailwind 3 가 빌드를 실행한 디렉터리 기준으로 풀리므로 모노레포 루트에서 빌드하면 `content: { relative: true, files: [...] }` 를 쓰세요(판정은 프로젝트 디렉터리에서 빌드한다고 보고 함). 1.7.7 부터 Plug'n'Play(`.pnp.cjs`)에서는 node_modules 가 없으므로 `./node_modules/...` glob 과 넓은 `./**` 를 덮음으로 보지 않고 WARN 으로 알리고(종전 PASS, 실제 빌드는 클래스가 생기지 않음. Tailwind 의 `**` · `*` 는 `.yarn` 처럼 점으로 시작하는 디렉터리를 넘지 않으므로 앱이 Plug'n'Play 루트이고 unplugged 가 있어도 같음), 덮지 않으면 FAIL 은 그대로이되 `./node_modules/...` 대신 `require.resolve` 로 실제 위치를 넣는 동적 형태(정적으로 확인할 수 없어 WARN)를 먼저, `dependenciesMeta` 의 `unplugged: true` 를 대안으로 안내합니다(안내에는 덮지 않은 패키지 이름이 들어감). unplugged 를 설정한 프로젝트는 앱 선언 범위에 맞는 `.yarn/unplugged/*/node_modules/<패키지>` 를 가리키는 glob(상대 · 절대, `.yarn` 을 글자 그대로 쓴 것)을 덮음으로 인정합니다(종료 코드가 1 에서 0 으로 바뀔 수 있음). 컴포넌트 패키지를 워크스페이스 루트에만 선언한 Plug'n'Play 앱은 경로를 안내 · 인정하지 않고 「앱 package.json 에 선언하세요」를 냅니다.
|
|
121
|
+
- `animation`: `@axis-ds/ui-react` 선언이나 `componentsDir` 의 `animate-in` 류 클래스가 있을 때 애니메이션 플러그인(Tailwind 3 `tailwindcss-animate` 선언 + 설치본 + `plugins` 배열 참조, Tailwind 4 는 전역 CSS 선택이 고른 파일(상대 `@import` 로 들여온 하위 파일 포함)의 `@import "tw-animate-css"`)이 없으면 WARN 입니다. 1.6.1 부터 Tailwind 3 은 `plugins` 배열 안의 `require("tailwindcss-animate")` 나 그 패키지를 받은 식별자(`import animate from` · `const animate = require(...)`)만 인정합니다(import 만 있거나 다른 곳의 같은 문자열은 아님). 배열을 정적으로 다 읽지 못하면(펼침 · 단축 속성) 「확인하지 못함」 WARN 입니다. 1.7.6 부터 Tailwind 4 는 CSS 의 줄마다 그 줄의 패키지(`tw-animate-css` · `tailwindcss-animate`)가 선언 · 설치돼 있어야 PASS 이고, 줄은 있는데 선언이나 설치본이 없으면 「애니메이션 플러그인을 쓸 수 없습니다」 WARN 입니다(1.7.5 까지는 줄만 보고 PASS, 실제 빌드는 실패). Plug'n'Play 에서는 플러그인 선언을 앱 `package.json` 에서만 봅니다.
|
|
117
122
|
- FAIL 이 하나라도 있으면 종료 코드 1 로 끝납니다. WARN 만 있으면 0 입니다(1.3.0 부터, 이전에는 결과와 관계없이 0).
|
|
118
123
|
- MCP `axis.check_project` 도 같은 항목 · 문구를 냅니다.
|
|
119
124
|
|
|
@@ -10,7 +10,7 @@ import fs from "fs-extra";
|
|
|
10
10
|
import path2 from "path";
|
|
11
11
|
|
|
12
12
|
// ../axis-registry-core/src/project.ts
|
|
13
|
-
import { existsSync, readFileSync, realpathSync, statSync } from "fs";
|
|
13
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
|
|
14
14
|
import path from "path";
|
|
15
15
|
function resolveBaseDir(baseDirInput) {
|
|
16
16
|
const resolved = path.resolve(baseDirInput);
|
|
@@ -227,6 +227,32 @@ function isDirectory(dir) {
|
|
|
227
227
|
function findFirstFile(baseDir, candidates) {
|
|
228
228
|
return candidates.find((c) => isFile(path.join(baseDir, c)));
|
|
229
229
|
}
|
|
230
|
+
function selectGlobalCss(baseDir, configured, candidates, options = {}) {
|
|
231
|
+
const result = {};
|
|
232
|
+
if (typeof configured === "string" && configured.trim() !== "") {
|
|
233
|
+
const file = path.resolve(baseDir, configured);
|
|
234
|
+
if (!isFile(file)) result.configuredMissing = configured;
|
|
235
|
+
else if (options.requireStylesheet && path.extname(file).toLowerCase() !== ".css") result.configuredRejected = configured;
|
|
236
|
+
else return { path: file, rel: path.relative(baseDir, file).split(path.sep).join("/") };
|
|
237
|
+
}
|
|
238
|
+
for (const candidate of candidates) {
|
|
239
|
+
const file = path.join(baseDir, candidate);
|
|
240
|
+
if (isFile(file)) {
|
|
241
|
+
result.path = file;
|
|
242
|
+
result.rel = candidate;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
function globalCssSelectionNote(selection) {
|
|
249
|
+
if (selection.configuredMissing !== void 0) return ` (globalCss ${selection.configuredMissing} \uC5C6\uC74C)`;
|
|
250
|
+
if (selection.configuredRejected !== void 0) return ` (globalCss ${selection.configuredRejected}: .css \uD30C\uC77C\uC774 \uC544\uB2D8)`;
|
|
251
|
+
return "";
|
|
252
|
+
}
|
|
253
|
+
function cssImportViaNote(files) {
|
|
254
|
+
return files !== void 0 && files.length > 0 ? ` (${files.join(" \xB7 ")} \uC758 import)` : "";
|
|
255
|
+
}
|
|
230
256
|
function detectProjectPaths(baseDirInput) {
|
|
231
257
|
const baseDir = path.resolve(baseDirInput);
|
|
232
258
|
const hasSrc = isDirectory(path.join(baseDir, "src"));
|
|
@@ -286,15 +312,295 @@ function findInstalledPackage(baseDirInput, name) {
|
|
|
286
312
|
}
|
|
287
313
|
}
|
|
288
314
|
function isPnpProject(baseDirInput) {
|
|
315
|
+
return pnpProjectRoot(baseDirInput) !== void 0;
|
|
316
|
+
}
|
|
317
|
+
function pnpProjectRoot(baseDirInput) {
|
|
289
318
|
let dir = resolveBaseDir(baseDirInput);
|
|
290
319
|
for (; ; ) {
|
|
291
|
-
if (isFile(path.join(dir, ".pnp.cjs")) || isFile(path.join(dir, ".pnp.js"))) return
|
|
292
|
-
if (existsSync(path.join(dir, ".git"))) return
|
|
320
|
+
if (isFile(path.join(dir, ".pnp.cjs")) || isFile(path.join(dir, ".pnp.js"))) return dir;
|
|
321
|
+
if (existsSync(path.join(dir, ".git"))) return void 0;
|
|
293
322
|
const parent = path.dirname(dir);
|
|
294
|
-
if (parent === dir) return
|
|
323
|
+
if (parent === dir) return void 0;
|
|
295
324
|
dir = parent;
|
|
296
325
|
}
|
|
297
326
|
}
|
|
327
|
+
var TAILWIND4_MIN_AXIS_VERSION = "1.4.0";
|
|
328
|
+
var COMPONENT_TAILWIND_CSS_MIN_VERSION = TAILWIND4_MIN_AXIS_VERSION;
|
|
329
|
+
function componentCssResolution(baseDir, pkg, name) {
|
|
330
|
+
if (pkg === void 0) return { kind: "undeclared" };
|
|
331
|
+
const own = hasDependency(pkg, name);
|
|
332
|
+
if (own !== void 0) return { kind: "app", range: own };
|
|
333
|
+
const pnpRoot = pnpRootOnlyDependency(baseDir, pkg, name);
|
|
334
|
+
if (pnpRoot !== void 0) return { kind: "pnp-root-only", range: pnpRoot.range };
|
|
335
|
+
const declared = declaredDependency(baseDir, pkg, name);
|
|
336
|
+
if (declared?.source !== "root") return { kind: "undeclared" };
|
|
337
|
+
if (!rootDeclarationsAllowed(baseDir, pkg)) return { kind: "app-lockfile", range: declared.range };
|
|
338
|
+
const installed = findInstalledPackage(baseDir, name);
|
|
339
|
+
if (installed === void 0) return { kind: "root-not-installed", range: declared.range };
|
|
340
|
+
if (isFile(path.join(installed.dir, "tailwind.css"))) {
|
|
341
|
+
return installed.version !== void 0 ? { kind: "root-ok", range: declared.range, installedVersion: installed.version } : { kind: "root-ok", range: declared.range };
|
|
342
|
+
}
|
|
343
|
+
const installedVersion = installed.version ?? "?";
|
|
344
|
+
const current = installedVersion !== "?" && (compareExactVersions(installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
|
|
345
|
+
return current ? { kind: "root-missing-file", range: declared.range, installedVersion } : { kind: "root-old", range: declared.range, installedVersion };
|
|
346
|
+
}
|
|
347
|
+
function componentCssResolvable(resolution) {
|
|
348
|
+
return resolution.kind === "app" || resolution.kind === "root-ok";
|
|
349
|
+
}
|
|
350
|
+
function tokensCssResolution(baseDir, pkg, name = "@axis-ds/tokens") {
|
|
351
|
+
const own = pkg !== void 0 ? hasDependency(pkg, name) : void 0;
|
|
352
|
+
if (own !== void 0) return { kind: "app", range: own };
|
|
353
|
+
const pnpRoot = pnpRootOnlyDependency(baseDir, pkg, name);
|
|
354
|
+
if (pnpRoot !== void 0) return { kind: "pnp-root-only", range: pnpRoot.range };
|
|
355
|
+
if (!isPnpProject(baseDir) && findInstalledPackage(baseDir, name) !== void 0) return { kind: "installed" };
|
|
356
|
+
const declared = rootDeclarationsAllowed(baseDir, pkg) ? declaredDependency(baseDir, pkg, name) : void 0;
|
|
357
|
+
return declared?.source === "root" ? { kind: "not-installed", source: "root", range: declared.range } : { kind: "not-installed", source: "none" };
|
|
358
|
+
}
|
|
359
|
+
function outsideCssPackageResolution(baseDir, cssDir, name, file) {
|
|
360
|
+
if (isPnpProject(baseDir)) return "unknown";
|
|
361
|
+
const usable = (p) => p !== void 0 && (file === void 0 || isFile(path.join(p.dir, file)));
|
|
362
|
+
if (!usable(findInstalledPackage(baseDir, name))) return "unknown";
|
|
363
|
+
return usable(findInstalledPackage(cssDir, name)) ? "resolved" : "unresolved";
|
|
364
|
+
}
|
|
365
|
+
var CSS_EXPORT_CONDITIONS = /* @__PURE__ */ new Set(["style", "default"]);
|
|
366
|
+
function splitPackageSpec(spec) {
|
|
367
|
+
const parts = spec.split("/");
|
|
368
|
+
const n = spec.startsWith("@") ? 2 : 1;
|
|
369
|
+
if (parts.length < n || parts.slice(0, n).some((p) => p === "" || p === "." || p === "..")) return void 0;
|
|
370
|
+
return { name: parts.slice(0, n).join("/"), rest: parts.slice(n).join("/") };
|
|
371
|
+
}
|
|
372
|
+
function resolveExportTarget(value) {
|
|
373
|
+
if (typeof value === "string") return value;
|
|
374
|
+
if (Array.isArray(value)) {
|
|
375
|
+
for (const v of value) {
|
|
376
|
+
const r = resolveExportTarget(v);
|
|
377
|
+
if (r !== void 0) return r;
|
|
378
|
+
}
|
|
379
|
+
return void 0;
|
|
380
|
+
}
|
|
381
|
+
if (isPlainObject(value)) {
|
|
382
|
+
for (const [key, v] of Object.entries(value)) {
|
|
383
|
+
if (!CSS_EXPORT_CONDITIONS.has(key)) continue;
|
|
384
|
+
if (v === null) return void 0;
|
|
385
|
+
const r = resolveExportTarget(v);
|
|
386
|
+
if (r !== void 0) return r;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return void 0;
|
|
390
|
+
}
|
|
391
|
+
function cssFileCandidates(p) {
|
|
392
|
+
return [p, `${p}.css`, path.join(p, "index.css")];
|
|
393
|
+
}
|
|
394
|
+
function exportsTarget(exportsField, subpath) {
|
|
395
|
+
const map = isPlainObject(exportsField) && Object.keys(exportsField).some((k) => k.startsWith(".")) ? exportsField : { ".": exportsField };
|
|
396
|
+
if (Object.prototype.hasOwnProperty.call(map, subpath)) {
|
|
397
|
+
const t = resolveExportTarget(map[subpath]);
|
|
398
|
+
if (t === void 0) return void 0;
|
|
399
|
+
return t.includes("*") || !t.startsWith("./") ? "?" : t;
|
|
400
|
+
}
|
|
401
|
+
if (Object.keys(map).some((k) => k.includes("*") || k.endsWith("/") && subpath.startsWith(k))) return "?";
|
|
402
|
+
return void 0;
|
|
403
|
+
}
|
|
404
|
+
function resolveCssPackageImport(fromDir, spec) {
|
|
405
|
+
const parsed = splitPackageSpec(spec);
|
|
406
|
+
if (parsed === void 0 || parsed.rest === "") return { kind: "unknown" };
|
|
407
|
+
const subpath = `./${parsed.rest}`;
|
|
408
|
+
let dir = resolveBaseDir(fromDir);
|
|
409
|
+
for (; ; ) {
|
|
410
|
+
const pkgDir = path.join(dir, "node_modules", ...parsed.name.split("/"));
|
|
411
|
+
if (isDirectory(pkgDir)) {
|
|
412
|
+
let manifest;
|
|
413
|
+
try {
|
|
414
|
+
const raw = JSON.parse(readFileSync(path.join(pkgDir, "package.json"), "utf8"));
|
|
415
|
+
manifest = isPlainObject(raw) ? raw : void 0;
|
|
416
|
+
} catch {
|
|
417
|
+
manifest = void 0;
|
|
418
|
+
}
|
|
419
|
+
if (manifest !== void 0 && manifest.exports) {
|
|
420
|
+
const version = exactVersionOf(manifest.version);
|
|
421
|
+
const target = exportsTarget(manifest.exports, subpath);
|
|
422
|
+
if (target === "?") return { kind: "unknown" };
|
|
423
|
+
if (target === void 0) {
|
|
424
|
+
return version !== void 0 ? { kind: "not-exported", pkgDir, subpath, version } : { kind: "not-exported", pkgDir, subpath };
|
|
425
|
+
}
|
|
426
|
+
const file = cssFileCandidates(path.join(pkgDir, target)).find(isFile);
|
|
427
|
+
if (file !== void 0) return { kind: "resolved", pkgDir, file };
|
|
428
|
+
return version !== void 0 ? { kind: "target-missing", pkgDir, subpath, target, version } : { kind: "target-missing", pkgDir, subpath, target };
|
|
429
|
+
}
|
|
430
|
+
const bare = cssFileCandidates(path.join(pkgDir, parsed.rest)).find(isFile);
|
|
431
|
+
if (bare !== void 0) return { kind: "resolved", pkgDir, file: bare };
|
|
432
|
+
}
|
|
433
|
+
const parent = path.dirname(dir);
|
|
434
|
+
if (parent === dir) return { kind: "not-found" };
|
|
435
|
+
dir = parent;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function installBase(pkgDir, name) {
|
|
439
|
+
let base = pkgDir;
|
|
440
|
+
for (let i = 0; i < name.split("/").length + 1; i++) base = path.dirname(base);
|
|
441
|
+
try {
|
|
442
|
+
return realpathSync(base);
|
|
443
|
+
} catch {
|
|
444
|
+
return path.resolve(base);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function isAncestorInstall(hit, app, name) {
|
|
448
|
+
const h = installBase(hit, name);
|
|
449
|
+
const a = installBase(app, name);
|
|
450
|
+
return a !== h && a.startsWith(h.endsWith(path.sep) ? h : h + path.sep);
|
|
451
|
+
}
|
|
452
|
+
function sameRealDir(a, b) {
|
|
453
|
+
const real = (p) => {
|
|
454
|
+
try {
|
|
455
|
+
return realpathSync(p);
|
|
456
|
+
} catch {
|
|
457
|
+
return path.resolve(p);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
return real(a) === real(b);
|
|
461
|
+
}
|
|
462
|
+
function cssPackageLineResolution(baseDir, lineDir, spec, otherDirs = []) {
|
|
463
|
+
if (isPnpProject(baseDir)) return { kind: "ok" };
|
|
464
|
+
const parsed = splitPackageSpec(spec);
|
|
465
|
+
if (parsed === void 0) return { kind: "ok" };
|
|
466
|
+
const r = resolveCssPackageImport(lineDir, spec);
|
|
467
|
+
if (r.kind === "resolved" || r.kind === "unknown") return { kind: "ok" };
|
|
468
|
+
const app = findInstalledPackage(baseDir, parsed.name);
|
|
469
|
+
if (r.kind === "not-exported" || r.kind === "target-missing") {
|
|
470
|
+
if (app !== void 0 && sameRealDir(app.dir, r.pkgDir)) return { kind: "ok" };
|
|
471
|
+
if (app !== void 0 && isAncestorInstall(r.pkgDir, app.dir, parsed.name)) return { kind: "ok" };
|
|
472
|
+
return r.kind === "not-exported" ? { ...r, kind: "shadow-not-exported" } : { ...r, kind: "shadow-target-missing" };
|
|
473
|
+
}
|
|
474
|
+
if (app !== void 0) return { kind: "ok" };
|
|
475
|
+
for (const other of typeof otherDirs === "function" ? otherDirs() : otherDirs) {
|
|
476
|
+
const o = resolveCssPackageImport(other, spec);
|
|
477
|
+
if (o.kind === "resolved") return { kind: "not-visible", pkgDir: o.pkgDir, fromDir: resolveBaseDir(other) };
|
|
478
|
+
}
|
|
479
|
+
return { kind: "ok" };
|
|
480
|
+
}
|
|
481
|
+
function deferredComponentImportReason(d, installCommand) {
|
|
482
|
+
const line = `@import "${d.name}/tailwind.css";`;
|
|
483
|
+
const current = d.installedVersion !== void 0 && d.installedVersion !== "?" && (compareExactVersions(d.installedVersion, COMPONENT_TAILWIND_CSS_MIN_VERSION) ?? -1) >= 0;
|
|
484
|
+
return d.installedVersion === void 0 ? `${d.name} \uAC00 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB410\uC9C0\uB9CC \uC124\uCE58\uB418\uC9C0 \uC54A\uC544 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58(${installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : current ? `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4 ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uAC00 \uC190\uC0C1\uB410\uC744 \uC218 \uC788\uC73C\uB2C8 \uB2E4\uC2DC \uC124\uCE58(${installCommand}) \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.` : `\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8\uC5D0 \uC120\uC5B8\uB41C ${d.name} \uC758 \uC124\uCE58\uBCF8(${d.installedVersion === "?" ? "\uBC84\uC804 \uBAA8\uB984" : d.installedVersion})\uC5D0 tailwind.css \uAC00 \uC5C6\uC5B4(${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uBD80\uD130 \uC81C\uACF5) ${line} \uB97C \uB123\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ${COMPONENT_TAILWIND_CSS_MIN_VERSION} \uC774\uC0C1\uC73C\uB85C \uC62C\uB9B0 \uB4A4 theme add \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uAC70\uB098 \uC9C1\uC811 \uB123\uC73C\uC138\uC694.`;
|
|
485
|
+
}
|
|
486
|
+
function findPnpUnpluggedPackages(baseDirInput, name, range) {
|
|
487
|
+
const root = pnpProjectRoot(baseDirInput);
|
|
488
|
+
if (root === void 0) return [];
|
|
489
|
+
const unplugged = path.join(root, ".yarn", "unplugged");
|
|
490
|
+
let entries;
|
|
491
|
+
try {
|
|
492
|
+
entries = readdirSync(unplugged).sort();
|
|
493
|
+
} catch {
|
|
494
|
+
return [];
|
|
495
|
+
}
|
|
496
|
+
const found = [];
|
|
497
|
+
for (const entry of entries) {
|
|
498
|
+
const pkgDir = path.join(unplugged, entry, "node_modules", ...name.split("/"));
|
|
499
|
+
let version;
|
|
500
|
+
try {
|
|
501
|
+
const parsed = JSON.parse(readFileSync(path.join(pkgDir, "package.json"), "utf8"));
|
|
502
|
+
version = isPlainObject(parsed) && parsed.name === name ? exactVersionOf(parsed.version) : void 0;
|
|
503
|
+
} catch {
|
|
504
|
+
version = void 0;
|
|
505
|
+
}
|
|
506
|
+
if (version !== void 0 && versionSatisfiesRange(version, range) === true) found.push(pkgDir);
|
|
507
|
+
}
|
|
508
|
+
return found;
|
|
509
|
+
}
|
|
510
|
+
function parsePartialVersion(token) {
|
|
511
|
+
const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(token.trim());
|
|
512
|
+
if (!m) return void 0;
|
|
513
|
+
const num = (s) => s === void 0 || /^[xX*]$/.test(s) ? void 0 : Number(s);
|
|
514
|
+
const major = num(m[1]);
|
|
515
|
+
const minor = major === void 0 ? void 0 : num(m[2]);
|
|
516
|
+
const patch = minor === void 0 ? void 0 : num(m[3]);
|
|
517
|
+
return { major, minor, patch, pre: patch === void 0 ? void 0 : m[4] };
|
|
518
|
+
}
|
|
519
|
+
function coreOf(v) {
|
|
520
|
+
return v.replace(/^v/, "").replace(/[-+].*$/, "");
|
|
521
|
+
}
|
|
522
|
+
function intervalsOfToken(token) {
|
|
523
|
+
const t = token.trim();
|
|
524
|
+
if (t === "" || t === "*" || /^[xX]$/.test(t)) return [{ preCores: [] }];
|
|
525
|
+
const op = /^(\^|~>?|>=|<=|>|<|=)?\s*(.+)$/.exec(t);
|
|
526
|
+
if (!op) return void 0;
|
|
527
|
+
const p = parsePartialVersion(op[2]);
|
|
528
|
+
if (!p) return void 0;
|
|
529
|
+
const full = (maj, min, pat, pre) => `${maj}.${min}.${pat}${pre ? `-${pre}` : ""}`;
|
|
530
|
+
const preCores = p.pre !== void 0 ? [full(p.major ?? 0, p.minor ?? 0, p.patch ?? 0)] : [];
|
|
531
|
+
const lower = full(p.major ?? 0, p.minor ?? 0, p.patch ?? 0, p.pre);
|
|
532
|
+
const kind = op[1] ?? "";
|
|
533
|
+
if (p.major === void 0) return kind === "" || kind === "=" || kind === ">=" ? [{ preCores }] : void 0;
|
|
534
|
+
const next = p.minor === void 0 ? full(p.major + 1, 0, 0) : p.patch === void 0 ? full(p.major, p.minor + 1, 0) : void 0;
|
|
535
|
+
switch (kind) {
|
|
536
|
+
case "":
|
|
537
|
+
case "=":
|
|
538
|
+
return [next === void 0 ? { min: { v: lower, inclusive: true }, max: { v: lower, inclusive: true }, preCores } : { min: { v: lower, inclusive: true }, max: { v: next, inclusive: false, coreOnly: true }, preCores }];
|
|
539
|
+
case ">=":
|
|
540
|
+
return [{ min: { v: lower, inclusive: true }, preCores }];
|
|
541
|
+
case ">":
|
|
542
|
+
return [next === void 0 ? { min: { v: lower, inclusive: false }, preCores } : { min: { v: next, inclusive: true }, preCores }];
|
|
543
|
+
case "<":
|
|
544
|
+
return [{ max: { v: lower, inclusive: false, coreOnly: p.pre === void 0 }, preCores }];
|
|
545
|
+
case "<=":
|
|
546
|
+
return [next === void 0 ? { max: { v: lower, inclusive: true }, preCores } : { max: { v: next, inclusive: false, coreOnly: true }, preCores }];
|
|
547
|
+
case "~":
|
|
548
|
+
case "~>": {
|
|
549
|
+
const upper = p.minor === void 0 ? full(p.major + 1, 0, 0) : full(p.major, p.minor + 1, 0);
|
|
550
|
+
return [{ min: { v: lower, inclusive: true }, max: { v: upper, inclusive: false, coreOnly: true }, preCores }];
|
|
551
|
+
}
|
|
552
|
+
case "^": {
|
|
553
|
+
const upper = p.major > 0 || p.minor === void 0 ? full(p.major + 1, 0, 0) : p.minor > 0 || p.patch === void 0 ? full(0, p.minor + 1, 0) : full(0, 0, p.patch + 1);
|
|
554
|
+
return [{ min: { v: lower, inclusive: true }, max: { v: upper, inclusive: false, coreOnly: true }, preCores }];
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return void 0;
|
|
558
|
+
}
|
|
559
|
+
function satisfiesInterval(version, iv) {
|
|
560
|
+
if (iv.min !== void 0) {
|
|
561
|
+
const c = compareExactVersions(version, iv.min.v);
|
|
562
|
+
if (c === void 0) return void 0;
|
|
563
|
+
if (c < 0 || c === 0 && !iv.min.inclusive) return false;
|
|
564
|
+
}
|
|
565
|
+
if (iv.max !== void 0) {
|
|
566
|
+
const c = iv.max.coreOnly ? compareExactVersions(coreOf(version), coreOf(iv.max.v)) : compareExactVersions(version, iv.max.v);
|
|
567
|
+
if (c === void 0) return void 0;
|
|
568
|
+
if (c > 0 || c === 0 && !iv.max.inclusive) return false;
|
|
569
|
+
}
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
function versionSatisfiesRange(version, range) {
|
|
573
|
+
if (exactVersionOf(version) === void 0) return void 0;
|
|
574
|
+
const alternatives = range.trim().split("||");
|
|
575
|
+
let unknown = false;
|
|
576
|
+
for (const alt of alternatives) {
|
|
577
|
+
const a = alt.trim();
|
|
578
|
+
let intervals;
|
|
579
|
+
const hyphen = /^(\S+)\s+-\s+(\S+)$/.exec(a);
|
|
580
|
+
if (hyphen) {
|
|
581
|
+
const lo = intervalsOfToken(`>=${hyphen[1]}`);
|
|
582
|
+
const hi = intervalsOfToken(`<=${hyphen[2]}`);
|
|
583
|
+
intervals = lo && hi ? [...lo, ...hi] : void 0;
|
|
584
|
+
} else {
|
|
585
|
+
const tokens = a === "" ? [""] : a.replace(/(>=|<=|>|<|=|\^|~>?)\s+/g, "$1").split(/\s+/);
|
|
586
|
+
const parts = tokens.map(intervalsOfToken);
|
|
587
|
+
intervals = parts.every((x) => x !== void 0) ? parts.flat() : void 0;
|
|
588
|
+
}
|
|
589
|
+
if (intervals === void 0) {
|
|
590
|
+
unknown = true;
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
const pre = /-/.test(version.replace(/\+.*$/, ""));
|
|
594
|
+
if (pre && !intervals.some((iv) => iv.preCores.includes(coreOf(version)))) continue;
|
|
595
|
+
const results = intervals.map((iv) => satisfiesInterval(version, iv));
|
|
596
|
+
if (results.some((x) => x === void 0)) {
|
|
597
|
+
unknown = true;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
if (results.every((x) => x === true)) return true;
|
|
601
|
+
}
|
|
602
|
+
return unknown ? void 0 : false;
|
|
603
|
+
}
|
|
298
604
|
function compareExactVersions(a, b) {
|
|
299
605
|
const parse = (v) => {
|
|
300
606
|
const m = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?/.exec(v.trim());
|
|
@@ -506,11 +812,23 @@ export {
|
|
|
506
812
|
runScriptCommand,
|
|
507
813
|
workspaceRunCommand,
|
|
508
814
|
GLOBAL_CSS_CANDIDATES,
|
|
815
|
+
selectGlobalCss,
|
|
816
|
+
globalCssSelectionNote,
|
|
817
|
+
cssImportViaNote,
|
|
509
818
|
detectProjectPaths,
|
|
510
819
|
projectFileExists,
|
|
511
820
|
ROOT_LAYOUT_FILES,
|
|
512
821
|
findInstalledPackage,
|
|
513
822
|
isPnpProject,
|
|
823
|
+
pnpProjectRoot,
|
|
824
|
+
TAILWIND4_MIN_AXIS_VERSION,
|
|
825
|
+
componentCssResolution,
|
|
826
|
+
componentCssResolvable,
|
|
827
|
+
tokensCssResolution,
|
|
828
|
+
outsideCssPackageResolution,
|
|
829
|
+
cssPackageLineResolution,
|
|
830
|
+
deferredComponentImportReason,
|
|
831
|
+
findPnpUnpluggedPackages,
|
|
514
832
|
compareExactVersions,
|
|
515
833
|
MONET_CATEGORIES,
|
|
516
834
|
MonetClient,
|