@seed-design/cli 1.1.0 → 1.2.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 +10 -8
- package/package.json +4 -2
- package/src/commands/add-all.ts +12 -1
- package/src/commands/add.ts +5 -0
- package/src/utils/write.ts +80 -14
package/bin/index.mjs
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as
|
|
3
|
-
${
|
|
4
|
-
`)}`),
|
|
2
|
+
import*as k from"@clack/prompts";import{cosmiconfig as $e}from"cosmiconfig";import{execa as Ie}from"execa";import{z}from"zod";import be from"picocolors";var i=e=>be.cyan(e);import{detect as xe}from"@antfu/ni";async function B(e){let t=await xe({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t==="deno"?"deno":t??"npm"}var se="seed-design",Pe=$e(se,{searchPlaces:[`${se}.json`]}),oe=z.object({$schema:z.string().optional(),rsc:z.coerce.boolean().default(!1),tsx:z.coerce.boolean().default(!0),path:z.string(),telemetry:z.coerce.boolean().optional().default(!0)}).strict();async function M(e){let t=await Se(e);return t?oe.parse(t):null}async function Se(e){try{let t=await Pe.search(e);return oe.parse(t.config)}catch{k.log.error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uACBD\uB85C\uC5D0 `seed-design.json` \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694."),await k.confirm({message:"seed-design.json \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC2DC\uACA0\uC5B4\uC694?"})||(k.outro(i("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1));let o=await B(e);await Ie(o,["seed-design","init","--default"],{cwd:e}),k.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}}function J({selectedItemKeys:e,publicRegistries:t}){let o=[],c=new Set;function l(r,a){let p=o.find(n=>n.registryId===r);if(!p?.items.some(n=>n.id===a.id)){if(p?p.items.push(a):o.push({registryId:r,items:[a]}),a.dependencies?.length)for(let n of a.dependencies)c.add(n);if(a.innerDependencies?.length)for(let n of a.innerDependencies)for(let u of n.itemIds){let $=t.find(S=>S.id===n.registryId)?.items.find(S=>S.id===u);if(!$)throw new Error(`Cannot find dependency item: ${n.registryId}:${u}`);l(n.registryId,$)}}}for(let r of e){let[a,...p]=r.split(":"),n=p.join(":");if(!a||!n)throw new Error(`Invalid snippet format: "${r}"`);let u=t.find($=>$.id===a)?.items.find($=>$.id===n);if(!u)throw new Error(`Cannot find snippet: "${r}"`);l(a,u)}return{registryItemsToAdd:o,npmDependenciesToAdd:c}}import*as ee 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()}))}),Z=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()}))}))}),ie=f.array(f.object({id:f.string()}));async function H({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 o=await t.json(),{success:c,data:l,error:r}=ie.safeParse(o);if(!c)throw new Error(`Failed to parse registries: ${r?.message}`);return l}async function V({baseUrl:e,registryId:t}){let o=await fetch(`${e}/__registry__/${t}/index.json`);if(!o.ok)throw new Error(`Failed to fetch ${t} registry: ${o.status} ${o.statusText}`);let c=await o.json(),{success:l,data:r,error:a}=Z.safeParse(c);if(!l)throw new Error(`Failed to parse ${t} registry: ${a?.message}`);return r}async function ve({baseUrl:e,registryId:t,registryItemId:o}){let c=await fetch(`${e}/__registry__/${t}/${o}.json`);if(!c.ok)throw new Error(`Failed to fetch ${o}: ${c.status} ${c.statusText}`);let l=await c.json(),{success:r,data:a,error:p}=Q.safeParse(l);if(!r)throw new Error(`Failed to parse ${o}: ${p?.message}`);return a}async function ne({baseUrl:e,registryId:t,registryItemIds:o}){return await Promise.all(o.map(async c=>{try{return await ve({baseUrl:e,registryId:t,registryItemId:c})}catch(l){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 a=await r.json(),{success:p,data:n}=Z.safeParse(a);throw p?(ee.log.error(`${c} \uC2A4\uB2C8\uD3AB\uC774 ${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC5C6\uC5B4\uC694.`),ee.log.info(`${t} \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uB294 \uC2A4\uB2C8\uD3AB:
|
|
3
|
+
${n.items.map(u=>u.id).join(`
|
|
4
|
+
`)}`),l):new Error(`Failed to parse registry index for ${t}`)}}))}import{promises as Ae}from"fs";import{tmpdir as _e}from"os";import pe from"path";import{transformFromAstSync as Re}from"@babel/core";import Te from"@babel/plugin-transform-typescript";import*as G from"recast";import{parse as je}from"@babel/parser";var Ce={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"]},ae=async({sourceFile:e,config:t})=>{let o=e.getFullText();if(t.tsx)return o;let c=G.parse(o,{parser:{parse:r=>je(r,Ce)}}),l=Re(c,o,{cloneInputAst:!1,code:!1,ast:!0,plugins:[Te],configFile:!1});if(!l||!l.ast)throw new Error("Failed to transform JSX");return G.print(l.ast).code};import{SyntaxKind as Ee}from"ts-morph";var ce=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let o=e.getFirstChildByKind(Ee.ExpressionStatement);if(!o)return e;let c=o.getExpression();if(!c)return e;let l=c.getText().trim();if(l!=='"use client"'&&l!=="'use client'")return e;let r=o.getText(),a=o.getFullText();if(r.trim()===a.trim())return e;let n=a.replace(r,"").replace(/^\s*\n/,"").replace(/\n\s*$/,"");return o.replaceWithText(n),e};import{Project as De,ScriptKind as Oe}from"ts-morph";var ke=[ce],Fe=new De({compilerOptions:{}});async function ze(e){let t=await Ae.mkdtemp(pe.join(_e(),"seed-design-"));return pe.join(t,e)}async function le(e){let t=await ze(e.filename),o=Fe.createSourceFile(t,e.raw,{scriptKind:Oe.TSX});for(let c of ke)c({sourceFile:o,...e});return await ae({sourceFile:o,...e})}import*as E from"@clack/prompts";import U from"fs-extra";import A from"path";import{createPatch as Me}from"diff";import Ue from"@npmcli/disparity-colors";async function Y({registryItemsToAdd:e,rootPath:t,cwd:o,baseUrl:c,config:l,overwrite:r=!1}){let a=[];for(let{registryId:p,items:n}of e){let u=A.join(t,p);U.ensureDirSync(u);let $=await ne({baseUrl:c,registryId:p,registryItemIds:n.map(S=>S.id)});for(let{id:S,snippets:D}of $){let I=await Promise.all(D.map(async x=>{let y=await le({filename:x.path,config:l,raw:x.content}),b=A.join(u,x.path);return l.tsx||(b=b.replace(/\.tsx$/,".jsx"),b=b.replace(/\.ts$/,".js")),{filePath:b,content:y,relativePath:A.relative(o,b),name:`${p}:${S}`}})),T=[];for(let x of I){let{filePath:y,content:b,relativePath:j}=x;if(await U.ensureDir(A.dirname(y)),U.existsSync(y)){let O=await U.readFile(y,"utf-8");if(O===b){E.log.info(`${i(j)}: \uC774\uBBF8 \uCD5C\uC2E0 \uC0C1\uD0DC\uC608\uC694.`);continue}if(!r){let N=Me(j,O,b),w=Ue(N);E.log.message(`
|
|
5
|
+
${i(j)}: \uD604\uC7AC \uD30C\uC77C\uACFC \uBC1B\uC73C\uB824\uB294 \uD30C\uC77C\uC758 \uB0B4\uC6A9\uC774 \uB2EC\uB77C\uC694.
|
|
6
|
+
`),E.log.message(w);let s=A.basename(y),m=A.extname(y),C=A.basename(y,m),v=Date.now(),P=`legacy-${C}-${v}${m}`,R=await E.select({message:"\uD604\uC7AC \uD30C\uC77C\uC5D0 \uC2A4\uD0C0\uC77C \uBCC0\uACBD, \uB85C\uAE45 \uB4F1 \uCEE4\uC2A4\uD130\uB9C8\uC774\uC9D5\uC774 \uC801\uC6A9\uB418\uC5B4 \uC788\uB294 \uACBD\uC6B0 \uC2E0\uADDC \uD30C\uC77C\uC5D0 \uB3D9\uC77C\uD55C \uCEE4\uC2A4\uD130\uB9C8\uC774\uC9D5\uC744 \uC801\uC6A9\uD558\uB294 \uAC83\uC744 \uAC80\uD1A0\uD574\uBCF4\uC138\uC694.",options:[{value:"overwrite",label:`${s} \uB36E\uC5B4\uC4F0\uAE30`},{value:"backup",label:`\uAE30\uC874 \uD30C\uC77C \uB0B4\uC6A9\uC744 ${P}\uC73C\uB85C \uC62E\uAE30\uACE0 ${s} \uBC1B\uAE30`},{value:"skip",label:"\uC0C8 \uD30C\uC77C \uBC1B\uC9C0 \uC54A\uACE0 \uADF8\uB300\uB85C \uB450\uAE30"}]});if(E.isCancel(R)||R==="skip"){E.log.info(`${i(j)}: \uD30C\uC77C\uC744 \uBC1B\uC9C0 \uC54A\uACE0 \uAC74\uB108\uB6F0\uC5C8\uC5B4\uC694.`);continue}if(R==="backup"){let we=A.dirname(y),re=A.join(we,P);await U.rename(y,re),E.log.info(`${i(j)}: \uAE30\uC874 \uD30C\uC77C\uC744 ${i(A.relative(o,re))}\uB85C \uC62E\uACBC\uC5B4\uC694.`)}}}await U.writeFile(y,b),T.push(x)}if(T.length>0){let x=T.map(({name:y,relativePath:b})=>({name:y,path:b}));a.push(...x),E.log.success(`${i(`${p}:${S}`)} \uAD00\uB828 \uC2A4\uB2C8\uD3AB \uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC: ${i(x.map(y=>y.path).join(", "))}`)}}}}import*as d from"@clack/prompts";import We from"path";import{z as F}from"zod";var X="https://seed-design.io";import*as me from"@clack/prompts";import{execa as Je}from"execa";import Le from"findup-sync";import Ke from"fs-extra";var Ne="package.json";function Be(){let e=Le(Ne);if(!e)throw new Error("No package.json file found in the project.");return e}function q(){let e=Be();return Ke.readJSONSync(e)}async function W({cwd:e,deps:t,dev:o=!1}){let{start:c,stop:l}=me.spinner(),r=await B(e),p={...q().dependencies},n=new Set(t.filter(I=>!p[I])),u=new Set(t.filter(I=>p[I]));if(!n.size)return{installed:new Set,filtered:n};c("\uC758\uC874\uC131 \uC124\uCE58\uC911...");let D=[r==="npm"?"install":"add",o?"-D":null,...n].filter(Boolean);try{await Je(r,D,{cwd:e})}catch(I){console.error(`\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328: ${I}`),process.exit(1)}return l("\uC758\uC874\uC131 \uC124\uCE58\uAC00 \uC644\uB8CC\uB410\uC5B4\uC694."),{installed:n,filtered:u}}import{randomUUID as He}from"node:crypto";import*as fe from"@clack/prompts";var Ve="seed_cli";async function Ge(e){if(process.env.DISABLE_TELEMETRY==="true"||process.env.SEED_DISABLE_TELEMETRY==="true")return!1;try{if((await M(e))?.telemetry===!1)return!1}catch{}return!0}function Ye(){return He()}var Xe=Ye(),de=!1;async function qe(e,{event:t,properties:o={}}){if(!await Ge(e))return;let l=`${Ve}.${t}`;de||(fe.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",a={"Content-Type":"application/json"},p={api_key:"phc_seod8HhifElOP1R92KmvsQybrtUmkOTgZBsq0mfCelR",event:l,distinct_id:Xe,properties:{...o,$process_person_profile:!1},timestamp:new Date().toISOString()},n=new AbortController,u=setTimeout(()=>n.abort(),5e3);try{await fetch(r,{method:"POST",headers:a,body:JSON.stringify(p),signal:n.signal})}finally{clearTimeout(u)}}catch{}}var L={track:qe};var Qe=F.object({itemIds:F.array(F.string()).optional(),all:F.boolean(),cwd:F.string(),baseUrl:F.string().optional(),overwrite:F.boolean().optional()}),ge=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:X}).option("--overwrite","Overwrite existing files without confirmation",{default:!1}).example("seed-design add ui:action-button").example("seed-design add ui:alert-dialog").action(async(t,o)=>{let c=Date.now();d.intro("seed-design add");let{success:l,data:{all:r,...a},error:p}=Qe.safeParse({itemIds:t,...o});l||(d.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${p?.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 n=a.cwd,u=a.baseUrl,$=await M(n),S=We.resolve(n,$.path),{start:D,stop:I}=d.spinner();D("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let T=await Promise.all((await H({baseUrl:u})).map(async({id:s})=>V({baseUrl:u,registryId:s})));I("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let x=await(async()=>{if(a.itemIds.length>0)return a.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:T.filter(({hideFromCLICatalog:m})=>!m).flatMap(({id:m,items:C})=>C.filter(({hideFromCLICatalog:v})=>!v).sort((v,P)=>v.id.localeCompare(P.id)).map(({id:v,description:P,deprecated:R})=>({label:`${R?"(deprecated) ":""}${i(m)}:${v}`,value:`${m}:${v}`,hint:P,deprecated:R,registryItemCount:C.length}))).sort((m,C)=>m.deprecated!==C.deprecated?m.deprecated?1:-1:C.registryItemCount-m.registryItemCount)});return d.isCancel(s)&&(d.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),s})();x?.length||(d.log.error("\uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0)),d.log.message(`\uC120\uD0DD\uB41C \uD56D\uBAA9: ${i(x.join(", "))}`);let y=[];for(let s of x){let[m,...C]=s.split(":"),v=C.join(":");(!m||!v)&&(d.log.error(`${i(s)}: \uD56D\uBAA9 \uC774\uB984\uC774 \uC798\uBABB\uB418\uC5C8\uC5B4\uC694. ${i("ui:action-button")}\uACFC \uAC19\uC740 \uD615\uC2DD\uC73C\uB85C \uC785\uB825\uD574\uBCF4\uC138\uC694.`),process.exit(1));let P=T.find(R=>R.id===m)?.items.find(R=>R.id===v);if(P||(d.log.error(`${i(s)}: \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694.`),process.exit(1)),P.deprecated){let R=await d.confirm({message:`${i(P.id)}: deprecated \uB418\uC5C8\uC5B4\uC694. \uCD94\uAC00\uD560\uAE4C\uC694?`,initialValue:!1});if(R===!1||d.isCancel(R)){d.log.info(`${i(P.id)}: \uCD94\uAC00\uD558\uC9C0 \uC54A\uC744\uAC8C\uC694.`);continue}}y.push(s)}let{registryItemsToAdd:b,npmDependenciesToAdd:j}=J({selectedItemKeys:y,publicRegistries:T});d.log.info(`\uCD94\uAC00\uD560 \uD56D\uBAA9: ${i(b.map(s=>s.items.map(m=>`${s.registryId}:${m.id}`).join(", ")).join(", ")||"\uC5C6\uC74C")}
|
|
5
7
|
|
|
6
|
-
\uC124\uCE58\uD560 \uC758\uC874\uC131: ${
|
|
7
|
-
`,"utf-8");let
|
|
8
|
+
\uC124\uCE58\uD560 \uC758\uC874\uC131: ${i(Array.from(j).join(", ")||"\uC5C6\uC74C")}`),await Y({registryItemsToAdd:b,rootPath:S,cwd:n,baseUrl:u,config:$,overwrite:a.overwrite});try{let{installed:s,filtered:m}=await W({cwd:n,deps:Array.from(j)});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: ${i(Array.from(s).join(", "))}`),m.size&&d.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${i(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(i("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let O=Date.now()-c,N=new Set(b.map(s=>s.registryId)),w=x.some(s=>{let[m,...C]=s.split(":"),v=C.join(":");return T.find(P=>P.id===m)?.items.find(P=>P.id===v)?.deprecated});await L.track(a.cwd,{event:"add",properties:{items_count:y.length,registries:Array.from(N),has_deprecated:w,dependencies_count:j.size,duration_ms:O}})})};import*as g from"@clack/prompts";import Ze from"path";import{z as _}from"zod";var et=_.object({registryIds:_.array(_.string()).optional(),all:_.boolean(),includeDeprecated:_.boolean().optional(),cwd:_.string(),baseUrl:_.string().optional(),overwrite:_.boolean().optional()}),ue=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:X}).option("--overwrite","Overwrite existing files without confirmation",{default:!1}).example("seed-design add-all ui --include-deprecated").example("seed-design add-all ui lib breeze").action(async(t,o)=>{let c=Date.now();g.intro("seed-design add-all");let{success:l,data:r,error:a}=et.safeParse({registryIds:t,...o});l||(g.log.error(`\uC798\uBABB\uB41C \uC635\uC158\uC774\uC5D0\uC694: ${a?.message}`),process.exit(1));let p=r.cwd,n=r.baseUrl,u=await M(p),$=Ze.resolve(p,u.path),{start:S,stop:D}=g.spinner();S("Registry\uB97C \uAC00\uC838\uC624\uACE0 \uC788\uC5B4\uC694...");let I=await Promise.all((await H({baseUrl:n})).map(async({id:w})=>V({baseUrl:n,registryId:w})));D("Registry\uB97C \uAC00\uC838\uC654\uC5B4\uC694.");let T=await(async()=>{if(r.all){let s=I.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: ${i(s.join(", "))}`),s}if(r.registryIds?.length){let s=I.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: ${i(r.registryIds.join(", "))}`),r.registryIds}let w=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:I.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(w)&&(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: ${i(w.join(", "))}`),w})(),x=I.filter(w=>T.includes(w.id)),y=x.flatMap(w=>w.items.filter(s=>s.deprecated?r.includeDeprecated:!0).map(s=>`${w.id}:${s.id}`)),b=x.flatMap(w=>w.items.filter(s=>s.deprecated).map(()=>1)).length;!r.includeDeprecated&&b>0&&g.log.info(`${b}\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.`),y.length||(g.log.error("\uCD94\uAC00\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC5B4\uC694."),process.exit(0)),g.log.message(`\uCD1D ${i(y.length.toString())}\uAC1C\uC758 \uD56D\uBAA9\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4.`);let{registryItemsToAdd:j,npmDependenciesToAdd:O}=J({selectedItemKeys:y,publicRegistries:I});await Y({registryItemsToAdd:j,rootPath:$,cwd:p,baseUrl:n,config:u,overwrite:r.overwrite});try{let{installed:w,filtered:s}=await W({cwd:p,deps:Array.from(O)});w.size===0&&g.log.message("\uBAA8\uB4E0 \uC758\uC874\uC131\uC774 \uC774\uBBF8 \uC124\uCE58\uB418\uC5B4 \uC788\uC5B4\uC694."),w.size&&(g.log.message(`\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC: ${i(Array.from(w).join(", "))}`),s.size&&g.log.message(`\uC124\uCE58\uD558\uC9C0 \uC54A\uC740 \uC758\uC874\uC131 (\uC774\uBBF8 \uC124\uCE58\uB428): ${i(Array.from(s).join(", "))}`)),g.outro("\uC644\uB8CC\uD588\uC5B4\uC694.")}catch(w){g.log.error(`\uCD94\uAC00\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${w}`),g.outro(i("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let N=Date.now()-c;await L.track(r.cwd,{event:"add-all",properties:{registries:T,items_count:y.length,include_deprecated:r.includeDeprecated||!1,dependencies_count:O.size,duration_ms:N}})})};import*as h from"@clack/prompts";import tt from"fs-extra";import ye from"path";import{z as te}from"zod";import rt from"dedent";var st=te.object({cwd:te.string(),yes:te.boolean().optional()}),he=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 o=Date.now();h.intro("seed-design.json \uD30C\uC77C \uC0DD\uC131");let c=st.parse(t),l=c.yes,r={rsc:!1,tsx:!0,path:"./seed-design",telemetry:!0};l||(r={...await h.group({tsx:()=>h.confirm({message:`${i("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>h.confirm({message:`${i("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),path:()=>h.text({message:`${i("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:()=>h.confirm({message:`\uAC1C\uC120\uC744 \uC704\uD574 ${i("\uC775\uBA85 \uC0AC\uC6A9 \uB370\uC774\uD130")}\uB97C \uC218\uC9D1\uD560\uAE4C\uC694?`,initialValue:!0})},{onCancel:()=>{h.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:p,stop:n}=h.spinner();p("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let u=ye.resolve(c.cwd,"seed-design.json");await tt.writeFile(u,`${JSON.stringify(r,null,2)}
|
|
9
|
+
`,"utf-8");let $=ye.relative(process.cwd(),u);n(`seed-design.json \uD30C\uC77C\uC774 ${i($)}\uC5D0 \uC0DD\uC131\uB410\uC5B4\uC694.`),h.log.info(i("seed-design add {component} \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD574\uBCF4\uC138\uC694!")),h.log.info(i("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.")),h.note(rt(`SEED Design CLI\uB294 \uAC1C\uC120\uC744 \uC704\uD574 \uC775\uBA85 \uC0AC\uC6A9 \uB370\uC774\uD130\uB97C \uC218\uC9D1\uD574\uC694.
|
|
8
10
|
|
|
9
11
|
\uBE44\uD65C\uC131\uD654\uD558\uB824\uBA74:
|
|
10
|
-
\u2022 seed-design.json\uC5D0\uC11C ${
|
|
11
|
-
\u2022 ${
|
|
12
|
+
\u2022 seed-design.json\uC5D0\uC11C ${i('"telemetry": false')}\uB85C \uC124\uC815
|
|
13
|
+
\u2022 ${i("DISABLE_TELEMETRY=true")} \uD658\uACBD \uBCC0\uC218 \uC124\uC815
|
|
12
14
|
|
|
13
|
-
\uC790\uC138\uD55C \uB0B4\uC6A9: https://seed-design.com/react/getting-started/cli/configuration#telemetry`),"Telemetry \uC548\uB0B4"),
|
|
15
|
+
\uC790\uC138\uD55C \uB0B4\uC6A9: https://seed-design.com/react/getting-started/cli/configuration#telemetry`),"Telemetry \uC548\uB0B4"),h.outro("\uC791\uC5C5\uC774 \uC644\uB8CC\uB410\uC5B4\uC694.")}catch(p){h.log.error(`seed-design.json \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${p}`),h.outro(i("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}let a=Date.now()-o;await L.track(c.cwd,{event:"init",properties:{tsx:r.tsx,rsc:r.rsc,telemetry:r.telemetry,yes_option:l,duration_ms:a}})})};import{cac as ot}from"cac";var it="seed-design",K=ot(it);async function nt(){let e=q();ge(K),ue(K),he(K),K.version(e.version||"1.0.0","-v, --version"),K.help(),K.parse()}nt();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,14 +25,16 @@
|
|
|
25
25
|
"lint:publish": "bun publint"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@antfu/ni": "^
|
|
28
|
+
"@antfu/ni": "^28.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
|
+
"@npmcli/disparity-colors": "^3.0.1",
|
|
33
34
|
"cac": "^6.7.14",
|
|
34
35
|
"cosmiconfig": "^9.0.0",
|
|
35
36
|
"dedent": "^1.7.0",
|
|
37
|
+
"diff": "^8.0.3",
|
|
36
38
|
"execa": "^9.5.2",
|
|
37
39
|
"findup-sync": "^5.0.0",
|
|
38
40
|
"fs-extra": "^11.3.0",
|
package/src/commands/add-all.ts
CHANGED
|
@@ -18,6 +18,7 @@ const addAllOptionsSchema = z.object({
|
|
|
18
18
|
includeDeprecated: z.boolean().optional(),
|
|
19
19
|
cwd: z.string(),
|
|
20
20
|
baseUrl: z.string().optional(),
|
|
21
|
+
overwrite: z.boolean().optional(),
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
export const addAllCommand = (cli: CAC) => {
|
|
@@ -37,6 +38,9 @@ export const addAllCommand = (cli: CAC) => {
|
|
|
37
38
|
"the base url of the registry. defaults to the current directory.",
|
|
38
39
|
{ default: BASE_URL },
|
|
39
40
|
)
|
|
41
|
+
.option("--overwrite", "Overwrite existing files without confirmation", {
|
|
42
|
+
default: false,
|
|
43
|
+
})
|
|
40
44
|
.example("seed-design add-all ui --include-deprecated")
|
|
41
45
|
.example("seed-design add-all ui lib breeze")
|
|
42
46
|
.action(async (registryIds, opts) => {
|
|
@@ -156,7 +160,14 @@ export const addAllCommand = (cli: CAC) => {
|
|
|
156
160
|
publicRegistries,
|
|
157
161
|
});
|
|
158
162
|
|
|
159
|
-
await writeRegistryItemSnippets({
|
|
163
|
+
await writeRegistryItemSnippets({
|
|
164
|
+
registryItemsToAdd,
|
|
165
|
+
rootPath,
|
|
166
|
+
cwd,
|
|
167
|
+
baseUrl,
|
|
168
|
+
config,
|
|
169
|
+
overwrite: options.overwrite,
|
|
170
|
+
});
|
|
160
171
|
|
|
161
172
|
try {
|
|
162
173
|
const { installed, filtered } = await installDependencies({
|
package/src/commands/add.ts
CHANGED
|
@@ -20,6 +20,7 @@ const addOptionsSchema = z.object({
|
|
|
20
20
|
all: z.boolean(),
|
|
21
21
|
cwd: z.string(),
|
|
22
22
|
baseUrl: z.string().optional(),
|
|
23
|
+
overwrite: z.boolean().optional(),
|
|
23
24
|
});
|
|
24
25
|
|
|
25
26
|
export const addCommand = (cli: CAC) => {
|
|
@@ -36,6 +37,9 @@ export const addCommand = (cli: CAC) => {
|
|
|
36
37
|
"the base url of the registry. defaults to the current directory.",
|
|
37
38
|
{ default: BASE_URL },
|
|
38
39
|
)
|
|
40
|
+
.option("--overwrite", "Overwrite existing files without confirmation", {
|
|
41
|
+
default: false,
|
|
42
|
+
})
|
|
39
43
|
.example("seed-design add ui:action-button")
|
|
40
44
|
.example("seed-design add ui:alert-dialog")
|
|
41
45
|
.action(async (itemIds, opts) => {
|
|
@@ -180,6 +184,7 @@ export const addCommand = (cli: CAC) => {
|
|
|
180
184
|
cwd,
|
|
181
185
|
baseUrl,
|
|
182
186
|
config,
|
|
187
|
+
overwrite: options.overwrite,
|
|
183
188
|
});
|
|
184
189
|
|
|
185
190
|
try {
|
package/src/utils/write.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { transform } from "@/src/utils/transformers";
|
|
|
3
3
|
import * as p from "@clack/prompts";
|
|
4
4
|
import fs from "fs-extra";
|
|
5
5
|
import path from "path";
|
|
6
|
+
import { createPatch } from "diff";
|
|
7
|
+
import colorize from "@npmcli/disparity-colors";
|
|
6
8
|
import { highlight } from "./color";
|
|
7
9
|
import type { Config } from "@/src/utils/get-config";
|
|
8
10
|
import type { PublicRegistry } from "@/src/schema";
|
|
@@ -13,12 +15,14 @@ export async function writeRegistryItemSnippets({
|
|
|
13
15
|
cwd,
|
|
14
16
|
baseUrl,
|
|
15
17
|
config,
|
|
18
|
+
overwrite = false,
|
|
16
19
|
}: {
|
|
17
20
|
registryItemsToAdd: { registryId: string; items: PublicRegistry["items"] }[];
|
|
18
21
|
rootPath: string;
|
|
19
22
|
cwd: string;
|
|
20
23
|
baseUrl: string;
|
|
21
24
|
config: Config;
|
|
25
|
+
overwrite?: boolean;
|
|
22
26
|
}) {
|
|
23
27
|
const registryResult: { name: string; path: string }[] = [];
|
|
24
28
|
|
|
@@ -53,23 +57,85 @@ export async function writeRegistryItemSnippets({
|
|
|
53
57
|
}),
|
|
54
58
|
);
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
transformedSnippets.map(async ({ filePath, content }) => {
|
|
58
|
-
await fs.ensureDir(path.dirname(filePath));
|
|
59
|
-
await fs.writeFile(filePath, content);
|
|
60
|
-
}),
|
|
61
|
-
);
|
|
60
|
+
const writtenSnippets: typeof transformedSnippets = [];
|
|
62
61
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
path: relativePath,
|
|
66
|
-
}));
|
|
62
|
+
for (const snippet of transformedSnippets) {
|
|
63
|
+
const { filePath, content, relativePath } = snippet;
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// 파일 존재 여부 확인
|
|
68
|
+
if (fs.existsSync(filePath)) {
|
|
69
|
+
const existingContent = await fs.readFile(filePath, "utf-8");
|
|
70
|
+
|
|
71
|
+
// 내용이 동일하면 스킵
|
|
72
|
+
if (existingContent === content) {
|
|
73
|
+
p.log.info(`${highlight(relativePath)}: 이미 최신 상태예요.`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// diff가 있는 경우
|
|
78
|
+
if (!overwrite) {
|
|
79
|
+
// diff 생성 및 색상 적용
|
|
80
|
+
const patch = createPatch(relativePath, existingContent, content);
|
|
81
|
+
const coloredDiff = colorize(patch);
|
|
82
|
+
|
|
83
|
+
p.log.message(
|
|
84
|
+
`\n${highlight(relativePath)}: 현재 파일과 받으려는 파일의 내용이 달라요.\n`,
|
|
85
|
+
);
|
|
86
|
+
p.log.message(coloredDiff);
|
|
87
|
+
|
|
88
|
+
const filename = path.basename(filePath);
|
|
89
|
+
const ext = path.extname(filePath);
|
|
90
|
+
const base = path.basename(filePath, ext);
|
|
91
|
+
const timestamp = Date.now();
|
|
92
|
+
const legacyFilename = `legacy-${base}-${timestamp}${ext}`;
|
|
93
|
+
|
|
94
|
+
const action = await p.select({
|
|
95
|
+
message:
|
|
96
|
+
"현재 파일에 스타일 변경, 로깅 등 커스터마이징이 적용되어 있는 경우 신규 파일에 동일한 커스터마이징을 적용하는 것을 검토해보세요.",
|
|
97
|
+
options: [
|
|
98
|
+
{ value: "overwrite", label: `${filename} 덮어쓰기` },
|
|
99
|
+
{
|
|
100
|
+
value: "backup",
|
|
101
|
+
label: `기존 파일 내용을 ${legacyFilename}으로 옮기고 ${filename} 받기`,
|
|
102
|
+
},
|
|
103
|
+
{ value: "skip", label: "새 파일 받지 않고 그대로 두기" },
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (p.isCancel(action) || action === "skip") {
|
|
108
|
+
p.log.info(`${highlight(relativePath)}: 파일을 받지 않고 건너뛰었어요.`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (action === "backup") {
|
|
113
|
+
const dir = path.dirname(filePath);
|
|
114
|
+
const legacyPath = path.join(dir, legacyFilename);
|
|
115
|
+
await fs.rename(filePath, legacyPath);
|
|
116
|
+
p.log.info(
|
|
117
|
+
`${highlight(relativePath)}: 기존 파일을 ${highlight(path.relative(cwd, legacyPath))}로 옮겼어요.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await fs.writeFile(filePath, content);
|
|
124
|
+
writtenSnippets.push(snippet);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (writtenSnippets.length > 0) {
|
|
128
|
+
const snippetResults = writtenSnippets.map(({ name, relativePath }) => ({
|
|
129
|
+
name,
|
|
130
|
+
path: relativePath,
|
|
131
|
+
}));
|
|
132
|
+
|
|
133
|
+
registryResult.push(...snippetResults);
|
|
134
|
+
|
|
135
|
+
p.log.success(
|
|
136
|
+
`${highlight(`${registryId}:${id}`)} 관련 스니펫 다운로드 완료: ${highlight(snippetResults.map((r) => r.path).join(", "))}`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
73
139
|
}
|
|
74
140
|
}
|
|
75
141
|
}
|