UNPKG

create-abi

Version:

Interactive CLI for create Abi.js projects.

7 lines (6 loc) 19.2 kB
"use strict";var Tt=Object.create;var I=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var jt=Object.getOwnPropertyNames;var It=Object.getPrototypeOf,Dt=Object.prototype.hasOwnProperty;var Rt=(n,t)=>{for(var e in t)I(n,e,{get:t[e],enumerable:!0})},Q=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of jt(t))!Dt.call(n,i)&&i!==e&&I(n,i,{get:()=>t[i],enumerable:!(r=At(t,i))||r.enumerable});return n};var m=(n,t,e)=>(e=n!=null?Tt(It(n)):{},Q(t||!n||!n.__esModule?I(e,"default",{value:n,enumerable:!0}):e,n)),Ot=n=>Q(I({},"__esModule",{value:!0}),n);var oe={};Rt(oe,{app:()=>H,default:()=>se,run:()=>vt});module.exports=Ot(oe);var P=m(require("fs"),1),T=m(require("path"),1),k=require("fs-extra/esm"),$=require("panam/executor"),x=m(require("panam/pm"),1);var N={name:"create-abi",type:"module",license:"MIT",version:"0.0.0",description:"Interactive CLI for create Abi.js projects.",scripts:{check:"tsc --noEmit",build:"tsup-node --env.NODE_ENV production",prod:"pnpm check && pnpm build",start:"tsup-node --env.NODE_ENV development --watch",test:"pnm tsx bin/test.ts",tsx:"tsx"},contributors:[{name:"Sigui Kess\xE9 Emmanuel",email:"contact@sigui.ci",url:"https://twitter.com/siguici"}],repository:{type:"git",url:"https://github.com/abi-js/abi",directory:"packages/create-abi"},types:"./dist/index.d.ts",main:"./dist/index.js",module:"./dist/index.js",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs",default:"./dist/index.js"},"./app":{types:"./dist/app.d.ts",import:"./dist/app.js",require:"./dist/app.cjs",default:"./dist/app.js"},"./cli":{types:"./dist/cli.d.ts",import:"./dist/cli.js",require:"./dist/cli.cjs",default:"./dist/cli.js"},"./console":{types:"./dist/console.d.ts",import:"./dist/console.js",require:"./dist/console.cjs",default:"./dist/console.js"},"./core":{types:"./dist/core.d.ts",import:"./dist/core.js",require:"./dist/core.cjs",default:"./dist/core.js"},"./tester":{types:"./dist/tester.d.ts",import:"./dist/tester.js",require:"./dist/tester.cjs",default:"./dist/tester.js"},"./utils":{types:"./dist/utils.d.ts",import:"./dist/utils.js",require:"./dist/utils.cjs",default:"./dist/utils.js"},"./package.json":"./package.json"},files:["dist","starters"],bin:"./dist/cli.js",keywords:["abi","abi-js","abi.js","cli","console","create-abi","generator","skeleton","starter-kit","template"],publishConfig:{access:"public"},bugs:"https://github.com/@abi-js/abi/issues",dependencies:{"@clack/prompts":"^0.11.0","cross-spawn":"^7.0.6","fs-extra":"^11.3.0",kleur:"^4.1.5",panam:"^0.3.0",tsx:"^4.20.3",which:"^5.0.0","which-pm-runs":"^1.1.0",yargs:"^18.0.0"},devDependencies:{"@japa/assert":"^4.0.1","@japa/runner":"^4.2.0","@types/cross-spawn":"^6.0.6","@types/fs-extra":"^11.0.4","@types/node":"^24.0.10","@types/which":"^3.0.4","@types/which-pm-runs":"^1.0.2","@types/yargs":"^17.0.33",rimraf:"^6.0.1",tsup:"^8.5.0",typescript:"^5.8.3"}};var g=require("@clack/prompts"),s=require("kleur/colors"),u=require("@clack/prompts");function Pt(){return process.platform!=="win32"?process.env.TERM!=="linux":!!process.env.CI||!!process.env.WT_SESSION||!!process.env.TERMINUS_SUBLIME||process.env.ConEmuTask==="{cmd::Cmder}"||process.env.TERM_PROGRAM==="Terminus-Sublime"||process.env.TERM_PROGRAM==="vscode"||process.env.TERM==="xterm-256color"||process.env.TERM==="alacritty"||process.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var h=Pt(),R={success:h?"\u2705":"[OK]",error:h?"\u274C":"[ERROR]",info:h?"\u2139\uFE0F":"[INFO]",warning:h?"\u26A0\uFE0F":"[WARN]",debug:h?"\u{1F41E}":"[DEBUG]",verbose:h?"\u{1F50D}":"[DETAILS]",line:h?"\u2500\u2500":"----"},p={red:s.red,green:s.green,blue:s.blue,yellow:s.yellow,magenta:s.magenta,cyan:s.cyan,gray:s.gray,grey:s.grey,white:s.white,black:s.black},d={red:s.bgRed,green:s.bgGreen,blue:s.bgBlue,yellow:s.bgYellow,magenta:s.bgMagenta,cyan:s.bgCyan,white:s.bgWhite,black:s.bgBlack},f={reset:s.reset,bold:s.bold,dim:s.dim,italic:s.italic,underline:s.underline,inverse:s.inverse,hidden:s.hidden,strikethrough:s.strikethrough};function $t(n){return(0,s.green)(`${R.success} ${n}`)}function et(n){return(0,s.red)(`${R.error} ${n}`)}function Nt(n){return(0,s.blue)(`${R.info} ${n}`)}function Bt(n){return(0,s.yellow)(`${R.warning} ${n}`)}function nt(n){g.log.info(Nt(n))}function rt(n){g.log.success($t(n))}function it(n){g.log.step(n)}function st(n){g.log.warn(Bt(n))}function ot(n){g.log.error(et(n))}function D(n){console.error(`${X()}${et(n)}${X()}`),process.exit(1)}function X(n=1){return` `.repeat(n)}async function B(n,t,e){let r=e&&await(0,g.text)({message:n,placeholder:t,defaultValue:t})||t;return r!==t&&b(r),r}async function M(n,t,e,r){let i=r&&await(0,g.select)({message:n,options:t,initialValue:e})||e;return i!==e&&b(i),i}async function W(n,t,e,r,i){let o=i===!0&&!t?!1:r===!0&&t===void 0?!0:e?await(0,g.confirm)({message:n,initialValue:t}):t;return o!==t&&U(o),o}function b(n,t){at(n,t?e=>tt(e)&&t(e):tt,"string")}function U(n){at(n,Wt,"boolean")}function at(n,t,e){Mt(n,t,e,typeof n)}function Mt(n,t,e,r){Ut(n)&&D("Operation canceled."),t(n)||D(`Invalid input${e?`: ${e} expected`:""}${r?`, ${r} provided`:""}.`)}function tt(n){return typeof n=="string"||n instanceof String}function Wt(n){return typeof n=="boolean"}function Ut(n){return(0,g.isCancel)(n)||typeof n=="symbol"}var bt=m(require("yargs"),1),xt=require("yargs/helpers");var l=m(require("fs"),1),V=m(require("os"),1),c=m(require("path"),1),J=require("url"),w=require("fs-extra/esm"),ct=m(require("panam/pm"),1),ne={},Jt=Kt(),S=c.default.dirname(Jt);function G(n,t){(0,l.statSync)(n).isDirectory()?Vt(n,t):Gt(n,t)}function Vt(n,t){let e=(0,l.readdirSync)(n);(0,w.ensureDirSync)(t);for(let r of e)G((0,c.join)(n,r),(0,c.join)(t,r))}function Gt(n,t){let e=(0,c.basename)(n);(0,w.pathExistsSync)(t)?e.endsWith(".json")?zt(t,n,!0):e.startsWith(".")&&e.endsWith("ignore")&&qt(t,n,!0):(0,w.copySync)(n,t)}function zt(n,t,e=!1){let r=_t(v(n),v(t));return e&&yt(n,r),r}function _t(n,t){return gt(JSON.parse(n),JSON.parse(t))}function gt(n,t){for(let e of Object.keys(t)){let r=n[e],i=t[e];ut(r)&&ut(i)?n[e]=gt(r,i):Array.isArray(r)&&Array.isArray(i)?n[e]=Array.from(new Set([...r,...i])):n[e]=i}return n}function ut(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function qt(n,t,e=!1){let r=Lt(v(n),v(t));return e&&L(n,r),r}function Lt(n,t){return Yt(n.split(` `),t.split(` `)).join(` `)}function Yt(n,t){let e=Array.from(new Set([...n.map(r=>r.trim()),...t.map(r=>r.trim())])).filter(r=>r!=="");return Ft(e)}function Ft(n){let t=[],e=!1;return n.forEach((r,i)=>{let o=r.startsWith("#");o&&!e&&i!==0&&t.push(""),t.push(r),e=o}),t}function Kt(){let e=new Error().stack?.match(/^Error\s+at[^\r\n]+\s+at *(?:[^\r\n(]+\((.+?)(?::\d+:\d+)?\)|(.+?)(?::\d+:\d+)?) *([\r\n]|$)/),r=e?.[1]||e?.[2];return r?.startsWith("file://")?(0,J.fileURLToPath)(r):r||(0,J.fileURLToPath)(ne.url)}function lt(){return!!(process.env.CI||process.env.GITHUB_ACTIONS)}function pt(){return!1}function dt(n){return n.startsWith(process.env.HOME??"~/")}function z(n){return dt(n)?(0,c.resolve)(V.default.homedir(),n):(0,c.resolve)(process.cwd(),n)}function _(n){return dt(n)?(0,c.relative)(V.default.homedir(),n):(0,c.relative)(process.cwd(),n)}function q(n){return l.default.existsSync(n)&&l.default.readdirSync(n).length>0}var ft=async n=>{let t=await l.default.promises.readdir(n);return await Promise.all(t.map(e=>l.default.promises.rm((0,c.join)(n,e),{recursive:!0})))};function v(n){if(!l.default.existsSync(n))throw new Error(`File ${n} not found`);return l.default.readFileSync(n,{encoding:"utf8"}).toString()}function L(n,t){return l.default.writeFileSync(n,t,{encoding:"utf8"})}function Ht(n,t,e){let r=v(n);r=r.replace(t,e),L(n,r)}function C(n,t=S){return(0,c.join)(t,`${n}.json`)}function Zt(n,t,e,r){Ht(C(n,t),e,r)}function mt(n,t){Zt(n,t,/npm run/g,ct.default.runCommand())}var Qt=/^(?:(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*)$/;function O(n){return n=n.trim().replace(/\\/g,"/").split("/").filter(Boolean).map(t=>t.toLowerCase().replace(/[^a-z0-9-_]/g,"-").replace(/^-+|-+$/g,"")).join("-"),n=n.normalize("NFD").replace(/[\u0300-\u036f]/g,""),n=n.replace(/[^a-zA-Z0-9\-._~/@]/g,"-"),n=n.replace(/^[-.]+|[-.]+$/g,""),n=n.replace(/[-.]{2,}/g,"-"),n=n.toLowerCase(),n}function Xt(n){return Qt.test(n)}function te(n){if(n=O(n),!Xt(n))throw new Error(`Invalid package name: ${n}`);return n}function Y(n,t){let e=C(n,t);return JSON.parse(v(e))}function ee(n,t,e){yt(C(n,t),e)}function yt(n,t){L(n,JSON.stringify(t,null,2))}function ht(n,t="package",e=S){let r=te(n),i=Y(t,e);i.name=r,ee(t,e,i)}var F=class{constructor(t,e){this.signature=t;this.description=e}arguments=new Map;options=new Map;examples=new Set;#t="";setArgument(t,e){return this.arguments.set(t,e),this}getArgument(t){return this.arguments.get(t)}hasArgument(t){return this.arguments.has(t)}argument(t,e){return e?this.setArgument(t,e):this.getArgument(t)}setOption(t,e){return this.options.set(t,e),this}getOption(t){return this.options.get(t)}hasOption(t){return this.options.has(t)}option(t,e){return e?this.setOption(t,e):this.getOption(t)}addExample(t,e){return this.examples.add({command:t,description:e}),this}getExample(t){return this.examples.values().find(e=>e.command===t||e.description===t)}example(t,e){return e?this.addExample(t,e):this.getExample(t)}getExamples(){return this.examples.values().toArray()}setUsage(t){return this.#t=t,this}getUsage(){return this.#t}usage(t){return t?this.setUsage(t):this.getUsage()}},E=class{constructor(t,e){this.name=t;this.version=e;this.configure()}#t=!1;#r=!1;#e=!1;#n=!1;#i={};commands=new Set;aliases=new Set;interactions=new Map;configure(){}addCommand(t,e){let r=new F(t,e);return this.#e&&r.option("yes",{alias:"y",type:"boolean",desc:"Skip all prompts by accepting defaults"}),this.#n&&r.option("no",{alias:"n",type:"boolean",desc:"Skip all prompts by declining defaults"}),this.commands.add(r),r}getCommand(t){return this.commands.values().find(e=>e.signature===t||e.description===t)}command(t,e){return e?this.addCommand(t,e):this.getCommand(t)}getCommands(){return this.commands.values().toArray()}strict(t=!0){return this.#t=t,this}conflict(t,e){return this.#i[t]=e,this}interactive(t=!0){return this.#r=t,this}useYes(t=!0){return this.#e=t,this}useNo(t=!0){return this.#n=t,this}addAlias(t,e){return this.aliases.add({shortName:t,longName:e}),this}getAlias(t){return this.aliases.values().find(e=>e.shortName===t||e.longName===t)}alias(t,e){return e?this.addAlias(t,e):this.getAlias(t)}getAliases(){return this.aliases.values().toArray()}async run(t=process.argv){let e=(0,xt.hideBin)(t),r=this.parse(e),i;return this.isIt()?i=await this.interact(r):i=this.validate(r),await this.execute(i)}isIt(){return this.#r&&!(pt()||lt())}intercept(t,e){return this.setInteraction(t,e)}async interact(t){return this.validate(t)}parse(t){let e=(0,bt.default)(t);e.scriptName(this.name),this.#t&&e.strict(),this.#e&&this.#n&&e.conflicts("yes","no"),this.#s(e),e.version(this.version);for(let[i,o]of Object.entries(this.#i))e.conflicts(i,o);for(let{shortName:i,longName:o}of this.aliases)e.alias(i,o);return e.argv}#s(t){for(let e of this.commands)this.#o(t,e)}#o(t,e){t.command(e.signature,e.description,r=>{this.#a(t,e.arguments),this.#c(t,e.options),this.#l(t,e.examples),r.usage(e.usage())})}#a(t,e){for(let[r,i]of e)this.#u(t,r,i)}#u(t,e,r){t.positional(e,r)}#c(t,e){for(let[r,i]of e)this.#g(t,r,i)}#g(t,e,r){t.option(e,r)}#l(t,e){for(let r of e)this.#p(t,r.command,r.description)}#p(t,e,r){t.example(e,r)}getInteraction(t){for(let e of this.interactions.keys())if(t.includes(e)||RegExp(e).test(t))return this.interactions.get(e)}setInteraction(t,e){return this.interactions.set(t,e),this}async scanBoolean(t,e,r){let i=this.getInteraction(e);return i!==void 0?(U(i),i):r!==void 0?W(e,r,this.isIt(),this.#e&&t.yes,this.#n&&t.no):W(e,void 0,this.isIt(),this.#e&&t.yes,this.#n&&t.no)}async scanString(t,e){let r=this.getInteraction(t);return r!==void 0?(b(r),r):e?B(t,e,this.isIt()):B(t,void 0,this.isIt())}async scanChoice(t,e,r){let i=this.getInteraction(t);return i!==void 0?(b(i,o=>e.find(a=>a.value===o)!==void 0),i):r?M(t,e,r,this.isIt()):M(t,e,void 0,this.isIt())}panic(t){D(t)}cancel(t){(0,u.cancel)(t)}intro(t){(0,u.intro)(t)}outro(t){(0,u.outro)(t)}note(t,e){(0,u.note)(t,e)}spinner(){return(0,u.spinner)()}info(t){nt(t)}warn(t){st(t)}error(t){ot(t)}step(t){it(t)}success(t){rt(t)}red(t){return p.red(t)}green(t){return p.green(t)}blue(t){return p.blue(t)}yellow(t){return p.yellow(t)}magenta(t){return p.magenta(t)}cyan(t){return p.cyan(t)}gray(t){return p.gray(t)}grey(t){return p.grey(t)}white(t){return p.white(t)}black(t){return p.black(t)}bgRed(t){return d.red(t)}bgGreen(t){return d.green(t)}bgBlue(t){return d.blue(t)}bgYellow(t){return d.yellow(t)}bgMagenta(t){return d.magenta(t)}bgCyan(t){return d.cyan(t)}bgWhite(t){return d.white(t)}bgBlack(t){return d.black(t)}reset(t){return f.reset(t)}dim(t){return f.dim(t)}bold(t){return f.bold(t)}italic(t){return f.italic(t)}underline(t){return f.underline(t)}inverse(t){return f.inverse(t)}hidden(t){return f.hidden(t)}strikethrough(t){return f.strikethrough(t)}};var y={destination:"./abi-app",runtime:"node",force:void 0,install:void 0,git:void 0,yes:void 0,no:void 0,dryRun:void 0};function re(n){return{...y,...n}}var K=class extends E{configure(){this.strict().interactive().alias("h","help").useYes().useNo().command("* [destination] [runtime]","Create a new project powered by Abi.js").argument("destination",{type:"string",default:y.destination,desc:"Directory of the project"}).argument("runtime",{type:"string",default:y.runtime,desc:"JavaScript/TypeScript runtime to use",choices:["node","deno","bun"]}).option("force",{alias:"f",type:"boolean",default:y.force,desc:"Overwrite target directory if it exists"}).option("install",{alias:"i",type:"boolean",default:y.install,desc:"Install dependencies"}).option("git",{type:"boolean",default:y.git,desc:"Use Git to save changes"}).option("dryRun",{type:"boolean",desc:"Walk through steps without executing"}).example("npm create abi@latest","Create a project with default options").example("npm create abi@latest ./abi-app","Create a project in a specific directory").example("npm create abi@latest ./abi-app node","Create a project using a server runtime").example("npm create abi@latest ./abi-app node --it","Create a project in interactive command mode").usage("npm create abi [destination] [runtime] [...options]")}parse(t){return re(super.parse(t))}validate(t){return{destination:t.destination,runtime:t.runtime,force:t.force??(!!t.yes&&!t.no),install:t.install??(!!t.yes&&!t.no),git:t.git??(!!t.yes&&!t.no),dryRun:!!t.dryRun,outDir:z(t.destination),packageName:O(t.destination)}}async interact(t){let e=t.destination===y.destination?await this.scanString(`Where would you like to create your new project? ${this.gray("(Use './' for current directory)")}`,t.destination):t.destination,r=z(e.trim()),i=q(r),o=t.force===void 0?i&&!!await this.scanBoolean(t,`Directory "./${_(r)}" already exists and is not empty. Would you like to force the copy?`,!1):t.force,a;if(t.runtime===y.runtime){let Z=await this.scanBoolean(t,"Would you like to use another runtime instead of Node.js?",!1)&&await this.scanChoice("Which runtime do you prefer?",[{value:"node",label:"Node"},{value:"deno",label:"Deno"},{value:"bun",label:"Bun"}],t.runtime)||"node";b(Z,St=>["node","deno","bun"].includes(St)),a=Z}else a=t.runtime;let wt=!!(t.install===void 0?await this.scanBoolean(t,`Would you like to install ${x.default.name} dependencies?`):t.install),Ct=!!(t.git===void 0?await this.scanBoolean(t,!i||o?"Would you like to initialize Git?":"Would you like to save the changes with Git?"):t.git),kt=!!t.dryRun,A="";i&&o&&(P.default.existsSync(C("deno",r))?A="deno":P.default.existsSync(C("package",r))&&(A="package"));let j=A!==""?Y(A,r).name:O(e);return j=t.yes?j:await this.scanString("What should be the name of this package?",j),{destination:e,runtime:a,install:wt,git:Ct,force:o,outDir:r,packageName:j,dryRun:kt}}async execute(t){try{let e=await this.start(t);return this.updatePackageJson(t),await this.runGit(t),this.end(t,e),0}catch(e){return console.error("An error occurred during Abi.js project creation:",e),1}}async prepareDir(t){let e=t.outDir;q(e)&&(t.force?(t.dryRun||await ft(e),this.info(`Directory "${e}" successfully emptied \u{1F525}`)):(this.error(`Directory "${e}" already exists.`),this.info("Please either remove this directory, choose another location or run the command again with '--force | -f' flag."),this.cancel(),process.exit(1)))}async runCreate(t){await this.prepareDir(t),this.copyStarter(t)}async start(t){return this.intro(`Let's create a ${this.bgYellow(" Abi.js")} App \u2728`),await this.runCreate(t),this.runInstall(t)}end(t,e){let r=t.outDir,i=process.cwd()===r,o=_(r),a=[];i?a.push(`\u{1F984} ${this.bgMagenta(" Success! ")}`):a.push(`\u{1F984} ${this.bgMagenta(" Success! ")} ${this.cyan("Project created in")} ${this.bold(this.magenta(o))} ${this.cyan("directory")}`),a.push(""),a.push(`\u{1F430} ${this.cyan("Next steps:")}`),i||a.push(` cd ${o}`),e||a.push(` ${x.default.name} install`),a.push(` ${x.default.name} start`),this.note(a.join(` `),"Ready to start \u{1F680}"),this.outro("Happy coding! \u{1F4BB}\u{1F389}")}updatePackageJson(t){let{outDir:e,packageName:r}=t,i=t.runtime==="deno"?"deno":"package";ht(r,i,e),this.info(`Updated package name to "${r}" \u{1F4E6}\uFE0F`),x.default.isNpm()||(this.info(`Replacing 'npm run' by '${x.default.runCommand()}' in package.json...`),mt(i,e))}async runInstall(t){let e=!1;return t.install&&(this.step("Installing dependencies..."),t.dryRun||await x.default.install({cwd:t.outDir}),e=!0),e}async runGit(t){if(t.git){let e=this.spinner(),r=t.outDir,i=P.default.existsSync(T.default.join(r,".git"));if(i&&this.info("Git has already been initialized before."),e.start("Initializing Git..."),!t.dryRun){let o=[];try{if(i||o.push(await(0,$.$)("git",["init"],{cwd:r}).result),o.push(await(0,$.$)("git",["add","-A"],{cwd:r}).result),o.push(await(0,$.$)("git",["commit","-m","Initial commit \u{1F389}"],{cwd:r}).result),o.some(a=>a.status===!1))throw"";e.stop("Git initialized \u{1F3B2}")}catch{e.stop("Git failed to initialize"),i?this.error("Git failed to add new changes. You can do this manually by running: git add -A && git commit"):this.error("Git failed to initialize. You can do this manually by running: git init")}}}}copyShared(t){for(let e of["gitignore"]){let r=e;e==="gitignore"&&(r=".gitignore");let i=T.default.join(t.outDir,r),o=(0,k.pathExistsSync)(i);if(e.startsWith(".")&&e.endsWith("ignore")&&this.step(`${o?"Merging":"Copying"} \`${r}\` file... \u{1F648}`),!t.dryRun){let a=T.default.join(S,"..","starters",e);G(a,i)}}}copyStarter(t,e){if(this.step(`Creating new project in ${this.bgBlue(` ${t.outDir} `)} ... \u{1F407}`),!t.dryRun){let r=t.outDir;try{(0,k.ensureDirSync)(r),e||(e=T.default.join(S,"..","starters",t.runtime)),(0,k.copySync)(e,r),this.copyShared(t)}catch(i){this.error(this.red(`Template copy failed: ${i}`))}}}};function ie(n=N.name,t=N.version){return new K(n,t)}var H=ie();async function vt(n){return H.run(n)}async function se(){return vt(process.argv)}0&&(module.exports={app,run});