create-pylon
Version:
CLI for creating a Pylon
17 lines (13 loc) • 7.61 kB
JavaScript
import{Option as k,program as J}from"commander";import u from"consola";import{input as E,select as W,confirm as N}from"@inquirer/prompts";import c from"path";import m from"chalk";import*as r from"fs";import*as L from"@getcronit/pylon-telemetry";import{fileURLToPath as ne}from"url";import{dirname as re}from"path";import{spawnSync as ce}from"child_process";import*as y from"node:fs";import*as h from"node:path";import M from"node:process";import{execSync as X}from"node:child_process";import I from"consola";function x(e){try{return X(`${e} --version`,{stdio:"ignore"}),!0}catch(a){return console.error(a),!1}}function z(){return typeof Bun<"u"&&x("bun")}function G(){return M.env.npm_execpath?.includes("npm")??!1}function Q(){return M.env.npm_execpath?.includes("yarn")??!1}function Z(){return typeof Deno<"u"&&x("deno")}function ee(){return M.env.npm_execpath?.includes("pnpm")??!1}function te(e){return y.existsSync(h.join(e,"bun.lockb"))?"bun":y.existsSync(h.join(e,"package-lock.json"))?"npm":y.existsSync(h.join(e,"yarn.lock"))?"yarn":y.existsSync(h.join(e,"deno.json"))||y.existsSync(h.join(e,"deno.lock"))?"deno":y.existsSync(h.join(e,"pnpm-lock.yaml"))?"pnpm":null}function R({preferredPm:e,cwd:a=M.cwd()}){if(e&&x(e))return e;if(z())return"bun";if(G())return"npm";if(ee())return"pnpm";if(Z())return"deno";if(Q())return"yarn";let n=te(a);if(n){if(I.info(`Detected package manager by lock file: ${n}`),x(n))return n;I.warn(`Lock file detected, but ${n} is not installed.`)}return"unknown"}function T(e){switch(e){case"bun":return"bun";case"npm":return"npm run";case"yarn":return"yarn";case"pnpm":return"pnpm run";case"deno":return"deno task";default:return"npm run"}}var ae=ne(import.meta.url),A=re(ae),q=JSON.parse(r.readFileSync(c.join(A,"..","package.json"),"utf-8")).version;function ie(e){try{r.mkdirSync(e,{recursive:!0})}catch(a){if(a instanceof Error&&"code"in a&&a.code==="EEXIST")return;throw a}}var D=[{key:"bun",name:"Bun.js",website:"https://bunjs.dev",templates:["default"]},{key:"node",name:"Node.js",website:"https://nodejs.org",templates:["default"]},{key:"cf-workers",name:"Cloudflare Workers",website:"https://workers.cloudflare.com",templates:["default"]},{key:"deno",name:"Deno",website:"https://deno.land",templates:["default"]}],U=[{key:"default",name:"Default",description:"Default template"},{key:"database",name:"Database (Prisma)",description:"Template with Prisma ORM"}],se=(e,a)=>{let n=e;return Object.entries(a).forEach(([i,f])=>{n=n.replaceAll(i,f)}),n},B=e=>{let a=n=>{let i=[];return r.readdirSync(n).forEach(b=>{let l=c.join(n,b);r.statSync(l).isDirectory()&&i.push(...a(l)),r.statSync(l).isFile()&&i.push(l)}),i};return a(e).map(n=>n.replace(e,"."))},oe=async e=>{let{runtime:a,template:n,target:i}=e,f=D.find(({key:t})=>t===a)?.name,b=U.find(({key:t})=>t===n)?.name;if(!f)throw new Error(`Invalid runtime: ${a}`);if(!b)throw new Error(`Invalid template: ${n}`);let l=c.join(A,"..","templates","shared");if(!r.existsSync(l))throw new Error(`Shared templates not found: ${l}`);let w=c.join(A,"..","templates",a,n);if(!r.existsSync(w))throw new Error(`Template not found: ${w}`);let P=c.join(process.cwd(),i);u.start(`Creating pylon in ${P}`);let v=t=>se(t,{__PYLON_NAME__:e.name});B(l).forEach(t=>{let d=c.join(l,t),s=c.join(P,t),p=c.dirname(s);if(a==="cf-workers"&&d.includes(".github/workflows/publish.yaml"))return;r.existsSync(p)||r.mkdirSync(p,{recursive:!0}),s.endsWith(".example")&&(s=s.replace(".example",""));let g=v(r.readFileSync(d,"utf-8"));r.writeFileSync(s,g)}),B(w).forEach(t=>{let d=c.join(w,t),s=c.join(P,t),p=c.dirname(s);r.existsSync(p)||r.mkdirSync(p,{recursive:!0}),s.endsWith(".example")&&(s=s.replace(".example",""));let g=v(r.readFileSync(d,"utf-8"));r.writeFileSync(s,g)}),u.success("Pylon created")},le=async e=>{let a=c.resolve(e.target),n=e.packageManager,i="";switch(n){case"yarn":i="yarn";break;case"npm":i="npm install";break;case"pnpm":i="pnpm install";break;case"bun":i="bun install";break;case"deno":i="deno install";break;default:throw new Error(`Invalid package manager: ${n}`)}if(u.start(`Installing dependencies using ${n}`),ce(i,{cwd:a,shell:!0,stdio:"inherit"}).status!==0)throw new Error("Failed to install dependencies");u.success("Dependencies installed")};J.name("create-pylon").version(q).arguments("[target]").addOption(new k("-i, --install","Install dependencies")).addOption(new k("-r, --runtime <runtime>","Runtime").choices(D.map(({key:e})=>e))).addOption(new k("-t, --template <template>","Template")).addOption(new k("-pm, --package-manager <packageManager>","Package manager")).addOption(new k("--client","Enable client generation (https://pylon.cronit.io/docs/integrations/gqty)")).addOption(new k("--client-path <clientPath>","Client path")).addOption(new k("--client-port <clientPort>","Client port")).action(me);var pe=e=>{if(e==="bun")return"bun";if(e==="deno")return"deno"};async function me(e,a,n){try{u.log(`${n.name()} version ${n.version()}`);let{install:i,runtime:f,template:b,packageManager:l,client:w,clientPath:P,clientPort:v}=a,t="";e?(t=e,u.success(`Using target directory \u2026 ${t}`)):t=await E({message:"Target directory",default:"my-pylon"});let d="";t==="."?d=c.basename(process.cwd()):d=c.basename(t);let s=f||await W({message:"Which runtime would you like to use?",choices:D.map(o=>({name:`${o.name} (${o.website})`,value:o.key})),default:0});if(!s)throw new Error("No runtime selected");let p=D.find(({key:o})=>o===s);if(!p)throw new Error(`Invalid runtime selected: ${s}`);let g=b||await W({message:"Which template would you like to use?",choices:U.filter(o=>p.templates?.includes(o.key)).map(o=>({name:o.name,value:o.key})),default:0});if(!g)throw new Error("No template selected");r.existsSync(t)?r.readdirSync(t).length>0&&(await N({message:"Directory not empty. Continue?",default:!1})||process.exit(1)):ie(t);let V=i||await N({message:"Would you like to install dependencies?"});await oe({name:d,runtime:s,template:g,target:t});let F=R({preferredPm:pe(p.key),cwd:t});V&&await le({target:t,packageManager:F});let Y=w||await N({message:"Would you like to enable client generation? (https://pylon.cronit.io/docs/integrations/gqty)",default:!1}),j="",C="",O="";if(Y){P||(j=await E({message:"Path to the root where the client should be generated",default:"."}),C=await E({message:"Path to generate the client to",default:c.join(j,"gqty/index.ts"),validate:K=>K.startsWith(j==="."?"":j)?!0:"Path must start with the client root"})),O=v||await E({message:"Port of the pylon server to generate the client from",default:"3000"}),u.start("Updating pylon dev script to generate client");let o,S;p.key==="deno"?(o=c.join(t,"deno.json"),S="tasks"):(o=c.join(t,"package.json"),S="scripts");let $=JSON.parse(r.readFileSync(o,"utf-8"));$[S]={...$[S],dev:$[S].dev+` --client --client-port ${O} --client-path ${C}`},r.writeFileSync(o,JSON.stringify($,null,2)),u.success("Pylon dev script updated")}let _=T(F),H=`
\u{1F389} ${m.green.bold("Pylon created successfully.")}
\u{1F4BB} ${m.cyan.bold("Continue Developing")}
${m.yellow("Change directories:")} cd ${m.blue(t)}
${m.yellow("Start dev server:")} ${_} dev
${m.yellow("Deploy:")} ${_} deploy
\u{1F4D6} ${m.cyan.bold("Explore Documentation")}
${m.underline.blue("https://pylon.cronit.io/docs")}
\u{1F4AC} ${m.cyan.bold("Join our Community")}
${m.underline.blue("https://discord.gg/cbJjkVrnHe")}
`;await L.sendCreateEvent({name:d,pylonCreateVersion:q,runtime:s,template:g,clientPath:C||void 0,clientPort:parseInt(O)||void 0}),u.box(H)}catch(i){u.error(i)}}J.parse();
//# sourceMappingURL=index.js.map