@seed-design/cli 0.0.0-alpha-20241101153412 → 0.0.0-alpha-20241204134404

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 CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{cosmiconfig as oe}from"cosmiconfig";import T from"path";import{z as f}from"zod";var A="seed-design",ne=oe(A,{searchPlaces:[`${A}.json`]}),M=f.object({$schema:f.string().optional(),rsc:f.coerce.boolean().default(!1),tsx:f.coerce.boolean().default(!0),css:f.coerce.boolean().default(!0),path:f.string()}).strict(),te=M.extend({resolvedUIPaths:f.string()});async function O(e){let n=await ie(e);return n?await re(e,n):null}async function re(e,n){let r=T.resolve(e,n.path);return te.parse({...n,resolvedUIPaths:T.join(r,"ui")})}async function ie(e){try{let n=await ne.search(e);return n?M.parse(n.config):null}catch(n){throw console.log(n),new Error(`Invalid configuration found in ${e}/seed-design.json.`)}}import{z as c}from"zod";var F=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())}),D=c.array(F),ce=F.omit({files:!0}),se=ce.extend({registries:c.array(c.object({name:c.string(),content:c.string()}))}),Ge=c.array(se);var b="https://v3.seed-design.io";async function P(e){try{return await Promise.all(e.map(async r=>await(await fetch(`${b}/__registry__/component/${r}.json`)).json()))}catch(n){throw console.log(n),new Error(`Failed to fetch registry from ${b}.`)}}async function E(){try{let[e]=await P(["index"]);return D.parse(e)}catch(e){throw console.log(e),new Error(`Failed to fetch components from ${b}.`)}}import{detect as ae}from"@antfu/ni";async function N(e){let n=await ae({programmatic:!0,cwd:e});return n==="yarn@berry"?"yarn":n==="pnpm@6"?"pnpm":n==="bun"?"bun":n??"npm"}import{promises as fe}from"fs";import{tmpdir as ge}from"os";import L from"path";import{transformFromAstSync as pe}from"@babel/core";import le from"@babel/plugin-transform-typescript";import*as v from"recast";import{parse as me}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"]},z=async({sourceFile:e,config:n})=>{let r=e.getFullText();if(n.tsx)return r;let i=v.parse(r,{parser:{parse:t=>me(t,_e)}}),o=pe(i,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[le],configFile:!1});if(!o||!o.ast)throw new Error("Failed to transform JSX");return v.print(o.ast).code};import{SyntaxKind as de}from"ts-morph";var G=async({sourceFile:e,config:n})=>{if(n.rsc)return e;let r=e.getFirstChildByKind(de.ExpressionStatement);return r?.getText()==='"use client";'&&r.remove(),e};var J=async({sourceFile:e,config:n})=>{if(n.css)return e;let i=e.getImportDeclarations().filter(o=>o.getModuleSpecifierValue().endsWith(".css"));for(let o of i)o.remove();return e};import{Project as ue,ScriptKind as he}from"ts-morph";var ye=[G,J],we=new ue({compilerOptions:{}});async function Ce(e){let n=await fe.mkdtemp(L.join(ge(),"seed-deisgn-"));return L.join(n,e)}async function V(e){let n=await Ce(e.filename),r=we.createSourceFile(n,e.raw,{scriptKind:he.TSX});for(let i of ye)i({sourceFile:r,...e});return await z({sourceFile:r,...e})}import*as s from"@clack/prompts";import{execa as B}from"execa";import S from"fs-extra";import I from"path";import R from"picocolors";import{z as C}from"zod";function U(e,n){let r=new Set;function i(o){if(r.has(o))return;r.add(o);let t=n.find(l=>l.name===o);if(t&&t.innerDependencies)for(let l of t.innerDependencies)i(l)}for(let o of e)i(o);return Array.from(r)}var xe=C.object({components:C.array(C.string()).optional(),cwd:C.string(),all:C.boolean()}),K=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()}).example("seed-design add box-button").example("seed-design add alert-dialog").action(async(n,r)=>{let i=xe.parse({components:n,...r}),o=a=>R.cyan(a),t=i.cwd;S.existsSync(t)||(s.log.error(`The path ${t} does not exist. Please try again.`),process.exit(1));let l=await E(),d=i.all?l.map(a=>a.name):i.components;if(!i.components?.length&&!i.all){let a=await s.multiselect({message:"Select all components to add",options:l.map(_=>({label:_.name,value:_.name,hint:_.description}))});s.isCancel(a)&&(s.log.error("Aborted."),process.exit(0)),d=a}d?.length||(s.log.error("No components found."),process.exit(0));let h=U(d,l),x=h.filter(a=>!d.includes(a)),y=await O(t),Y=await P(h);s.log.message(`Selection: ${o(d.join(", "))}`),x.length&&s.log.message(`Inner Dependencies: ${o(x.join(", "))} will be also added.`);for(let a of Y){for(let m of a.registries){let w=I.resolve(t,"seed-design/ui"),k=y.resolvedUIPaths||w;S.existsSync(k)||await S.mkdir(k,{recursive:!0});let g=I.resolve(k,m.name),Z=await V({filename:m.name,config:y,raw:m.content});y.tsx||(g=g.replace(/\.tsx$/,".jsx"),g=g.replace(/\.ts$/,".js")),await S.writeFile(g,Z);let ee=I.relative(t,g);s.log.info(`Added ${o(m.name)} to ${o(ee)}`)}let _=await N(t),{start:j,stop:$}=s.spinner();if(a.dependencies?.length){j(R.gray("Installing dependencies"));let m=await B(_,[_==="npm"?"install":"add",...a.dependencies],{cwd:t});if(m.failed)console.error(m.all),process.exit(1);else{for(let w of a.dependencies)s.log.info(`- ${w}`);$("Dependencies installed.")}}if(a.devDependencies?.length){j(R.gray("Installing devDependencies"));let m=await B(_,[_==="npm"?"install":"add","-D",...a.devDependencies],{cwd:t});if(m.failed)console.error(m.all),process.exit(1);else{for(let w of a.devDependencies)s.log.info(`- ${w}`);$("Dependencies installed.")}}}s.outro("Components added.")})};import ve from"findup-sync";import Se from"fs-extra";var ke="package.json";function be(){let e=ve(ke);if(!e)throw new Error("No package.json file found in the project.");return e}function W(){return Se.readJSONSync(be())}import{cac as Ae}from"cac";import*as p from"@clack/prompts";import Pe from"fs-extra";import q from"path";import Ie from"picocolors";import{z as X}from"zod";var Re=X.object({cwd:X.string()}),H=e=>{e.command("init","initialize seed-design.json").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",{default:process.cwd()}).action(async n=>{let r=Re.parse({...n}),i=y=>Ie.cyan(y),o=await p.group({tsx:()=>p.confirm({message:`Would you like to use ${i("TypeScript")} (recommended)?`,initialValue:!0}),rsc:()=>p.confirm({message:`Are you using ${i("React Server Components")}?`,initialValue:!1}),css:()=>p.confirm({message:`Would you like to use ${i("CSS Modules")}? (If true, CSS import will be added in components)`,initialValue:!0}),path:()=>p.text({message:`Enter the path to your ${i("seed-design directory")}`,initialValue:"./seed-design",defaultValue:"./seed-design",placeholder:"./seed-design"})},{onCancel:()=>{p.cancel("Operation cancelled."),process.exit(0)}}),t={rsc:o.rsc,tsx:o.tsx,css:o.css,path:o.path},{start:l,stop:d}=p.spinner();l("Writing seed-design.json...");let h=q.resolve(r.cwd,"seed-design.json");await Pe.writeFile(h,`${JSON.stringify(t,null,2)}
3
- `,"utf-8");let x=q.relative(process.cwd(),h);d(`seed-design.json written to ${i(x)}`)})};import je from"node:fs";var Q=e=>{e.command("check-deprecated-icon-files [path]","Check deprecated icon files").action(async n=>{let r=je.readdirSync(n,{recursive:!0}),i=Te.flatMap(o=>{let t=o.replace("icon_","");return[o,t,o.replace(/_/g,"-"),o.replace(/_/g,""),`${o.replace(/_/g,"")}thin`,`${o.replace(/_/g,"")}regular`,`${o.replace(/_/g,"")}fill`,t.replace(/_/g,"-"),t.replace(/_/g,""),`${t.replace(/_/g,"")}thin`,`${t.replace(/_/g,"")}regular`,`${t.replace(/_/g,"")}fill`]});for(let o of r){if(typeof o!="string"||o.includes("node_modules/"))continue;let t=o.split("/").pop().split(".")[0].toLowerCase();$e.every(l=>o.endsWith(l)===!1)||i.includes(t)&&console.log(`Possible deprecated icon file found: ${o}`)}})},$e=[".tsx",".jsx",".svg",".png"],Te=["icon_add","icon_add_circle","icon_aeb","icon_ai","icon_android_share","icon_arrow","icon_arrow_downward","icon_arrow_drop_down","icon_arrow_drop_up","icon_arrow_upward","icon_article","icon_backward","icon_bill","icon_bold","icon_bookmark","icon_bookmark_list","icon_calendar","icon_call","icon_call_declined","icon_camera","icon_car","icon_car_around_view","icon_car_blind_spot","icon_car_cruise_control","icon_car_epb","icon_car_heated_seat","icon_car_heated_steering_wheel","icon_car_ldws","icon_car_leather_seat","icon_car_navigation","icon_car_power_trunk","icon_car_rear_camera","icon_car_rear_sensor","icon_car_smart_key","icon_car_ventilation_seat","icon_cart","icon_certification","icon_challenge","icon_chart","icon_chat_bubble_check","icon_chatting","icon_chatting_send","icon_check","icon_check_flower","icon_chevron_left","icon_chevron_right","icon_click","icon_clock","icon_close","icon_cobuying","icon_community","icon_condo","icon_confirmation","icon_confirmation_pay","icon_confirmation_profile","icon_contents","icon_convert","icon_copy","icon_coupon","icon_coupon_download_done","icon_coupon_used","icon_delete_keyboard","icon_delivery","icon_direction","icon_download","icon_edit","icon_emoticon","icon_emoticon_bad","icon_expand","icon_expand_less","icon_expand_more","icon_file","icon_filter02","icon_forward","icon_gender","icon_global","icon_gps","icon_gps_enable","icon_gps_enable2","icon_groupchat_king","icon_handle","icon_hashtag","icon_headphone","icon_heart","icon_help","icon_helpcenter","icon_helper","icon_home","icon_house","icon_housekeeping_book","icon_import","icon_info","icon_interest","icon_interest_list","icon_invite","icon_invite_friend","icon_ios_share","icon_jobs","icon_keyboard_hiding","icon_keyword","icon_laptop","icon_leaf","icon_list","icon_list_card","icon_list_check","icon_list_select","icon_list_thumbnail","icon_location","icon_lock","icon_loudspeaker","icon_map","icon_market","icon_market_check","icon_market_write","icon_mention","icon_menu","icon_mic","icon_mic_off","icon_mission","icon_mobile","icon_money_send","icon_money_won","icon_moon","icon_more_horiz","icon_more_vert","icon_my","icon_my_profile","icon_near_me","icon_newtopic","icon_note","icon_notification","icon_notification_fall","icon_notification_off","icon_order","icon_pause","icon_payment","icon_percent","icon_photo","icon_photo_edit","icon_photo_edit_crop","icon_photo_edit_draw","icon_photo_edit_rotate","icon_photo_several","icon_play","icon_poll","icon_price_won","icon_product","icon_profile","icon_profile_badge","icon_prohibition","icon_pushpin","icon_question_check","icon_redo","icon_refund","icon_remove_circle","icon_reply","icon_reply_mission","icon_reply_re","icon_report","icon_reservation","icon_restaurant","icon_retry","icon_review_star","icon_scanner","icon_search","icon_search_doc","icon_sell","icon_setting","icon_signout","icon_sort","icon_story","icon_story_article","icon_subtract_circle","icon_subtraction","icon_suggest","icon_sun","icon_talkingdown","icon_talkingup","icon_text","icon_thumb_down","icon_thumb_up","icon_toolbox","icon_translate","icon_trash","icon_undo","icon_user_group","icon_video","icon_view_count","icon_view_count_off","icon_volume_off","icon_volume_on","icon_vote","icon_voucher","icon_walk","icon_warning","icon_write","icon_write_frequent_use","icon_write_story"];var Me="seed-design",u=Ae(Me);async function Oe(){let e=W();K(u),H(u),Q(u),u.version(e.version||"1.0.0","-v, --version"),u.help(),u.parse()}Oe();
2
+ import*as S from"@clack/prompts";import{cosmiconfig as ie}from"cosmiconfig";import{execa as ae}from"execa";import u from"fs";import k from"path";import{z as d}from"zod";import ne from"picocolors";var x=e=>ne.cyan(e);import{detect as se}from"@antfu/ni";async function R(e){let t=await se({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t??"npm"}var E="seed-design",ce=ie(E,{searchPlaces:[`${E}.json`]}),D=d.object({$schema:d.string().optional(),rsc:d.coerce.boolean().default(!1),tsx:d.coerce.boolean().default(!0),css:d.coerce.boolean().default(!0),path:d.string()}).strict(),pe=D.extend({resolvedUIPaths:d.string(),resolbedHookPaths:d.string(),resolvedUtilPaths:d.string()});async function F(e){let t=await fe(e);return t?await me(e,t):null}async function me(e,t){let r=k.resolve(e,t.path);u.existsSync(r)||u.mkdirSync(r,{recursive:!0});let n=k.join(r,"ui"),o=k.join(r,"hook"),c=k.join(r,"util");return u.existsSync(n)||u.mkdirSync(n,{recursive:!0}),u.existsSync(o)||u.mkdirSync(o,{recursive:!0}),u.existsSync(c)||u.mkdirSync(c,{recursive:!0}),pe.parse({...t,resolvedUIPaths:n,resolbedHookPaths:o,resolvedUtilPaths:c})}async function fe(e){try{let t=await ce.search(e);return D.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 R(e);await ae(r,["seed-design","init","--default"],{cwd:e}),S.log.message("seed-design.json \uD30C\uC77C\uC774 \uC0DD\uC131\uB410\uC5B4\uC694.")}else S.outro(x("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}}import*as w from"@clack/prompts";import{z as s}from"zod";var le=s.union([s.literal("ui"),s.literal("hook"),s.literal("util")]),_=s.object({name:s.string(),description:s.string().optional(),dependencies:s.array(s.string()).optional(),devDependencies:s.array(s.string()).optional(),innerDependencies:s.array(s.string()).optional(),files:s.array(s.string())}),b=s.array(_),ge=_.omit({files:!0}),de=ge.extend({registries:s.array(s.object({name:s.string(),type:le,content:s.string()}))}),qe=s.array(de);async function M(e,t){return await Promise.all(e.map(async n=>{try{return await(await fetch(`${t}/__registry__/ui/${n}.json`)).json()}catch(o){let c=await fetch(`${t}/__registry__/ui/index.json`).then(f=>f.json()),h=b.parse(c).map(f=>f.name);w.log.error(`${n} \uCEF4\uD3EC\uB10C\uD2B8\uB294 \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC544\uC694.`),w.log.info(`\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8: ${h.join(", ")}`),w.log.info(JSON.stringify({baseUrl:t,error:o.toString()},null,2)),process.exit(1)}}))}async function J(e){try{let[t]=await M(["index"],e);return b.parse(t)}catch(t){w.log.error("\uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC778\uB371\uC2A4\uB97C \uAC00\uC838\uC624\uB294 \uB370 \uC2E4\uD328\uD588\uC5B4\uC694."),w.log.info(JSON.stringify({baseUrl:e,error:t.toString()},null,2)),process.exit(1)}}import{promises as Ie}from"fs";import{tmpdir as we}from"os";import V from"path";import{transformFromAstSync as ye}from"@babel/core";import ue from"@babel/plugin-transform-typescript";import*as j from"recast";import{parse as he}from"@babel/parser";var xe={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"]},N=async({sourceFile:e,config:t})=>{let r=e.getFullText();if(t.tsx)return r;let n=j.parse(r,{parser:{parse:c=>he(c,xe)}}),o=ye(n,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[ue],configFile:!1});if(!o||!o.ast)throw new Error("Failed to transform JSX");return j.print(o.ast).code};import{SyntaxKind as Se}from"ts-morph";var H=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let r=e.getFirstChildByKind(Se.ExpressionStatement);return r?.getText()==='"use client";'&&r.remove(),e};var L=async({sourceFile:e,config:t})=>{if(t.css)return e;let n=e.getImportDeclarations().filter(o=>o.getModuleSpecifierValue().endsWith(".css"));for(let o of n)o.remove();return e};import{Project as Ce,ScriptKind as ve}from"ts-morph";var Pe=[H,L],Ue=new Ce({compilerOptions:{}});async function Re(e){let t=await Ie.mkdtemp(V.join(we(),"seed-deisgn-"));return V.join(t,e)}async function B(e){let t=await Re(e.filename),r=Ue.createSourceFile(t,e.raw,{scriptKind:ve.TSX});for(let n of Pe)n({sourceFile:r,...e});return await N({sourceFile:r,...e})}import*as a from"@clack/prompts";import{execa as W}from"execa";import O from"fs-extra";import q from"path";import $ from"picocolors";import{z as C}from"zod";function K(e,t){let r=new Set;function n(o){if(r.has(o))return;r.add(o);let c=t.find(p=>p.name===o);if(c&&c.innerDependencies)for(let p of c.innerDependencies)n(p)}for(let o of e)n(o);return Array.from(r)}var X="https://v3.seed-design.io";var ke=C.object({components:C.array(C.string()).optional(),cwd:C.string(),all:C.boolean(),baseUrl:C.string().optional()}),Q=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:X}).example("seed-design add box-button").example("seed-design add alert-dialog").action(async(t,r)=>{a.intro($.bgCyan("\uCEF4\uD3EC\uB10C\uD2B8 \uCD94\uAC00\uD558\uAE30"));let n=ke.parse({components:t,...r}),o=n.cwd,c=n.baseUrl,p=await F(o),h=await J(c),f=n.all?h.map(m=>m.name):n.components;if(!n.components?.length&&!n.all){let m=await a.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:h.map(y=>({label:y.name,value:y.name,hint:y.description}))});a.isCancel(m)&&(a.log.error("\uCDE8\uC18C\uB418\uC5C8\uC5B4\uC694."),process.exit(0)),f=m}f?.length||(a.log.error("\uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4\uC694."),process.exit(0));let U=K(f,h),T=U.filter(m=>!f.includes(m)),te=await M(U,c);a.log.message(`\uC120\uD0DD\uB41C \uCEF4\uD3EC\uB10C\uD2B8: ${x(f.join(", "))}`),T.length&&a.log.message(`\uB0B4\uBD80 \uC758\uC874\uC131: ${x(T.join(", "))} \uCD94\uAC00\uB429\uB2C8\uB2E4.`);for(let m of te){for(let l of m.registries){let g="";switch(l.type){case"ui":g=p.resolvedUIPaths;break;case"hook":g=p.resolbedHookPaths;break;case"util":g=p.resolvedUtilPaths;break;default:break}O.existsSync(g)||await O.mkdir(g,{recursive:!0});let I=q.resolve(g,l.name),re=await B({filename:l.name,config:p,raw:l.content});p.tsx||(I=I.replace(/\.tsx$/,".jsx"),I=I.replace(/\.ts$/,".js")),await O.writeFile(I,re);let oe=q.relative(o,I);a.log.info(`${x(l.name)} \uCD94\uAC00\uB428: ${x(oe)}`)}let y=await R(o),{start:z,stop:A}=a.spinner();if(m.dependencies?.length){z($.gray("\uC758\uC874\uC131 \uC124\uCE58\uC911..."));let l=await W(y,[y==="npm"?"install":"add",...m.dependencies],{cwd:o});if(l.failed)console.error(l.all),process.exit(1);else{for(let g of m.dependencies)a.log.info(`- ${g}`);A("\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC.")}}if(m.devDependencies?.length){z($.gray("\uAC1C\uBC1C \uC758\uC874\uC131 \uC124\uCE58\uC911..."));let l=await W(y,[y==="npm"?"install":"add","-D",...m.devDependencies],{cwd:o});if(l.failed)console.error(l.all),process.exit(1);else{for(let g of m.devDependencies)a.log.info(`- ${g}`);A("\uAC1C\uBC1C \uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC.")}}}a.outro(`${t.join(", ")} \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD588\uC5B4\uC694.`)})};import*as i from"@clack/prompts";import je from"fs-extra";import Y from"path";import v from"picocolors";import{z as G}from"zod";var be=G.object({cwd:G.string(),default:G.boolean().optional()}),Z=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("-d, --default","\uBAA8\uB4E0 \uC9C8\uBB38\uC5D0 \uB300\uD574 \uAE30\uBCF8\uAC12\uC73C\uB85C \uB2F5\uBCC0\uD569\uB2C8\uB2E4.").action(async t=>{let r=p=>v.cyan(p);i.intro(v.bgCyan("seed-design.json \uD30C\uC77C \uC0DD\uC131"));let n=be.parse(t),o=n.default,c={rsc:!1,tsx:!0,css:!0,path:"./seed-design"};o||(c={...await i.group({tsx:()=>i.confirm({message:`${r("TypeScript")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!0}),rsc:()=>i.confirm({message:`${r("React Server Components")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694?`,initialValue:!1}),css:()=>i.confirm({message:`${r("CSS Loader")}\uB97C \uC0AC\uC6A9\uC911\uC774\uC2E0\uAC00\uC694? (true\uC77C \uACBD\uC6B0 \uCEF4\uD3EC\uB10C\uD2B8\uC5D0 CSS import\uAC00 \uCD94\uAC00\uB429\uB2C8\uB2E4.)`,initialValue:!0}),path:()=>i.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:()=>{i.cancel("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694."),process.exit(0)}})});try{let{start:p,stop:h}=i.spinner();p("seed-design.json \uD30C\uC77C \uC0DD\uC131\uC911...");let f=Y.resolve(n.cwd,"seed-design.json");await je.writeFile(f,`${JSON.stringify(c,null,2)}
3
+ `,"utf-8");let U=Y.relative(process.cwd(),f);h(`seed-design.json \uD30C\uC77C\uC774 ${r(U)}\uC5D0 \uC0DD\uC131\uB410\uC5B4\uC694.`),i.log.info(v.gray("seed-design add {component} \uBA85\uB839\uC5B4\uB85C \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uCD94\uAC00\uD574\uBCF4\uC138\uC694!")),i.log.info(v.gray("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.")),i.outro("\uC791\uC5C5\uC774 \uC644\uB8CC\uB410\uC5B4\uC694.")}catch(p){i.log.error(`seed-design.json \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694. ${p}`),i.outro(v.bgRed("\uC791\uC5C5\uC774 \uCDE8\uC18C\uB410\uC5B4\uC694.")),process.exit(1)}})};import Me from"findup-sync";import Oe from"fs-extra";var $e="package.json";function Ge(){let e=Me($e);if(!e)throw new Error("No package.json file found in the project.");return e}function ee(){return Oe.readJSONSync(Ge())}import{cac as Te}from"cac";var ze="seed-design",P=Te(ze);async function Ae(){let e=ee();Q(P),Z(P),P.version(e.version||"1.0.0","-v, --version"),P.help(),P.parse()}Ae();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/cli",
3
- "version": "0.0.0-alpha-20241101153412",
3
+ "version": "0.0.0-alpha-20241204134404",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -55,7 +55,6 @@
55
55
  },
56
56
  "ultra": {
57
57
  "concurrent": [
58
- "dev",
59
58
  "build"
60
59
  ]
61
60
  }
@@ -1,5 +1,5 @@
1
1
  import { getConfig } from "@/src/utils/get-config";
2
- import { fetchRegistryComponentItem, getRegistryComponentIndex } from "@/src/utils/get-metadata";
2
+ import { fetchRegistryUIItem, getRegistryUIIndex } from "@/src/utils/get-metadata";
3
3
  import { getPackageManager } from "@/src/utils/get-package-manager";
4
4
  import { transform } from "@/src/utils/transformers";
5
5
  import * as p from "@clack/prompts";
@@ -11,11 +11,14 @@ import { z } from "zod";
11
11
 
12
12
  import type { CAC } from "cac";
13
13
  import { addRelativeComponents } from "../utils/add-relative-components";
14
+ import { BASE_URL } from "../constants";
15
+ import { highlight } from "../utils/color";
14
16
 
15
17
  const addOptionsSchema = z.object({
16
18
  components: z.array(z.string()).optional(),
17
19
  cwd: z.string(),
18
20
  all: z.boolean(),
21
+ baseUrl: z.string().optional(),
19
22
  // yes: z.boolean(),
20
23
  // overwrite: z.boolean(),
21
24
  // path: z.string().optional(),
@@ -30,22 +33,25 @@ export const addCommand = (cli: CAC) => {
30
33
  .option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
31
34
  default: process.cwd(),
32
35
  })
36
+ .option(
37
+ "-u, --baseUrl <baseUrl>",
38
+ "the base url of the registry. defaults to the current directory.",
39
+ {
40
+ default: BASE_URL,
41
+ },
42
+ )
33
43
  .example("seed-design add box-button")
34
44
  .example("seed-design add alert-dialog")
35
45
  .action(async (components, opts) => {
46
+ p.intro(color.bgCyan("컴포넌트 추가하기"));
36
47
  const options = addOptionsSchema.parse({
37
48
  components,
38
49
  ...opts,
39
50
  });
40
- const highlight = (text: string) => color.cyan(text);
41
51
  const cwd = options.cwd;
42
-
43
- if (!fs.existsSync(cwd)) {
44
- p.log.error(`The path ${cwd} does not exist. Please try again.`);
45
- process.exit(1);
46
- }
47
-
48
- const registryComponentIndex = await getRegistryComponentIndex();
52
+ const baseUrl = options.baseUrl;
53
+ const config = await getConfig(cwd);
54
+ const registryComponentIndex = await getRegistryUIIndex(baseUrl);
49
55
 
50
56
  let selectedComponents: string[] = options.all
51
57
  ? registryComponentIndex.map((registry) => registry.name)
@@ -56,7 +62,7 @@ export const addCommand = (cli: CAC) => {
56
62
  { label: string; value: string; hint: string }[],
57
63
  string
58
64
  >({
59
- message: "Select all components to add",
65
+ message: "추가할 컴포넌트를 선택해주세요 (스페이스바로 여러 개 선택 가능)",
60
66
  options: registryComponentIndex.map((metadata) => {
61
67
  return {
62
68
  label: metadata.name,
@@ -67,7 +73,7 @@ export const addCommand = (cli: CAC) => {
67
73
  });
68
74
 
69
75
  if (p.isCancel(selects)) {
70
- p.log.error("Aborted.");
76
+ p.log.error("취소되었어요.");
71
77
  process.exit(0);
72
78
  }
73
79
 
@@ -75,32 +81,42 @@ export const addCommand = (cli: CAC) => {
75
81
  }
76
82
 
77
83
  if (!selectedComponents?.length) {
78
- p.log.error("No components found.");
84
+ p.log.error("컴포넌트를 찾을 수 없어요.");
79
85
  process.exit(0);
80
86
  }
81
87
 
82
88
  const allComponents = addRelativeComponents(selectedComponents, registryComponentIndex);
83
89
  const addedComponents = allComponents.filter((c) => !selectedComponents.includes(c));
84
- const config = await getConfig(cwd);
85
- const registryComponentItems = await fetchRegistryComponentItem(allComponents);
90
+ const registryComponentItems = await fetchRegistryUIItem(allComponents, baseUrl);
86
91
 
87
- p.log.message(`Selection: ${highlight(selectedComponents.join(", "))}`);
92
+ p.log.message(`선택된 컴포넌트: ${highlight(selectedComponents.join(", "))}`);
88
93
  if (addedComponents.length) {
89
- p.log.message(
90
- `Inner Dependencies: ${highlight(addedComponents.join(", "))} will be also added.`,
91
- );
94
+ p.log.message(`내부 의존성: ${highlight(addedComponents.join(", "))} 추가됩니다.`);
92
95
  }
93
96
 
97
+ // 선택된 컴포넌트.json 레지스트리 파일 기반으로 컴포넌트를 추가합니다.
94
98
  for (const component of registryComponentItems) {
95
99
  for (const registry of component.registries) {
96
- const defaultPath = path.resolve(cwd, "seed-design/ui");
97
- const UIFolderPath = config.resolvedUIPaths || defaultPath;
100
+ let targetPath = "";
101
+ switch (registry.type) {
102
+ case "ui":
103
+ targetPath = config.resolvedUIPaths;
104
+ break;
105
+ case "hook":
106
+ targetPath = config.resolbedHookPaths;
107
+ break;
108
+ case "util":
109
+ targetPath = config.resolvedUtilPaths;
110
+ break;
111
+ default:
112
+ break;
113
+ }
98
114
 
99
- if (!fs.existsSync(UIFolderPath)) {
100
- await fs.mkdir(UIFolderPath, { recursive: true });
115
+ if (!fs.existsSync(targetPath)) {
116
+ await fs.mkdir(targetPath, { recursive: true });
101
117
  }
102
118
 
103
- let filePath = path.resolve(UIFolderPath, registry.name);
119
+ let filePath = path.resolve(targetPath, registry.name);
104
120
 
105
121
  const content = await transform({
106
122
  filename: registry.name,
@@ -115,7 +131,7 @@ export const addCommand = (cli: CAC) => {
115
131
 
116
132
  await fs.writeFile(filePath, content);
117
133
  const relativePath = path.relative(cwd, filePath);
118
- p.log.info(`Added ${highlight(registry.name)} to ${highlight(relativePath)}`);
134
+ p.log.info(`${highlight(registry.name)} 추가됨: ${highlight(relativePath)}`);
119
135
  }
120
136
 
121
137
  const packageManager = await getPackageManager(cwd);
@@ -124,7 +140,7 @@ export const addCommand = (cli: CAC) => {
124
140
 
125
141
  // Install dependencies.
126
142
  if (component.dependencies?.length) {
127
- start(color.gray("Installing dependencies"));
143
+ start(color.gray("의존성 설치중..."));
128
144
 
129
145
  const result = await execa(
130
146
  packageManager,
@@ -141,13 +157,13 @@ export const addCommand = (cli: CAC) => {
141
157
  for (const deps of component.dependencies) {
142
158
  p.log.info(`- ${deps}`);
143
159
  }
144
- stop("Dependencies installed.");
160
+ stop("의존성 설치 완료.");
145
161
  }
146
162
  }
147
163
 
148
164
  // Install devDependencies.
149
165
  if (component.devDependencies?.length) {
150
- start(color.gray("Installing devDependencies"));
166
+ start(color.gray("개발 의존성 설치중..."));
151
167
 
152
168
  const result = await execa(
153
169
  packageManager,
@@ -164,11 +180,11 @@ export const addCommand = (cli: CAC) => {
164
180
  for (const deps of component.devDependencies) {
165
181
  p.log.info(`- ${deps}`);
166
182
  }
167
- stop("Dependencies installed.");
183
+ stop("개발 의존성 설치 완료.");
168
184
  }
169
185
  }
170
186
  }
171
187
 
172
- p.outro("Components added.");
188
+ p.outro(`${components.join(", ")} 컴포넌트를 추가했어요.`);
173
189
  });
174
190
  };
@@ -10,63 +10,85 @@ import type { CAC } from "cac";
10
10
 
11
11
  const initOptionsSchema = z.object({
12
12
  cwd: z.string(),
13
+ default: z.boolean().optional(),
13
14
  });
14
15
 
15
16
  export const initCommand = (cli: CAC) => {
16
17
  cli
17
- .command("init", "initialize seed-design.json")
18
- .option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", {
18
+ .command("init", "seed-design.json 파일 생성")
19
+ .option("-c, --cwd <cwd>", "작업 디렉토리. 기본값은 현재 디렉토리.", {
19
20
  default: process.cwd(),
20
21
  })
22
+ .option("-d, --default", "모든 질문에 대해 기본값으로 답변합니다.")
21
23
  .action(async (opts) => {
22
- const options = initOptionsSchema.parse({ ...opts });
23
24
  const highlight = (text: string) => color.cyan(text);
25
+ p.intro(color.bgCyan("seed-design.json 파일 생성"));
24
26
 
25
- const group = await p.group(
26
- {
27
- tsx: () =>
28
- p.confirm({
29
- message: `Would you like to use ${highlight("TypeScript")} (recommended)?`,
30
- initialValue: true,
31
- }),
32
- rsc: () =>
33
- p.confirm({
34
- message: `Are you using ${highlight("React Server Components")}?`,
35
- initialValue: false,
36
- }),
37
- css: () =>
38
- p.confirm({
39
- message: `Would you like to use ${highlight("CSS Modules")}? (If true, CSS import will be added in components)`,
40
- initialValue: true,
41
- }),
42
- path: () =>
43
- p.text({
44
- message: `Enter the path to your ${highlight("seed-design directory")}`,
45
- initialValue: "./seed-design",
46
- defaultValue: "./seed-design",
47
- placeholder: "./seed-design",
48
- }),
49
- },
50
- {
51
- onCancel: () => {
52
- p.cancel("Operation cancelled.");
53
- process.exit(0);
54
- },
55
- },
56
- );
27
+ const options = initOptionsSchema.parse(opts);
28
+ const isDefaultOption = options.default;
57
29
 
58
- const config: RawConfig = {
59
- rsc: group.rsc,
60
- tsx: group.tsx,
61
- css: group.css,
62
- path: group.path,
30
+ let config: RawConfig = {
31
+ rsc: false,
32
+ tsx: true,
33
+ css: true,
34
+ path: "./seed-design",
63
35
  };
64
36
 
65
- const { start, stop } = p.spinner();
66
- start("Writing seed-design.json...");
67
- const targetPath = path.resolve(options.cwd, "seed-design.json");
68
- await fs.writeFile(targetPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
69
- const relativePath = path.relative(process.cwd(), targetPath);
70
- stop(`seed-design.json written to ${highlight(relativePath)}`);
37
+ if (!isDefaultOption) {
38
+ const group = await p.group(
39
+ {
40
+ tsx: () =>
41
+ p.confirm({
42
+ message: `${highlight("TypeScript")}를 사용중이신가요?`,
43
+ initialValue: true,
44
+ }),
45
+ rsc: () =>
46
+ p.confirm({
47
+ message: `${highlight("React Server Components")}를 사용중이신가요?`,
48
+ initialValue: false,
49
+ }),
50
+ css: () =>
51
+ p.confirm({
52
+ message: `${highlight("CSS Loader")}를 사용중이신가요? (true일 경우 컴포넌트에 CSS import가 추가됩니다.)`,
53
+ initialValue: true,
54
+ }),
55
+ path: () =>
56
+ p.text({
57
+ message: `${highlight("seed-design 폴더")} 경로를 입력해주세요. (기본값은 프로젝트 루트에 생성됩니다.)`,
58
+ initialValue: "./seed-design",
59
+ defaultValue: "./seed-design",
60
+ placeholder: "./seed-design",
61
+ }),
62
+ },
63
+ {
64
+ onCancel: () => {
65
+ p.cancel("작업이 취소됐어요.");
66
+ process.exit(0);
67
+ },
68
+ },
69
+ );
70
+
71
+ config = {
72
+ ...group,
73
+ };
74
+ }
75
+
76
+ try {
77
+ const { start, stop } = p.spinner();
78
+ start("seed-design.json 파일 생성중...");
79
+ const targetPath = path.resolve(options.cwd, "seed-design.json");
80
+ await fs.writeFile(targetPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
81
+ const relativePath = path.relative(process.cwd(), targetPath);
82
+ stop(`seed-design.json 파일이 ${highlight(relativePath)}에 생성됐어요.`);
83
+ p.log.info(color.gray("seed-design add {component} 명령어로 컴포넌트를 추가해보세요!"));
84
+ p.log.info(
85
+ color.gray("seed-design add 명령어로 추가할 수 있는 모든 컴포넌트를 확인해보세요."),
86
+ );
87
+ p.outro("작업이 완료됐어요.");
88
+ } catch (error) {
89
+ p.log.error(`seed-design.json 파일 생성에 실패했어요. ${error}`);
90
+ p.outro(color.bgRed("작업이 취소됐어요."));
91
+ process.exit(1);
92
+ }
71
93
  });
72
94
  };
@@ -0,0 +1,2 @@
1
+ export const BASE_URL =
2
+ process.env.NODE_ENV === "prod" ? "https://v3.seed-design.io" : "http://localhost:3000";
package/src/index.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { addCommand } from "@/src/commands/add";
4
+ import { initCommand } from "@/src/commands/init";
4
5
  import { getPackageInfo } from "@/src/utils/get-package-info";
5
6
  import { cac } from "cac";
6
- import { initCommand } from "./commands/init";
7
- import { checkDeprecatedIconFilesCommand } from "@/src/commands/check-deprecated-icon-files";
8
7
 
9
8
  const NAME = "seed-design";
10
9
  const CLI = cac(NAME);
@@ -15,7 +14,6 @@ async function main() {
15
14
  /* Commands */
16
15
  addCommand(CLI);
17
16
  initCommand(CLI);
18
- checkDeprecatedIconFilesCommand(CLI);
19
17
 
20
18
  CLI.version(packageInfo.version || "1.0.0", "-v, --version");
21
19
  CLI.help();
package/src/schema.ts CHANGED
@@ -1,10 +1,11 @@
1
+ // TODO: Extract to shared package
1
2
  import { z } from "zod";
2
3
 
3
- // TODO: Extract this to a shared package.
4
- // INFO: also used in docs
5
- export const registryComponentItemSchema = z.object({
4
+ export const registryType = z.union([z.literal("ui"), z.literal("hook"), z.literal("util")]);
5
+
6
+ export const registryUIItemSchema = z.object({
6
7
  /**
7
- * @description 컴포넌트 이름
8
+ * @description 레지스트리 이름
8
9
  * @example chip-tabs, alert-dialog
9
10
  */
10
11
  name: z.string(),
@@ -12,50 +13,67 @@ export const registryComponentItemSchema = z.object({
12
13
  description: z.string().optional(),
13
14
 
14
15
  /**
15
- * @description 컴포넌트 의존성
16
+ * @description 레지스트리 의존성
16
17
  * @example @seed-design/react-tabs
17
18
  */
18
19
  dependencies: z.array(z.string()).optional(),
19
20
 
20
21
  /**
21
- * @description 컴포넌트 개발 의존성
22
+ * @description 레지스트리 개발 의존성
22
23
  */
23
24
  devDependencies: z.array(z.string()).optional(),
24
25
 
25
26
  /**
26
- * @description 컴포넌트 내부의 Seed Design 컴포넌트 의존성
27
+ * @description 레지스트리 내부의 Seed Design 컴포넌트 의존성
27
28
  * @example action-button
28
29
  */
29
30
  innerDependencies: z.array(z.string()).optional(),
30
31
 
31
32
  /**
32
- * @description 컴포넌트 코드 스니펫 경로, 여러 파일이 될 수 있어서 배열로 정의
33
- * @example component/alert-dialog.tsx
33
+ * @description
34
+ * 컴포넌트 코드 스니펫 경로, 여러 파일이 될 수 있어서 배열로 정의
35
+ * `:`를 기준으로 왼쪽은 {registryType}, 오른쪽은 파일 이름
36
+ * @example ui:alert-dialog.tsx
37
+ * @example hook:use-dismissible.ts
34
38
  */
35
39
  files: z.array(z.string()),
36
40
  });
41
+ export const registryUISchema = z.array(registryUIItemSchema);
37
42
 
38
- export const registryComponentSchema = z.array(registryComponentItemSchema);
39
-
40
- const omittedRegistryComponentSchema = registryComponentItemSchema.omit({ files: true });
41
- export const registryComponentItemMachineGeneratedSchema = omittedRegistryComponentSchema.extend({
43
+ /**
44
+ * @description 머신이 생성한 registry component schema
45
+ */
46
+ const omittedRegistryUISchema = registryUIItemSchema.omit({
47
+ files: true,
48
+ });
49
+ export const registryUIItemMachineGeneratedSchema = omittedRegistryUISchema.extend({
42
50
  registries: z.array(
43
51
  z.object({
44
52
  name: z.string(),
53
+ type: registryType,
45
54
  content: z.string(),
46
55
  }),
47
56
  ),
48
57
  });
49
-
50
58
  export const registryComponentMachineGeneratedSchema = z.array(
51
- registryComponentItemMachineGeneratedSchema,
59
+ registryUIItemMachineGeneratedSchema,
52
60
  );
53
61
 
54
- export type RegistryComponentItem = z.infer<typeof registryComponentItemSchema>;
55
- export type RegistryComponent = z.infer<typeof registryComponentSchema>;
56
- export type RegistryComponentItemMachineGenerated = z.infer<
57
- typeof registryComponentItemMachineGeneratedSchema
58
- >;
59
- export type RegistryComponentMachineGenerated = z.infer<
60
- typeof registryComponentMachineGeneratedSchema
61
- >;
62
+ // NOTE: 현재는 hook, util이 ui와 타입이 동일하지만, 따로 가져가야한다면 타입을 변경해야해요.
63
+ export const registryHookItemMachineGeneratedSchema = registryUIItemMachineGeneratedSchema;
64
+ export const registryUtilItemMachineGeneratedSchema = registryUIItemMachineGeneratedSchema;
65
+
66
+ // NOTE: 현재는 hook, util이 ui와 타입이 동일하지만, 따로 가져가야한다면 타입을 변경해야해요.
67
+ export type RegistryUtilItem = z.infer<typeof registryUIItemSchema>;
68
+ export type RegistryUtil = z.infer<typeof registryUISchema>;
69
+ export type RegistryHookItem = z.infer<typeof registryUIItemSchema>;
70
+ export type RegistryHook = z.infer<typeof registryUISchema>;
71
+ export type RegistryUIItem = z.infer<typeof registryUIItemSchema>;
72
+ export type RegistryUI = z.infer<typeof registryUISchema>;
73
+
74
+ export type RegistryUIItemMachineGenerated = z.infer<typeof registryUIItemMachineGeneratedSchema>;
75
+ export type RegistryUIMachineGenerated = z.infer<typeof registryComponentMachineGeneratedSchema>;
76
+ export type RegistryHookItemMachineGenerated = z.infer<typeof registryUIItemMachineGeneratedSchema>;
77
+ export type RegistryHookMachineGenerated = z.infer<typeof registryComponentMachineGeneratedSchema>;
78
+ export type RegistryUtilItemMachineGenerated = z.infer<typeof registryUIItemMachineGeneratedSchema>;
79
+ export type RegistryUtilMachineGenerated = z.infer<typeof registryComponentMachineGeneratedSchema>;
@@ -1,8 +1,8 @@
1
- import type { RegistryComponentMachineGenerated } from "@/src/schema";
1
+ import type { RegistryUIMachineGenerated } from "@/src/schema";
2
2
 
3
3
  export function addRelativeComponents(
4
4
  userSelects: string[],
5
- registryIndex: RegistryComponentMachineGenerated,
5
+ registryIndex: RegistryUIMachineGenerated,
6
6
  ) {
7
7
  const selectedComponents = new Set<string>();
8
8
 
@@ -0,0 +1,3 @@
1
+ import color from "picocolors";
2
+
3
+ export const highlight = (text: string) => color.cyan(text);
@@ -1,6 +1,11 @@
1
+ import * as p from "@clack/prompts";
1
2
  import { cosmiconfig } from "cosmiconfig";
3
+ import { execa } from "execa";
4
+ import fs from "fs";
2
5
  import path from "path";
3
6
  import { z } from "zod";
7
+ import { highlight } from "./color";
8
+ import { getPackageManager } from "./get-package-manager";
4
9
 
5
10
  const MODULE_NAME = "seed-design";
6
11
 
@@ -22,6 +27,8 @@ export type RawConfig = z.infer<typeof rawConfigSchema>;
22
27
 
23
28
  export const configSchema = rawConfigSchema.extend({
24
29
  resolvedUIPaths: z.string(),
30
+ resolbedHookPaths: z.string(),
31
+ resolvedUtilPaths: z.string(),
25
32
  });
26
33
 
27
34
  export async function getConfig(cwd: string) {
@@ -39,23 +46,49 @@ export type Config = z.infer<typeof configSchema>;
39
46
  export async function resolveConfigPaths(cwd: string, config: RawConfig) {
40
47
  const seedComponentRootPath = path.resolve(cwd, config.path);
41
48
 
49
+ if (!fs.existsSync(seedComponentRootPath)) {
50
+ fs.mkdirSync(seedComponentRootPath, { recursive: true });
51
+ }
52
+
53
+ const resolvedUIPaths = path.join(seedComponentRootPath, "ui");
54
+ const resolbedHookPaths = path.join(seedComponentRootPath, "hook");
55
+ const resolvedUtilPaths = path.join(seedComponentRootPath, "util");
56
+
57
+ if (!fs.existsSync(resolvedUIPaths)) {
58
+ fs.mkdirSync(resolvedUIPaths, { recursive: true });
59
+ }
60
+
61
+ if (!fs.existsSync(resolbedHookPaths)) {
62
+ fs.mkdirSync(resolbedHookPaths, { recursive: true });
63
+ }
64
+
65
+ if (!fs.existsSync(resolvedUtilPaths)) {
66
+ fs.mkdirSync(resolvedUtilPaths, { recursive: true });
67
+ }
68
+
42
69
  return configSchema.parse({
43
70
  ...config,
44
- resolvedUIPaths: path.join(seedComponentRootPath, "ui"),
71
+ resolvedUIPaths,
72
+ resolbedHookPaths,
73
+ resolvedUtilPaths,
45
74
  });
46
75
  }
47
76
 
48
77
  export async function getRawConfig(cwd: string): Promise<RawConfig | null> {
49
78
  try {
50
79
  const configResult = await explorer.search(cwd);
80
+ return rawConfigSchema.parse(configResult.config);
81
+ } catch {
82
+ p.log.error("프로젝트 루트 경로에 `seed-design.json` 파일이 없어요.");
51
83
 
52
- if (!configResult) {
53
- return null;
84
+ const isConfirm = await p.confirm({ message: "seed-design.json 파일을 생성하시겠어요?" });
85
+ if (isConfirm === true) {
86
+ const packageManager = await getPackageManager(cwd);
87
+ await execa(packageManager, ["seed-design", "init", "--default"], { cwd });
88
+ p.log.message("seed-design.json 파일이 생성됐어요.");
89
+ } else {
90
+ p.outro(highlight("작업이 취소됐어요."));
91
+ process.exit(1);
54
92
  }
55
-
56
- return rawConfigSchema.parse(configResult.config);
57
- } catch (error) {
58
- console.log(error);
59
- throw new Error(`Invalid configuration found in ${cwd}/seed-design.json.`);
60
93
  }
61
94
  }
@@ -1,33 +1,59 @@
1
- import { registryComponentSchema, type RegistryComponentMachineGenerated } from "@/src/schema";
1
+ import * as p from "@clack/prompts";
2
+ import { registryUISchema, type RegistryUIMachineGenerated } from "@/src/schema";
2
3
 
3
- const BASE_URL =
4
- process.env.NODE_ENV === "prod" ? "https://v3.seed-design.io" : "http://localhost:3000";
5
-
6
- export async function fetchRegistryComponentItem(
4
+ export async function fetchRegistryUIItem(
7
5
  fileNames?: string[],
8
- ): Promise<RegistryComponentMachineGenerated> {
9
- try {
10
- const results = await Promise.all(
11
- fileNames.map(async (fileName) => {
12
- const response = await fetch(`${BASE_URL}/__registry__/component/${fileName}.json`);
6
+ baseUrl?: string,
7
+ ): Promise<RegistryUIMachineGenerated> {
8
+ const results = await Promise.all(
9
+ fileNames.map(async (fileName) => {
10
+ try {
11
+ const response = await fetch(`${baseUrl}/__registry__/ui/${fileName}.json`);
13
12
  return await response.json();
14
- }),
15
- );
13
+ } catch (error) {
14
+ const index = await fetch(`${baseUrl}/__registry__/ui/index.json`).then((res) =>
15
+ res.json(),
16
+ );
17
+ const parsedIndex = registryUISchema.parse(index);
18
+ const availableComponents = parsedIndex.map((component) => component.name);
16
19
 
17
- return results;
18
- } catch (error) {
19
- console.log(error);
20
- throw new Error(`Failed to fetch registry from ${BASE_URL}.`);
21
- }
20
+ p.log.error(`${fileName} 컴포넌트는 레지스트리에 존재하지 않아요.`);
21
+ p.log.info(`사용 가능한 컴포넌트: ${availableComponents.join(", ")}`);
22
+ p.log.info(
23
+ JSON.stringify(
24
+ {
25
+ baseUrl,
26
+ error: error.toString(),
27
+ },
28
+ null,
29
+ 2,
30
+ ),
31
+ );
32
+ process.exit(1);
33
+ }
34
+ }),
35
+ );
36
+
37
+ return results;
22
38
  }
23
39
 
24
- export async function getRegistryComponentIndex() {
40
+ export async function getRegistryUIIndex(baseUrl?: string) {
25
41
  try {
26
- const [result] = await fetchRegistryComponentItem(["index"]);
42
+ const [result] = await fetchRegistryUIItem(["index"], baseUrl);
27
43
 
28
- return registryComponentSchema.parse(result);
44
+ return registryUISchema.parse(result);
29
45
  } catch (error) {
30
- console.log(error);
31
- throw new Error(`Failed to fetch components from ${BASE_URL}.`);
46
+ p.log.error("레지스트리 인덱스를 가져오는 데 실패했어요.");
47
+ p.log.info(
48
+ JSON.stringify(
49
+ {
50
+ baseUrl,
51
+ error: error.toString(),
52
+ },
53
+ null,
54
+ 2,
55
+ ),
56
+ );
57
+ process.exit(1);
32
58
  }
33
59
  }
@@ -1,256 +0,0 @@
1
- import type { CAC } from "cac";
2
- import fs from "node:fs";
3
-
4
- export const checkDeprecatedIconFilesCommand = (cli: CAC) => {
5
- cli
6
- .command("check-deprecated-icon-files [path]", "Check deprecated icon files")
7
- .action(async (path) => {
8
- const files = fs.readdirSync(path, { recursive: true });
9
-
10
- const deprecatedIconFileNames = deprecatedIconNames.flatMap((name) => {
11
- const nameTrimmed = name.replace("icon_", "");
12
-
13
- return [
14
- // icon_arrow_downward
15
- name,
16
- // arrow_downward
17
- nameTrimmed,
18
- // icon-arrow-downward
19
- name.replace(/_/g, "-"),
20
- // iconarrowdownward
21
- name.replace(/_/g, ""),
22
- // iconarrowdownwardthin
23
- `${name.replace(/_/g, "")}thin`,
24
- // iconarrowdownwardregular
25
- `${name.replace(/_/g, "")}regular`,
26
- // iconarrowdownwardfill
27
- `${name.replace(/_/g, "")}fill`,
28
- // arrow-downward
29
- nameTrimmed.replace(/_/g, "-"),
30
- // arrowdownward
31
- nameTrimmed.replace(/_/g, ""),
32
- // arrowdownwardthin
33
- `${nameTrimmed.replace(/_/g, "")}thin`,
34
- // arrowdownwardregular
35
- `${nameTrimmed.replace(/_/g, "")}regular`,
36
- // arrowdownwardfill
37
- `${nameTrimmed.replace(/_/g, "")}fill`,
38
- ];
39
- });
40
-
41
- for (const file of files) {
42
- if (typeof file !== "string") continue;
43
- if (file.includes("node_modules/")) continue;
44
-
45
- const fileNameLowered = file.split("/").pop().split(".")[0].toLowerCase();
46
- if (extensionsToCheck.every((ext) => file.endsWith(ext) === false)) continue;
47
-
48
- if (deprecatedIconFileNames.includes(fileNameLowered)) {
49
- console.log(`Possible deprecated icon file found: ${file}`);
50
- }
51
- }
52
- });
53
- };
54
-
55
- const extensionsToCheck = [".tsx", ".jsx", ".svg", ".png"];
56
-
57
- const deprecatedIconNames = [
58
- "icon_add",
59
- "icon_add_circle",
60
- "icon_aeb",
61
- "icon_ai",
62
- "icon_android_share",
63
- "icon_arrow",
64
- "icon_arrow_downward",
65
- "icon_arrow_drop_down",
66
- "icon_arrow_drop_up",
67
- "icon_arrow_upward",
68
- "icon_article",
69
- "icon_backward",
70
- "icon_bill",
71
- "icon_bold",
72
- "icon_bookmark",
73
- "icon_bookmark_list",
74
- "icon_calendar",
75
- "icon_call",
76
- "icon_call_declined",
77
- "icon_camera",
78
- "icon_car",
79
- "icon_car_around_view",
80
- "icon_car_blind_spot",
81
- "icon_car_cruise_control",
82
- "icon_car_epb",
83
- "icon_car_heated_seat",
84
- "icon_car_heated_steering_wheel",
85
- "icon_car_ldws",
86
- "icon_car_leather_seat",
87
- "icon_car_navigation",
88
- "icon_car_power_trunk",
89
- "icon_car_rear_camera",
90
- "icon_car_rear_sensor",
91
- "icon_car_smart_key",
92
- "icon_car_ventilation_seat",
93
- "icon_cart",
94
- "icon_certification",
95
- "icon_challenge",
96
- "icon_chart",
97
- "icon_chat_bubble_check",
98
- "icon_chatting",
99
- "icon_chatting_send",
100
- "icon_check",
101
- "icon_check_flower",
102
- "icon_chevron_left",
103
- "icon_chevron_right",
104
- "icon_click",
105
- "icon_clock",
106
- "icon_close",
107
- "icon_cobuying",
108
- "icon_community",
109
- "icon_condo",
110
- "icon_confirmation",
111
- "icon_confirmation_pay",
112
- "icon_confirmation_profile",
113
- "icon_contents",
114
- "icon_convert",
115
- "icon_copy",
116
- "icon_coupon",
117
- "icon_coupon_download_done",
118
- "icon_coupon_used",
119
- "icon_delete_keyboard",
120
- "icon_delivery",
121
- "icon_direction",
122
- "icon_download",
123
- "icon_edit",
124
- "icon_emoticon",
125
- "icon_emoticon_bad",
126
- "icon_expand",
127
- "icon_expand_less",
128
- "icon_expand_more",
129
- "icon_file",
130
- "icon_filter02",
131
- "icon_forward",
132
- "icon_gender",
133
- "icon_global",
134
- "icon_gps",
135
- "icon_gps_enable",
136
- "icon_gps_enable2",
137
- "icon_groupchat_king",
138
- "icon_handle",
139
- "icon_hashtag",
140
- "icon_headphone",
141
- "icon_heart",
142
- "icon_help",
143
- "icon_helpcenter",
144
- "icon_helper",
145
- "icon_home",
146
- "icon_house",
147
- "icon_housekeeping_book",
148
- "icon_import",
149
- "icon_info",
150
- "icon_interest",
151
- "icon_interest_list",
152
- "icon_invite",
153
- "icon_invite_friend",
154
- "icon_ios_share",
155
- "icon_jobs",
156
- "icon_keyboard_hiding",
157
- "icon_keyword",
158
- "icon_laptop",
159
- "icon_leaf",
160
- "icon_list",
161
- "icon_list_card",
162
- "icon_list_check",
163
- "icon_list_select",
164
- "icon_list_thumbnail",
165
- "icon_location",
166
- "icon_lock",
167
- "icon_loudspeaker",
168
- "icon_map",
169
- "icon_market",
170
- "icon_market_check",
171
- "icon_market_write",
172
- "icon_mention",
173
- "icon_menu",
174
- "icon_mic",
175
- "icon_mic_off",
176
- "icon_mission",
177
- "icon_mobile",
178
- "icon_money_send",
179
- "icon_money_won",
180
- "icon_moon",
181
- "icon_more_horiz",
182
- "icon_more_vert",
183
- "icon_my",
184
- "icon_my_profile",
185
- "icon_near_me",
186
- "icon_newtopic",
187
- "icon_note",
188
- "icon_notification",
189
- "icon_notification_fall",
190
- "icon_notification_off",
191
- "icon_order",
192
- "icon_pause",
193
- "icon_payment",
194
- "icon_percent",
195
- "icon_photo",
196
- "icon_photo_edit",
197
- "icon_photo_edit_crop",
198
- "icon_photo_edit_draw",
199
- "icon_photo_edit_rotate",
200
- "icon_photo_several",
201
- "icon_play",
202
- "icon_poll",
203
- "icon_price_won",
204
- "icon_product",
205
- "icon_profile",
206
- "icon_profile_badge",
207
- "icon_prohibition",
208
- "icon_pushpin",
209
- "icon_question_check",
210
- "icon_redo",
211
- "icon_refund",
212
- "icon_remove_circle",
213
- "icon_reply",
214
- "icon_reply_mission",
215
- "icon_reply_re",
216
- "icon_report",
217
- "icon_reservation",
218
- "icon_restaurant",
219
- "icon_retry",
220
- "icon_review_star",
221
- "icon_scanner",
222
- "icon_search",
223
- "icon_search_doc",
224
- "icon_sell",
225
- "icon_setting",
226
- "icon_signout",
227
- "icon_sort",
228
- "icon_story",
229
- "icon_story_article",
230
- "icon_subtract_circle",
231
- "icon_subtraction",
232
- "icon_suggest",
233
- "icon_sun",
234
- "icon_talkingdown",
235
- "icon_talkingup",
236
- "icon_text",
237
- "icon_thumb_down",
238
- "icon_thumb_up",
239
- "icon_toolbox",
240
- "icon_translate",
241
- "icon_trash",
242
- "icon_undo",
243
- "icon_user_group",
244
- "icon_video",
245
- "icon_view_count",
246
- "icon_view_count_off",
247
- "icon_volume_off",
248
- "icon_volume_on",
249
- "icon_vote",
250
- "icon_voucher",
251
- "icon_walk",
252
- "icon_warning",
253
- "icon_write",
254
- "icon_write_frequent_use",
255
- "icon_write_story",
256
- ];