@seed-design/cli 0.0.0-alpha-20241016030836 → 0.0.0-alpha-20241031064135

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,9 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{cosmiconfig as fe}from"cosmiconfig";import M from"path";import{z as I}from"zod";var A="seed-design",de=fe(A,{searchPlaces:[`${A}.json`]}),O=I.object({$schema:I.string().optional(),rsc:I.coerce.boolean().default(!1),tsx:I.coerce.boolean().default(!0),css:I.coerce.boolean().default(!0),path:I.string()}).strict(),ge=O.extend({resolvedUIPaths:I.string()});async function W(e){let t=await he(e);return t?await ue(e,t):null}async function ue(e,t){let r=M.resolve(e,t.path);return ge.parse({...t,resolvedUIPaths:M.join(r,"ui")})}async function he(e){try{let t=await de.search(e);return t?O.parse(t.config):null}catch(t){throw console.log(t),new Error(`Invalid configuration found in ${e}/seed-design.json.`)}}import{z as l}from"zod";var G=l.object({name:l.string(),description:l.string().optional(),dependencies:l.array(l.string()).optional(),devDependencies:l.array(l.string()).optional(),innerDependencies:l.array(l.string()).optional(),files:l.array(l.string())}),V=l.array(G),ye=G.omit({files:!0}),xe=ye.extend({registries:l.array(l.object({name:l.string(),content:l.string()}))}),ot=l.array(xe);var N="https://component.seed-design.io";async function D(e){try{return await Promise.all(e.map(async r=>await(await fetch(`${N}/__registry__/component/${r}.json`)).json()))}catch(t){throw console.log(t),new Error(`Failed to fetch registry from ${N}.`)}}async function _(){try{let[e]=await D(["index"]);return V.parse(e)}catch(e){throw console.log(e),new Error(`Failed to fetch components from ${N}.`)}}import{detect as we}from"@antfu/ni";async function z(e){let t=await we({programmatic:!0,cwd:e});return t==="yarn@berry"?"yarn":t==="pnpm@6"?"pnpm":t==="bun"?"bun":t??"npm"}import{promises as je}from"fs";import{tmpdir as Fe}from"os";import K from"path";import{transformFromAstSync as Ce}from"@babel/core";import Ie from"@babel/plugin-transform-typescript";import*as R from"recast";import{parse as Se}from"@babel/parser";var Pe={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"]},J=async({sourceFile:e,config:t})=>{let r=e.getFullText();if(t.tsx)return r;let o=R.parse(r,{parser:{parse:s=>Se(s,Pe)}}),n=Ce(o,r,{cloneInputAst:!1,code:!1,ast:!0,plugins:[Ie],configFile:!1});if(!n||!n.ast)throw new Error("Failed to transform JSX");return R.print(n.ast).code};import{SyntaxKind as Te}from"ts-morph";var H=async({sourceFile:e,config:t})=>{if(t.rsc)return e;let r=e.getFirstChildByKind(Te.ExpressionStatement);return r?.getText()==='"use client";'&&r.remove(),e};var U=async({sourceFile:e,config:t})=>{if(t.css)return e;let o=e.getImportDeclarations().filter(n=>n.getModuleSpecifierValue().endsWith(".css"));for(let n of o)n.remove();return e};import{Project as ve,ScriptKind as Re}from"ts-morph";var be=[H,U],Ne=new ve({compilerOptions:{}});async function De(e){let t=await je.mkdtemp(K.join(Fe(),"seed-deisgn-"));return K.join(t,e)}async function L(e){let t=await De(e.filename),r=Ne.createSourceFile(t,e.raw,{scriptKind:Re.TSX});for(let o of be)o({sourceFile:r,...e});return await J({sourceFile:r,...e})}import*as f from"@clack/prompts";import{execa as X}from"execa";import b from"fs-extra";import q from"path";import $ from"picocolors";import{z as j}from"zod";function B(e,t){let r=new Set;function o(n){if(r.has(n))return;r.add(n);let s=t.find(c=>c.name===n);if(s&&s.innerDependencies)for(let c of s.innerDependencies)o(c)}for(let n of e)o(n);return Array.from(r)}var $e=j.object({components:j.array(j.string()).optional(),cwd:j.string(),all:j.boolean()}),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()}).example("seed-design add box-button").example("seed-design add alert-dialog").action(async(t,r)=>{let o=$e.parse({components:t,...r}),n=i=>$.cyan(i),s=o.cwd;b.existsSync(s)||(f.log.error(`The path ${s} does not exist. Please try again.`),process.exit(1));let c=await _(),p=o.all?c.map(i=>i.name):o.components;if(!o.components?.length&&!o.all){let i=await f.multiselect({message:"Select all components to add",options:c.map(d=>({label:d.name,value:d.name,hint:d.description}))});f.isCancel(i)&&(f.log.error("Aborted."),process.exit(0)),p=i}p?.length||(f.log.error("No components found."),process.exit(0));let u=B(p,c),m=u.filter(i=>!p.includes(i)),a=await W(s),w=await D(u);f.log.message(`Selection: ${n(p.join(", "))}`),m.length&&f.log.message(`Inner Dependencies: ${n(m.join(", "))} will be also added.`);for(let i of w){for(let y of i.registries){let C=a.resolvedUIPaths;b.existsSync(C)||await b.mkdir(C,{recursive:!0});let S=q.resolve(C,y.name),me=await L({filename:y.name,config:a,raw:y.content});a.tsx||(S=S.replace(/\.tsx$/,".jsx"),S=S.replace(/\.ts$/,".js")),await b.writeFile(S,me);let le=q.relative(s,S);f.log.info(`Added ${n(y.name)} to ${n(le)}`)}let d=await z(s),{start:h,stop:v}=f.spinner();if(i.dependencies?.length){h($.gray("Installing dependencies"));let y=await X(d,[d==="npm"?"install":"add",...i.dependencies],{cwd:s});if(y.failed)console.error(y.all),process.exit(1);else{for(let C of i.dependencies)f.log.info(`- ${C}`);v("Dependencies installed.")}}if(i.devDependencies?.length){h($.gray("Installing devDependencies"));let y=await X(d,[d==="npm"?"install":"add","-D",...i.devDependencies],{cwd:s});if(y.failed)console.error(y.all),process.exit(1);else{for(let C of i.devDependencies)f.log.info(`- ${C}`);v("Dependencies installed.")}}}f.outro("Components added.")})};import ke from"findup-sync";import Ee from"fs-extra";var Me="package.json";function Ae(){let e=ke(Me);if(!e)throw new Error("No package.json file found in the project.");return e}function Y(){return Ee.readJSONSync(Ae())}import{cac as Xe}from"cac";import*as g from"@clack/prompts";import Oe from"fs-extra";import Z from"path";import We from"picocolors";import{z as ee}from"zod";var Ge=ee.object({cwd:ee.string()}),te=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 t=>{let r=Ge.parse({...t}),o=a=>We.cyan(a),n=await g.group({tsx:()=>g.confirm({message:`Would you like to use ${o("TypeScript")} (recommended)?`,initialValue:!0}),rsc:()=>g.confirm({message:`Are you using ${o("React Server Components")}?`,initialValue:!1}),css:()=>g.confirm({message:`Would you like to use ${o("CSS Modules")}? (If true, CSS import will be added in components)`,initialValue:!0}),path:()=>g.text({message:`Enter the path to your ${o("seed-design directory")}`,initialValue:"./seed-design",defaultValue:"./seed-design",placeholder:"./seed-design"})},{onCancel:()=>{g.cancel("Operation cancelled."),process.exit(0)}}),s={rsc:n.rsc,tsx:n.tsx,css:n.css,path:n.path},{start:c,stop:p}=g.spinner();c("Writing seed-design.json...");let u=Z.resolve(r.cwd,"seed-design.json");await Oe.writeFile(u,`${JSON.stringify(s,null,2)}
3
- `,"utf-8");let m=Z.relative(process.cwd(),u);p(`seed-design.json written to ${o(m)}`)})};import*as x from"@clack/prompts";import{z as E}from"zod";import P from"typescript";import Ve from"fs";import _e from"path";function k({dir:e,extensionsToFind:t,extensionsToExclude:r}){return Ve.readdirSync(e,{withFileTypes:!0,recursive:!0}).filter(o=>o.isFile()&&t.some(n=>o.name.endsWith(n))&&(r?!r.some(n=>o.name.endsWith(n)):!0)).map(o=>`${o.parentPath}/${o.name}`)}function re({dirToFindTsconfig:e,excludeDTs:t}){let r=P.findConfigFile(e,P.sys.fileExists),o=P.readConfigFile(r,P.sys.readFile),{fileNames:n}=P.parseJsonConfigFileContent(o.config,P.sys,_e.dirname(r));return n.filter(s=>t?!s.endsWith(".d.ts"):!0)}async function oe({git:e,filePaths:t}){let r=await Promise.all(t.map(o=>ze(e,o)));return t.filter((o,n)=>r[n])}async function ze(e,t){return(await e.checkIgnore(t)).length<=0}import{simpleGit as Ue}from"simple-git";import Ke from"jscodeshift";import F from"jscodeshift";import ne from"fs";function se({filePath:e,jscodeshift:t,importTransformers:r}){let o=ne.readFileSync(e,"utf-8"),n=t(o),s=ie({tree:n,jscodeshift:t});Je({importDeclarations:n.find(t.ImportDeclaration,{source:{value:p=>typeof p!="string"?!1:r.source.some(({startsWith:u})=>p.startsWith(u))}}),importTransformers:r}),He({identifiers:n.find(t.Identifier,{name:p=>Object.keys(r.identifier).includes(p)}),identifierTransformers:r.identifier});let c=ie({tree:n,jscodeshift:t});s!==c&&(c.comments=s.comments),ne.writeFileSync(e,n.toSource())}function ie({tree:e,jscodeshift:t}){return e.find(t.Program).get("body",0).node}function Je({importDeclarations:e,importTransformers:t}){e.replaceWith(r=>{let o=r.node.source.value,n=r.node.specifiers,s=r.node.importKind,c=(()=>{if(typeof o!="string")return o;let{startsWith:m,replaceWith:a}=t.source.find(({startsWith:h})=>o.startsWith(h)),i=(a?o.replace(m,a):o).split("/");return i.map((h,v)=>v!==i.length-1||!(h in t.identifier)?h:t.identifier[h]).join("/")})(),p=n.map(m=>{switch(m.type){case"ImportSpecifier":{let a=m.imported.name;if(!(a in t.identifier))return m;let w=t.identifier[a];if(w===a)return m;let d=F.identifier(w);return F.importSpecifier(d,m.local)}case"ImportDefaultSpecifier":return m;case"ImportNamespaceSpecifier":return m}});return F.importDeclaration(p,F.literal(c),s)})}function He({identifiers:e,identifierTransformers:t}){e.replaceWith(r=>{let o=r.node.name;return o in t?F.identifier(t[o]):r})}var Le={source:[{startsWith:"@seed-design/icons",replaceWith:"@seed-design/react-icon"},{startsWith:"@seed-design/react-icon"}],identifier:{Icon:"NewIcon"}},Be=E.object({path:E.string().optional(),includeIgnored:E.boolean().optional()}),ae=[".js",".jsx",".ts",".tsx"],ce=[".d.ts"],pe=e=>{e.command("icon-shift","V2 \uC544\uC774\uCF58\uC744 V3 \uC544\uC774\uCF58\uC73C\uB85C \uBCC0\uD658\uD558\uB294 \uBA85\uB839\uC5B4").option("--path <path>","\uB9C8\uC774\uADF8\uB808\uC774\uC158\uD560 \uC18C\uC2A4 \uCF54\uB4DC\uAC00 \uC788\uB294 \uACBD\uB85C (\uC120\uD0DD)").option("--include-ignored",".gitignore\uB97C \uD1B5\uD574 \uD2B8\uB798\uD0B9\uB418\uC9C0 \uC54A\uB294 \uD30C\uC77C\uB3C4 \uD3EC\uD568\uD560\uC9C0 \uC5EC\uBD80 (\uC120\uD0DD)").example("seed-design icon-shift").action(async t=>{let r=Be.parse({...t}),o={target:()=>x.select({message:`\uC785\uB825\uD55C \uACBD\uB85C: ${r.path} \uB9DE\uB098\uC694?`,options:[{label:"\uB124",value:"path"}]})},n={target:()=>x.select({message:"\uC5B4\uB5A4 \uD30C\uC77C\uC744 \uB300\uC0C1\uC73C\uB85C \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC744 \uC9C4\uD589\uD560\uAE4C\uC694?",options:[{label:"\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC0AC\uC6A9\uB418\uB294 tsconfig\uAC00 \uCEF4\uD30C\uC77C\uD558\uB294 \uD30C\uC77C",value:"tsconfig"},{label:"\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC \uC548\uC758 .js, .jsx, .ts, .tsx (excluding d.ts)",value:"cwd"}],initialValue:"tsconfig.json"})},s=await x.group({...r.path?o:n,...r.includeIgnored&&{includeIgnored:()=>x.confirm({message:"git\uC5D0 \uD2B8\uB798\uD0B9\uB418\uC9C0 \uC54A\uB294 \uD30C\uC77C\uB3C4 \uD3EC\uD568\uD560\uAE4C\uC694?",initialValue:!0})},migrateIdentifiers:()=>x.select({message:"\uC5B4\uB514\uAE4C\uC9C0 \uBCC0\uACBD\uD560\uAE4C\uC694?",options:[{label:"\uBAA8\uB450 \uBCC0\uACBD",value:"all",hint:`
4
- (old) import { IconHeart } from "old-package"; <IconHeart />;
5
- \u2192 (new) import { NewIconHeart } from "new-package"; <NewIconHeart />;
6
- `},{label:"import\uB9CC \uBCC0\uACBD",value:"importOnly",hint:`
7
- (old) import { IconHeart } from "old-package"; <IconHeart />;
8
- \u2192 (new) import { NewIconHeart as IconHeart } from "new-package"; <IconHeart />;
9
- `}],initialValue:"all"})}),c=(()=>{switch(s.target){case"tsconfig":return re({dirToFindTsconfig:process.cwd(),excludeDTs:!0});case"cwd":return k({dir:process.cwd(),extensionsToFind:ae,extensionsToExclude:ce});case"path":return k({dir:r.path,extensionsToFind:ae,extensionsToExclude:ce})}})(),{start:p,message:u,stop:m}=x.spinner();p("\uBA87 \uAC1C\uC758 \uD30C\uC77C\uC744 \uD655\uC778\uD560\uC9C0 \uACB0\uC815\uD558\uACE0 \uC788\uC5B4\uC694.");let a=r.includeIgnored?c:await oe({git:Ue(),filePaths:c});m(`${a.length}\uAC1C \uD30C\uC77C\uC5D0\uC11C \uC608\uC804 \uC544\uC774\uCF58\uC744 \uCC3E\uC544\uBCFC\uAC8C\uC694.`),p(`${a.length}\uAC1C \uD30C\uC77C\uC5D0\uC11C \uC608\uC804 \uC544\uC774\uCF58\uC744 \uCC3E\uC544\uBCFC\uAC8C\uC694.`);let w=Ke.withParser("tsx");for(let i=0;i<a.length;i++){let d=a[i],h=((i+1)/a.length*100).toFixed(1);u(`\uD30C\uC77C ${i+1}/${a.length} \uBCC0\uACBD \uC2DC\uC791 (${h}%): ${d}`),se({filePath:d,jscodeshift:w,importTransformers:Le})}m("\uCF54\uB4DC \uBCC0\uACBD\uC774 \uB05D\uB0AC\uC5B4\uC694.")})};var qe="seed-design",T=Xe(qe);async function Qe(){let e=Y();Q(T),te(T),pe(T),T.version(e.version||"1.0.0","-v, --version"),T.help(),T.parse()}Qe();
2
+ import{cosmiconfig as ee}from"cosmiconfig";import j from"path";import{z as g}from"zod";var $="seed-design",oe=ee($,{searchPlaces:[`${$}.json`]}),T=g.object({$schema:g.string().optional(),rsc:g.coerce.boolean().default(!1),tsx:g.coerce.boolean().default(!0),css:g.coerce.boolean().default(!0),path:g.string()}).strict(),ne=T.extend({resolvedUIPaths:g.string()});async function A(e){let n=await re(e);return n?await te(e,n):null}async function te(e,n){let t=j.resolve(e,n.path);return ne.parse({...n,resolvedUIPaths:j.join(t,"ui")})}async function re(e){try{let n=await oe.search(e);return n?T.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 M=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())}),O=c.array(M),ie=M.omit({files:!0}),ce=ie.extend({registries:c.array(c.object({name:c.string(),content:c.string()}))}),ze=c.array(ce);var k="https://component.seed-design.io";async function b(e){try{return await Promise.all(e.map(async t=>await(await fetch(`${k}/__registry__/component/${t}.json`)).json()))}catch(n){throw console.log(n),new Error(`Failed to fetch registry from ${k}.`)}}async function F(){try{let[e]=await b(["index"]);return O.parse(e)}catch(e){throw console.log(e),new Error(`Failed to fetch components from ${k}.`)}}import{detect as se}from"@antfu/ni";async function D(e){let n=await se({programmatic:!0,cwd:e});return n==="yarn@berry"?"yarn":n==="pnpm@6"?"pnpm":n==="bun"?"bun":n??"npm"}import{promises as de}from"fs";import{tmpdir as fe}from"os";import G from"path";import{transformFromAstSync as ae}from"@babel/core";import pe from"@babel/plugin-transform-typescript";import*as v from"recast";import{parse as le}from"@babel/parser";var me={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"]},E=async({sourceFile:e,config:n})=>{let t=e.getFullText();if(n.tsx)return t;let i=v.parse(t,{parser:{parse:r=>le(r,me)}}),o=ae(i,t,{cloneInputAst:!1,code:!1,ast:!0,plugins:[pe],configFile:!1});if(!o||!o.ast)throw new Error("Failed to transform JSX");return v.print(o.ast).code};import{SyntaxKind as _e}from"ts-morph";var N=async({sourceFile:e,config:n})=>{if(n.rsc)return e;let t=e.getFirstChildByKind(_e.ExpressionStatement);return t?.getText()==='"use client";'&&t.remove(),e};var z=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 ge,ScriptKind as ue}from"ts-morph";var he=[N,z],ye=new ge({compilerOptions:{}});async function we(e){let n=await de.mkdtemp(G.join(fe(),"seed-deisgn-"));return G.join(n,e)}async function J(e){let n=await we(e.filename),t=ye.createSourceFile(n,e.raw,{scriptKind:ue.TSX});for(let i of he)i({sourceFile:t,...e});return await E({sourceFile:t,...e})}import*as s from"@clack/prompts";import{execa as V}from"execa";import S from"fs-extra";import U from"path";import I from"picocolors";import{z as C}from"zod";function L(e,n){let t=new Set;function i(o){if(t.has(o))return;t.add(o);let r=n.find(l=>l.name===o);if(r&&r.innerDependencies)for(let l of r.innerDependencies)i(l)}for(let o of e)i(o);return Array.from(t)}var Ce=C.object({components:C.array(C.string()).optional(),cwd:C.string(),all:C.boolean()}),B=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,t)=>{let i=Ce.parse({components:n,...t}),o=a=>I.cyan(a),r=i.cwd;S.existsSync(r)||(s.log.error(`The path ${r} does not exist. Please try again.`),process.exit(1));let l=await F(),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 y=L(d,l),x=y.filter(a=>!d.includes(a)),w=await A(r),Q=await b(y);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 Q){for(let m of a.registries){let f=w.resolvedUIPaths;S.existsSync(f)||await S.mkdir(f,{recursive:!0});let u=U.resolve(f,m.name),Y=await J({filename:m.name,config:w,raw:m.content});w.tsx||(u=u.replace(/\.tsx$/,".jsx"),u=u.replace(/\.ts$/,".js")),await S.writeFile(u,Y);let Z=U.relative(r,u);s.log.info(`Added ${o(m.name)} to ${o(Z)}`)}let _=await D(r),{start:P,stop:R}=s.spinner();if(a.dependencies?.length){P(I.gray("Installing dependencies"));let m=await V(_,[_==="npm"?"install":"add",...a.dependencies],{cwd:r});if(m.failed)console.error(m.all),process.exit(1);else{for(let f of a.dependencies)s.log.info(`- ${f}`);R("Dependencies installed.")}}if(a.devDependencies?.length){P(I.gray("Installing devDependencies"));let m=await V(_,[_==="npm"?"install":"add","-D",...a.devDependencies],{cwd:r});if(m.failed)console.error(m.all),process.exit(1);else{for(let f of a.devDependencies)s.log.info(`- ${f}`);R("Dependencies installed.")}}}s.outro("Components added.")})};import xe from"findup-sync";import ve from"fs-extra";var Se="package.json";function ke(){let e=xe(Se);if(!e)throw new Error("No package.json file found in the project.");return e}function K(){return ve.readJSONSync(ke())}import{cac as Te}from"cac";import*as p from"@clack/prompts";import be from"fs-extra";import W from"path";import Ie from"picocolors";import{z as q}from"zod";var Pe=q.object({cwd:q.string()}),X=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 t=Pe.parse({...n}),i=w=>Ie.cyan(w),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)}}),r={rsc:o.rsc,tsx:o.tsx,css:o.css,path:o.path},{start:l,stop:d}=p.spinner();l("Writing seed-design.json...");let y=W.resolve(t.cwd,"seed-design.json");await be.writeFile(y,`${JSON.stringify(r,null,2)}
3
+ `,"utf-8");let x=W.relative(process.cwd(),y);d(`seed-design.json written to ${i(x)}`)})};import Re from"node:fs";var H=e=>{e.command("check-deprecated-icon-files [path]","Check deprecated icon files").action(async n=>{let t=Re.readdirSync(n,{recursive:!0}),i=$e.flatMap(o=>{let r=o.replace("icon_","");return[o,r,o.replace(/_/g,"-"),o.replace(/_/g,""),`${o.replace(/_/g,"")}thin`,`${o.replace(/_/g,"")}regular`,`${o.replace(/_/g,"")}fill`,r.replace(/_/g,"-"),r.replace(/_/g,""),`${r.replace(/_/g,"")}thin`,`${r.replace(/_/g,"")}regular`,`${r.replace(/_/g,"")}fill`]});for(let o of t){if(typeof o!="string"||o.includes("node_modules/"))continue;let r=o.split("/").pop().split(".")[0].toLowerCase();je.every(l=>o.endsWith(l)===!1)||i.includes(r)&&console.log(`Possible deprecated icon file found: ${o}`)}})},je=[".tsx",".jsx",".svg",".png"],$e=["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 Ae="seed-design",h=Te(Ae);async function Me(){let e=K();B(h),X(h),H(h),h.version(e.version||"1.0.0","-v, --version"),h.help(),h.parse()}Me();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/cli",
3
- "version": "0.0.0-alpha-20241016030836",
3
+ "version": "0.0.0-alpha-20241031064135",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,30 +29,24 @@
29
29
  "@babel/core": "^7.24.9",
30
30
  "@babel/parser": "^7.24.8",
31
31
  "@babel/plugin-transform-typescript": "^7.24.8",
32
- "@biomejs/js-api": "^0.7.1",
33
- "@biomejs/wasm-nodejs": "^1.9.3",
34
32
  "@clack/prompts": "^0.7.0",
35
33
  "cac": "^6.7.14",
36
34
  "cosmiconfig": "^9.0.0",
37
35
  "execa": "^9.3.0",
38
36
  "findup-sync": "^5.0.0",
39
37
  "fs-extra": "^11.2.0",
40
- "jscodeshift": "^17.0.0",
41
38
  "mktemp": "^1.0.1",
42
39
  "picocolors": "^1.0.1",
43
40
  "recast": "^0.23.9",
44
- "simple-git": "^3.27.0",
45
41
  "ts-morph": "^23.0.0",
46
- "typescript": "^5.4.5",
47
42
  "zod": "^3.23.8"
48
43
  },
49
44
  "devDependencies": {
50
45
  "@types/babel__core": "^7.20.5",
51
46
  "@types/fs-extra": "^11.0.4",
52
- "@types/jscodeshift": "^0.12.0",
53
- "@types/node": "^20",
54
47
  "esbuild": "^0.19.3",
55
48
  "type-fest": "^4.23.0",
49
+ "typescript": "^5.4.5",
56
50
  "ultra-runner": "^3.10.5",
57
51
  "vitest": "^2.0.5"
58
52
  },
@@ -0,0 +1,256 @@
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
+ ];
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import { addCommand } from "@/src/commands/add";
4
4
  import { getPackageInfo } from "@/src/utils/get-package-info";
5
5
  import { cac } from "cac";
6
6
  import { initCommand } from "./commands/init";
7
- import { iconShiftCommand } from "./commands/icon-shift";
7
+ import { checkDeprecatedIconFilesCommand } from "@/src/commands/check-deprecated-icon-files";
8
8
 
9
9
  const NAME = "seed-design";
10
10
  const CLI = cac(NAME);
@@ -15,7 +15,7 @@ async function main() {
15
15
  /* Commands */
16
16
  addCommand(CLI);
17
17
  initCommand(CLI);
18
- iconShiftCommand(CLI);
18
+ checkDeprecatedIconFilesCommand(CLI);
19
19
 
20
20
  CLI.version(packageInfo.version || "1.0.0", "-v, --version");
21
21
  CLI.help();
package/src/schema.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  // TODO: Extract this to a shared package.
4
- // INFO: also used in component-docs
4
+ // INFO: also used in docs
5
5
  export const registryComponentItemSchema = z.object({
6
6
  /**
7
7
  * @description 컴포넌트 이름
@@ -1,147 +0,0 @@
1
- import * as prompt from "@clack/prompts";
2
- import { z } from "zod";
3
- import type { CAC } from "cac";
4
- import {
5
- filterGitIgnoredFiles,
6
- getAllFileNamesWithMatchingExtension,
7
- getAllTypeScriptCompiledFileNames,
8
- } from "@/src/utils/files";
9
- import { simpleGit } from "simple-git";
10
- import jscodeshift from "jscodeshift";
11
- import { migrateFile, type ImportTransformers } from "@/src/utils/migrate";
12
-
13
- const importTransformersReact: ImportTransformers = {
14
- source: [
15
- { startsWith: "@seed-design/icons", replaceWith: "@seed-design/react-icon" },
16
- { startsWith: "@seed-design/react-icon" },
17
- ],
18
- identifier: {
19
- Icon: "NewIcon",
20
- },
21
- };
22
-
23
- const iconShiftOptionsSchema = z.object({
24
- path: z.string().optional(),
25
- includeIgnored: z.boolean().optional(),
26
- });
27
-
28
- // 3. 로그 파일
29
- // 3-1. 변경된 파일, (라인)
30
- // 3-2. 에러났을 때 에러 메세지도 같이 들어있고, 어디서 문제 생겼는지도 나와야 한다.
31
- // 3-2. 그 안에서의 아이콘 AS-IS, TO-BE
32
- // 4. 마이그레이션 끝났습니다. 로그 파일은 어디 생성됐고, 총 몇개의 아이콘 변경됐습니다.
33
-
34
- const EXTENSIONS_TO_FIND = [".js", ".jsx", ".ts", ".tsx"];
35
- const EXTENSIONS_TO_EXCLUDE = [".d.ts"];
36
-
37
- export const iconShiftCommand = (cli: CAC) => {
38
- cli
39
- .command("icon-shift", "V2 아이콘을 V3 아이콘으로 변환하는 명령어")
40
- .option("--path <path>", "마이그레이션할 소스 코드가 있는 경로 (선택)")
41
- .option("--include-ignored", ".gitignore를 통해 트래킹되지 않는 파일도 포함할지 여부 (선택)")
42
- .example("seed-design icon-shift")
43
- .action(async (opts) => {
44
- const options = iconShiftOptionsSchema.parse({ ...opts });
45
-
46
- const pathAvailableTargetPrompt = {
47
- target: () =>
48
- prompt.select({
49
- message: `입력한 경로: ${options.path} 맞나요?`,
50
- options: [{ label: "네", value: "path" }],
51
- }),
52
- };
53
-
54
- const pathUnavailableTargetPrompt = {
55
- target: () =>
56
- prompt.select({
57
- message: "어떤 파일을 대상으로 마이그레이션을 진행할까요?",
58
- options: [
59
- {
60
- label: "현재 디렉토리에서 사용되는 tsconfig가 컴파일하는 파일",
61
- value: "tsconfig",
62
- },
63
- {
64
- // FIXME: 확장자
65
- label: "현재 디렉토리 안의 .js, .jsx, .ts, .tsx (excluding d.ts)",
66
- value: "cwd",
67
- },
68
- ],
69
- initialValue: "tsconfig.json",
70
- }),
71
- };
72
-
73
- const group = await prompt.group({
74
- ...(options.path ? pathAvailableTargetPrompt : pathUnavailableTargetPrompt),
75
- ...(options.includeIgnored && {
76
- includeIgnored: () =>
77
- prompt.confirm({
78
- message: "git에 트래킹되지 않는 파일도 포함할까요?",
79
- initialValue: true,
80
- }),
81
- }),
82
- migrateIdentifiers: () =>
83
- prompt.select({
84
- message: "어디까지 변경할까요?",
85
- options: [
86
- {
87
- label: "모두 변경",
88
- value: "all",
89
- hint: `\n(old) import { IconHeart } from "old-package"; <IconHeart />;\n→ (new) import { NewIconHeart } from "new-package"; <NewIconHeart />;\n`,
90
- },
91
- {
92
- label: "import만 변경",
93
- value: "importOnly",
94
- hint: `\n(old) import { IconHeart } from "old-package"; <IconHeart />;\n→ (new) import { NewIconHeart as IconHeart } from "new-package"; <IconHeart />;\n`,
95
- },
96
- ],
97
- initialValue: "all",
98
- }),
99
- });
100
-
101
- const filesFound = (() => {
102
- switch (group.target) {
103
- case "tsconfig":
104
- return getAllTypeScriptCompiledFileNames({
105
- dirToFindTsconfig: process.cwd(),
106
- excludeDTs: true,
107
- });
108
- case "cwd":
109
- return getAllFileNamesWithMatchingExtension({
110
- dir: process.cwd(),
111
- extensionsToFind: EXTENSIONS_TO_FIND,
112
- extensionsToExclude: EXTENSIONS_TO_EXCLUDE,
113
- });
114
- case "path":
115
- return getAllFileNamesWithMatchingExtension({
116
- dir: options.path,
117
- extensionsToFind: EXTENSIONS_TO_FIND,
118
- extensionsToExclude: EXTENSIONS_TO_EXCLUDE,
119
- });
120
- }
121
- })();
122
-
123
- const { start, message, stop } = prompt.spinner();
124
-
125
- start("몇 개의 파일을 확인할지 결정하고 있어요.");
126
-
127
- const filesTracked = options.includeIgnored
128
- ? filesFound
129
- : await filterGitIgnoredFiles({ git: simpleGit(), filePaths: filesFound });
130
-
131
- stop(`${filesTracked.length}개 파일에서 예전 아이콘을 찾아볼게요.`);
132
-
133
- start(`${filesTracked.length}개 파일에서 예전 아이콘을 찾아볼게요.`);
134
- const j = jscodeshift.withParser("tsx");
135
-
136
- for (let i = 0; i < filesTracked.length; i++) {
137
- const filePath = filesTracked[i];
138
- const percent = (((i + 1) / filesTracked.length) * 100).toFixed(1);
139
-
140
- message(`파일 ${i + 1}/${filesTracked.length} 변경 시작 (${percent}%): ${filePath}`);
141
-
142
- migrateFile({ filePath, jscodeshift: j, importTransformers: importTransformersReact });
143
- }
144
-
145
- stop("코드 변경이 끝났어요.");
146
- });
147
- };
@@ -1,11 +0,0 @@
1
- // @ts-nocheck
2
-
3
- export function IconDiv() {
4
- console.log(IconHeart);
5
-
6
- return (
7
- <div>
8
- <IconHeart />
9
- </div>
10
- );
11
- }
@@ -1,11 +0,0 @@
1
- // @ts-nocheck
2
-
3
- export function IconDiv() {
4
- console.log(IconLike);
5
-
6
- return (
7
- <div>
8
- <IconLike />
9
- </div>
10
- );
11
- }
@@ -1,3 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconHeart as IconLike } from "some-new-package";
@@ -1,3 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconLike } from "some-package";
@@ -1,6 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconHeart as IconLike } from "some-new-package";
4
- import { IconStar as IconFavorite } from "some-new-package";
5
- import IconNight from "some-new-package/IconMoon";
6
- import * as IconHot from "some-new-package/IconFlame";
@@ -1,6 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconLike } from "some-package";
4
- import { IconFavorite } from "some-package";
5
- import IconNight from "some-package/IconNight";
6
- import * as IconHot from "some-package/IconHot";
@@ -1,19 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconHeart } from "some-new-package";
4
- import { IconStar } from "some-new-package";
5
- import IconMoon from "some-new-package/IconMoon";
6
- import * as IconFlame from "some-new-package/IconFlame";
7
-
8
- export function IconDiv() {
9
- console.log(IconHeart);
10
-
11
- return (
12
- <div>
13
- <IconHeart />
14
- <IconStar />
15
- <IconMoon />
16
- <IconFlame />
17
- </div>
18
- );
19
- }
@@ -1,19 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconLike } from "some-package";
4
- import { IconFavorite } from "some-package";
5
- import IconNight from "some-package/IconNight";
6
- import * as IconHot from "some-package/IconHot";
7
-
8
- export function IconDiv() {
9
- console.log(IconLike);
10
-
11
- return (
12
- <div>
13
- <IconLike />
14
- <IconFavorite />
15
- <IconNight />
16
- <IconHot />
17
- </div>
18
- );
19
- }
@@ -1,13 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconHeart } from "some-new-package";
4
-
5
- export function IconDiv() {
6
- console.log(IconHeart);
7
-
8
- return (
9
- <div>
10
- <IconHeart />
11
- </div>
12
- );
13
- }
@@ -1,13 +0,0 @@
1
- // @ts-nocheck
2
-
3
- import { IconLike } from "some-package";
4
-
5
- export function IconDiv() {
6
- console.log(IconLike);
7
-
8
- return (
9
- <div>
10
- <IconLike />
11
- </div>
12
- );
13
- }
@@ -1,90 +0,0 @@
1
- import {
2
- getFirstNode,
3
- migrateIdentifiers,
4
- migrateImportDeclarations,
5
- type ImportTransformers,
6
- } from "../../utils/migrate";
7
- import jscodeshift from "jscodeshift";
8
- import { describe, expect, test } from "vitest";
9
- import { Biome, Distribution } from "@biomejs/js-api";
10
- import fs from "fs";
11
- import path from "path";
12
-
13
- const biome = await Biome.create({ distribution: Distribution.NODE });
14
- biome.applyConfiguration({ formatter: { indentStyle: "space", lineWidth: 100 } });
15
-
16
- describe("shiftingIcons", () => {
17
- const j = jscodeshift.withParser("tsx");
18
-
19
- const importTransformers: ImportTransformers = {
20
- source: [{ startsWith: "some-package", replaceWith: "some-new-package" }],
21
- identifier: {
22
- IconLike: "IconHeart",
23
- IconFavorite: "IconStar",
24
- IconHot: "IconFlame",
25
- IconNight: "IconMoon",
26
- },
27
- };
28
-
29
- const cases: Record<string, ("migrateImportDeclarations" | "migrateIdentifiers")[]> = {
30
- migrateImportDeclarations: ["migrateImportDeclarations"],
31
- migrateImportDeclarationsVariousTypes: ["migrateImportDeclarations"],
32
- migrateIdentifiers: ["migrateIdentifiers"],
33
- migrateImportDeclarationsWithMigrateIdentifiers: [
34
- "migrateImportDeclarations",
35
- "migrateIdentifiers",
36
- ],
37
- migrateImportDeclarationsVariousTypesWithMigrateIdentifiers: [
38
- "migrateImportDeclarations",
39
- "migrateIdentifiers",
40
- ],
41
- };
42
-
43
- // migrateImportDeclarations
44
- for (const name in cases) {
45
- test(name, () => {
46
- const input = fs.readFileSync(path.resolve(__dirname, `./cases/${name}/input.tsx`), "utf-8");
47
- const expected = fs.readFileSync(
48
- path.resolve(__dirname, `./cases/${name}/expected.tsx`),
49
- "utf-8",
50
- );
51
-
52
- const tree = j(input);
53
- const firstNode = getFirstNode({ tree, jscodeshift: j });
54
-
55
- if (cases[name].includes("migrateImportDeclarations")) {
56
- const importDeclarations = tree.find(j.ImportDeclaration, {
57
- source: {
58
- value: (value: unknown) => {
59
- if (typeof value !== "string") return false;
60
-
61
- return importTransformers.source.some(({ startsWith }) =>
62
- value.startsWith(startsWith),
63
- );
64
- },
65
- },
66
- });
67
- migrateImportDeclarations({ importDeclarations, importTransformers });
68
- }
69
-
70
- if (cases[name].includes("migrateIdentifiers")) {
71
- const identifiers = tree.find(j.Identifier, {
72
- name: (value) => Object.keys(importTransformers.identifier).includes(value),
73
- });
74
- migrateIdentifiers({ identifiers, identifierTransformers: importTransformers.identifier });
75
- }
76
-
77
- const firstNodeAfterModification = getFirstNode({ tree, jscodeshift: j });
78
-
79
- if (firstNode !== firstNodeAfterModification) {
80
- firstNodeAfterModification.comments = firstNode.comments;
81
- }
82
-
83
- const { content } = biome.formatContent(tree.toSource(), {
84
- filePath: `${name}.tsx`,
85
- });
86
-
87
- expect(content).toBe(expected);
88
- });
89
- }
90
- });
@@ -1,63 +0,0 @@
1
- import ts from "typescript";
2
- import fs from "fs";
3
- import path from "path";
4
- import type { SimpleGit } from "simple-git";
5
-
6
- export function getAllFileNamesWithMatchingExtension({
7
- dir,
8
- extensionsToFind,
9
- extensionsToExclude,
10
- }: {
11
- dir: string;
12
- extensionsToFind: string[];
13
- extensionsToExclude?: string[];
14
- }) {
15
- // XXX: requires Node.js 20+
16
- return fs
17
- .readdirSync(dir, { withFileTypes: true, recursive: true })
18
- .filter(
19
- (item) =>
20
- item.isFile() &&
21
- extensionsToFind.some((ext) => item.name.endsWith(ext)) &&
22
- (extensionsToExclude ? !extensionsToExclude.some((ext) => item.name.endsWith(ext)) : true),
23
- )
24
- .map((item) => `${item.parentPath}/${item.name}`);
25
- }
26
-
27
- export function getAllTypeScriptCompiledFileNames({
28
- dirToFindTsconfig,
29
- excludeDTs,
30
- }: {
31
- dirToFindTsconfig: string;
32
- excludeDTs?: boolean;
33
- }) {
34
- const tsconfigPath = ts.findConfigFile(dirToFindTsconfig, ts.sys.fileExists);
35
- const tsconfigFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
36
-
37
- // FIXME: throw할 수 있을 것 같음
38
- const { fileNames } = ts.parseJsonConfigFileContent(
39
- tsconfigFile.config,
40
- ts.sys,
41
- path.dirname(tsconfigPath),
42
- );
43
-
44
- return fileNames.filter((fileName) => (excludeDTs ? !fileName.endsWith(".d.ts") : true));
45
- }
46
-
47
- export async function filterGitIgnoredFiles({
48
- git,
49
- filePaths,
50
- }: {
51
- git: SimpleGit;
52
- filePaths: string[];
53
- }) {
54
- const promises = await Promise.all(filePaths.map((file) => isFileGitTracked(git, file)));
55
-
56
- return filePaths.filter((_, index) => promises[index]);
57
- }
58
-
59
- async function isFileGitTracked(git: SimpleGit, filePath: string) {
60
- const result = await git.checkIgnore(filePath);
61
-
62
- return result.length <= 0;
63
- }
@@ -1,156 +0,0 @@
1
- import jscodeshift from "jscodeshift";
2
- import fs from "fs";
3
-
4
- export interface ImportTransformers {
5
- source: { startsWith: string; replaceWith?: string }[];
6
- identifier: Record<string, string>;
7
- }
8
-
9
- interface MigrateFileParams {
10
- filePath: string;
11
- jscodeshift: jscodeshift.JSCodeshift;
12
- importTransformers: ImportTransformers;
13
- }
14
-
15
- export function migrateFile({ filePath, jscodeshift, importTransformers }: MigrateFileParams) {
16
- const file = fs.readFileSync(filePath, "utf-8");
17
-
18
- const tree = jscodeshift(file);
19
- const firstNode = getFirstNode({ tree, jscodeshift: jscodeshift });
20
-
21
- migrateImportDeclarations({
22
- importDeclarations: tree.find(jscodeshift.ImportDeclaration, {
23
- source: {
24
- value: (value: unknown) => {
25
- if (typeof value !== "string") return false;
26
-
27
- return importTransformers.source.some(({ startsWith }) => value.startsWith(startsWith));
28
- },
29
- },
30
- }),
31
- importTransformers,
32
- });
33
-
34
- migrateIdentifiers({
35
- identifiers: tree.find(jscodeshift.Identifier, {
36
- name: (value) => Object.keys(importTransformers.identifier).includes(value),
37
- }),
38
- identifierTransformers: importTransformers.identifier,
39
- });
40
-
41
- const firstNodeAfterModification = getFirstNode({ tree, jscodeshift: jscodeshift });
42
-
43
- if (firstNode !== firstNodeAfterModification) {
44
- firstNodeAfterModification.comments = firstNode.comments;
45
- }
46
-
47
- fs.writeFileSync(filePath, tree.toSource());
48
- }
49
-
50
- export function getFirstNode({
51
- tree,
52
- jscodeshift,
53
- }: { tree: jscodeshift.Collection; jscodeshift: jscodeshift.JSCodeshift }) {
54
- return tree.find(jscodeshift.Program).get("body", 0).node;
55
- }
56
-
57
- interface MigrateImportDeclarationsParams {
58
- importDeclarations: jscodeshift.Collection<jscodeshift.ImportDeclaration>;
59
- importTransformers: ImportTransformers;
60
- }
61
-
62
- export function migrateImportDeclarations({
63
- importDeclarations,
64
- importTransformers,
65
- }: MigrateImportDeclarationsParams) {
66
- importDeclarations.replaceWith((imp) => {
67
- const currentSourceValue = imp.node.source.value;
68
- const currentSpecifiers = imp.node.specifiers;
69
- const currentImportKind = imp.node.importKind;
70
-
71
- const newSourceValue = (() => {
72
- if (typeof currentSourceValue !== "string") return currentSourceValue;
73
-
74
- const { startsWith, replaceWith } = importTransformers.source.find(({ startsWith }) =>
75
- currentSourceValue.startsWith(startsWith),
76
- );
77
-
78
- const sourceReplaced = replaceWith
79
- ? currentSourceValue.replace(startsWith, replaceWith)
80
- : currentSourceValue;
81
-
82
- const slashSplits = sourceReplaced.split("/");
83
-
84
- const itemReplaced = slashSplits
85
- .map((split, index) => {
86
- if (index !== slashSplits.length - 1 || split in importTransformers.identifier === false)
87
- return split;
88
-
89
- return importTransformers.identifier[split];
90
- })
91
- .join("/");
92
-
93
- return itemReplaced;
94
- })();
95
-
96
- const newSpecifiers = currentSpecifiers.map((currentSpecifier) => {
97
- switch (currentSpecifier.type) {
98
- case "ImportSpecifier": {
99
- // import { IconHeart } from "some-package";
100
- const currentImportedName = currentSpecifier.imported.name;
101
-
102
- if (currentImportedName in importTransformers.identifier === false)
103
- return currentSpecifier;
104
-
105
- const newImportedName = importTransformers.identifier[currentImportedName];
106
-
107
- const hasNoChange = newImportedName === currentImportedName;
108
-
109
- if (hasNoChange) return currentSpecifier;
110
-
111
- // TODO
112
- // impactedSpecifierCount++;
113
- const newImportedIdentifier = jscodeshift.identifier(newImportedName);
114
-
115
- // import { IconHeart as Heart } from "some-package"; 에서
116
- // imported: "IconHeart", local: "Heart"
117
- return jscodeshift.importSpecifier(newImportedIdentifier, currentSpecifier.local);
118
- }
119
- case "ImportDefaultSpecifier": {
120
- // import Icon from "some-package";
121
- return currentSpecifier;
122
- }
123
- case "ImportNamespaceSpecifier": {
124
- // import * as Icon from "some-package";
125
- return currentSpecifier;
126
- }
127
- }
128
- });
129
-
130
- const newImportDeclaration = jscodeshift.importDeclaration(
131
- newSpecifiers,
132
- jscodeshift.literal(newSourceValue),
133
- currentImportKind,
134
- );
135
-
136
- return newImportDeclaration;
137
- });
138
- }
139
-
140
- interface MigrateIdentifiersParams {
141
- identifiers: jscodeshift.Collection<jscodeshift.Identifier>;
142
- identifierTransformers: ImportTransformers["identifier"];
143
- }
144
-
145
- export function migrateIdentifiers({
146
- identifiers,
147
- identifierTransformers,
148
- }: MigrateIdentifiersParams) {
149
- identifiers.replaceWith((identifier) => {
150
- const currentName = identifier.node.name;
151
-
152
- if (currentName in identifierTransformers === false) return identifier;
153
-
154
- return jscodeshift.identifier(identifierTransformers[currentName]);
155
- });
156
- }