@seed-design/cli 0.0.2 → 1.0.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/bin/index.mjs +6 -2
- package/package.json +6 -6
- package/src/commands/add-all.ts +180 -0
- package/src/commands/add.ts +142 -145
- package/src/commands/init.ts +7 -8
- package/src/index.ts +2 -0
- package/src/schema.ts +38 -59
- package/src/tests/resolve-dependencies.test.ts +424 -0
- package/src/utils/fetch.ts +122 -0
- package/src/utils/get-config.ts +14 -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/bin/index.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as w from"@clack/prompts";import{cosmiconfig as ce}from"cosmiconfig";import{execa as pe}from"execa";import I from"fs";import D from"path";import{z as x}from"zod";import ie from"picocolors";var y=e=>ie.cyan(e);import{detect as ae}from"@antfu/ni";async function M(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`]}),_=x.object({$schema:x.string().optional(),rsc:x.coerce.boolean().default(!1),tsx:x.coerce.boolean().default(!0),path:x.string()}).strict(),le=_.extend({resolvedUIPaths:x.string(),resolvedLibPaths:x.string()});async function J(e){let t=await ge(e);return t?await fe(e,t):null}async function fe(e,t){let r=D.resolve(e,t.path);I.existsSync(r)||I.mkdirSync(r,{recursive:!0});let n=D.join(r,"ui"),o=D.join(r,"lib");return I.existsSync(n)||I.mkdirSync(n,{recursive:!0}),I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),le.parse({...t,resolvedUIPaths:n,resolvedLibPaths:o})}async function ge(e){try{let t=await me.search(e);return _.parse(t.config)}catch{if(w.log.error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0 `seed-design.json` \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694."),await w.confirm({message:"seed-design.json \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC2DC\uACA0\uC5B4\uC694?"})===!0){let r=await M(e);await pe(r,["seed-design","init","--default"],{cwd:e}),w.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}else w.outro(y("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}}import*as R from"@clack/prompts";import{z as c}from"zod";var de=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())}),U=c.array(N),ue=N.omit({files:!0}),ye=ue.extend({registries:c.array(c.object({name:c.string(),type:de,content:c.string()}))}),tt=c.array(ye);async function G(e,t,r="ui"){return await Promise.all(e.map(async o=>{try{return await(await fetch(`${t}/__registry__/${r}/${o}.json`)).json()}catch(s){let a=await fetch(`${t}/__registry__/${r}/index.json`).then(g=>g.json()),m=U.parse(a).map(g=>g.name);R.log.error(`${r}:${o} \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC544\uC694.`),R.log.info(`\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8: ${m.join(", ")}`),R.log.info(JSON.stringify({baseUrl:t,error:s.toString()},null,2)),process.exit(1)}}))}async function B(e,t,r="ui"){let[n]=await G([e],t,r);return n}async function K(e){try{let[t]=await G(["index"],e,"ui");return U.parse(t)}catch(t){R.log.error("\uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC778\uB371\uC2A4\uB97C \uAC00\uC838\uC624\uB294 \uB370 \uC2E4\uD328\uD588\uC5B4\uC694."),R.log.info(JSON.stringify({baseUrl:e,error:t.toString()},null,2)),process.exit(1)}}async function V(e){let[t]=await G(["index"],e,"lib");return U.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 Se={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 n=$.parse(r,{parser:{parse:s=>we(s,Se)}}),o=he(n,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[xe],configFile:!1});if(!o||!o.ast)throw new Error("Failed to transform JSX");return $.print(o.ast).code};import{SyntaxKind as Ie}from"ts-morph";var Y=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let r=e.getFirstChildByKind(Ie.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 ke(e){let t=await Re.mkdtemp(q.join(be(),"seed-deisgn-"));return q.join(t,e)}async function H(e){let t=await ke(e.filename),r=je.createSourceFile(t,e.raw,{scriptKind:ve.TSX});for(let n of Pe)n({sourceFile:r,...e});return await X({sourceFile:r,...e})}import*as l from"@clack/prompts";import z from"fs-extra";import ee from"path";import De from"picocolors";import{z as b}from"zod";var Q="https://seed-design.io";function W({userSelects:e,uiRegistryIndex:t,libRegistryIndex:r}){let n=[];function o({registryName:s,type:a}){if(n.some(m=>m.name===s&&m.type===a))return;n.push({type:a,name:s});let d=a==="ui"?t.find(m=>m.name===s):r.find(m=>m.name===s);if(d&&d.innerDependencies)for(let m of d.innerDependencies){let[g,k]=m.split(":");o({registryName:k,type:g})}}for(let s of e)o({registryName:s,type:"ui"});return Array.from(n)}import*as Z from"@clack/prompts";import{execa as Ae}from"execa";import Te from"picocolors";import Me from"findup-sync";import Ue from"fs-extra";var $e="package.json";function Oe(){let e=Me($e);if(!e)throw new Error("No package.json file found in the project.");return e}function O(){let e=Oe();return Ue.readJSONSync(e)}async function L({cwd:e,deps:t,dev:r=!1}){let{start:n,stop:o}=Z.spinner(),s=await M(e),a=O(),d={...a.dependencies,...a.devDependencies},m=t.filter(h=>!d[h]),g=t.filter(h=>d[h]);if(!m.length)return{installed:new Set,filtered:new Set};n(Te.gray("\uC758\uC874\uC131 \uC124\uCE58\uC911..."));let A=[s==="npm"?"install":"add",r?"-D":null,...m].filter(Boolean);try{await Ae(s,A,{cwd:e})}catch(h){console.error(`\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328: ${h}`),process.exit(1)}return o("\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC."),{installed:m,filtered:g}}var Ge=b.object({components:b.array(b.string()).optional(),cwd:b.string(),all:b.boolean(),baseUrl:b.string().optional()}),te=e=>{e.command("add [...components]","add component").option("-a, --all","Add all components",{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)=>{l.intro(De.bgCyan("seed-design add"));let n=Ge.parse({components:t,...r}),o=n.cwd,s=n.baseUrl,a=await J(o),d=await K(s),m=await V(s),g=n.all?d.map(f=>f.name):n.components;if(!n.components?.length&&!n.all){let f=await l.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:d.map(i=>({label:i.name,value:i.name,hint:i.description}))});l.isCancel(f)&&(l.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),g=f}g?.length||(l.log.error("\uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0)),l.log.message(`\uC120\uD0DD\uB41C \uCEF4\uD3EC\uB10C\uD2B8: ${y(g.join(", "))}`);let k=W({userSelects:g,uiRegistryIndex:d,libRegistryIndex:m}),C=[],{start:A,stop:h}=l.spinner();A("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");for(let f of k){let i=await B(f.name,s,f.type);C.push(i)}if(h(),C.length){let f=C.filter(i=>!g.includes(i.name));l.log.message(`\uCD94\uAC00\uB85C \uC124\uCE58\uB420 \uB808\uC9C0\uC2A4\uD2B8\uB9AC: ${y(f.map(i=>i.name).join(", "))}`)}let T=[],u={installed:new Set,filtered:new Set};for(let f of C){for(let i of f.registries){let v="";switch(i.type){case"ui":v=a.resolvedUIPaths;break;case"lib":v=a.resolvedLibPaths;break;default:break}z.existsSync(v)||await z.mkdir(v,{recursive:!0});let S=ee.resolve(v,i.name),oe=await H({filename:i.name,config:a,raw:i.content});a.tsx||(S=S.replace(/\.tsx$/,".jsx"),S=S.replace(/\.ts$/,".js")),await z.writeFile(S,oe);let se=ee.relative(o,S);T.push({name:i.name,path:se})}if(f.dependencies?.length){let i=await L({cwd:o,deps:f.dependencies});u.installed=new Set([...u.installed,...i.installed]),u.filtered=new Set([...u.filtered,...i.filtered])}if(f.devDependencies?.length){let i=await L({cwd:o,deps:f.devDependencies,dev:!0});u.installed=new Set([...u.installed,...i.installed]),u.filtered=new Set([...u.filtered,...i.filtered])}l.log.success(`${y(f.name)} \uAD00\uB828 \uD30C\uC77C \uCD94\uAC00 \uC644\uB8CC`)}if(u.installed.size&&l.log.message(`\uC124\uCE58\uB41C \uC758\uC874\uC131: ${y(Array.from(u.installed).join(", "))}`),u.filtered.size&&l.log.message(`\uC774\uBBF8 \uC124\uCE58\uB41C \uC758\uC874\uC131: ${y(Array.from(u.filtered).join(", "))}`),T.length)for(let f of T)l.log.message(`\uCD94\uAC00\uB41C \uD30C\uC77C: ${y(f.path)}`);l.outro("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00 \uC644\uB8CC.")})};import*as p 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=a=>P.cyan(a);p.intro(P.bgCyan("seed-design.json \uD30C\uC77C \uC0DD\uC131"));let n=ze.parse(t),o=n.yes,s={rsc:!1,tsx:!0,path:"./seed-design"};o||(s={...await p.group({tsx:()=>p.confirm({message:`${r("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>p.confirm({message:`${r("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),path:()=>p.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:()=>{p.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:a,stop:d}=p.spinner();a("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let m=re.resolve(n.cwd,"seed-design.json");await Le.writeFile(m,`${JSON.stringify(s,null,2)}
|
|
3
|
-
|
|
2
|
+
import*as A from"@clack/prompts";import{cosmiconfig as ge}from"cosmiconfig";import{execa as ue}from"execa";import{z as O}from"zod";import de from"picocolors";var a=e=>de.cyan(e);import{detect as fe}from"@antfu/ni";async function _(e){let t=await fe({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t==="deno"?"deno":t??"npm"}var Q="seed-design",ye=ge(Q,{searchPlaces:[`${Q}.json`]}),Z=O.object({$schema:O.string().optional(),rsc:O.coerce.boolean().default(!1),tsx:O.coerce.boolean().default(!0),path:O.string()}).strict();async function U(e){let t=await he(e);return t?Z.parse(t):null}async function he(e){try{let t=await ye.search(e);return Z.parse(t.config)}catch{A.log.error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0 `seed-design.json` \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694."),await A.confirm({message:"seed-design.json \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC2DC\uACA0\uC5B4\uC694?"})||(A.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1));let r=await _(e);await ue(r,["seed-design","init","--default"],{cwd:e}),A.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}}function z({selectedItemKeys:e,publicRegistries:t}){let r=[],c=new Set;function i(s,o){let l=r.find(n=>n.registryId===s);if(!l?.items.some(n=>n.id===o.id)){if(l?l.items.push(o):r.push({registryId:s,items:[o]}),o.dependencies?.length)for(let n of o.dependencies)c.add(n);if(o.innerDependencies?.length)for(let n of o.innerDependencies)for(let w of n.itemIds){let x=t.find(j=>j.id===n.registryId)?.items.find(j=>j.id===w);if(!x)throw new Error(`Cannot find dependency item: ${n.registryId}:${w}`);i(n.registryId,x)}}}for(let s of e){let[o,...l]=s.split(":"),n=l.join(":");if(!o||!n)throw new Error(`Invalid snippet format: "${s}"`);let w=t.find(x=>x.id===o)?.items.find(x=>x.id===n);if(!w)throw new Error(`Cannot find snippet: "${s}"`);i(o,w)}return{registryItemsToAdd:r,npmDependenciesToAdd:c}}import*as Y from"@clack/prompts";import{z as d}from"zod";var X=d.object({id:d.string(),description:d.string().optional(),deprecated:d.boolean().optional(),hideFromCLICatalog:d.boolean().optional(),dependencies:d.array(d.string()).optional(),innerDependencies:d.array(d.object({registryId:d.string(),itemIds:d.array(d.string())})).optional(),snippets:d.array(d.object({path:d.string(),content:d.string()}))}),W=d.object({id:d.string(),hideFromCLICatalog:d.boolean().optional(),items:d.array(X.omit({snippets:!0}).extend({snippets:d.array(d.object({path:d.string()}))}))}),ee=d.array(d.object({id:d.string()}));async function M({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 r=await t.json(),{success:c,data:i,error:s}=ee.safeParse(r);if(!c)throw new Error(`Failed to parse registries: ${s?.message}`);return i}async function K({baseUrl:e,registryId:t}){let r=await fetch(`${e}/__registry__/${t}/index.json`);if(!r.ok)throw new Error(`Failed to fetch ${t} registry: ${r.status} ${r.statusText}`);let c=await r.json(),{success:i,data:s,error:o}=W.safeParse(c);if(!i)throw new Error(`Failed to parse ${t} registry: ${o?.message}`);return s}async function we({baseUrl:e,registryId:t,registryItemId:r}){let c=await fetch(`${e}/__registry__/${t}/${r}.json`);if(!c.ok)throw new Error(`Failed to fetch ${r}: ${c.status} ${c.statusText}`);let i=await c.json(),{success:s,data:o,error:l}=X.safeParse(i);if(!s)throw new Error(`Failed to parse ${r}: ${l?.message}`);return o}async function te({baseUrl:e,registryId:t,registryItemIds:r}){return await Promise.all(r.map(async c=>{try{return await we({baseUrl:e,registryId:t,registryItemId:c})}catch(i){let s=await fetch(`${e}/__registry__/${t}/index.json`);if(!s.ok)throw new Error(`${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uB97C \uAC00\uC838\uC624\uC9C0 \uBABB\uD588\uC5B4\uC694: ${s.status} ${s.statusText}`);let o=await s.json(),{success:l,data:n}=W.safeParse(o);throw l?(Y.log.error(`${c} \uC2A4\uB2C8\uD3AB\uC774 ${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC5C6\uC5B4\uC694.`),Y.log.info(`${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uB294 \uC2A4\uB2C8\uD3AB:
|
|
3
|
+
${n.items.map(w=>w.id).join(`
|
|
4
|
+
`)}`),i):new Error(`Failed to parse registry index for ${t}`)}}))}import{promises as Re}from"fs";import{tmpdir as je}from"os";import ie from"path";import{transformFromAstSync as xe}from"@babel/core";import be from"@babel/plugin-transform-typescript";import*as J from"recast";import{parse as Ie}from"@babel/parser";var $e={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"]},re=async({sourceFile:e,config:t})=>{let r=e.getFullText();if(t.tsx)return r;let c=J.parse(r,{parser:{parse:s=>Ie(s,$e)}}),i=xe(c,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[be],configFile:!1});if(!i||!i.ast)throw new Error("Failed to transform JSX");return J.print(i.ast).code};import{SyntaxKind as Pe}from"ts-morph";var se=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let r=e.getFirstChildByKind(Pe.ExpressionStatement);if(!r)return e;let c=r.getExpression();if(!c)return e;let i=c.getText().trim();if(i!=='"use client"'&&i!=="'use client'")return e;let s=r.getText(),o=r.getFullText();if(s.trim()===o.trim())return e;let n=o.replace(s,"").replace(/^\s*\n/,"").replace(/\n\s*$/,"");return r.replaceWithText(n),e};import{Project as Ce,ScriptKind as Se}from"ts-morph";var Ae=[se],ve=new Ce({compilerOptions:{}});async function Te(e){let t=await Re.mkdtemp(ie.join(je(),"seed-design-"));return ie.join(t,e)}async function oe(e){let t=await Te(e.filename),r=ve.createSourceFile(t,e.raw,{scriptKind:Se.TSX});for(let c of Ae)c({sourceFile:r,...e});return await re({sourceFile:r,...e})}import*as ne from"@clack/prompts";import q from"fs-extra";import N from"path";async function L({registryItemsToAdd:e,rootPath:t,cwd:r,baseUrl:c,config:i}){let s=[];for(let{registryId:o,items:l}of e){let n=N.join(t,o);q.ensureDirSync(n);let w=await te({baseUrl:c,registryId:o,registryItemIds:l.map(x=>x.id)});for(let{id:x,snippets:j}of w){let $=await Promise.all(j.map(async h=>{let P=await oe({filename:h.path,config:i,raw:h.content}),R=N.join(n,h.path);return i.tsx||(R=R.replace(/\.tsx$/,".jsx"),R=R.replace(/\.ts$/,".js")),{filePath:R,content:P,relativePath:N.relative(r,R),name:`${o}:${x}`}}));await Promise.all($.map(async({filePath:h,content:P})=>{await q.ensureDir(N.dirname(h)),await q.writeFile(h,P)}));let I=$.map(({name:h,relativePath:P})=>({name:h,path:P}));s.push(...I),ne.log.success(`${a(`${o}:${x}`)} \uAD00\uB828 \uC2A4\uB2C8\uD3AB \uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC: ${a(I.map(h=>h.path).join(", "))}`)}}}import*as f from"@clack/prompts";import _e from"path";import{z as E}from"zod";var B="https://seed-design.io";import*as ae from"@clack/prompts";import{execa as Fe}from"execa";import Ee from"findup-sync";import ke from"fs-extra";var De="package.json";function Oe(){let e=Ee(De);if(!e)throw new Error("No package.json file found in the project.");return e}function V(){let e=Oe();return ke.readJSONSync(e)}async function G({cwd:e,deps:t,dev:r=!1}){let{start:c,stop:i}=ae.spinner(),s=await _(e),l={...V().dependencies},n=new Set(t.filter(I=>!l[I])),w=new Set(t.filter(I=>l[I]));if(!n.size)return{installed:new Set,filtered:n};c("\uC758\uC874\uC131 \uC124\uCE58\uC911...");let $=[s==="npm"?"install":"add",r?"-D":null,...n].filter(Boolean);try{await Fe(s,$,{cwd:e})}catch(I){console.error(`\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328: ${I}`),process.exit(1)}return i("\uC758\uC874\uC131 \uC124\uCE58\uAC00 \uC644\uB8CC\uB410\uC5B4\uC694."),{installed:n,filtered:w}}var Ue=E.object({itemIds:E.array(E.string()).optional(),all:E.boolean(),cwd:E.string(),baseUrl:E.string().optional()}),ce=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:B}).example("seed-design add ui:action-button").example("seed-design add ui:alert-dialog").action(async(t,r)=>{f.intro("seed-design add");let{success:c,data:{all:i,...s},error:o}=Ue.safeParse({itemIds:t,...r});c||(f.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${o?.message}`),process.exit(1)),i&&(f.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 l=s.cwd,n=s.baseUrl,w=await U(l),x=_e.resolve(l,w.path),{start:j,stop:$}=f.spinner();j("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let I=await Promise.all((await M({baseUrl:n})).map(async({id:b})=>K({baseUrl:n,registryId:b})));$("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let h=await(async()=>{if(s.itemIds.length>0)return s.itemIds;let b=await f.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:I.filter(({hideFromCLICatalog:m})=>!m).flatMap(({id:m,items:p})=>p.filter(({hideFromCLICatalog:y})=>!y).sort((y,S)=>y.id.localeCompare(S.id)).map(({id:y,description:S,deprecated:C})=>({label:`${C?"(deprecated) ":""}${a(m)}:${y}`,value:`${m}:${y}`,hint:S,deprecated:C,registryItemCount:p.length}))).sort((m,p)=>m.deprecated!==p.deprecated?m.deprecated?1:-1:p.registryItemCount-m.registryItemCount)});return f.isCancel(b)&&(f.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),b})();h?.length||(f.log.error("\uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0)),f.log.message(`\uC120\uD0DD\uB41C \uD56D\uBAA9: ${a(h.join(", "))}`);let P=[];for(let b of h){let[m,...p]=b.split(":"),y=p.join(":");(!m||!y)&&(f.log.error(`${a(b)}: \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 S=I.find(C=>C.id===m)?.items.find(C=>C.id===y);if(S||(f.log.error(`${a(b)}: \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694.`),process.exit(1)),S.deprecated){let C=await f.confirm({message:`${a(S.id)}: deprecated \uB418\uC5C8\uC5B4\uC694. \uCD94\uAC00\uD560\uAE4C\uC694?`,initialValue:!1});if(C===!1||f.isCancel(C)){f.log.info(`${a(S.id)}: \uCD94\uAC00\uD558\uC9C0 \uC54A\uC744\uAC8C\uC694.`);continue}}P.push(b)}let{registryItemsToAdd:R,npmDependenciesToAdd:F}=z({selectedItemKeys:P,publicRegistries:I});f.log.info(`\uCD94\uAC00\uD560 \uD56D\uBAA9: ${a(R.map(b=>b.items.map(m=>`${b.registryId}:${m.id}`).join(", ")).join(", ")||"\uC5C6\uC74C")}
|
|
5
|
+
|
|
6
|
+
\uC124\uCE58\uD560 \uC758\uC874\uC131: ${a(Array.from(F).join(", ")||"\uC5C6\uC74C")}`),await L({registryItemsToAdd:R,rootPath:x,cwd:l,baseUrl:n,config:w});let{installed:D,filtered:T}=await G({cwd:l,deps:Array.from(F)});D.size===0&&f.log.message("\uBAA8\uB4E0 \uC758\uC874\uC131\uC774 \uC774\uBBF8 \uC124\uCE58\uB418\uC5B4 \uC788\uC5B4\uC694."),D.size&&(f.log.message(`\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC: ${a(Array.from(D).join(", "))}`),T.size&&f.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${a(Array.from(T).join(", "))}`)),f.outro("\uC644\uB8CC\uD588\uC5B4\uC694.")})};import*as g from"@clack/prompts";import ze from"path";import{z as v}from"zod";var Me=v.object({registryIds:v.array(v.string()).optional(),all:v.boolean(),includeDeprecated:v.boolean().optional(),cwd:v.string(),baseUrl:v.string().optional()}),pe=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:B}).example("seed-design add-all ui --include-deprecated").example("seed-design add-all ui lib breeze").action(async(t,r)=>{g.intro("seed-design add-all");let{success:c,data:i,error:s}=Me.safeParse({registryIds:t,...r});c||(g.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${s?.message}`),process.exit(1));let o=i.cwd,l=i.baseUrl,n=await U(o),w=ze.resolve(o,n.path),{start:x,stop:j}=g.spinner();x("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let $=await Promise.all((await M({baseUrl:l})).map(async({id:m})=>K({baseUrl:l,registryId:m})));j("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let I=await(async()=>{if(i.all){let p=$.map(y=>y.id);return g.log.message(`\uBAA8\uB4E0 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC758 \uBAA8\uB4E0 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4: ${a(p.join(", "))}`),p}if(i.registryIds?.length){let p=$.map(y=>y.id);for(let y of i.registryIds)p.includes(y)||(g.log.error(`\uB808\uC9C0\uC2A4\uD2B8\uB9AC '${y}'\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694.`),g.log.info(`\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB808\uC9C0\uC2A4\uD2B8\uB9AC: ${p.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(i.registryIds.join(", "))}`),i.registryIds}let m=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:$.filter(({hideFromCLICatalog:p})=>!p).sort((p,y)=>y.items.length-p.items.length).map(p=>({label:p.id,value:p.id,hint:`${p.items.length}\uAC1C \uD56D\uBAA9 (${p.items[0].id} \uB4F1)`}))});return g.isCancel(m)&&(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(m.join(", "))}`),m})(),h=$.filter(m=>I.includes(m.id)),P=h.flatMap(m=>m.items.filter(p=>p.deprecated?i.includeDeprecated:!0).map(p=>`${m.id}:${p.id}`)),R=h.flatMap(m=>m.items.filter(p=>p.deprecated).map(()=>1)).length;!i.includeDeprecated&&R>0&&g.log.info(`${R}\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.`),P.length||(g.log.error("\uCD94\uAC00\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC5B4\uC694."),process.exit(0)),g.log.message(`\uCD1D ${a(P.length.toString())}\uAC1C\uC758 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4.`);let{registryItemsToAdd:F,npmDependenciesToAdd:D}=z({selectedItemKeys:P,publicRegistries:$});await L({registryItemsToAdd:F,rootPath:w,cwd:o,baseUrl:l,config:n});let{installed:T,filtered:b}=await G({cwd:o,deps:Array.from(D)});T.size===0&&g.log.message("\uBAA8\uB4E0 \uC758\uC874\uC131\uC774 \uC774\uBBF8 \uC124\uCE58\uB418\uC5B4 \uC788\uC5B4\uC694."),T.size&&(g.log.message(`\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC: ${a(Array.from(T).join(", "))}`),b.size&&g.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${a(Array.from(b).join(", "))}`)),g.outro("\uC644\uB8CC\uD588\uC5B4\uC694.")})};import*as u from"@clack/prompts";import Ke from"fs-extra";import le from"path";import{z as H}from"zod";var Je=H.object({cwd:H.string(),yes:H.boolean().optional()}),me=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=>{u.intro("seed-design.json \uD30C\uC77C \uC0DD\uC131");let r=Je.parse(t),c=r.yes,i={rsc:!1,tsx:!0,path:"./seed-design"};c||(i={...await u.group({tsx:()=>u.confirm({message:`${a("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>u.confirm({message:`${a("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),path:()=>u.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"})},{onCancel:()=>{u.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:s,stop:o}=u.spinner();s("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let l=le.resolve(r.cwd,"seed-design.json");await Ke.writeFile(l,`${JSON.stringify(i,null,2)}
|
|
7
|
+
`,"utf-8");let n=le.relative(process.cwd(),l);o(`seed-design.json \uD30C\uC77C\uC774 ${a(n)}\uC5D0 \uC0DD\uC131\uB410\uC5B4\uC694.`),u.log.info(a("seed-design add {component} \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD574\uBCF4\uC138\uC694!")),u.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.")),u.outro("\uC791\uC5C5\uC774 \uC644\uB8CC\uB410\uC5B4\uC694.")}catch(s){u.log.error(`seed-design.json \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${s}`),u.outro(a("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}})};import{cac as Ne}from"cac";var Le="seed-design",k=Ne(Le);async function Be(){let e=V();ce(k),pe(k),me(k),k.version(e.version||"1.0.0","-v, --version"),k.help(),k.parse()}Be();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/cli",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"lint:publish": "bun publint"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@antfu/ni": "^
|
|
28
|
+
"@antfu/ni": "^26.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
|
-
"@clack/prompts": "^0.
|
|
32
|
+
"@clack/prompts": "^0.11.0",
|
|
33
33
|
"cac": "^6.7.14",
|
|
34
34
|
"cosmiconfig": "^9.0.0",
|
|
35
35
|
"execa": "^9.5.2",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"fs-extra": "^11.3.0",
|
|
38
38
|
"picocolors": "^1.1.1",
|
|
39
39
|
"recast": "^0.23.11",
|
|
40
|
-
"ts-morph": "^
|
|
40
|
+
"ts-morph": "^27.0.0",
|
|
41
41
|
"zod": "^3.24.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/babel__core": "^7.20.5",
|
|
45
45
|
"@types/fs-extra": "^11.0.4",
|
|
46
46
|
"esbuild": "^0.25.3",
|
|
47
|
-
"type-fest": "^
|
|
48
|
-
"typescript": "^5.
|
|
47
|
+
"type-fest": "^5.0.0",
|
|
48
|
+
"typescript": "^5.9.2"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { getConfig } from "@/src/utils/get-config";
|
|
2
|
+
import { resolveDependencies } from "@/src/utils/resolve-dependencies";
|
|
3
|
+
import { fetchAvailableRegistries, fetchRegistry } from "@/src/utils/fetch";
|
|
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 { highlight } from "../utils/color";
|
|
12
|
+
import { installDependencies } from "../utils/install";
|
|
13
|
+
|
|
14
|
+
const addAllOptionsSchema = z.object({
|
|
15
|
+
registryIds: z.array(z.string()).optional(),
|
|
16
|
+
all: z.boolean(),
|
|
17
|
+
includeDeprecated: z.boolean().optional(),
|
|
18
|
+
cwd: z.string(),
|
|
19
|
+
baseUrl: z.string().optional(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const addAllCommand = (cli: CAC) => {
|
|
23
|
+
cli
|
|
24
|
+
.command("add-all [...registry-ids]", "add all items from registries")
|
|
25
|
+
.option("-a, --all", "Add all items from all registries", {
|
|
26
|
+
default: false,
|
|
27
|
+
})
|
|
28
|
+
.option("--include-deprecated", "Include deprecated items when used with `--all`", {
|
|
29
|
+
default: false,
|
|
30
|
+
})
|
|
31
|
+
.option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
|
|
32
|
+
default: process.cwd(),
|
|
33
|
+
})
|
|
34
|
+
.option(
|
|
35
|
+
"-u, --baseUrl <baseUrl>",
|
|
36
|
+
"the base url of the registry. defaults to the current directory.",
|
|
37
|
+
{ default: BASE_URL },
|
|
38
|
+
)
|
|
39
|
+
.example("seed-design add-all ui --include-deprecated")
|
|
40
|
+
.example("seed-design add-all ui lib breeze")
|
|
41
|
+
.action(async (registryIds, opts) => {
|
|
42
|
+
p.intro("seed-design add-all");
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
success,
|
|
46
|
+
data: options,
|
|
47
|
+
error,
|
|
48
|
+
} = addAllOptionsSchema.safeParse({ registryIds, ...opts });
|
|
49
|
+
|
|
50
|
+
if (!success) {
|
|
51
|
+
p.log.error(`잘못된 옵션이에요: ${error?.message}`);
|
|
52
|
+
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const cwd = options.cwd;
|
|
57
|
+
const baseUrl = options.baseUrl;
|
|
58
|
+
const config = await getConfig(cwd);
|
|
59
|
+
const rootPath = path.resolve(cwd, config.path);
|
|
60
|
+
|
|
61
|
+
const { start, stop } = p.spinner();
|
|
62
|
+
|
|
63
|
+
start("Registry를 가져오고 있어요...");
|
|
64
|
+
|
|
65
|
+
const publicRegistries = await Promise.all(
|
|
66
|
+
(await fetchAvailableRegistries({ baseUrl })).map(async ({ id }) =>
|
|
67
|
+
fetchRegistry({ baseUrl, registryId: id }),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
stop("Registry를 가져왔어요.");
|
|
72
|
+
|
|
73
|
+
const selectedRegistryIds: string[] = await (async () => {
|
|
74
|
+
if (options.all) {
|
|
75
|
+
const ids = publicRegistries.map((r) => r.id);
|
|
76
|
+
p.log.message(`모든 레지스트리의 모든 항목을 추가합니다: ${highlight(ids.join(", "))}`);
|
|
77
|
+
|
|
78
|
+
return ids;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (options.registryIds?.length) {
|
|
82
|
+
const availableIds = publicRegistries.map((r) => r.id);
|
|
83
|
+
|
|
84
|
+
for (const registryId of options.registryIds) {
|
|
85
|
+
if (!availableIds.includes(registryId)) {
|
|
86
|
+
p.log.error(`레지스트리 '${registryId}'를 찾을 수 없어요.`);
|
|
87
|
+
p.log.info(`사용 가능한 레지스트리: ${availableIds.join(", ")}`);
|
|
88
|
+
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
p.log.message(
|
|
94
|
+
`선택된 레지스트리의 모든 항목을 추가합니다: ${highlight(options.registryIds.join(", "))}`,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return options.registryIds;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const selected = await p.multiselect({
|
|
101
|
+
message: "추가할 레지스트리를 선택해주세요 (스페이스 바로 여러 개 선택 가능)",
|
|
102
|
+
options: publicRegistries
|
|
103
|
+
.filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
|
|
104
|
+
.sort((a, b) => b.items.length - a.items.length)
|
|
105
|
+
.map((registry) => ({
|
|
106
|
+
label: registry.id,
|
|
107
|
+
value: registry.id,
|
|
108
|
+
hint: `${registry.items.length}개 항목 (${registry.items[0].id} 등)`,
|
|
109
|
+
})),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (p.isCancel(selected)) {
|
|
113
|
+
p.log.error("취소되었어요.");
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
p.log.message(`선택된 레지스트리의 항목을 추가합니다: ${highlight(selected.join(", "))}`);
|
|
118
|
+
|
|
119
|
+
return selected;
|
|
120
|
+
})();
|
|
121
|
+
|
|
122
|
+
const selectedRegistries = publicRegistries.filter((r) => selectedRegistryIds.includes(r.id));
|
|
123
|
+
|
|
124
|
+
const itemKeys = selectedRegistries.flatMap((registry) =>
|
|
125
|
+
registry.items
|
|
126
|
+
.filter((item) => {
|
|
127
|
+
if (item.deprecated) return options.includeDeprecated;
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
})
|
|
131
|
+
.map((item) => `${registry.id}:${item.id}`),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const deprecatedCount = selectedRegistries.flatMap((r) =>
|
|
135
|
+
r.items.filter((item) => item.deprecated).map(() => 1),
|
|
136
|
+
).length;
|
|
137
|
+
|
|
138
|
+
if (!options.includeDeprecated && deprecatedCount > 0) {
|
|
139
|
+
p.log.info(
|
|
140
|
+
`${deprecatedCount}개의 deprecated 항목은 제외되었어요. --include-deprecated 옵션을 사용하면 추가할 수 있어요.`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!itemKeys.length) {
|
|
145
|
+
p.log.error("추가할 항목이 없어요.");
|
|
146
|
+
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
p.log.message(`총 ${highlight(itemKeys.length.toString())}개의 항목을 추가합니다.`);
|
|
151
|
+
|
|
152
|
+
const { registryItemsToAdd, npmDependenciesToAdd } = resolveDependencies({
|
|
153
|
+
selectedItemKeys: itemKeys,
|
|
154
|
+
publicRegistries,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await writeRegistryItemSnippets({ registryItemsToAdd, rootPath, cwd, baseUrl, config });
|
|
158
|
+
|
|
159
|
+
const { installed, filtered } = await installDependencies({
|
|
160
|
+
cwd,
|
|
161
|
+
deps: Array.from(npmDependenciesToAdd),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (installed.size === 0) {
|
|
165
|
+
p.log.message("모든 의존성이 이미 설치되어 있어요.");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (installed.size) {
|
|
169
|
+
p.log.message(`의존성 설치 완료: ${highlight(Array.from(installed).join(", "))}`);
|
|
170
|
+
|
|
171
|
+
if (filtered.size) {
|
|
172
|
+
p.log.message(
|
|
173
|
+
`설치하지 않은 의존성 (이미 설치됨): ${highlight(Array.from(filtered).join(", "))}`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
p.outro("완료했어요.");
|
|
179
|
+
});
|
|
180
|
+
};
|
package/src/commands/add.ts
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
import { getConfig } from "@/src/utils/get-config";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
getRegistryUIIndex,
|
|
6
|
-
} from "@/src/utils/get-metadata";
|
|
7
|
-
import { transform } from "@/src/utils/transformers";
|
|
2
|
+
import { resolveDependencies } from "@/src/utils/resolve-dependencies";
|
|
3
|
+
import { fetchAvailableRegistries, fetchRegistry } from "@/src/utils/fetch";
|
|
4
|
+
import { writeRegistryItemSnippets } from "@/src/utils/write";
|
|
8
5
|
import * as p from "@clack/prompts";
|
|
9
|
-
import fs from "fs-extra";
|
|
10
6
|
import path from "path";
|
|
11
|
-
import color from "picocolors";
|
|
12
7
|
import { z } from "zod";
|
|
13
8
|
|
|
14
9
|
import type { CAC } from "cac";
|
|
15
10
|
import { BASE_URL } from "../constants";
|
|
16
|
-
import { addRelativeRegistries } from "../utils/add-relative-registries";
|
|
17
11
|
import { highlight } from "../utils/color";
|
|
18
12
|
import { installDependencies } from "../utils/install";
|
|
19
13
|
|
|
20
14
|
const addOptionsSchema = z.object({
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
itemIds: z.array(z.string()).optional(),
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated use `seed-design add-all` instead
|
|
18
|
+
*/
|
|
23
19
|
all: z.boolean(),
|
|
20
|
+
cwd: z.string(),
|
|
24
21
|
baseUrl: z.string().optional(),
|
|
25
|
-
// yes: z.boolean(),
|
|
26
|
-
// overwrite: z.boolean(),
|
|
27
|
-
// path: z.string().optional(),
|
|
28
22
|
});
|
|
29
23
|
|
|
30
24
|
export const addCommand = (cli: CAC) => {
|
|
31
25
|
cli
|
|
32
|
-
.command("add [...
|
|
33
|
-
.option("-a, --all", "Add all
|
|
26
|
+
.command("add [...item-ids]", "add items")
|
|
27
|
+
.option("-a, --all", "[Deprecated] Add all items", {
|
|
34
28
|
default: false,
|
|
35
29
|
})
|
|
36
30
|
.option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
|
|
@@ -39,169 +33,172 @@ export const addCommand = (cli: CAC) => {
|
|
|
39
33
|
.option(
|
|
40
34
|
"-u, --baseUrl <baseUrl>",
|
|
41
35
|
"the base url of the registry. defaults to the current directory.",
|
|
42
|
-
{
|
|
43
|
-
default: BASE_URL,
|
|
44
|
-
},
|
|
36
|
+
{ default: BASE_URL },
|
|
45
37
|
)
|
|
46
|
-
.example("seed-design add action-button")
|
|
47
|
-
.example("seed-design add alert-dialog")
|
|
48
|
-
.action(async (
|
|
49
|
-
p.intro(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
.example("seed-design add ui:action-button")
|
|
39
|
+
.example("seed-design add ui:alert-dialog")
|
|
40
|
+
.action(async (itemIds, opts) => {
|
|
41
|
+
p.intro("seed-design add");
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
success,
|
|
45
|
+
data: { all, ...options },
|
|
46
|
+
error,
|
|
47
|
+
} = addOptionsSchema.safeParse({ itemIds, ...opts });
|
|
48
|
+
|
|
49
|
+
if (!success) {
|
|
50
|
+
p.log.error(`잘못된 옵션이에요: ${error?.message}`);
|
|
51
|
+
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (all) {
|
|
56
|
+
p.log.error(
|
|
57
|
+
"`--all` 옵션은 더 이상 지원되지 않아요. 대신 `seed-design add-all` 명령어를 사용해주세요.",
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
const cwd = options.cwd;
|
|
55
64
|
const baseUrl = options.baseUrl;
|
|
56
65
|
const config = await getConfig(cwd);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
const rootPath = path.resolve(cwd, config.path);
|
|
67
|
+
|
|
68
|
+
const { start, stop } = p.spinner();
|
|
69
|
+
|
|
70
|
+
start("Registry를 가져오고 있어요...");
|
|
71
|
+
|
|
72
|
+
const publicRegistries = await Promise.all(
|
|
73
|
+
(await fetchAvailableRegistries({ baseUrl })).map(async ({ id }) =>
|
|
74
|
+
fetchRegistry({ baseUrl, registryId: id }),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
stop("Registry를 가져왔어요.");
|
|
79
|
+
|
|
80
|
+
const selectedItemKeys: string[] = await (async () => {
|
|
81
|
+
if (options.itemIds.length > 0) return options.itemIds;
|
|
82
|
+
|
|
83
|
+
const selected = await p.multiselect({
|
|
84
|
+
message: "추가할 항목을 선택해주세요 (스페이스 바로 여러 개 선택 가능)",
|
|
85
|
+
options: publicRegistries
|
|
86
|
+
.filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
|
|
87
|
+
.flatMap(({ id: registryId, items }) =>
|
|
88
|
+
items
|
|
89
|
+
.filter(({ hideFromCLICatalog }) => !hideFromCLICatalog)
|
|
90
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
91
|
+
.map(({ id, description, deprecated }) => ({
|
|
92
|
+
label: `${deprecated ? "(deprecated) " : ""}${highlight(registryId)}:${id}`,
|
|
93
|
+
value: `${registryId}:${id}`,
|
|
94
|
+
hint: description,
|
|
95
|
+
|
|
96
|
+
// used for sorting
|
|
97
|
+
deprecated,
|
|
98
|
+
registryItemCount: items.length,
|
|
99
|
+
})),
|
|
100
|
+
)
|
|
101
|
+
.sort((a, b) => {
|
|
102
|
+
if (a.deprecated !== b.deprecated) return a.deprecated ? 1 : -1;
|
|
103
|
+
|
|
104
|
+
return b.registryItemCount - a.registryItemCount;
|
|
105
|
+
}),
|
|
76
106
|
});
|
|
77
107
|
|
|
78
|
-
if (p.isCancel(
|
|
108
|
+
if (p.isCancel(selected)) {
|
|
79
109
|
p.log.error("취소되었어요.");
|
|
80
110
|
process.exit(0);
|
|
81
111
|
}
|
|
82
112
|
|
|
83
|
-
|
|
84
|
-
}
|
|
113
|
+
return selected;
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
if (!selectedItemKeys?.length) {
|
|
117
|
+
p.log.error("항목을 찾을 수 없어요.");
|
|
85
118
|
|
|
86
|
-
if (!selectedComponents?.length) {
|
|
87
|
-
p.log.error("컴포넌트를 찾을 수 없어요.");
|
|
88
119
|
process.exit(0);
|
|
89
120
|
}
|
|
90
121
|
|
|
91
|
-
p.log.message(`선택된
|
|
122
|
+
p.log.message(`선택된 항목: ${highlight(selectedItemKeys.join(", "))}`);
|
|
92
123
|
|
|
93
|
-
const
|
|
94
|
-
userSelects: selectedComponents,
|
|
95
|
-
uiRegistryIndex: registryComponentIndex,
|
|
96
|
-
libRegistryIndex,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const allRegistryItems = [];
|
|
100
|
-
|
|
101
|
-
const { start, stop } = p.spinner();
|
|
102
|
-
start("Registry를 가져오고 있어요...");
|
|
124
|
+
const filteredItemKeys: string[] = [];
|
|
103
125
|
|
|
104
|
-
for (const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
}
|
|
126
|
+
for (const itemKey of selectedItemKeys) {
|
|
127
|
+
const [registryId, ...rest] = itemKey.split(":");
|
|
128
|
+
const itemId = rest.join(":");
|
|
108
129
|
|
|
109
|
-
|
|
130
|
+
if (!registryId || !itemId) {
|
|
131
|
+
p.log.error(
|
|
132
|
+
`${highlight(itemKey)}: 항목 이름이 잘못되었어요. ${highlight("ui:action-button")}과 같은 형식으로 입력해보세요.`,
|
|
133
|
+
);
|
|
110
134
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(c) => !selectedComponents.includes(c.name),
|
|
114
|
-
);
|
|
115
|
-
p.log.message(
|
|
116
|
-
`추가로 설치될 레지스트리: ${highlight(
|
|
117
|
-
filteredRegistryItems.map((c) => c.name).join(", "),
|
|
118
|
-
)}`,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
121
137
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
installed: new Set(),
|
|
126
|
-
filtered: new Set(),
|
|
127
|
-
};
|
|
128
|
-
for (const component of allRegistryItems) {
|
|
129
|
-
for (const registry of component.registries) {
|
|
130
|
-
let targetPath = "";
|
|
131
|
-
switch (registry.type) {
|
|
132
|
-
case "ui":
|
|
133
|
-
targetPath = config.resolvedUIPaths;
|
|
134
|
-
break;
|
|
135
|
-
case "lib":
|
|
136
|
-
targetPath = config.resolvedLibPaths;
|
|
137
|
-
break;
|
|
138
|
-
default:
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
138
|
+
const foundItem = publicRegistries
|
|
139
|
+
.find((r) => r.id === registryId)
|
|
140
|
+
?.items.find((i) => i.id === itemId);
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
142
|
+
if (!foundItem) {
|
|
143
|
+
p.log.error(`${highlight(itemKey)}: 항목을 찾을 수 없어요.`);
|
|
145
144
|
|
|
146
|
-
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
if (foundItem.deprecated) {
|
|
149
|
+
const confirm = await p.confirm({
|
|
150
|
+
message: `${highlight(foundItem.id)}: deprecated 되었어요. 추가할까요?`,
|
|
151
|
+
initialValue: false,
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
if (confirm === false || p.isCancel(confirm)) {
|
|
155
|
+
p.log.info(`${highlight(foundItem.id)}: 추가하지 않을게요.`);
|
|
156
|
+
|
|
157
|
+
continue;
|
|
157
158
|
}
|
|
159
|
+
}
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
filteredItemKeys.push(itemKey);
|
|
162
|
+
}
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
164
|
+
const { registryItemsToAdd, npmDependenciesToAdd } = resolveDependencies({
|
|
165
|
+
selectedItemKeys: filteredItemKeys,
|
|
166
|
+
publicRegistries,
|
|
167
|
+
});
|
|
167
168
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const result = await installDependencies({ cwd, deps: component.dependencies });
|
|
171
|
-
installResult.installed = new Set([...installResult.installed, ...result.installed]);
|
|
172
|
-
installResult.filtered = new Set([...installResult.filtered, ...result.filtered]);
|
|
173
|
-
}
|
|
169
|
+
p.log.info(
|
|
170
|
+
`추가할 항목: ${highlight(registryItemsToAdd.map((r) => r.items.map((i) => `${r.registryId}:${i.id}`).join(", ")).join(", ") || "없음")}
|
|
174
171
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const result = await installDependencies({
|
|
178
|
-
cwd,
|
|
179
|
-
deps: component.devDependencies,
|
|
180
|
-
dev: true,
|
|
181
|
-
});
|
|
182
|
-
installResult.installed = new Set([...installResult.installed, ...result.installed]);
|
|
183
|
-
installResult.filtered = new Set([...installResult.filtered, ...result.filtered]);
|
|
184
|
-
}
|
|
172
|
+
설치할 의존성: ${highlight(Array.from(npmDependenciesToAdd).join(", ") || "없음")}`,
|
|
173
|
+
);
|
|
185
174
|
|
|
186
|
-
|
|
187
|
-
|
|
175
|
+
await writeRegistryItemSnippets({
|
|
176
|
+
registryItemsToAdd,
|
|
177
|
+
rootPath,
|
|
178
|
+
cwd,
|
|
179
|
+
baseUrl,
|
|
180
|
+
config,
|
|
181
|
+
});
|
|
188
182
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
p.log.message(
|
|
196
|
-
`이미 설치된 의존성: ${highlight(Array.from(installResult.filtered).join(", "))}`,
|
|
197
|
-
);
|
|
183
|
+
const { installed, filtered } = await installDependencies({
|
|
184
|
+
cwd,
|
|
185
|
+
deps: Array.from(npmDependenciesToAdd),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (installed.size === 0) {
|
|
189
|
+
p.log.message("모든 의존성이 이미 설치되어 있어요.");
|
|
198
190
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
191
|
+
|
|
192
|
+
if (installed.size) {
|
|
193
|
+
p.log.message(`의존성 설치 완료: ${highlight(Array.from(installed).join(", "))}`);
|
|
194
|
+
|
|
195
|
+
if (filtered.size) {
|
|
196
|
+
p.log.message(
|
|
197
|
+
`설치하지 않은 의존성 (이미 설치됨): ${highlight(Array.from(filtered).join(", "))}`,
|
|
198
|
+
);
|
|
202
199
|
}
|
|
203
200
|
}
|
|
204
201
|
|
|
205
|
-
p.outro("
|
|
202
|
+
p.outro("완료했어요.");
|
|
206
203
|
});
|
|
207
204
|
};
|