@seed-design/cli 0.0.3 → 1.1.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 +73 -4
- package/bin/index.mjs +12 -2
- package/package.json +8 -6
- package/src/commands/add-all.ts +201 -0
- package/src/commands/add.ts +149 -149
- package/src/commands/init.ts +42 -8
- package/src/env.d.ts +13 -0
- package/src/index.ts +2 -0
- package/src/schema.ts +38 -64
- package/src/tests/resolve-dependencies.test.ts +424 -0
- package/src/utils/analytics.ts +119 -0
- package/src/utils/fetch.ts +122 -0
- package/src/utils/get-config.ts +15 -48
- package/src/utils/install.ts +7 -12
- package/src/utils/resolve-dependencies.ts +77 -0
- package/src/utils/transformers/index.ts +2 -1
- package/src/utils/transformers/transform-jsx.ts +0 -1
- package/src/utils/transformers/transform-rsc.ts +21 -4
- package/src/utils/write.ts +75 -0
- package/src/test/add-relative-registries.test.ts +0 -182
- package/src/utils/add-relative-registries.ts +0 -43
- package/src/utils/get-metadata.ts +0 -75
package/README.md
CHANGED
|
@@ -1,7 +1,76 @@
|
|
|
1
1
|
# @seed-design/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SEED Design 컴포넌트를 프로젝트에 추가하기 위한 CLI 도구입니다.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
## 개발 환경 설정
|
|
6
|
+
|
|
7
|
+
### 의존성 설치
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### 환경 변수 설정 (선택사항)
|
|
14
|
+
|
|
15
|
+
PostHog 텔레메트리를 사용하려면 `.env` 파일을 생성하세요:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# packages/cli/.env
|
|
19
|
+
POSTHOG_API_KEY=your-api-key
|
|
20
|
+
POSTHOG_HOST=https://us.i.posthog.com
|
|
21
|
+
|
|
22
|
+
# 텔레메트리 비활성화 (로컬 개발 시)
|
|
23
|
+
DISABLE_TELEMETRY=true
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**참고**: 환경 변수가 없어도 CLI는 정상적으로 동작합니다. 텔레메트리만 비활성화됩니다.
|
|
27
|
+
|
|
28
|
+
## 개발
|
|
29
|
+
|
|
30
|
+
### Dev 모드 실행
|
|
31
|
+
|
|
32
|
+
Watch 모드로 CLI를 실행합니다:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bun dev
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Dev 모드에서는:
|
|
39
|
+
- 코드 변경 시 자동으로 재빌드됩니다
|
|
40
|
+
- `NODE_ENV=dev`로 설정되어 텔레메트리 이벤트가 콘솔에만 출력됩니다
|
|
41
|
+
- PostHog API 호출이 실제로 발생하지 않습니다
|
|
42
|
+
|
|
43
|
+
### 로컬 테스트
|
|
44
|
+
|
|
45
|
+
1. `@seed-design/docs`에서 `bun dev` 실행 (snippet 서버)
|
|
46
|
+
2. `packages/cli`에서 `bun dev` 실행 (watch 모드)
|
|
47
|
+
3. `bun run ./bin/index.mjs` 실행하여 CLI 명령어 테스트:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bun run ./bin/index.mjs init
|
|
51
|
+
bun run ./bin/index.mjs add ui:action-button
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 빌드
|
|
55
|
+
|
|
56
|
+
프로덕션 빌드:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
bun run build
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
빌드 결과물:
|
|
63
|
+
- `bin/index.mjs` - 번들링 및 minify된 CLI 실행 파일
|
|
64
|
+
- 환경 변수 (`POSTHOG_API_KEY`, `POSTHOG_HOST`)가 빌드 시 번들에 주입됩니다
|
|
65
|
+
|
|
66
|
+
## 테스트
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
bun test
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 배포
|
|
73
|
+
|
|
74
|
+
이 패키지는 [Changesets](https://github.com/changesets/changesets)을 통해 자동으로 배포됩니다.
|
|
75
|
+
|
|
76
|
+
**참고**: 배포 시 GitHub Secrets에 `POSTHOG_API_KEY`와 `POSTHOG_HOST`가 설정되어 있어야 텔레메트리가 활성화됩니다.
|
package/bin/index.mjs
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as S from"@clack/prompts";import{cosmiconfig as ce}from"cosmiconfig";import{execa as pe}from"execa";import b from"fs";import T from"path";import{z as I}from"zod";import se from"picocolors";var y=e=>se.cyan(e);import{detect as ae}from"@antfu/ni";async function U(e){let t=await ae({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t==="deno"?"deno":t??"npm"}var F="seed-design",me=ce(F,{searchPlaces:[`${F}.json`]}),_=I.object({$schema:I.string().optional(),rsc:I.coerce.boolean().default(!1),tsx:I.coerce.boolean().default(!0),path:I.string()}).strict(),le=_.extend({resolvedUIPaths:I.string(),resolvedLibPaths:I.string()});async function J(e){let t=await fe(e);return t?await de(e,t):null}async function de(e,t){let r=T.resolve(e,t.path);b.existsSync(r)||b.mkdirSync(r,{recursive:!0});let o=T.join(r,"ui"),s=T.join(r,"lib");return b.existsSync(o)||b.mkdirSync(o,{recursive:!0}),b.existsSync(s)||b.mkdirSync(s,{recursive:!0}),le.parse({...t,resolvedUIPaths:o,resolvedLibPaths:s})}async function fe(e){try{let t=await me.search(e);return _.parse(t.config)}catch{if(S.log.error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0 `seed-design.json` \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694."),await S.confirm({message:"seed-design.json \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC2DC\uACA0\uC5B4\uC694?"})===!0){let r=await U(e);await pe(r,["seed-design","init","--default"],{cwd:e}),S.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}else S.outro(y("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}}import*as C from"@clack/prompts";import{z as c}from"zod";var ge=c.union([c.literal("ui"),c.literal("lib")]),N=c.object({name:c.string(),description:c.string().optional(),dependencies:c.array(c.string()).optional(),devDependencies:c.array(c.string()).optional(),innerDependencies:c.array(c.string()).optional(),files:c.array(c.string()),deprecated:c.literal(!0).optional()}),k=c.array(N),ue=N.omit({files:!0}),ye=ue.extend({registries:c.array(c.object({name:c.string(),type:ge,content:c.string()}))}),tt=c.array(ye);async function G(e,t,r="ui"){return await Promise.all(e.map(async s=>{try{return await(await fetch(`${t}/__registry__/${r}/${s}.json`)).json()}catch(a){let p=await fetch(`${t}/__registry__/${r}/index.json`).then(g=>g.json()),l=k.parse(p).map(g=>g.name);C.log.error(`${r}:${s} \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC544\uC694.`),C.log.info(`\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8: ${l.join(", ")}`),C.log.info(JSON.stringify({baseUrl:t,error:a.toString()},null,2)),process.exit(1)}}))}async function B(e,t,r="ui"){let[o]=await G([e],t,r);return o}async function V(e){try{let[t]=await G(["index"],e,"ui");return k.parse(t)}catch(t){C.log.error("\uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC778\uB371\uC2A4\uB97C \uAC00\uC838\uC624\uB294 \uB370 \uC2E4\uD328\uD588\uC5B4\uC694."),C.log.info(JSON.stringify({baseUrl:e,error:t.toString()},null,2)),process.exit(1)}}async function K(e){let[t]=await G(["index"],e,"lib");return k.parse(t)}import{promises as Re}from"fs";import{tmpdir as be}from"os";import q from"path";import{transformFromAstSync as he}from"@babel/core";import xe from"@babel/plugin-transform-typescript";import*as $ from"recast";import{parse as we}from"@babel/parser";var Ie={sourceType:"module",allowImportExportEverywhere:!0,allowReturnOutsideFunction:!0,startLine:1,tokens:!0,plugins:["asyncGenerators","bigInt","classPrivateMethods","classPrivateProperties","classProperties","classStaticBlock","decimal","decorators-legacy","doExpressions","dynamicImport","exportDefaultFrom","exportNamespaceFrom","functionBind","functionSent","importAssertions","importMeta","nullishCoalescingOperator","numericSeparator","objectRestSpread","optionalCatchBinding","optionalChaining",["pipelineOperator",{proposal:"minimal"}],["recordAndTuple",{syntaxType:"hash"}],"throwExpressions","topLevelAwait","v8intrinsic","typescript","jsx"]},X=async({sourceFile:e,config:t})=>{let r=e.getFullText();if(t.tsx)return r;let o=$.parse(r,{parser:{parse:a=>we(a,Ie)}}),s=he(o,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[xe],configFile:!1});if(!s||!s.ast)throw new Error("Failed to transform JSX");return $.print(s.ast).code};import{SyntaxKind as Se}from"ts-morph";var Y=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let r=e.getFirstChildByKind(Se.ExpressionStatement);return r?.getText()==='"use client";'&&r.remove(),e};import{Project as Ce,ScriptKind as ve}from"ts-morph";var Pe=[Y],je=new Ce({compilerOptions:{}});async function Me(e){let t=await Re.mkdtemp(q.join(be(),"seed-deisgn-"));return q.join(t,e)}async function H(e){let t=await Me(e.filename),r=je.createSourceFile(t,e.raw,{scriptKind:ve.TSX});for(let o of Pe)o({sourceFile:r,...e});return await X({sourceFile:r,...e})}import*as i from"@clack/prompts";import z from"fs-extra";import ee from"path";import Te from"picocolors";import{z as R}from"zod";var Q="https://seed-design.io";function W({userSelects:e,uiRegistryIndex:t,libRegistryIndex:r}){let o=[];function s({registryName:a,type:p}){if(o.some(l=>l.name===a&&l.type===p))return;o.push({type:p,name:a});let f=p==="ui"?t.find(l=>l.name===a):r.find(l=>l.name===a);if(f&&f.innerDependencies)for(let l of f.innerDependencies){let[g,M]=l.split(":");s({registryName:M,type:g})}}for(let a of e)s({registryName:a,type:"ui"});return Array.from(o)}import*as Z from"@clack/prompts";import{execa as Oe}from"execa";import Ae from"picocolors";import Ue from"findup-sync";import ke from"fs-extra";var $e="package.json";function De(){let e=Ue($e);if(!e)throw new Error("No package.json file found in the project.");return e}function D(){let e=De();return ke.readJSONSync(e)}async function L({cwd:e,deps:t,dev:r=!1}){let{start:o,stop:s}=Z.spinner(),a=await U(e),p=D(),f={...p.dependencies,...p.devDependencies},l=t.filter(w=>!f[w]),g=t.filter(w=>f[w]);if(!l.length)return{installed:new Set,filtered:new Set};o(Ae.gray("\uC758\uC874\uC131 \uC124\uCE58\uC911..."));let O=[a==="npm"?"install":"add",r?"-D":null,...l].filter(Boolean);try{await Oe(a,O,{cwd:e})}catch(w){console.error(`\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328: ${w}`),process.exit(1)}return s("\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC."),{installed:l,filtered:g}}var Ge=R.object({components:R.array(R.string()).optional(),all:R.boolean(),includeDeprecated:R.boolean().optional(),cwd:R.string(),baseUrl:R.string().optional()}),te=e=>{e.command("add [...components]","add component").option("-a, --all","Add all components",{default:!1}).option("--include-deprecated","Include deprecated components when used with `--all`",{default:!1}).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",{default:process.cwd()}).option("-u, --baseUrl <baseUrl>","the base url of the registry. defaults to the current directory.",{default:Q}).example("seed-design add action-button").example("seed-design add alert-dialog").action(async(t,r)=>{i.intro(Te.bgCyan("seed-design add"));let o=Ge.parse({components:t,...r}),s=o.cwd,a=o.baseUrl,p=await J(s),f=await V(a),l=await K(a),g=await(async()=>{if(o.all)return o.includeDeprecated?f.map(n=>n.name):f.filter(({deprecated:n})=>!n).map(n=>n.name);if(o.components.length>0)return o.components;let d=await i.multiselect({message:"\uCD94\uAC00\uD560 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (\uC2A4\uD398\uC774\uC2A4 \uBC14\uB85C \uC5EC\uB7EC \uAC1C \uC120\uD0DD \uAC00\uB2A5)",options:f.map(({name:n,description:h,deprecated:x})=>({label:`${x?"(deprecated) ":""}${n}`,value:n,hint:h,deprecated:x})).sort((n,h)=>n.deprecated===h.deprecated?n.label.localeCompare(h.label):n.deprecated?1:-1)});return i.isCancel(d)&&(i.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),d})();g?.length||(i.log.error("\uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0)),i.log.message(`\uC120\uD0DD\uB41C \uCEF4\uD3EC\uB10C\uD2B8: ${y(g.join(", "))}`);let M=W({userSelects:g,uiRegistryIndex:f,libRegistryIndex:l}),v=[],{start:O,stop:w}=i.spinner();O("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");for(let d of M){let n=await B(d.name,a,d.type);v.push(n)}if(w(),v.length){let d=v.filter(n=>!g.includes(n.name));i.log.message(`\uCD94\uAC00\uB85C \uC124\uCE58\uB420 \uB808\uC9C0\uC2A4\uD2B8\uB9AC: ${y(d.map(n=>n.name).join(", "))}`)}let A=[],u={installed:new Set,filtered:new Set};for(let d of v){if(d.deprecated&&!o.includeDeprecated){let n=await i.confirm({message:`${y(d.name)}\uB294 deprecated \uB418\uC5C8\uC5B4\uC694. \uCD94\uAC00\uD560\uAE4C\uC694?`,initialValue:!1});if(n===!1||i.isCancel(n)){i.log.info(`${y(d.name)} \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC744\uAC8C\uC694.`);continue}}for(let n of d.registries){let h="";switch(n.type){case"ui":h=p.resolvedUIPaths;break;case"lib":h=p.resolvedLibPaths;break;default:break}z.existsSync(h)||await z.mkdir(h,{recursive:!0});let x=ee.resolve(h,n.name),oe=await H({filename:n.name,config:p,raw:n.content});p.tsx||(x=x.replace(/\.tsx$/,".jsx"),x=x.replace(/\.ts$/,".js")),await z.writeFile(x,oe);let ie=ee.relative(s,x);A.push({name:n.name,path:ie})}if(d.dependencies?.length){let n=await L({cwd:s,deps:d.dependencies});u.installed=new Set([...u.installed,...n.installed]),u.filtered=new Set([...u.filtered,...n.filtered])}if(d.devDependencies?.length){let n=await L({cwd:s,deps:d.devDependencies,dev:!0});u.installed=new Set([...u.installed,...n.installed]),u.filtered=new Set([...u.filtered,...n.filtered])}i.log.success(`${y(d.name)} \uAD00\uB828 \uD30C\uC77C \uCD94\uAC00 \uC644\uB8CC`)}if(u.installed.size&&i.log.message(`\uC124\uCE58\uB41C \uC758\uC874\uC131: ${y(Array.from(u.installed).join(", "))}`),u.filtered.size&&i.log.message(`\uC774\uBBF8 \uC124\uCE58\uB41C \uC758\uC874\uC131: ${y(Array.from(u.filtered).join(", "))}`),A.length)for(let d of A)i.log.message(`\uCD94\uAC00\uB41C \uD30C\uC77C: ${y(d.path)}`);i.outro("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00 \uC644\uB8CC.")})};import*as m from"@clack/prompts";import Le from"fs-extra";import re from"path";import P from"picocolors";import{z as E}from"zod";var ze=E.object({cwd:E.string(),yes:E.boolean().optional()}),ne=e=>{e.command("init","seed-design.json \uD30C\uC77C \uC0DD\uC131").option("-c, --cwd <cwd>","\uC791\uC5C5 \uB514\uB809\uD1A0\uB9AC. \uAE30\uBCF8\uAC12\uC740 \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC.",{default:process.cwd()}).option("-y, --yes","\uBAA8\uB4E0 \uC9C8\uBB38\uC5D0 \uB300\uD574 \uAE30\uBCF8\uAC12\uC73C\uB85C \uB2F5\uBCC0\uD569\uB2C8\uB2E4.").action(async t=>{let r=p=>P.cyan(p);m.intro(P.bgCyan("seed-design.json \uD30C\uC77C \uC0DD\uC131"));let o=ze.parse(t),s=o.yes,a={rsc:!1,tsx:!0,path:"./seed-design"};s||(a={...await m.group({tsx:()=>m.confirm({message:`${r("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>m.confirm({message:`${r("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),path:()=>m.text({message:`${r("seed-design \uD3F4\uB354")} \uACBD\uB85C\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. (\uAE30\uBCF8\uAC12\uC740 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0 \uC0DD\uC131\uB429\uB2C8\uB2E4.)`,initialValue:"./seed-design",defaultValue:"./seed-design",placeholder:"./seed-design"})},{onCancel:()=>{m.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:p,stop:f}=m.spinner();p("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let l=re.resolve(o.cwd,"seed-design.json");await Le.writeFile(l,`${JSON.stringify(a,null,2)}
|
|
3
|
-
|
|
2
|
+
import*as C from"@clack/prompts";import{cosmiconfig as xe}from"cosmiconfig";import{execa as be}from"execa";import{z as _}from"zod";import he from"picocolors";var a=e=>he.cyan(e);import{detect as we}from"@antfu/ni";async function z(e){let t=await we({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t==="deno"?"deno":t??"npm"}var te="seed-design",Ie=xe(te,{searchPlaces:[`${te}.json`]}),re=_.object({$schema:_.string().optional(),rsc:_.coerce.boolean().default(!1),tsx:_.coerce.boolean().default(!0),path:_.string(),telemetry:_.coerce.boolean().optional().default(!0)}).strict();async function D(e){let t=await $e(e);return t?re.parse(t):null}async function $e(e){try{let t=await Ie.search(e);return re.parse(t.config)}catch{C.log.error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0 `seed-design.json` \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694."),await C.confirm({message:"seed-design.json \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC2DC\uACA0\uC5B4\uC694?"})||(C.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1));let i=await z(e);await be(i,["seed-design","init","--default"],{cwd:e}),C.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}}function L({selectedItemKeys:e,publicRegistries:t}){let i=[],c=new Set;function p(r,n){let l=i.find(o=>o.registryId===r);if(!l?.items.some(o=>o.id===n.id)){if(l?l.items.push(n):i.push({registryId:r,items:[n]}),n.dependencies?.length)for(let o of n.dependencies)c.add(o);if(n.innerDependencies?.length)for(let o of n.innerDependencies)for(let u of o.itemIds){let w=t.find(R=>R.id===o.registryId)?.items.find(R=>R.id===u);if(!w)throw new Error(`Cannot find dependency item: ${o.registryId}:${u}`);p(o.registryId,w)}}}for(let r of e){let[n,...l]=r.split(":"),o=l.join(":");if(!n||!o)throw new Error(`Invalid snippet format: "${r}"`);let u=t.find(w=>w.id===n)?.items.find(w=>w.id===o);if(!u)throw new Error(`Cannot find snippet: "${r}"`);p(n,u)}return{registryItemsToAdd:i,npmDependenciesToAdd:c}}import*as Q from"@clack/prompts";import{z as f}from"zod";var q=f.object({id:f.string(),description:f.string().optional(),deprecated:f.boolean().optional(),hideFromCLICatalog:f.boolean().optional(),dependencies:f.array(f.string()).optional(),innerDependencies:f.array(f.object({registryId:f.string(),itemIds:f.array(f.string())})).optional(),snippets:f.array(f.object({path:f.string(),content:f.string()}))}),W=f.object({id:f.string(),hideFromCLICatalog:f.boolean().optional(),items:f.array(q.omit({snippets:!0}).extend({snippets:f.array(f.object({path:f.string()}))}))}),se=f.array(f.object({id:f.string()}));async function K({baseUrl:e}){let t=await fetch(`${e}/__registry__/index.json`);if(!t.ok)throw new Error(`Failed to fetch registries: ${t.status} ${t.statusText}`);let i=await t.json(),{success:c,data:p,error:r}=se.safeParse(i);if(!c)throw new Error(`Failed to parse registries: ${r?.message}`);return p}async function N({baseUrl:e,registryId:t}){let i=await fetch(`${e}/__registry__/${t}/index.json`);if(!i.ok)throw new Error(`Failed to fetch ${t} registry: ${i.status} ${i.statusText}`);let c=await i.json(),{success:p,data:r,error:n}=W.safeParse(c);if(!p)throw new Error(`Failed to parse ${t} registry: ${n?.message}`);return r}async function Pe({baseUrl:e,registryId:t,registryItemId:i}){let c=await fetch(`${e}/__registry__/${t}/${i}.json`);if(!c.ok)throw new Error(`Failed to fetch ${i}: ${c.status} ${c.statusText}`);let p=await c.json(),{success:r,data:n,error:l}=q.safeParse(p);if(!r)throw new Error(`Failed to parse ${i}: ${l?.message}`);return n}async function ie({baseUrl:e,registryId:t,registryItemIds:i}){return await Promise.all(i.map(async c=>{try{return await Pe({baseUrl:e,registryId:t,registryItemId:c})}catch(p){let r=await fetch(`${e}/__registry__/${t}/index.json`);if(!r.ok)throw new Error(`${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uAC00\uC838\uC624\uC9C0 \uBABB\uD588\uC5B4\uC694: ${r.status} ${r.statusText}`);let n=await r.json(),{success:l,data:o}=W.safeParse(n);throw l?(Q.log.error(`${c} \uC2A4\uB2C8\uD3AB\uC774 ${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC5C6\uC5B4\uC694.`),Q.log.info(`${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uB294 \uC2A4\uB2C8\uD3AB:
|
|
3
|
+
${o.items.map(u=>u.id).join(`
|
|
4
|
+
`)}`),p):new Error(`Failed to parse registry index for ${t}`)}}))}import{promises as Ce}from"fs";import{tmpdir as Ae}from"os";import ae from"path";import{transformFromAstSync as Se}from"@babel/core";import Re from"@babel/plugin-transform-typescript";import*as B from"recast";import{parse as Te}from"@babel/parser";var je={sourceType:"module",allowImportExportEverywhere:!0,allowReturnOutsideFunction:!0,startLine:1,tokens:!0,plugins:["asyncGenerators","bigInt","classPrivateMethods","classPrivateProperties","classProperties","classStaticBlock","decimal","decorators-legacy","doExpressions","dynamicImport","exportDefaultFrom","exportNamespaceFrom","functionBind","functionSent","importAssertions","importMeta","nullishCoalescingOperator","numericSeparator","objectRestSpread","optionalCatchBinding","optionalChaining",["pipelineOperator",{proposal:"minimal"}],["recordAndTuple",{syntaxType:"hash"}],"throwExpressions","topLevelAwait","v8intrinsic","typescript","jsx"]},oe=async({sourceFile:e,config:t})=>{let i=e.getFullText();if(t.tsx)return i;let c=B.parse(i,{parser:{parse:r=>Te(r,je)}}),p=Se(c,i,{cloneInputAst:!1,code:!1,ast:!0,plugins:[Re],configFile:!1});if(!p||!p.ast)throw new Error("Failed to transform JSX");return B.print(p.ast).code};import{SyntaxKind as Ee}from"ts-morph";var ne=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let i=e.getFirstChildByKind(Ee.ExpressionStatement);if(!i)return e;let c=i.getExpression();if(!c)return e;let p=c.getText().trim();if(p!=='"use client"'&&p!=="'use client'")return e;let r=i.getText(),n=i.getFullText();if(r.trim()===n.trim())return e;let o=n.replace(r,"").replace(/^\s*\n/,"").replace(/\n\s*$/,"");return i.replaceWithText(o),e};import{Project as ve,ScriptKind as _e}from"ts-morph";var De=[ne],Oe=new ve({compilerOptions:{}});async function ke(e){let t=await Ce.mkdtemp(ae.join(Ae(),"seed-design-"));return ae.join(t,e)}async function ce(e){let t=await ke(e.filename),i=Oe.createSourceFile(t,e.raw,{scriptKind:_e.TSX});for(let c of De)c({sourceFile:i,...e});return await oe({sourceFile:i,...e})}import*as pe from"@clack/prompts";import Z from"fs-extra";import J from"path";async function H({registryItemsToAdd:e,rootPath:t,cwd:i,baseUrl:c,config:p}){let r=[];for(let{registryId:n,items:l}of e){let o=J.join(t,n);Z.ensureDirSync(o);let u=await ie({baseUrl:c,registryId:n,registryItemIds:l.map(w=>w.id)});for(let{id:w,snippets:R}of u){let E=await Promise.all(R.map(async x=>{let $=await ce({filename:x.path,config:p,raw:x.content}),I=J.join(o,x.path);return p.tsx||(I=I.replace(/\.tsx$/,".jsx"),I=I.replace(/\.ts$/,".js")),{filePath:I,content:$,relativePath:J.relative(i,I),name:`${n}:${w}`}}));await Promise.all(E.map(async({filePath:x,content:$})=>{await Z.ensureDir(J.dirname(x)),await Z.writeFile(x,$)}));let b=E.map(({name:x,relativePath:$})=>({name:x,path:$}));r.push(...b),pe.log.success(`${a(`${n}:${w}`)} \uAD00\uB828 \uC2A4\uB2C8\uD3AB \uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC: ${a(b.map(x=>x.path).join(", "))}`)}}}import*as d from"@clack/prompts";import Ge from"path";import{z as k}from"zod";var V="https://seed-design.io";import*as le from"@clack/prompts";import{execa as Le}from"execa";import Fe from"findup-sync";import Me from"fs-extra";var Ue="package.json";function ze(){let e=Fe(Ue);if(!e)throw new Error("No package.json file found in the project.");return e}function G(){let e=ze();return Me.readJSONSync(e)}async function Y({cwd:e,deps:t,dev:i=!1}){let{start:c,stop:p}=le.spinner(),r=await z(e),l={...G().dependencies},o=new Set(t.filter(b=>!l[b])),u=new Set(t.filter(b=>l[b]));if(!o.size)return{installed:new Set,filtered:o};c("\uC758\uC874\uC131 \uC124\uCE58\uC911...");let E=[r==="npm"?"install":"add",i?"-D":null,...o].filter(Boolean);try{await Le(r,E,{cwd:e})}catch(b){console.error(`\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328: ${b}`),process.exit(1)}return p("\uC758\uC874\uC131 \uC124\uCE58\uAC00 \uC644\uB8CC\uB410\uC5B4\uC694."),{installed:o,filtered:u}}import{randomUUID as Ke}from"node:crypto";import*as me from"@clack/prompts";var Ne="seed_cli";async function Be(e){if(process.env.DISABLE_TELEMETRY==="true"||process.env.SEED_DISABLE_TELEMETRY==="true")return!1;try{if((await D(e))?.telemetry===!1)return!1}catch{}return!0}function Je(){return Ke()}var He=Je(),de=!1;async function Ve(e,{event:t,properties:i={}}){if(!await Be(e))return;let p=`${Ne}.${t}`;de||(me.log.info("\u{1F4CA} \uC0AC\uC6A9 \uB370\uC774\uD130 \uC218\uC9D1 \uC911 (\uBE44\uD65C\uC131\uD654: seed-design.json \uB610\uB294 DISABLE_TELEMETRY \uD658\uACBD \uBCC0\uC218)"),de=!0);try{let r="https://us.i.posthog.com/capture",n={"Content-Type":"application/json"},l={api_key:"phc_seod8HhifElOP1R92KmvsQybrtUmkOTgZBsq0mfCelR",event:p,distinct_id:He,properties:{...i,$process_person_profile:!1},timestamp:new Date().toISOString()},o=new AbortController,u=setTimeout(()=>o.abort(),5e3);try{await fetch(r,{method:"POST",headers:n,body:JSON.stringify(l),signal:o.signal})}finally{clearTimeout(u)}}catch{}}var O={track:Ve};var Ye=k.object({itemIds:k.array(k.string()).optional(),all:k.boolean(),cwd:k.string(),baseUrl:k.string().optional()}),fe=e=>{e.command("add [...item-ids]","add items").option("-a, --all","[Deprecated] Add all items",{default:!1}).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",{default:process.cwd()}).option("-u, --baseUrl <baseUrl>","the base url of the registry. defaults to the current directory.",{default:V}).example("seed-design add ui:action-button").example("seed-design add ui:alert-dialog").action(async(t,i)=>{let c=Date.now();d.intro("seed-design add");let{success:p,data:{all:r,...n},error:l}=Ye.safeParse({itemIds:t,...i});p||(d.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${l?.message}`),process.exit(1)),r&&(d.log.error("`--all` \uC635\uC158\uC740 \uB354 \uC774\uC0C1 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC544\uC694. \uB300\uC2E0 `seed-design add-all` \uBA85\uB839\uC5B4\uB97C \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694."),process.exit(1));let o=n.cwd,u=n.baseUrl,w=await D(o),R=Ge.resolve(o,w.path),{start:E,stop:b}=d.spinner();E("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let x=await Promise.all((await K({baseUrl:u})).map(async({id:s})=>N({baseUrl:u,registryId:s})));b("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let $=await(async()=>{if(n.itemIds.length>0)return n.itemIds;let s=await d.multiselect({message:"\uCD94\uAC00\uD560 \uD56D\uBAA9\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (\uC2A4\uD398\uC774\uC2A4 \uBC14\uB85C \uC5EC\uB7EC \uAC1C \uC120\uD0DD \uAC00\uB2A5)",options:x.filter(({hideFromCLICatalog:m})=>!m).flatMap(({id:m,items:T})=>T.filter(({hideFromCLICatalog:S})=>!S).sort((S,P)=>S.id.localeCompare(P.id)).map(({id:S,description:P,deprecated:j})=>({label:`${j?"(deprecated) ":""}${a(m)}:${S}`,value:`${m}:${S}`,hint:P,deprecated:j,registryItemCount:T.length}))).sort((m,T)=>m.deprecated!==T.deprecated?m.deprecated?1:-1:T.registryItemCount-m.registryItemCount)});return d.isCancel(s)&&(d.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),s})();$?.length||(d.log.error("\uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0)),d.log.message(`\uC120\uD0DD\uB41C \uD56D\uBAA9: ${a($.join(", "))}`);let I=[];for(let s of $){let[m,...T]=s.split(":"),S=T.join(":");(!m||!S)&&(d.log.error(`${a(s)}: \uD56D\uBAA9 \uC774\uB984\uC774 \uC798\uBABB\uB418\uC5C8\uC5B4\uC694. ${a("ui:action-button")}\uACFC \uAC19\uC740 \uD615\uC2DD\uC73C\uB85C \uC785\uB825\uD574\uBCF4\uC138\uC694.`),process.exit(1));let P=x.find(j=>j.id===m)?.items.find(j=>j.id===S);if(P||(d.log.error(`${a(s)}: \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694.`),process.exit(1)),P.deprecated){let j=await d.confirm({message:`${a(P.id)}: deprecated \uB418\uC5C8\uC5B4\uC694. \uCD94\uAC00\uD560\uAE4C\uC694?`,initialValue:!1});if(j===!1||d.isCancel(j)){d.log.info(`${a(P.id)}: \uCD94\uAC00\uD558\uC9C0 \uC54A\uC744\uAC8C\uC694.`);continue}}I.push(s)}let{registryItemsToAdd:v,npmDependenciesToAdd:M}=L({selectedItemKeys:I,publicRegistries:x});d.log.info(`\uCD94\uAC00\uD560 \uD56D\uBAA9: ${a(v.map(s=>s.items.map(m=>`${s.registryId}:${m.id}`).join(", ")).join(", ")||"\uC5C6\uC74C")}
|
|
5
|
+
|
|
6
|
+
\uC124\uCE58\uD560 \uC758\uC874\uC131: ${a(Array.from(M).join(", ")||"\uC5C6\uC74C")}`),await H({registryItemsToAdd:v,rootPath:R,cwd:o,baseUrl:u,config:w});try{let{installed:s,filtered:m}=await Y({cwd:o,deps:Array.from(M)});s.size===0&&d.log.message("\uBAA8\uB4E0 \uC758\uC874\uC131\uC774 \uC774\uBBF8 \uC124\uCE58\uB418\uC5B4 \uC788\uC5B4\uC694."),s.size&&(d.log.message(`\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC: ${a(Array.from(s).join(", "))}`),m.size&&d.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${a(Array.from(m).join(", "))}`)),d.outro("\uC644\uB8CC\uD588\uC5B4\uC694.")}catch(s){d.log.error(`\uCD94\uAC00\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${s}`),d.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let U=Date.now()-c,X=new Set(v.map(s=>s.registryId)),h=$.some(s=>{let[m,...T]=s.split(":"),S=T.join(":");return x.find(P=>P.id===m)?.items.find(P=>P.id===S)?.deprecated});await O.track(n.cwd,{event:"add",properties:{items_count:I.length,registries:Array.from(X),has_deprecated:h,dependencies_count:M.size,duration_ms:U}})})};import*as g from"@clack/prompts";import Xe from"path";import{z as A}from"zod";var qe=A.object({registryIds:A.array(A.string()).optional(),all:A.boolean(),includeDeprecated:A.boolean().optional(),cwd:A.string(),baseUrl:A.string().optional()}),ge=e=>{e.command("add-all [...registry-ids]","add all items from registries").option("-a, --all","Add all items from all registries",{default:!1}).option("--include-deprecated","Include deprecated items when used with `--all`",{default:!1}).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",{default:process.cwd()}).option("-u, --baseUrl <baseUrl>","the base url of the registry. defaults to the current directory.",{default:V}).example("seed-design add-all ui --include-deprecated").example("seed-design add-all ui lib breeze").action(async(t,i)=>{let c=Date.now();g.intro("seed-design add-all");let{success:p,data:r,error:n}=qe.safeParse({registryIds:t,...i});p||(g.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${n?.message}`),process.exit(1));let l=r.cwd,o=r.baseUrl,u=await D(l),w=Xe.resolve(l,u.path),{start:R,stop:E}=g.spinner();R("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let b=await Promise.all((await K({baseUrl:o})).map(async({id:h})=>N({baseUrl:o,registryId:h})));E("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let x=await(async()=>{if(r.all){let s=b.map(m=>m.id);return g.log.message(`\uBAA8\uB4E0 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uBAA8\uB4E0 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4: ${a(s.join(", "))}`),s}if(r.registryIds?.length){let s=b.map(m=>m.id);for(let m of r.registryIds)s.includes(m)||(g.log.error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC '${m}'\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694.`),g.log.info(`\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB808\uC9C0\uC2A4\uD2B8\uB9AC: ${s.join(", ")}`),process.exit(1));return g.log.message(`\uC120\uD0DD\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uBAA8\uB4E0 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4: ${a(r.registryIds.join(", "))}`),r.registryIds}let h=await g.multiselect({message:"\uCD94\uAC00\uD560 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (\uC2A4\uD398\uC774\uC2A4 \uBC14\uB85C \uC5EC\uB7EC \uAC1C \uC120\uD0DD \uAC00\uB2A5)",options:b.filter(({hideFromCLICatalog:s})=>!s).sort((s,m)=>m.items.length-s.items.length).map(s=>({label:s.id,value:s.id,hint:`${s.items.length}\uAC1C \uD56D\uBAA9 (${s.items[0].id} \uB4F1)`}))});return g.isCancel(h)&&(g.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),g.log.message(`\uC120\uD0DD\uB41C \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4: ${a(h.join(", "))}`),h})(),$=b.filter(h=>x.includes(h.id)),I=$.flatMap(h=>h.items.filter(s=>s.deprecated?r.includeDeprecated:!0).map(s=>`${h.id}:${s.id}`)),v=$.flatMap(h=>h.items.filter(s=>s.deprecated).map(()=>1)).length;!r.includeDeprecated&&v>0&&g.log.info(`${v}\uAC1C\uC758 deprecated \uD56D\uBAA9\uC740 \uC81C\uC678\uB418\uC5C8\uC5B4\uC694. --include-deprecated \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uBA74 \uCD94\uAC00\uD560 \uC218 \uC788\uC5B4\uC694.`),I.length||(g.log.error("\uCD94\uAC00\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC5B4\uC694."),process.exit(0)),g.log.message(`\uCD1D ${a(I.length.toString())}\uAC1C\uC758 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4.`);let{registryItemsToAdd:M,npmDependenciesToAdd:U}=L({selectedItemKeys:I,publicRegistries:b});await H({registryItemsToAdd:M,rootPath:w,cwd:l,baseUrl:o,config:u});try{let{installed:h,filtered:s}=await Y({cwd:l,deps:Array.from(U)});h.size===0&&g.log.message("\uBAA8\uB4E0 \uC758\uC874\uC131\uC774 \uC774\uBBF8 \uC124\uCE58\uB418\uC5B4 \uC788\uC5B4\uC694."),h.size&&(g.log.message(`\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC: ${a(Array.from(h).join(", "))}`),s.size&&g.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${a(Array.from(s).join(", "))}`)),g.outro("\uC644\uB8CC\uD588\uC5B4\uC694.")}catch(h){g.log.error(`\uCD94\uAC00\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${h}`),g.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let X=Date.now()-c;await O.track(r.cwd,{event:"add-all",properties:{registries:x,items_count:I.length,include_deprecated:r.includeDeprecated||!1,dependencies_count:U.size,duration_ms:X}})})};import*as y from"@clack/prompts";import We from"fs-extra";import ue from"path";import{z as ee}from"zod";import Qe from"dedent";var Ze=ee.object({cwd:ee.string(),yes:ee.boolean().optional()}),ye=e=>{e.command("init","seed-design.json \uD30C\uC77C \uC0DD\uC131").option("-c, --cwd <cwd>","\uC791\uC5C5 \uB514\uB809\uD1A0\uB9AC. \uAE30\uBCF8\uAC12\uC740 \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC.",{default:process.cwd()}).option("-y, --yes","\uBAA8\uB4E0 \uC9C8\uBB38\uC5D0 \uB300\uD574 \uAE30\uBCF8\uAC12\uC73C\uB85C \uB2F5\uBCC0\uD569\uB2C8\uB2E4.").action(async t=>{let i=Date.now();y.intro("seed-design.json \uD30C\uC77C \uC0DD\uC131");let c=Ze.parse(t),p=c.yes,r={rsc:!1,tsx:!0,path:"./seed-design",telemetry:!0};p||(r={...await y.group({tsx:()=>y.confirm({message:`${a("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>y.confirm({message:`${a("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),path:()=>y.text({message:`${a("seed-design \uD3F4\uB354")} \uACBD\uB85C\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. (\uAE30\uBCF8\uAC12\uC740 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0 \uC0DD\uC131\uB429\uB2C8\uB2E4.)`,initialValue:"./seed-design",defaultValue:"./seed-design",placeholder:"./seed-design"}),telemetry:()=>y.confirm({message:`\uAC1C\uC120\uC744 \uC704\uD574 ${a("\uC775\uBA85 \uC0AC\uC6A9 \uB370\uC774\uD130")}\uB97C \uC218\uC9D1\uD560\uAE4C\uC694?`,initialValue:!0})},{onCancel:()=>{y.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:l,stop:o}=y.spinner();l("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let u=ue.resolve(c.cwd,"seed-design.json");await We.writeFile(u,`${JSON.stringify(r,null,2)}
|
|
7
|
+
`,"utf-8");let w=ue.relative(process.cwd(),u);o(`seed-design.json \uD30C\uC77C\uC774 ${a(w)}\uC5D0 \uC0DD\uC131\uB410\uC5B4\uC694.`),y.log.info(a("seed-design add {component} \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD574\uBCF4\uC138\uC694!")),y.log.info(a("seed-design add \uBA85\uB839\uC5B4\uB85C \uCD94\uAC00\uD560 \uC218 \uC788\uB294 \uBAA8\uB4E0 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uD655\uC778\uD574\uBCF4\uC138\uC694.")),y.note(Qe(`SEED Design CLI\uB294 \uAC1C\uC120\uC744 \uC704\uD574 \uC775\uBA85 \uC0AC\uC6A9 \uB370\uC774\uD130\uB97C \uC218\uC9D1\uD574\uC694.
|
|
8
|
+
|
|
9
|
+
\uBE44\uD65C\uC131\uD654\uD558\uB824\uBA74:
|
|
10
|
+
\u2022 seed-design.json\uC5D0\uC11C ${a('"telemetry": false')}\uB85C \uC124\uC815
|
|
11
|
+
\u2022 ${a("DISABLE_TELEMETRY=true")} \uD658\uACBD \uBCC0\uC218 \uC124\uC815
|
|
12
|
+
|
|
13
|
+
\uC790\uC138\uD55C \uB0B4\uC6A9: https://seed-design.com/react/getting-started/cli/configuration#telemetry`),"Telemetry \uC548\uB0B4"),y.outro("\uC791\uC5C5\uC774 \uC644\uB8CC\uB410\uC5B4\uC694.")}catch(l){y.log.error(`seed-design.json \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${l}`),y.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let n=Date.now()-i;await O.track(c.cwd,{event:"init",properties:{tsx:r.tsx,rsc:r.rsc,telemetry:r.telemetry,yes_option:p,duration_ms:n}})})};import{cac as et}from"cac";var tt="seed-design",F=et(tt);async function rt(){let e=G();fe(F),ge(F),ye(F),F.version(e.version||"1.0.0","-v, --version"),F.help(),F.parse()}rt();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,27 +25,29 @@
|
|
|
25
25
|
"lint:publish": "bun publint"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@antfu/ni": "^
|
|
28
|
+
"@antfu/ni": "^27.0.0",
|
|
29
29
|
"@babel/core": "^7.26.10",
|
|
30
30
|
"@babel/parser": "^7.27.0",
|
|
31
31
|
"@babel/plugin-transform-typescript": "^7.27.0",
|
|
32
32
|
"@clack/prompts": "^0.11.0",
|
|
33
33
|
"cac": "^6.7.14",
|
|
34
34
|
"cosmiconfig": "^9.0.0",
|
|
35
|
+
"dedent": "^1.7.0",
|
|
35
36
|
"execa": "^9.5.2",
|
|
36
37
|
"findup-sync": "^5.0.0",
|
|
37
38
|
"fs-extra": "^11.3.0",
|
|
38
39
|
"picocolors": "^1.1.1",
|
|
39
40
|
"recast": "^0.23.11",
|
|
40
|
-
"ts-morph": "^
|
|
41
|
+
"ts-morph": "^27.0.0",
|
|
41
42
|
"zod": "^3.24.3"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@types/babel__core": "^7.20.5",
|
|
45
46
|
"@types/fs-extra": "^11.0.4",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
47
|
+
"dotenv": "^17.2.3",
|
|
48
|
+
"esbuild": "^0.27.0",
|
|
49
|
+
"type-fest": "^5.0.0",
|
|
50
|
+
"typescript": "^5.9.2"
|
|
49
51
|
},
|
|
50
52
|
"publishConfig": {
|
|
51
53
|
"access": "public"
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { fetchAvailableRegistries, fetchRegistry } from "@/src/utils/fetch";
|
|
2
|
+
import { getConfig } from "@/src/utils/get-config";
|
|
3
|
+
import { resolveDependencies } from "@/src/utils/resolve-dependencies";
|
|
4
|
+
import { writeRegistryItemSnippets } from "@/src/utils/write";
|
|
5
|
+
import * as p from "@clack/prompts";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
import type { CAC } from "cac";
|
|
10
|
+
import { BASE_URL } from "../constants";
|
|
11
|
+
import { analytics } from "../utils/analytics";
|
|
12
|
+
import { highlight } from "../utils/color";
|
|
13
|
+
import { installDependencies } from "../utils/install";
|
|
14
|
+
|
|
15
|
+
const addAllOptionsSchema = z.object({
|
|
16
|
+
registryIds: z.array(z.string()).optional(),
|
|
17
|
+
all: z.boolean(),
|
|
18
|
+
includeDeprecated: z.boolean().optional(),
|
|
19
|
+
cwd: z.string(),
|
|
20
|
+
baseUrl: z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const addAllCommand = (cli: CAC) => {
|
|
24
|
+
cli
|
|
25
|
+
.command("add-all [...registry-ids]", "add all items from registries")
|
|
26
|
+
.option("-a, --all", "Add all items from all registries", {
|
|
27
|
+
default: false,
|
|
28
|
+
})
|
|
29
|
+
.option("--include-deprecated", "Include deprecated items when used with `--all`", {
|
|
30
|
+
default: false,
|
|
31
|
+
})
|
|
32
|
+
.option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
|
|
33
|
+
default: process.cwd(),
|
|
34
|
+
})
|
|
35
|
+
.option(
|
|
36
|
+
"-u, --baseUrl <baseUrl>",
|
|
37
|
+
"the base url of the registry. defaults to the current directory.",
|
|
38
|
+
{ default: BASE_URL },
|
|
39
|
+
)
|
|
40
|
+
.example("seed-design add-all ui --include-deprecated")
|
|
41
|
+
.example("seed-design add-all ui lib breeze")
|
|
42
|
+
.action(async (registryIds, opts) => {
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
p.intro("seed-design add-all");
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
success,
|
|
48
|
+
data: options,
|
|
49
|
+
error,
|
|
50
|
+
} = addAllOptionsSchema.safeParse({ registryIds, ...opts });
|
|
51
|
+
|
|
52
|
+
if (!success) {
|
|
53
|
+
p.log.error(`잘못된 옵션이에요: ${error?.message}`);
|
|
54
|
+
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const cwd = options.cwd;
|
|
59
|
+
const baseUrl = options.baseUrl;
|
|
60
|
+
const config = await getConfig(cwd);
|
|
61
|
+
const rootPath = path.resolve(cwd, config.path);
|
|
62
|
+
|
|
63
|
+
const { start, stop } = p.spinner();
|
|
64
|
+
|
|
65
|
+
start("Registry를 가져오고 있어요...");
|
|
66
|
+
|
|
67
|
+
const publicRegistries = await Promise.all(
|
|
68
|
+
(await fetchAvailableRegistries({ baseUrl })).map(async ({ id }) =>
|
|
69
|
+
fetchRegistry({ baseUrl, registryId: id }),
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
stop("Registry를 가져왔어요.");
|
|
74
|
+
|
|
75
|
+
const selectedRegistryIds: string[] = await (async () => {
|
|
76
|
+
if (options.all) {
|
|
77
|
+
const ids = publicRegistries.map((r) => r.id);
|
|
78
|
+
p.log.message(`모든 레지스트리의 모든 항목을 추가합니다: ${highlight(ids.join(", "))}`);
|
|
79
|
+
|
|
80
|
+
return ids;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (options.registryIds?.length) {
|
|
84
|
+
const availableIds = publicRegistries.map((r) => r.id);
|
|
85
|
+
|
|
86
|
+
for (const registryId of options.registryIds) {
|
|
87
|
+
if (!availableIds.includes(registryId)) {
|
|
88
|
+
p.log.error(`레지스트리 '${registryId}'를 찾을 수 없어요.`);
|
|
89
|
+
p.log.info(`사용 가능한 레지스트리: ${availableIds.join(", ")}`);
|
|
90
|
+
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
p.log.message(
|
|
96
|
+
`선택된 레지스트리의 모든 항목을 추가합니다: ${highlight(options.registryIds.join(", "))}`,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return options.registryIds;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const selected = await p.multiselect({
|
|
103
|
+
message: "추가할 레지스트리를 선택해주세요 (스페이스 바로 여러 개 선택 가능)",
|
|
104
|
+
options: publicRegistries
|
|
105
|
+
.filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
|
|
106
|
+
.sort((a, b) => b.items.length - a.items.length)
|
|
107
|
+
.map((registry) => ({
|
|
108
|
+
label: registry.id,
|
|
109
|
+
value: registry.id,
|
|
110
|
+
hint: `${registry.items.length}개 항목 (${registry.items[0].id} 등)`,
|
|
111
|
+
})),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (p.isCancel(selected)) {
|
|
115
|
+
p.log.error("취소되었어요.");
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
p.log.message(`선택된 레지스트리의 항목을 추가합니다: ${highlight(selected.join(", "))}`);
|
|
120
|
+
|
|
121
|
+
return selected;
|
|
122
|
+
})();
|
|
123
|
+
|
|
124
|
+
const selectedRegistries = publicRegistries.filter((r) => selectedRegistryIds.includes(r.id));
|
|
125
|
+
|
|
126
|
+
const itemKeys = selectedRegistries.flatMap((registry) =>
|
|
127
|
+
registry.items
|
|
128
|
+
.filter((item) => {
|
|
129
|
+
if (item.deprecated) return options.includeDeprecated;
|
|
130
|
+
|
|
131
|
+
return true;
|
|
132
|
+
})
|
|
133
|
+
.map((item) => `${registry.id}:${item.id}`),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const deprecatedCount = selectedRegistries.flatMap((r) =>
|
|
137
|
+
r.items.filter((item) => item.deprecated).map(() => 1),
|
|
138
|
+
).length;
|
|
139
|
+
|
|
140
|
+
if (!options.includeDeprecated && deprecatedCount > 0) {
|
|
141
|
+
p.log.info(
|
|
142
|
+
`${deprecatedCount}개의 deprecated 항목은 제외되었어요. --include-deprecated 옵션을 사용하면 추가할 수 있어요.`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!itemKeys.length) {
|
|
147
|
+
p.log.error("추가할 항목이 없어요.");
|
|
148
|
+
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
p.log.message(`총 ${highlight(itemKeys.length.toString())}개의 항목을 추가합니다.`);
|
|
153
|
+
|
|
154
|
+
const { registryItemsToAdd, npmDependenciesToAdd } = resolveDependencies({
|
|
155
|
+
selectedItemKeys: itemKeys,
|
|
156
|
+
publicRegistries,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
await writeRegistryItemSnippets({ registryItemsToAdd, rootPath, cwd, baseUrl, config });
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const { installed, filtered } = await installDependencies({
|
|
163
|
+
cwd,
|
|
164
|
+
deps: Array.from(npmDependenciesToAdd),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (installed.size === 0) {
|
|
168
|
+
p.log.message("모든 의존성이 이미 설치되어 있어요.");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (installed.size) {
|
|
172
|
+
p.log.message(`의존성 설치 완료: ${highlight(Array.from(installed).join(", "))}`);
|
|
173
|
+
|
|
174
|
+
if (filtered.size) {
|
|
175
|
+
p.log.message(
|
|
176
|
+
`설치하지 않은 의존성 (이미 설치됨): ${highlight(Array.from(filtered).join(", "))}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
p.outro("완료했어요.");
|
|
182
|
+
} catch (error) {
|
|
183
|
+
p.log.error(`추가에 실패했어요. ${error}`);
|
|
184
|
+
p.outro(highlight("작업이 취소됐어요."));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// add-all 성공 이벤트 추적
|
|
189
|
+
const duration = Date.now() - startTime;
|
|
190
|
+
await analytics.track(options.cwd, {
|
|
191
|
+
event: "add-all",
|
|
192
|
+
properties: {
|
|
193
|
+
registries: selectedRegistryIds,
|
|
194
|
+
items_count: itemKeys.length,
|
|
195
|
+
include_deprecated: options.includeDeprecated || false,
|
|
196
|
+
dependencies_count: npmDependenciesToAdd.size,
|
|
197
|
+
duration_ms: duration,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
};
|