startx 1.0.4 → 1.0.5

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/_gitignore ADDED
@@ -0,0 +1,40 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # Dependencies
4
+ node_modules
5
+ .pnp
6
+ .pnp.js
7
+
8
+ # Local env files
9
+ .env
10
+ .env.local
11
+ .env.development.local
12
+ .env.test.local
13
+ .env.production.local
14
+
15
+ # Testing
16
+ coverage
17
+
18
+ # Turbo
19
+ .turbo
20
+
21
+ # Vercel
22
+ .vercel
23
+
24
+ # Build Outputs
25
+ .next/
26
+ out/
27
+ build
28
+ dist
29
+
30
+
31
+ # Debug
32
+ npm-debug.log*
33
+ yarn-debug.log*
34
+ yarn-error.log*
35
+ logs
36
+
37
+ # Misc
38
+ .DS_Store
39
+ *.pem
40
+ temp
@@ -215,4 +215,4 @@ $&`).replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g,`$1$2`).replace(/\
215
215
  `+t:``),o=Math.floor(n.length/i)-this.cursorPos.rows+(t?Sx(t):0);o>0&&(a+=_x(o)),a+=yx(this.cursorPos.cols),this.write(vx(this.extraLinesUnderPrompt)+xx(this.height)+a),this.extraLinesUnderPrompt=o,this.height=Sx(a)}checkCursorPos(){let e=this.rl.getCursorPos();e.cols!==this.cursorPos.cols&&(this.write(yx(e.cols)),this.cursorPos=e)}done({clearContent:e}){this.rl.setPrompt(``);let t=vx(this.extraLinesUnderPrompt);t+=e?xx(this.height):`
216
216
  `,t+=`\x1B[?25h`,this.write(t),this.rl.close()}},Tx=class extends Promise{static withResolver(){let e,t;return{promise:new Promise((n,r)=>{e=n,t=r}),resolve:e,reject:t}}},Ex=b(tx(),1);const Dx=globalThis.setImmediate;function Ox(){let e=Error.prepareStackTrace,t=[];try{Error.prepareStackTrace=(e,n)=>{let r=n.slice(1);return t=r,r},Error().stack}catch{return t}return Error.prepareStackTrace=e,t}function kx(e){let t=Ox();return(n,r={})=>{let{input:i=process.stdin,signal:a}=r,o=new Set,c=new Ex.default;c.pipe(r.output??process.stdout),c.mute();let l=u.createInterface({terminal:!0,input:i,output:c}),d=new wx(l),{promise:f,resolve:p,reject:m}=Tx.withResolver(),h=()=>m(new Jy);if(a){let e=()=>m(new qy({cause:a.reason}));if(a.aborted)return e(),Object.assign(f,{cancel:h});a.addEventListener(`abort`,e),o.add(()=>a.removeEventListener(`abort`,e))}o.add(px((e,t)=>{m(new Yy(`User force closed the prompt with ${e} ${t}`))}));let g=()=>m(new Yy(`User force closed the prompt with SIGINT`));return l.on(`SIGINT`,g),o.add(()=>l.removeListener(`SIGINT`,g)),eb(l,a=>{let u=s.bind(()=>ob.clearAll());l.on(`close`,u),o.add(()=>l.removeListener(`close`,u));let g=()=>{let r=()=>d.checkCursorPos();l.input.on(`keypress`,r),o.add(()=>l.input.removeListener(`keypress`,r)),a(()=>{try{let r=e(n,e=>{setImmediate(()=>p(e))});if(r===void 0){let e=t[1]?.getFileName();throw Error(`Prompt functions must return a string.\n at ${e}`)}let[i,a]=typeof r==`string`?[r]:r;d.render(i,a),ob.run()}catch(e){m(e)}})};return`readableFlowing`in i?Dx(g):g(),Object.assign(f.then(e=>(ob.clearAll(),e),e=>{throw ob.clearAll(),e}).finally(()=>{o.forEach(e=>e()),d.done({clearContent:!!r.clearPromptOnDone}),c.end()}).then(()=>f),{cancel:h})})}}var Ax=class{separator=l(`dim`,Array.from({length:15}).join(hb.line));type=`separator`;constructor(e){e&&(this.separator=e)}static isSeparator(e){return!!(e&&typeof e==`object`&&`type`in e&&e.type===`separator`)}};const jx={icon:{checked:l(`green`,hb.circleFilled),unchecked:hb.circle,cursor:hb.pointer,disabledChecked:l(`green`,hb.circleDouble),disabledUnchecked:`-`},style:{disabled:e=>l(`dim`,e),renderSelectedChoices:e=>e.map(e=>e.short).join(`, `),description:e=>l(`cyan`,e),keysHelpTip:e=>e.map(([e,t])=>`${l(`bold`,e)} ${l(`dim`,t)}`).join(l(`dim`,` • `))},i18n:{disabledError:`This option is disabled and cannot be toggled.`},keybindings:[]};function Mx(e){return!Ax.isSeparator(e)&&!e.disabled}function Nx(e){return!Ax.isSeparator(e)}function Px(e){return!Ax.isSeparator(e)&&e.checked}function Fx(e){return Mx(e)?{...e,checked:!e.checked}:e}function Ix(e){return function(t){return Mx(t)?{...t,checked:e}:t}}function Lx(e){return e.map(e=>{if(Ax.isSeparator(e))return e;if(typeof e==`string`)return{value:e,name:e,short:e,checkedName:e,disabled:!1,checked:!1};let t=e.name??String(e.value),n={value:e.value,name:t,short:e.short??t,checkedName:e.checkedName??t,disabled:e.disabled??!1,checked:e.checked??!1};return e.description&&(n.description=e.description),n})}var Rx=kx((e,t)=>{let{pageSize:n=7,loop:r=!0,required:i,validate:a=()=>!0}=e,o={all:`a`,invert:`i`,...e.shortcuts},s=yb(jx,e.theme),{keybindings:c}=s,[l,u]=sb(`idle`),d=bb({status:l,theme:s}),[f,p]=sb(Lx(e.choices)),m=xb(()=>{let e=f.findIndex(Nx),t=f.findLastIndex(Nx);if(e===-1)throw new Zy(`[checkbox prompt] No selectable choices. All choices are disabled.`);return{first:e,last:t}},[f]),[h,g]=sb(m.first),[_,v]=sb();Cb(async e=>{if(Ky(e)){let e=f.filter(Px),n=await a([...e]);i&&!e.length?v(`At least one choice must be selected`):n===!0?(u(`done`),t(e.map(e=>e.value))):v(n||`You must select a valid value`)}else if(By(e,c)||Vy(e,c)){if(_&&v(void 0),r||By(e,c)&&h!==m.first||Vy(e,c)&&h!==m.last){let t=By(e,c)?-1:1,n=h;do n=(n+t+f.length)%f.length;while(!Nx(f[n]));g(n)}}else if(Hy(e)){let e=f[h];e&&!Ax.isSeparator(e)&&(e.disabled?v(s.i18n.disabledError):(v(void 0),p(f.map((e,t)=>t===h?Fx(e):e))))}else if(e.name===o.all){let e=f.some(e=>Mx(e)&&!e.checked);p(f.map(Ix(e)))}else if(e.name===o.invert)p(f.map(Fx));else if(Gy(e)){let t=Number(e.name)-1,n=-1,r=f.findIndex(e=>Ax.isSeparator(e)?!1:(n++,n===t)),i=f[r];i&&Mx(i)&&(g(r),p(f.map((e,t)=>t===r?Fx(e):e)))}});let y=s.style.message(e.message,l),b,x=ex({items:f,active:h,renderItem({item:e,isActive:t}){if(Ax.isSeparator(e))return` ${e.separator}`;let n=t?s.icon.cursor:` `;if(e.disabled){let t=typeof e.disabled==`string`?e.disabled:`(disabled)`,r=e.checked?s.icon.disabledChecked:s.icon.disabledUnchecked;return s.style.disabled(`${n}${r} ${e.name} ${t}`)}t&&(b=e.description);let r=e.checked?s.icon.checked:s.icon.unchecked,i=e.checked?e.checkedName:e.name;return(t?s.style.highlight:e=>e)(`${n}${r} ${i}`)},pageSize:n,loop:r});if(l===`done`){let e=f.filter(Px);return[d,y,s.style.answer(s.style.renderSelectedChoices(e,f))].filter(Boolean).join(` `)}let S=[[`↑↓`,`navigate`],[`space`,`select`]];o.all&&S.push([o.all,`all`]),o.invert&&S.push([o.invert,`invert`]),S.push([`⏎`,`submit`]);let C=s.style.keysHelpTip(S);return`${[[d,y].filter(Boolean).join(` `),x,` `,b?s.style.description(b):``,_?s.style.error(_):``,C].filter(Boolean).join(`
217
217
  `).trimEnd()}${gx}`});function zx(e,t){let n=t!==!1;return/^(y|yes)/i.test(e)?n=!0:/^(n|no)/i.test(e)&&(n=!1),n}function Bx(e){return e?`Yes`:`No`}var Vx=kx((e,t)=>{let{transformer:n=Bx}=e,[r,i]=sb(`idle`),[a,o]=sb(``),s=yb(e.theme),c=bb({status:r,theme:s});Cb((s,c)=>{if(r===`idle`)if(Ky(s)){let r=zx(a,e.default);o(n(r)),i(`done`),t(r)}else if(Wy(s)){let t=Bx(!zx(a,e.default));c.clearLine(0),c.write(t),o(t)}else o(c.line)});let l=a,u=``;return r===`done`?l=s.style.answer(a):u=` ${s.style.defaultAnswer(e.default===!1?`y/N`:`Y/n`)}`,`${c} ${s.style.message(e.message,r)}${u} ${l}`});const Hx={validationFailureMode:`keep`};var Ux=kx((e,t)=>{let{prefill:n=`tab`}=e,r=yb(Hx,e.theme),[i,a]=sb(`idle`),[o,s]=sb(String(e.default??``)),[c,l]=sb(),[u,d]=sb(``),f=bb({status:i,theme:r});async function p(t){let{required:n,pattern:r,patternError:i=`Invalid input`}=e;return n&&!t?`You must provide a value`:r&&!r.test(t)?i:typeof e.validate==`function`?await e.validate(t)||`You must provide a valid value`:!0}Cb(async(e,n)=>{if(i===`idle`)if(Ky(e)){let e=u||o;a(`loading`);let i=await p(e);i===!0?(d(e),a(`done`),t(e)):(r.validationFailureMode===`clear`?d(``):n.write(u),l(i),a(`idle`))}else Uy(e)&&!u?s(``):Wy(e)&&!u?(s(``),n.clearLine(0),n.write(o),d(o)):(d(n.line),l(void 0))}),cb(e=>{n===`editable`&&o&&(e.write(o),d(o))},[]);let m=r.style.message(e.message,i),h=u;typeof e.transformer==`function`?h=e.transformer(u,{isFinal:i===`done`}):i===`done`&&(h=r.style.answer(u));let g;o&&i!==`done`&&!u&&(g=r.style.defaultAnswer(o));let _=``;return c&&(_=r.style.error(c)),[[f,m,g,h].filter(e=>e!==void 0).join(` `),_]});const Wx={icon:{cursor:hb.pointer},style:{disabled:e=>l(`dim`,e),description:e=>l(`cyan`,e),keysHelpTip:e=>e.map(([e,t])=>`${l(`bold`,e)} ${l(`dim`,t)}`).join(l(`dim`,` • `))},i18n:{disabledError:`This option is disabled and cannot be selected.`},indexMode:`hidden`,keybindings:[]};function Gx(e){return!Ax.isSeparator(e)&&!e.disabled}function Kx(e){return!Ax.isSeparator(e)}function qx(e){return e.map(e=>{if(Ax.isSeparator(e))return e;if(typeof e!=`object`||!e||!(`value`in e)){let t=String(e);return{value:e,name:t,short:t,disabled:!1}}let t=e.name??String(e.value),n={value:e.value,name:t,short:e.short??t,disabled:e.disabled??!1};return e.description&&(n.description=e.description),n})}var Jx=kx((e,t)=>{let{loop:n=!0,pageSize:r=7}=e,i=yb(Wx,e.theme),{keybindings:a}=i,[o,s]=sb(`idle`),c=bb({status:o,theme:i}),l=Sb(),u=!a.includes(`vim`),d=xb(()=>qx(e.choices),[e.choices]),f=xb(()=>{let e=d.findIndex(Kx),t=d.findLastIndex(Kx);if(e===-1)throw new Zy(`[select prompt] No selectable choices. All choices are disabled.`);return{first:e,last:t}},[d]),p=xb(()=>`default`in e?d.findIndex(t=>Gx(t)&&t.value===e.default):-1,[e.default,d]),[m,h]=sb(p===-1?f.first:p),g=d[m],[_,v]=sb();Cb((e,r)=>{if(clearTimeout(l.current),_&&v(void 0),Ky(e))g.disabled?v(i.i18n.disabledError):(s(`done`),t(g.value));else if(By(e,a)||Vy(e,a)){if(r.clearLine(0),n||By(e,a)&&m!==f.first||Vy(e,a)&&m!==f.last){let t=By(e,a)?-1:1,n=m;do n=(n+t+d.length)%d.length;while(!Kx(d[n]));h(n)}}else if(Gy(e)&&!Number.isNaN(Number(r.line))){let e=Number(r.line)-1,t=-1,n=d.findIndex(n=>Ax.isSeparator(n)?!1:(t++,t===e)),i=d[n];i!=null&&Gx(i)&&h(n),l.current=setTimeout(()=>{r.clearLine(0)},700)}else if(Uy(e))r.clearLine(0);else if(u){let e=r.line.toLowerCase(),t=d.findIndex(t=>Ax.isSeparator(t)||!Gx(t)?!1:t.name.toLowerCase().startsWith(e));t!==-1&&h(t),l.current=setTimeout(()=>{r.clearLine(0)},700)}}),cb(()=>()=>{clearTimeout(l.current)},[]);let y=i.style.message(e.message,o),b=i.style.keysHelpTip([[`↑↓`,`navigate`],[`⏎`,`select`]]),x=0,S=ex({items:d,active:m,renderItem({item:e,isActive:t,index:n}){if(Ax.isSeparator(e))return x++,` ${e.separator}`;let r=t?i.icon.cursor:` `,a=i.indexMode===`number`?`${n+1-x}. `:``;if(e.disabled){let n=typeof e.disabled==`string`?e.disabled:`(disabled)`,r=t?i.icon.cursor:`-`;return i.style.disabled(`${r} ${a}${e.name} ${n}`)}return(t?i.style.highlight:e=>e)(`${r} ${a}${e.name}`)},pageSize:r,loop:n});if(o===`done`)return[c,y,i.style.answer(g.short)].filter(Boolean).join(` `);let{description:C}=g;return`${[[c,y].filter(Boolean).join(` `),S,` `,C?i.style.description(C):``,_?i.style.error(_):``,b].filter(Boolean).join(`
218
- `).trimEnd()}${gx}`}),Yx=class{static async confirm(e){return await Vx({message:e.message,default:e.default})}static async getText(e){let{message:t,schema:n,default:r}=e,i;if(n&&r!==void 0){let e=n.safeParse(r);e.success&&(i=e.data)}else !n&&r!==void 0&&(i=r);if(n&&n instanceof wf)return await Jx({message:t,choices:n.options.map(e=>({value:e})),default:i});let a=await Ux({message:t,default:i,validate:e=>{if(!n)return!0;let t=e;if(n instanceof xd){if(e.trim()===``)return`Input cannot be empty`;let n=Number(e);if(Number.isNaN(n))return`Please enter a valid number`;t=n}let r=n.safeParse(t);return r.success?!0:r.error.issues[0]?.message??`Invalid input`}});if(!n)return a;let o=n instanceof xd?Number(a):a;return n.parse(o)}static async choose(e){let{message:t,options:n,mode:r=`single`,default:i,includeAllOption:a=!1,required:o=!1}=e,s=`__all__`,c=r===`single`?[i]:[...i||[]],l=[...r===`multiple`&&a?[{name:`All`,value:s,checked:c.includes(s)}]:[],...n.map(e=>({name:e,value:e,checked:c.includes(e)}))];if(r===`multiple`){let e=await Rx({message:t,choices:l,validate:e=>o&&e.length===0?`You must select at least one option.`:!0});return a&&e.includes(s)?n:e}return await Jx({message:t,choices:n.map(e=>({name:e,value:e})),default:typeof i==`string`?i:void 0})}},Xx=class e{static command=new uv(`init`).argument(`[projectName]`).option(`-d, --dir <path>`,`workspace directory`).action(e.run.bind(e));static async run(e,t){let n=await Fy.getPackageList(),r=n.filter(e=>e.type===`apps`&&e.packageJson?.startx?.mode!==`silent`),i=await this.getPrefs({projectName:e,options:t,projects:r}),a=n.filter(e=>e.type!==`apps`),o=await this.getConfigPrefs({selectedApps:i.selectedApps,packages:a}),s=await this.getPackagesPrefs({selectedPackages:o.selectedConfigs,packages:a,tags:o.gTags}),c=[...s.gTags,`runnable`];await this.installWorkspace({name:i.projectName,tags:[...c,`runnable`],dir:i.directory});let l=[...s.selectedPackages,...i.selectedApps];await Promise.all(l.map(async e=>{let t={},n=new Set(s.gTags);e.packageJson?.startx?.mode===`standalone`&&n.add(`runnable`),e.type===`apps`&&(n.add(`runnable`),s.selectedPackages.filter(t=>t.type!==`packages`||t.packageJson?.startx?.mode===`standalone`?!1:t.packageJson?.startx?.iTags?.every(t=>e.packageJson?.startx?.gTags?.includes(t))).forEach(e=>{let n=e.packageJson?.name||e.name;t[n]=`workspace:^`})),await this.installPackage({pkg:e,directory:i.directory,tags:Array.from(n),dependencies:t})}))}static async getPrefs(e){let n=await Yx.getText({message:`Project name`,name:`projectName`,default:e.projectName,schema:Bp.string().min(1,`Package name is required`).max(214,`Package name too long`).regex(/^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,`Invalid package name`)});if(e.projects.length===0)throw Error(`No apps found to install.`);let r=Fy.getDirectory(),i=e.options.dir?t.resolve(r.workspace,e.options.dir):t.join(r.workspace,n),a=await Yx.choose({message:`Select apps to install`,options:e.projects.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!0});return{projectName:n,directory:{workspace:i,template:r.template},selectedApps:e.projects.filter(e=>a.includes(e.name))}}static async getConfigPrefs(e){let t=new Set([`common`]),n=new Map;this.getGlobalTags({pkgs:e.selectedApps}).forEach(e=>t.add(e)),this.getPackageDeps({allPkgs:e.packages,pkgs:e.selectedApps}).forEach(e=>n.set(e.name,e));let r=e.packages.filter(e=>e.type!==`configs`||e.packageJson?.startx?.mode===`silent`||n.has(e.name)?!1:e.packageJson?.startx?.iTags?.every(e=>t.has(e))??!0);if(r.length>0){let e=await Yx.choose({message:`Select configs to install`,options:r.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!1});r.filter(t=>e.includes(t.name)).forEach(e=>n.set(e.name,e))}return t.has(`node`)&&(await Yx.choose({message:`Select formatter`,options:[`prettier + biome`,`prettier`],mode:`single`,default:`prettier`,required:!0})===`prettier`||t.add(`biome`),t.add(`prettier`)),this.getPackageDeps({allPkgs:e.packages,pkgs:Array.from(n.values())}).forEach(e=>n.set(e.name,e)),this.getGlobalTags({pkgs:Array.from(n.values())}).forEach(e=>t.add(e)),{gTags:Array.from(t),selectedConfigs:Array.from(n.values())}}static async getPackagesPrefs(e){let t=new Set(e.tags),n=new Map(e.selectedPackages.map(e=>[e.name,e])),r=e.packages.filter(e=>e.type!==`packages`||e.packageJson?.startx?.mode===`silent`||n.has(e.name)?!1:e.packageJson?.startx?.iTags?.every(e=>t.has(e))??!1);if(r.length>0){let e=await Yx.choose({message:`Select packages to install`,options:r.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!1});r.filter(t=>e.includes(t.name)).forEach(e=>n.set(e.name,e))}return this.getPackageDeps({allPkgs:e.packages,pkgs:Array.from(n.values())}).forEach(e=>n.set(e.name,e)),this.getGlobalTags({pkgs:Array.from(n.values())}).forEach(e=>t.add(e)),{gTags:Array.from(t),selectedPackages:Array.from(n.values())}}static async installPackage(e){if(!e.pkg.packageJson)throw Error(`Missing package.json for ${e.pkg.name}`);let n=new Set([...e.tags,...e.pkg.packageJson.startx?.tags||[]]),r=e.pkg.packageJson.startx?.ignore||[];r.includes(`eslint-config`)&&n.delete(`eslint`),r.includes(`vitest-config`)&&n.delete(`vitest`);let{packageJson:i,isWorkspace:a}=zy.handlePackageJson({app:e.pkg.packageJson,tags:Array.from(n),name:e.packageName||e.pkg.packageJson.name||e.pkg.name,dependencies:e.dependencies});if(a)throw Error(`Cannot install workspace as a package: ${e.pkg.name}`);let o=t.join(e.directory.workspace,e.pkg.relativePath),s=t.join(e.pkg.path);await My.writeJSONFile({dir:o,file:`package`,content:i}),await this.copyValidatedFilesFromFolder(s,o,n),await My.copyDirectory({from:t.join(s,`src`),to:t.join(o,`src`),exclude:n.has(`vitest`)?void 0:/\.test\.tsx?$/}),X_.info(`Successfully installed ${e.pkg.name}`)}static async installWorkspace(e){let t=await Fy.parsePackageJson({dir:e.dir.template}),n=await Fy.parsePackageJson({dir:e.dir.template,file:`startx`});if(!t)throw Error(`Failed to parse root package.json`);t.dependencies={...t.dependencies,...n?.dependencies||{}},t.devDependencies={...t.devDependencies,...n?.devDependencies||{}};let{packageJson:r}=zy.handlePackageJson({app:t,tags:[`root`,...e.tags],name:e.name});await My.writeJSONFile({dir:e.dir.workspace,file:`package`,content:r}),await this.copyValidatedFilesFromFolder(e.dir.template,e.dir.workspace,new Set([`root`,...e.tags]))}static getPackageDeps(e){let t=new Map(e.pkgs.map(e=>[e.name,e]));return Array.from(t.values()).forEach(n=>{[...n.packageJson?.startx?.requiredDeps||[],...n.packageJson?.startx?.requiredDevDeps||[]].forEach(n=>{let r=e.allPkgs.find(e=>e.packageJson?.name===n);r&&t.set(r.name,r)})}),e.pkgs.forEach(e=>t.delete(e.name)),Array.from(t.values())}static getGlobalTags(e){let t=new Set(e.gTags||[]);return e.pkgs.forEach(e=>{e.packageJson?.startx?.gTags?.forEach(e=>t.add(e))}),Array.from(t)}static async copyValidatedFilesFromFolder(e,n,r){let i=await My.listFiles({dir:e}).catch(()=>[]);for(let a of i){let i=Ny[a];if(!(i&&!i.tags.every(e=>r.has(e))))try{await My.copyFile({from:t.join(e,a),to:t.join(n,a)})}catch(e){X_.error(`Failed to copy file ${a}:`,e)}}}},Zx=`1.0.4`;const Qx=new uv;Qx.name(`startx`).description(`StartX CLI - Your all in one monorepo startup tool.`).version(Zx),Qx.command(`ping`).action(()=>{X_.info(`pong`)}),Qx.addCommand(Xx.command),Qx.parse(process.argv);export{};
218
+ `).trimEnd()}${gx}`}),Yx=class{static async confirm(e){return await Vx({message:e.message,default:e.default})}static async getText(e){let{message:t,schema:n,default:r}=e,i;if(n&&r!==void 0){let e=n.safeParse(r);e.success&&(i=e.data)}else !n&&r!==void 0&&(i=r);if(n&&n instanceof wf)return await Jx({message:t,choices:n.options.map(e=>({value:e})),default:i});let a=await Ux({message:t,default:i,validate:e=>{if(!n)return!0;let t=e;if(n instanceof xd){if(e.trim()===``)return`Input cannot be empty`;let n=Number(e);if(Number.isNaN(n))return`Please enter a valid number`;t=n}let r=n.safeParse(t);return r.success?!0:r.error.issues[0]?.message??`Invalid input`}});if(!n)return a;let o=n instanceof xd?Number(a):a;return n.parse(o)}static async choose(e){let{message:t,options:n,mode:r=`single`,default:i,includeAllOption:a=!1,required:o=!1}=e,s=`__all__`,c=r===`single`?[i]:[...i||[]],l=[...r===`multiple`&&a?[{name:`All`,value:s,checked:c.includes(s)}]:[],...n.map(e=>({name:e,value:e,checked:c.includes(e)}))];if(r===`multiple`){let e=await Rx({message:t,choices:l,validate:e=>o&&e.length===0?`You must select at least one option.`:!0});return a&&e.includes(s)?n:e}return await Jx({message:t,choices:n.map(e=>({name:e,value:e})),default:typeof i==`string`?i:void 0})}},Xx=class e{static command=new uv(`init`).argument(`[projectName]`).option(`-d, --dir <path>`,`workspace directory`).action(e.run.bind(e));static async run(e,t){let n=await Fy.getPackageList(),r=n.filter(e=>e.type===`apps`&&e.packageJson?.startx?.mode!==`silent`),i=await this.getPrefs({projectName:e,options:t,projects:r}),a=n.filter(e=>e.type!==`apps`),o=await this.getConfigPrefs({selectedApps:i.selectedApps,packages:a}),s=await this.getPackagesPrefs({selectedPackages:o.selectedConfigs,packages:a,tags:o.gTags}),c=[...s.gTags,`runnable`];await this.installWorkspace({name:i.projectName,tags:[...c,`runnable`],dir:i.directory});let l=[...s.selectedPackages,...i.selectedApps];await Promise.all(l.map(async e=>{let t={},n=new Set(s.gTags);e.packageJson?.startx?.mode===`standalone`&&n.add(`runnable`),e.type===`apps`&&(n.add(`runnable`),s.selectedPackages.filter(t=>t.type!==`packages`||t.packageJson?.startx?.mode===`standalone`?!1:t.packageJson?.startx?.iTags?.every(t=>e.packageJson?.startx?.gTags?.includes(t))).forEach(e=>{let n=e.packageJson?.name||e.name;t[n]=`workspace:^`})),await this.installPackage({pkg:e,directory:i.directory,tags:Array.from(n),dependencies:t})}))}static async getPrefs(e){let n=await Yx.getText({message:`Project name`,name:`projectName`,default:e.projectName,schema:Bp.string().min(1,`Package name is required`).max(214,`Package name too long`).regex(/^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,`Invalid package name`)});if(e.projects.length===0)throw Error(`No apps found to install.`);let r=Fy.getDirectory(),i=e.options.dir?t.resolve(r.workspace,e.options.dir):t.join(r.workspace,n),a=await Yx.choose({message:`Select apps to install`,options:e.projects.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!0});return{projectName:n,directory:{workspace:i,template:r.template},selectedApps:e.projects.filter(e=>a.includes(e.name))}}static async getConfigPrefs(e){let t=new Set([`common`]),n=new Map;this.getGlobalTags({pkgs:e.selectedApps}).forEach(e=>t.add(e)),this.getPackageDeps({allPkgs:e.packages,pkgs:e.selectedApps}).forEach(e=>n.set(e.name,e));let r=e.packages.filter(e=>e.type!==`configs`||e.packageJson?.startx?.mode===`silent`||n.has(e.name)?!1:e.packageJson?.startx?.iTags?.every(e=>t.has(e))??!0);if(r.length>0){let e=await Yx.choose({message:`Select configs to install`,options:r.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!1});r.filter(t=>e.includes(t.name)).forEach(e=>n.set(e.name,e))}return t.has(`node`)&&(await Yx.choose({message:`Select formatter`,options:[`prettier + biome`,`prettier`],mode:`single`,default:`prettier`,required:!0})===`prettier`||t.add(`biome`),t.add(`prettier`)),this.getPackageDeps({allPkgs:e.packages,pkgs:Array.from(n.values())}).forEach(e=>n.set(e.name,e)),this.getGlobalTags({pkgs:Array.from(n.values())}).forEach(e=>t.add(e)),{gTags:Array.from(t),selectedConfigs:Array.from(n.values())}}static async getPackagesPrefs(e){let t=new Set(e.tags),n=new Map(e.selectedPackages.map(e=>[e.name,e])),r=e.packages.filter(e=>e.type!==`packages`||e.packageJson?.startx?.mode===`silent`||n.has(e.name)?!1:e.packageJson?.startx?.iTags?.every(e=>t.has(e))??!1);if(r.length>0){let e=await Yx.choose({message:`Select packages to install`,options:r.map(e=>e.name),includeAllOption:!0,mode:`multiple`,required:!1});r.filter(t=>e.includes(t.name)).forEach(e=>n.set(e.name,e))}return this.getPackageDeps({allPkgs:e.packages,pkgs:Array.from(n.values())}).forEach(e=>n.set(e.name,e)),this.getGlobalTags({pkgs:Array.from(n.values())}).forEach(e=>t.add(e)),{gTags:Array.from(t),selectedPackages:Array.from(n.values())}}static async installPackage(e){if(!e.pkg.packageJson)throw Error(`Missing package.json for ${e.pkg.name}`);let n=new Set([...e.tags,...e.pkg.packageJson.startx?.tags||[]]),r=e.pkg.packageJson.startx?.ignore||[];r.includes(`eslint-config`)&&n.delete(`eslint`),r.includes(`vitest-config`)&&n.delete(`vitest`);let{packageJson:i,isWorkspace:a}=zy.handlePackageJson({app:e.pkg.packageJson,tags:Array.from(n),name:e.packageName||e.pkg.packageJson.name||e.pkg.name,dependencies:e.dependencies});if(a)throw Error(`Cannot install workspace as a package: ${e.pkg.name}`);let o=t.join(e.directory.workspace,e.pkg.relativePath),s=t.join(e.pkg.path);await My.writeJSONFile({dir:o,file:`package`,content:i}),await this.copyValidatedFilesFromFolder(s,o,n),await My.copyDirectory({from:t.join(s,`src`),to:t.join(o,`src`),exclude:n.has(`vitest`)?void 0:/\.test\.tsx?$/}),X_.info(`Successfully installed ${e.pkg.name}`)}static async installWorkspace(e){let t=await Fy.parsePackageJson({dir:e.dir.template}),n=await Fy.parsePackageJson({dir:e.dir.template,file:`startx`});if(!t)throw Error(`Failed to parse root package.json`);t.dependencies={...t.dependencies,...n?.dependencies||{}},t.devDependencies={...t.devDependencies,...n?.devDependencies||{}};let{packageJson:r}=zy.handlePackageJson({app:t,tags:[`root`,...e.tags],name:e.name});await My.writeJSONFile({dir:e.dir.workspace,file:`package`,content:r}),await this.copyValidatedFilesFromFolder(e.dir.template,e.dir.workspace,new Set([`root`,...e.tags]))}static getPackageDeps(e){let t=new Map(e.pkgs.map(e=>[e.name,e]));return Array.from(t.values()).forEach(n=>{[...n.packageJson?.startx?.requiredDeps||[],...n.packageJson?.startx?.requiredDevDeps||[]].forEach(n=>{let r=e.allPkgs.find(e=>e.packageJson?.name===n);r&&t.set(r.name,r)})}),e.pkgs.forEach(e=>t.delete(e.name)),Array.from(t.values())}static getGlobalTags(e){let t=new Set(e.gTags||[]);return e.pkgs.forEach(e=>{e.packageJson?.startx?.gTags?.forEach(e=>t.add(e))}),Array.from(t)}static async copyValidatedFilesFromFolder(e,n,r){let i=await My.listFiles({dir:e}).catch(()=>[]);for(let a of i){let i=Ny[a];if(i&&!i.tags.every(e=>r.has(e)))continue;let o=a===`_gitignore`?`.gitignore`:a;try{await My.copyFile({from:t.join(e,a),to:t.join(n,o)})}catch(e){X_.error(`Failed to copy file ${a}:`,e)}}}},Zx=`1.0.5`;const Qx=new uv;Qx.name(`startx`).description(`StartX CLI - Your all in one monorepo startup tool.`).version(Zx),Qx.command(`ping`).action(()=>{X_.info(`pong`)}),Qx.addCommand(Xx.command),Qx.parse(process.argv);export{};
@@ -329,10 +329,11 @@ export class InitCommand {
329
329
  for (const file of files) {
330
330
  const checked = FileCheck[file];
331
331
  if (checked && !checked.tags.every(tag => tags.has(tag))) continue;
332
+ const destFileName = file === "_gitignore" ? ".gitignore" : file;
332
333
  try {
333
334
  await fsTool.copyFile({
334
335
  from: path.join(source, file),
335
- to: path.join(destination, file),
336
+ to: path.join(destination, destFileName),
336
337
  });
337
338
  } catch (error) {
338
339
  logger.error(`Failed to copy file ${file}:`, error);
@@ -4,4 +4,5 @@ export default {
4
4
  // Config options...
5
5
  // Server-side render by default, to enable SPA mode set this to `false`
6
6
  ssr: false,
7
+ appDirectory: "src",
7
8
  } satisfies Config;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "startx",
3
3
  "description": "",
4
- "version": "1.0.4",
4
+ "version": "1.0.5",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/avinashid/startx.git"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes