@express-tool/cli 0.0.1 → 1.0.0

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/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  <div align="center">
2
2
 
3
- # 🚀 Express Next CLI
3
+ # 🚀 Express Tool CLI
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/express-next?style=flat-square)](https://www.npmjs.com/package/express-next)
5
+ [![npm version](https://img.shields.io/npm/v/@express-tool/cli?style=flat-square)](https://www.npmjs.com/package/@express-tool/cli)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
8
8
 
9
9
  </div>
10
10
 
11
11
  A production-grade Command Line Interface for generating robust, scalable Express.js applications.
12
- `express-next` automates the boring setup, enforcing best practices, modern tooling, and clean architecture from day one.
12
+ `express-tool` automates the boring setup, enforcing best practices, modern tooling, and clean architecture from day one.
13
13
 
14
14
  ## ✨ Features
15
15
 
@@ -36,25 +36,49 @@ Install globally via your preferred package manager:
36
36
  ### npm
37
37
 
38
38
  ```bash
39
- npm install -g express-next
39
+ npm install -g @express-tool/cli
40
40
  ```
41
41
 
42
42
  ### pnpm (Recommended)
43
43
 
44
44
  ```bash
45
- pnpm add -g express-next
45
+ pnpm add -g @express-tool/cli
46
46
  ```
47
47
 
48
48
  ### Yarn
49
49
 
50
50
  ```bash
51
- yarn global add express-next
51
+ yarn global add @express-tool/cli
52
52
  ```
53
53
 
54
54
  ### Bun
55
55
 
56
56
  ```bash
57
- bun add -g express-next
57
+ bun add -g @express-tool/cli
58
+ ```
59
+
60
+ ---
61
+
62
+ ## ⚡ Execution without Installation
63
+
64
+ You can also execute the CLI instantly without installing it globally:
65
+
66
+ ### npx (Node.js)
67
+
68
+ ```bash
69
+ npx @express-tool/cli init
70
+ ```
71
+
72
+ ### pnpm dlx
73
+
74
+ ```bash
75
+ pnpm dlx @express-tool/cli init
76
+ ```
77
+
78
+ ### bunx
79
+
80
+ ```bash
81
+ bunx @express-tool/cli init
58
82
  ```
59
83
 
60
84
  ---
@@ -66,7 +90,7 @@ bun add -g express-next
66
90
  The `init` command launches an interactive wizard to configure your new application.
67
91
 
68
92
  ```bash
69
- express-next init
93
+ express-tool init
70
94
  ```
71
95
 
72
96
  **Interactive Prompts:**
@@ -96,15 +120,15 @@ Quickly scaffold new resources (features) into your existing application. This c
96
120
  **Syntax:**
97
121
 
98
122
  ```bash
99
- express-next generate <resource-name>
123
+ express-tool generate <resource-name>
100
124
  # or shorcut
101
- express-next g <resource-name>
125
+ express-tool g <resource-name>
102
126
  ```
103
127
 
104
128
  **Example:**
105
129
 
106
130
  ```bash
107
- express-next g blogs
131
+ express-tool g blogs
108
132
  ```
109
133
 
110
134
  **Output:**
@@ -131,7 +155,7 @@ app.use('/blogs', blogsRouter);
131
155
  View debugging information about your local environment. useful for reporting issues.
132
156
 
133
157
  ```bash
134
- express-next info
158
+ express-tool info
135
159
  ```
136
160
 
137
161
  #### Update CLI
@@ -139,14 +163,14 @@ express-next info
139
163
  Check for updates or self-update the CLI tool.
140
164
 
141
165
  ```bash
142
- express-next upgrade
166
+ express-tool upgrade
143
167
  ```
144
168
 
145
169
  ---
146
170
 
147
171
  ## 📂 Project Structure
148
172
 
149
- A typical project created with `express-next` looks like this:
173
+ A typical project created with `@express-tool/cli` looks like this:
150
174
 
151
175
  ```
152
176
  my-express-app/
@@ -180,7 +204,7 @@ If you want to contribute to the project or run it from source, please check out
180
204
 
181
205
  ## 🤝 Contributing
182
206
 
183
- Contributions are welcome! Please open an issue or submit a pull request on our [GitHub Repository](https://github.com/iam-mustak-ak/express-next.git).
207
+ Contributions are welcome! Please open an issue or submit a pull request on our [GitHub Repository](https://github.com/iam-mustak-ak/express-tool.git).
184
208
 
185
209
  ## 📄 License
186
210
 
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import{createRequire as e}from"module";e(import.meta.url);import{Command as t}from"commander";import s from"picocolors";import{authPlugin as r}from"@express-tool/plugin-auth";import{ciPlugin as a}from"@express-tool/plugin-ci";import{commonPlugin as o}from"@express-tool/plugin-common";import{databasePlugin as n}from"@express-tool/plugin-database";import{dockerPlugin as i}from"@express-tool/plugin-docker";import{middlewarePlugin as p}from"@express-tool/plugin-middleware";import{qualityPlugin as l}from"@express-tool/plugin-quality";import{swaggerPlugin as c}from"@express-tool/plugin-swagger";import{testingPlugin as m}from"@express-tool/plugin-testing";import{viewsPlugin as g}from"@express-tool/plugin-views";import u from"fs-extra";import d from"prompts";import{z as w}from"zod";import{controllerJs as f,controllerTs as y,routesJs as v,routesTs as j,testJs as h,testTs as x}from"@express-tool/plugin-resource";import S from"envinfo";import{createRequire as b}from"node:module";let $=b(import.meta.url);var C={656(e,b,C){C.d(b,{x:()=>G});var k=JSON.parse('{"UU":"@express-tool/cli","rE":"0.0.1"}');let E=e=>console.log(s.blue("ℹ"),e),D=e=>console.log(s.green("✔"),e),N=e=>console.log(s.yellow("⚠"),e),T=e=>console.log(s.red("✖"),e),P=$("path");var M=C.n(P);async function O(e,t,s,r,a,o){E(`Applying plugin: ${e.name}`);let n=await e.apply(t,o);if(n.dependencies&&(r.dependencies={...r.dependencies,...n.dependencies}),n.devDependencies&&(r.devDependencies={...r.devDependencies,...n.devDependencies}),n.files)for(let e of n.files){let t=M().join(s,"src",e.path);u.ensureDirSync(M().dirname(t)),u.writeFileSync(t,e.content),E(` Created ${e.path}`)}if(n.env)for(let[e,t]of Object.entries(n.env))a.push(`${e}=${t}`);return n.scripts&&(r.scripts={...r.scripts,...n.scripts}),n}async function R(e){let t=M().resolve(process.cwd(),e.projectName);u.existsSync(t)&&(T(`Directory ${e.projectName} already exists.`),process.exit(1)),E(`Creating project in ${t}...`),u.mkdirSync(t);let s=[],d={name:e.projectName,version:"0.0.0",private:!0,type:"module",packageManager:`${e.packageManager}@latest`,scripts:{dev:"ts"===e.language?"tsx watch src/index.ts":"node --watch src/index.js",build:"ts"===e.language?"tsc":void 0,start:"ts"===e.language?"node dist/index.js":"node src/index.js"},dependencies:{express:"^4.18.2"},devDependencies:{}};"rest-swagger"===e.apiType&&(Object.assign(d.dependencies,{"swagger-ui-express":"^5.0.0",zod:"^3.22.4","@asteasolutions/zod-to-openapi":"^7.0.0"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/swagger-ui-express":"^4.1.6"})),"jwt"===e.auth&&(Object.assign(d.dependencies,{jsonwebtoken:"^9.0.2"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/jsonwebtoken":"^9.0.5"})),"none"!==e.templateEngine&&(Object.assign(d.dependencies,{[e.templateEngine]:"ejs"===e.templateEngine?"^3.1.9":"^3.0.2"}),"ts"===e.language&&Object.assign(d.devDependencies,{[`@types/${e.templateEngine}`]:"ejs"===e.templateEngine?"^3.1.5":"^2.0.10"})),u.writeJsonSync(M().join(t,"package.json"),d,{spaces:2});let w=M().join(t,"src");u.mkdirSync(w),e.language;let f={projectRoot:t,projectName:e.projectName,isTs:"ts"===e.language,language:e.language};await O(o,f,t,d,s),await O(p,f,t,d,s),"rest-swagger"===e.apiType&&await O(c,f,t,d,s),"none"!==e.database&&await O(n,f,t,d,s,{database:e.database}),"jwt"===e.auth&&await O(r,f,t,d,[]),"none"!==e.templateEngine&&await O(g,f,t,d,s,{templateEngine:e.templateEngine});let y=s.join("\n")+"\n";u.writeFileSync(M().join(t,".env"),y),u.writeFileSync(M().join(t,".env.example"),y);let v=`import 'dotenv/config';
3
- import express from 'express';
2
+ import{createRequire as e}from"module";e(import.meta.url);import{Command as t}from"commander";import s from"picocolors";import{authPlugin as a}from"@express-tool/plugin-auth";import{ciPlugin as o}from"@express-tool/plugin-ci";import{commonPlugin as r}from"@express-tool/plugin-common";import{databasePlugin as n}from"@express-tool/plugin-database";import{dockerPlugin as i}from"@express-tool/plugin-docker";import{middlewarePlugin as p}from"@express-tool/plugin-middleware";import{qualityPlugin as l}from"@express-tool/plugin-quality";import{swaggerPlugin as c}from"@express-tool/plugin-swagger";import{testingPlugin as g}from"@express-tool/plugin-testing";import{viewsPlugin as m}from"@express-tool/plugin-views";import u from"fs-extra";import d from"prompts";import{z as w}from"zod";import{controllerJs as f,controllerTs as y,routesJs as v,routesTs as h,testJs as j,testTs as x}from"@express-tool/plugin-resource";import S from"envinfo";import{createRequire as $}from"node:module";let b=$(import.meta.url);var C={656(e,$,C){C.d($,{x:()=>G});var k=JSON.parse('{"UU":"@express-tool/cli","rE":"1.0.0"}');let E=e=>console.log(s.blue("ℹ"),e),N=e=>console.log(s.green("✔"),e),P=e=>console.log(s.yellow("⚠"),e),R=e=>console.log(s.red("✖"),e),D=b("path");var M=C.n(D);async function T(e,t,s,a,o,r){E(`Applying plugin: ${e.name}`);let n=await e.apply(t,r);if(n.dependencies&&(a.dependencies={...a.dependencies,...n.dependencies}),n.devDependencies&&(a.devDependencies={...a.devDependencies,...n.devDependencies}),n.files)for(let e of n.files){let t=M().join(s,"src",e.path);u.ensureDirSync(M().dirname(t)),u.writeFileSync(t,e.content),E(` Created ${e.path}`)}if(n.env)for(let[e,t]of Object.entries(n.env))o.push(`${e}=${t}`);if(n.scripts&&(a.scripts={...a.scripts,...n.scripts}),n.commands)for(let e of n.commands){E(` Running command: ${e}`);try{C(317).execSync(e,{cwd:s,stdio:"inherit"})}catch(t){P(` Command failed: ${e}`)}}return n}async function O(e){let t=M().resolve(process.cwd(),e.projectName);u.existsSync(t)&&(R(`Directory ${e.projectName} already exists.`),process.exit(1)),E(`Creating project in ${t}...`),u.mkdirSync(t);let s=[],d={name:e.projectName,version:"0.0.0",private:!0,type:"module",packageManager:`${e.packageManager}@latest`,scripts:{dev:"ts"===e.language?"tsx watch src/index.ts":"node --watch src/index.js",build:"ts"===e.language?"tsc":void 0,start:"ts"===e.language?"node dist/index.js":"node src/index.js"},dependencies:{express:"latest"},devDependencies:{..."ts"===e.language?{"@types/node":"latest","@types/express":"latest"}:{}}};"rest-swagger"===e.apiType&&(Object.assign(d.dependencies,{"swagger-ui-express":"latest",zod:"latest","@asteasolutions/zod-to-openapi":"latest"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/swagger-ui-express":"latest"})),"jwt"===e.auth&&(Object.assign(d.dependencies,{jsonwebtoken:"latest"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/jsonwebtoken":"latest"})),"none"!==e.templateEngine&&(Object.assign(d.dependencies,{[e.templateEngine]:"latest"}),"ts"===e.language&&Object.assign(d.devDependencies,{[`@types/${e.templateEngine}`]:"latest"})),u.writeJsonSync(M().join(t,"package.json"),d,{spaces:2});let w=M().join(t,"src");u.mkdirSync(w),e.language;let f={projectRoot:t,projectName:e.projectName,isTs:"ts"===e.language,language:e.language};await T(r,f,t,d,s),await T(p,f,t,d,s),"rest-swagger"===e.apiType&&await T(c,f,t,d,s),"none"!==e.database&&await T(n,f,t,d,s,{database:e.database}),"jwt"===e.auth&&await T(a,f,t,d,[]),"none"!==e.templateEngine&&await T(m,f,t,d,s,{templateEngine:e.templateEngine});let y=s.join("\n")+"\n";u.writeFileSync(M().join(t,".env"),y),u.writeFileSync(M().join(t,".env.example"),y);let v=`import 'dotenv/config';
3
+ import express${"ts"===e.language?", { Request, Response }":""} from 'express';
4
4
  import cors from 'cors';
5
5
  import helmet from 'helmet';
6
6
  import path from 'path';
@@ -40,15 +40,15 @@ app.use(express.static(path.join(__dirname, 'public')));
40
40
 
41
41
  `,"rest-swagger"===e.apiType&&(v+=`app.use('/docs', swaggerRouter);
42
42
  `),"jwt"===e.auth&&(v+=`app.use('/auth', authRouter);
43
- `),v+=`app.get('/', (req, res) => {
43
+ `),v+=`app.get('/', (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
44
44
  ${"none"!==e.templateEngine?`res.render('index', { title: 'Express App', message: 'Hello from ${e.templateEngine.toUpperCase()}!' });`:"res.json({ status: 'ok', timestamp: new Date().toISOString() });"}
45
45
  });
46
46
 
47
- app.get('/health', (req, res) => {
47
+ app.get('/health', (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
48
48
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
49
49
  });
50
50
  `,"jwt"===e.auth&&(v+=`
51
- app.get('/protected', authenticateToken, (req, res) => {
51
+ app.get('/protected', authenticateToken, (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
52
52
  res.json({ message: 'This is a protected route', user: (req as any).user });
53
53
  });
54
54
  `),v+=`
@@ -56,7 +56,7 @@ app.use(errorHandler);
56
56
 
57
57
  // Export app for testing
58
58
  export { app };
59
- `;let j=`
59
+ `;let h=`
60
60
  const server = app.listen(port, () => {
61
61
  logger.info(\`Server running on http://localhost:\${port}\`);
62
62
  });
@@ -74,17 +74,20 @@ process.on('SIGTERM', shutdown);
74
74
  process.on('SIGINT', shutdown);
75
75
  `;"ts"===e.language?v+=`
76
76
  if (import.meta.url === \`file://\${process.argv[1]}\`) {
77
- ${j}
77
+ ${h}
78
78
  }
79
79
  `:v+=`
80
80
  if (process.argv[1] === import.meta.filename) { // Node 20.11+
81
- ${j}
81
+ ${h}
82
82
  } else if (import.meta.url === \`file://\${process.argv[1]}\`) {
83
- ${j}
83
+ ${h}
84
84
  }
85
- `;let h="ts"===e.language?"index.ts":"index.js";u.writeFileSync(M().join(w,h),v),await O(m,f,t,d,s),await O(l,f,t,d,s),await O(i,f,t,d,s,{packageManager:e.packageManager,database:e.database}),await O(a,f,t,d,s,{packageManager:e.packageManager}),"ts"===e.language&&u.writeJsonSync(M().join(t,"tsconfig.json"),{compilerOptions:{target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",outDir:"./dist",rootDir:"./src",strict:!0,esModuleInterop:!0},include:["src/**/*"]},{spaces:2});let x=`node_modules
85
+ `;let j="ts"===e.language?"index.ts":"index.js";u.writeFileSync(M().join(w,j),v),await T(g,f,t,d,s),await T(l,f,t,d,s),await T(i,f,t,d,s,{packageManager:e.packageManager,database:e.database}),await T(o,f,t,d,s,{packageManager:e.packageManager}),"ts"===e.language&&u.writeJsonSync(M().join(t,"tsconfig.json"),{compilerOptions:{target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",outDir:"./dist",rootDir:"./src",strict:!0,esModuleInterop:!0,skipLibCheck:!0,forceConsistentCasingInFileNames:!0},include:["src/**/*"]},{spaces:2});let x=`node_modules
86
86
  dist
87
87
  .env
88
88
  .DS_Store
89
- `;u.writeFileSync(M().join(t,".gitignore"),x),D(`Project ${e.projectName} created successfully!`)}let L=w.object({projectName:w.string().min(1).regex(/^[a-z0-9-]+$/,"Project name must be kebab-case (lowercase letters, numbers, and hyphens)"),language:w.enum(["ts","js"]),architecture:w.enum(["feature","mvc"]),apiType:w.enum(["rest","rest-swagger"]),database:w.enum(["postgresql","mysql","mongodb","mongodb-prisma","none"]),auth:w.enum(["jwt","none"]),templateEngine:w.enum(["ejs","pug","none"]),packageManager:w.enum(["npm","pnpm","yarn","bun"])});async function I(){return await d([{type:"text",name:"projectName",message:"What is your project name?",initial:"my-express-app",validate:e=>{let t=L.shape.projectName.safeParse(e);return!!t.success||t.error.issues[0].message}},{type:"select",name:"language",message:"Select language",choices:[{title:"TypeScript (Recommended)",value:"ts"},{title:"JavaScript",value:"js"}],initial:0},{type:"select",name:"packageManager",message:"Select package manager",choices:[{title:"pnpm (Recommended)",value:"pnpm"},{title:"npm",value:"npm"},{title:"Yarn",value:"yarn"},{title:"Bun",value:"bun"}],initial:0},{type:"select",name:"architecture",message:"Select architecture",choices:[{title:"Feature-based (Recommended)",value:"feature",description:"Modules grouped by feature (e.g., users, posts)"},{title:"MVC",value:"mvc",description:"Classic Model-View-Controller structure"}],initial:0},{type:"select",name:"apiType",message:"Select API type",choices:[{title:"REST API + Swagger",value:"rest-swagger"},{title:"REST API (Basic)",value:"rest"}],initial:0},{type:"select",name:"database",message:"Select database",choices:[{title:"PostgreSQL (Prisma)",value:"postgresql"},{title:"MySQL (Prisma)",value:"mysql"},{title:"MongoDB (Prisma)",value:"mongodb-prisma"},{title:"MongoDB (Mongoose)",value:"mongodb"},{title:"None",value:"none"}],initial:0},{type:"select",name:"auth",message:"Select authentication",choices:[{title:"JWT (JSON Web Token)",value:"jwt"},{title:"None",value:"none"}],initial:0},{type:"select",name:"templateEngine",message:"Select template engine",choices:[{title:"EJS (Embedded JavaScript)",value:"ejs"},{title:"Pug (Jade)",value:"pug"},{title:"None (API only)",value:"none"}],initial:0}],{onCancel:()=>{T("Operation cancelled"),process.exit(1)}})}let F=new t("init").description("Initialize a new Express.js project").action(async()=>{let e=await I();await R(e)});async function J(e){let t=process.cwd(),s=M().join(t,"package.json");u.existsSync(s)||(T("No package.json found. Are you in the root of the project?"),process.exit(1));let r=u.readJsonSync(s),a=r.devDependencies&&r.devDependencies.typescript,o=a?"ts":"js",n=M().join(t,"src"),i=M().join(n,"controllers"),p=M().join(n,"routes"),l=M().join(t,"test");u.ensureDirSync(i),u.ensureDirSync(p),u.ensureDirSync(l);let c=e.charAt(0).toUpperCase()+e.slice(1),m=M().join(i,`${e.toLowerCase()}.controller.${o}`);u.existsSync(m)?N(`Controller ${m} already exists. Skipping.`):(u.writeFileSync(m,a?y(c):f(c)),E(`Created controller: src/controllers/${e.toLowerCase()}.controller.${o}`));let g=M().join(p,`${e.toLowerCase()}.routes.${o}`);u.existsSync(g)?N(`Route ${g} already exists. Skipping.`):(u.writeFileSync(g,a?j(c):v(c)),E(`Created route: src/routes/${e.toLowerCase()}.routes.${o}`));let d=M().join(l,`${e.toLowerCase()}.test.${o}`);u.existsSync(d)?N(`Test ${d} already exists. Skipping.`):(u.writeFileSync(d,a?x(c):h(c)),E(`Created test: test/${e.toLowerCase()}.test.${o}`)),D(`Feature ${e} generated successfully!`),E(`
90
- Don't forget to register the route in src/index.${o}:`),E(`import { ${e.toLowerCase()}Router } from './routes/${e.toLowerCase()}.routes';`),E(`app.use('/${e.toLowerCase()}s', ${e.toLowerCase()}Router);`)}let q=new t().name("generate").alias("g").description("Generate a new feature (controller, routes, test)").argument("<name>","Name of the feature (e.g. users, blogs)").action(async e=>{await J(e)}),H=new t().name("info").description("Print debugging information about your environment").action(async()=>{console.log(" System:"),await S.run({System:["OS","CPU","Memory","Shell"],Binaries:["Node","Yarn","npm","pnpm"],Utilities:["Git"],IDEs:["VSCode"],Browsers:["Chrome","Edge","Firefox","Safari"],npmPackages:["typescript","express","express-next"]},{console:!0,showNotFound:!0})}),A=$("https");var B=C.n(A);let U=new t().name("upgrade").description("Check for updates").action(async()=>{E("Checking for updates...");let e=k.rE,t=k.UU;try{var s;let r=await (s=t,new Promise(e=>{B().get(`https://registry.npmjs.org/${s}/latest`,t=>{let s="";t.on("data",e=>s+=e),t.on("end",()=>{try{let t=JSON.parse(s);e(t.version)}catch{e(null)}})}).on("error",()=>e(null))}));if(!r)return void N("Could not fetch latest version info.");r!==e?(E(`New version available: ${r} (current: ${e})`),E(`Run 'npm install -g ${t}' to update.`)):D("You are using the latest version.")}catch(e){T("Failed to check for updates.")}}),{rE:_}=k,G=new t;G.name("express-next").description("Production-grade CLI for Express.js applications").version(_),G.hook("preAction",()=>{E("Welcome to express-next CLI")}),G.addCommand(F),G.addCommand(q),G.addCommand(H),G.addCommand(U)}},k={};function E(e){var t=k[e];if(void 0!==t)return t.exports;var s=k[e]={exports:{}};return C[e](s,s.exports,E),s.exports}E.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return E.d(t,{a:t}),t},E.d=(e,t)=>{for(var s in t)E.o(t,s)&&!E.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},E.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),E(656).x.parse(process.argv);
89
+ `;u.writeFileSync(M().join(t,".gitignore"),x),u.writeJsonSync(M().join(t,"package.json"),d,{spaces:2}),E("Installing dependencies...");try{let s=(e.packageManager,"install");C(317).execSync(`${e.packageManager} ${s}`,{cwd:t,stdio:"inherit"})}catch(e){P("Failed to install dependencies. Please run install manually.")}N(`Project ${e.projectName} created successfully!`),console.log(`
90
+ Next steps:`),console.log(` cd ${e.projectName}`),console.log(` ${e.packageManager} run dev`),"prisma-postgres"===e.database&&console.log(` ${e.packageManager} run db:init (To setup Prisma Postgres Managed DB)`),console.log(`
91
+ Happy Coding! 🚀
92
+ `)}let L=w.object({projectName:w.string().min(1).regex(/^[a-z0-9-]+$/,"Project name must be kebab-case (lowercase letters, numbers, and hyphens)"),language:w.enum(["ts","js"]),architecture:w.enum(["feature","mvc"]),apiType:w.enum(["rest","rest-swagger"]),database:w.enum(["postgresql","prisma-postgres","mysql","mongodb","none"]),auth:w.enum(["jwt","none"]),templateEngine:w.enum(["ejs","pug","none"]),packageManager:w.enum(["npm","pnpm","yarn","bun"])});async function I(){return await d([{type:"text",name:"projectName",message:"What is your project name?",initial:"my-express-app",validate:e=>{let t=L.shape.projectName.safeParse(e);return!!t.success||t.error.issues[0].message}},{type:"select",name:"language",message:"Select language",choices:[{title:"TypeScript (Recommended)",value:"ts"},{title:"JavaScript",value:"js"}],initial:0},{type:"select",name:"packageManager",message:"Select package manager",choices:[{title:"pnpm (Recommended)",value:"pnpm"},{title:"npm",value:"npm"},{title:"Yarn",value:"yarn"},{title:"Bun",value:"bun"}],initial:0},{type:"select",name:"architecture",message:"Select architecture",choices:[{title:"Feature-based (Recommended)",value:"feature",description:"Modules grouped by feature (e.g., users, posts)"},{title:"MVC",value:"mvc",description:"Classic Model-View-Controller structure"}],initial:0},{type:"select",name:"apiType",message:"Select API type",choices:[{title:"REST API + Swagger",value:"rest-swagger"},{title:"REST API (Basic)",value:"rest"}],initial:0},{type:"select",name:"database",message:"Select database",choices:[{title:"PostgreSQL (Prisma)",value:"postgresql"},{title:"PostgreSQL (Prisma Postgres Managed)",value:"prisma-postgres"},{title:"MySQL (Prisma)",value:"mysql"},{title:"MongoDB (Mongoose)",value:"mongodb"},{title:"None",value:"none"}],initial:0},{type:"select",name:"auth",message:"Select authentication",choices:[{title:"JWT (JSON Web Token)",value:"jwt"},{title:"None",value:"none"}],initial:0},{type:"select",name:"templateEngine",message:"Select template engine",choices:[{title:"EJS (Embedded JavaScript)",value:"ejs"},{title:"Pug (Jade)",value:"pug"},{title:"None (API only)",value:"none"}],initial:0}],{onCancel:()=>{R("Operation cancelled"),process.exit(1)}})}let F=new t("init").description("Initialize a new Express.js project").action(async()=>{let e=await I();await O(e)});async function q(e){let t=process.cwd(),s=M().join(t,"package.json");u.existsSync(s)||(R("No package.json found. Are you in the root of the project?"),process.exit(1));let a=u.readJsonSync(s),o=a.devDependencies&&a.devDependencies.typescript,r=o?"ts":"js",n=M().join(t,"src"),i=M().join(n,"controllers"),p=M().join(n,"routes"),l=M().join(t,"test");u.ensureDirSync(i),u.ensureDirSync(p),u.ensureDirSync(l);let c=e.charAt(0).toUpperCase()+e.slice(1),g=M().join(i,`${e.toLowerCase()}.controller.${r}`);u.existsSync(g)?P(`Controller ${g} already exists. Skipping.`):(u.writeFileSync(g,o?y(c):f(c)),E(`Created controller: src/controllers/${e.toLowerCase()}.controller.${r}`));let m=M().join(p,`${e.toLowerCase()}.routes.${r}`);u.existsSync(m)?P(`Route ${m} already exists. Skipping.`):(u.writeFileSync(m,o?h(c):v(c)),E(`Created route: src/routes/${e.toLowerCase()}.routes.${r}`));let d=M().join(l,`${e.toLowerCase()}.test.${r}`);u.existsSync(d)?P(`Test ${d} already exists. Skipping.`):(u.writeFileSync(d,o?x(c):j(c)),E(`Created test: test/${e.toLowerCase()}.test.${r}`)),N(`Feature ${e} generated successfully!`),E(`
93
+ Don't forget to register the route in src/index.${r}:`),E(`import { ${e.toLowerCase()}Router } from './routes/${e.toLowerCase()}.routes';`),E(`app.use('/${e.toLowerCase()}s', ${e.toLowerCase()}Router);`)}let J=new t().name("generate").alias("g").description("Generate a new feature (controller, routes, test)").argument("<name>","Name of the feature (e.g. users, blogs)").action(async e=>{await q(e)}),H=new t().name("info").description("Print debugging information about your environment").action(async()=>{console.log(" System:"),await S.run({System:["OS","CPU","Memory","Shell"],Binaries:["Node","Yarn","npm","pnpm"],Utilities:["Git"],IDEs:["VSCode"],Browsers:["Chrome","Edge","Firefox","Safari"],npmPackages:["typescript","express","express-tool"]},{console:!0,showNotFound:!0})}),A=b("https");var _=C.n(A);let B=new t().name("upgrade").description("Check for updates").action(async()=>{E("Checking for updates...");let e=k.rE,t=k.UU;try{var s;let a=await (s=t,new Promise(e=>{_().get(`https://registry.npmjs.org/${s}/latest`,t=>{let s="";t.on("data",e=>s+=e),t.on("end",()=>{try{let t=JSON.parse(s);e(t.version)}catch{e(null)}})}).on("error",()=>e(null))}));if(!a)return void P("Could not fetch latest version info.");a!==e?(E(`New version available: ${a} (current: ${e})`),E(`Run 'npm install -g ${t}' to update.`)):N("You are using the latest version.")}catch(e){R("Failed to check for updates.")}}),{rE:U}=k,G=new t;G.name("express-tool").description("Production-grade CLI for Express.js applications").version(U),G.hook("preAction",()=>{E("Welcome to express-tool CLI")}),G.addCommand(F),G.addCommand(J),G.addCommand(H),G.addCommand(B)},317(e){e.exports=b("child_process")}},k={};function E(e){var t=k[e];if(void 0!==t)return t.exports;var s=k[e]={exports:{}};return C[e](s,s.exports,E),s.exports}E.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return E.d(t,{a:t}),t},E.d=(e,t)=>{for(var s in t)E.o(t,s)&&!E.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},E.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),E(656).x.parse(process.argv);
@@ -1 +1 @@
1
- {"version":3,"file":"init.generator.d.ts","sourceRoot":"","sources":["../../src/commands/init.generator.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,iBAySzD"}
1
+ {"version":3,"file":"init.generator.d.ts","sourceRoot":"","sources":["../../src/commands/init.generator.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,iBAmUzD"}
@@ -15,9 +15,9 @@ export declare const initOptionsSchema: z.ZodObject<{
15
15
  }>;
16
16
  database: z.ZodEnum<{
17
17
  postgresql: "postgresql";
18
+ "prisma-postgres": "prisma-postgres";
18
19
  mysql: "mysql";
19
20
  mongodb: "mongodb";
20
- "mongodb-prisma": "mongodb-prisma";
21
21
  none: "none";
22
22
  }>;
23
23
  auth: z.ZodEnum<{
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import{Command as e}from"commander";import t from"picocolors";import{authPlugin as s}from"@express-tool/plugin-auth";import{ciPlugin as a}from"@express-tool/plugin-ci";import{commonPlugin as r}from"@express-tool/plugin-common";import{databasePlugin as o}from"@express-tool/plugin-database";import{dockerPlugin as n}from"@express-tool/plugin-docker";import{middlewarePlugin as i}from"@express-tool/plugin-middleware";import{qualityPlugin as p}from"@express-tool/plugin-quality";import{swaggerPlugin as l}from"@express-tool/plugin-swagger";import{testingPlugin as c}from"@express-tool/plugin-testing";import{viewsPlugin as m}from"@express-tool/plugin-views";import g from"fs-extra";import u from"prompts";import{z as d}from"zod";import{controllerJs as w,controllerTs as f,routesJs as y,routesTs as v,testJs as j,testTs as h}from"@express-tool/plugin-resource";import x from"envinfo";import{createRequire as S}from"node:module";let b=S(import.meta.url);var $={};$.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return $.d(t,{a:t}),t},$.d=(e,t)=>{for(var s in t)$.o(t,s)&&!$.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},$.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var C={};$.d(C,{x:()=>G});var k=JSON.parse('{"UU":"@express-tool/cli","rE":"0.0.1"}');let E=e=>console.log(t.blue("ℹ"),e),D=e=>console.log(t.green("✔"),e),N=e=>console.log(t.yellow("⚠"),e),T=e=>console.log(t.red("✖"),e),P=b("path");var M=$.n(P);async function O(e,t,s,a,r,o){E(`Applying plugin: ${e.name}`);let n=await e.apply(t,o);if(n.dependencies&&(a.dependencies={...a.dependencies,...n.dependencies}),n.devDependencies&&(a.devDependencies={...a.devDependencies,...n.devDependencies}),n.files)for(let e of n.files){let t=M().join(s,"src",e.path);g.ensureDirSync(M().dirname(t)),g.writeFileSync(t,e.content),E(` Created ${e.path}`)}if(n.env)for(let[e,t]of Object.entries(n.env))r.push(`${e}=${t}`);return n.scripts&&(a.scripts={...a.scripts,...n.scripts}),n}async function R(e){let t=M().resolve(process.cwd(),e.projectName);g.existsSync(t)&&(T(`Directory ${e.projectName} already exists.`),process.exit(1)),E(`Creating project in ${t}...`),g.mkdirSync(t);let u=[],d={name:e.projectName,version:"0.0.0",private:!0,type:"module",packageManager:`${e.packageManager}@latest`,scripts:{dev:"ts"===e.language?"tsx watch src/index.ts":"node --watch src/index.js",build:"ts"===e.language?"tsc":void 0,start:"ts"===e.language?"node dist/index.js":"node src/index.js"},dependencies:{express:"^4.18.2"},devDependencies:{}};"rest-swagger"===e.apiType&&(Object.assign(d.dependencies,{"swagger-ui-express":"^5.0.0",zod:"^3.22.4","@asteasolutions/zod-to-openapi":"^7.0.0"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/swagger-ui-express":"^4.1.6"})),"jwt"===e.auth&&(Object.assign(d.dependencies,{jsonwebtoken:"^9.0.2"}),"ts"===e.language&&Object.assign(d.devDependencies,{"@types/jsonwebtoken":"^9.0.5"})),"none"!==e.templateEngine&&(Object.assign(d.dependencies,{[e.templateEngine]:"ejs"===e.templateEngine?"^3.1.9":"^3.0.2"}),"ts"===e.language&&Object.assign(d.devDependencies,{[`@types/${e.templateEngine}`]:"ejs"===e.templateEngine?"^3.1.5":"^2.0.10"})),g.writeJsonSync(M().join(t,"package.json"),d,{spaces:2});let w=M().join(t,"src");g.mkdirSync(w),e.language;let f={projectRoot:t,projectName:e.projectName,isTs:"ts"===e.language,language:e.language};await O(r,f,t,d,u),await O(i,f,t,d,u),"rest-swagger"===e.apiType&&await O(l,f,t,d,u),"none"!==e.database&&await O(o,f,t,d,u,{database:e.database}),"jwt"===e.auth&&await O(s,f,t,d,[]),"none"!==e.templateEngine&&await O(m,f,t,d,u,{templateEngine:e.templateEngine});let y=u.join("\n")+"\n";g.writeFileSync(M().join(t,".env"),y),g.writeFileSync(M().join(t,".env.example"),y);let v=`import 'dotenv/config';
2
- import express from 'express';
1
+ import{createRequire as e}from"node:module";let t=e(import.meta.url);import{Command as s}from"commander";import a from"picocolors";import{authPlugin as o}from"@express-tool/plugin-auth";import{ciPlugin as r}from"@express-tool/plugin-ci";import{commonPlugin as n}from"@express-tool/plugin-common";import{databasePlugin as i}from"@express-tool/plugin-database";import{dockerPlugin as p}from"@express-tool/plugin-docker";import{middlewarePlugin as l}from"@express-tool/plugin-middleware";import{qualityPlugin as c}from"@express-tool/plugin-quality";import{swaggerPlugin as g}from"@express-tool/plugin-swagger";import{testingPlugin as m}from"@express-tool/plugin-testing";import{viewsPlugin as u}from"@express-tool/plugin-views";import d from"fs-extra";import w from"prompts";import{z as y}from"zod";import{controllerJs as f,controllerTs as v,routesJs as h,routesTs as j,testJs as x,testTs as S}from"@express-tool/plugin-resource";import $ from"envinfo";var b={317(e){e.exports=t("child_process")}},k={};function C(e){var t=k[e];if(void 0!==t)return t.exports;var s=k[e]={exports:{}};return b[e](s,s.exports,C),s.exports}C.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return C.d(t,{a:t}),t},C.d=(e,t)=>{for(var s in t)C.o(t,s)&&!C.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},C.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var E={};(()=>{C.d(E,{x:()=>U});var e=JSON.parse('{"UU":"@express-tool/cli","rE":"1.0.0"}');let b=e=>console.log(a.blue("ℹ"),e),k=e=>console.log(a.green("✔"),e),N=e=>console.log(a.yellow("⚠"),e),P=e=>console.log(a.red("✖"),e),R=t("path");var D=C.n(R);async function M(e,t,s,a,o,r){b(`Applying plugin: ${e.name}`);let n=await e.apply(t,r);if(n.dependencies&&(a.dependencies={...a.dependencies,...n.dependencies}),n.devDependencies&&(a.devDependencies={...a.devDependencies,...n.devDependencies}),n.files)for(let e of n.files){let t=D().join(s,"src",e.path);d.ensureDirSync(D().dirname(t)),d.writeFileSync(t,e.content),b(` Created ${e.path}`)}if(n.env)for(let[e,t]of Object.entries(n.env))o.push(`${e}=${t}`);if(n.scripts&&(a.scripts={...a.scripts,...n.scripts}),n.commands)for(let e of n.commands){b(` Running command: ${e}`);try{C(317).execSync(e,{cwd:s,stdio:"inherit"})}catch(t){N(` Command failed: ${e}`)}}return n}async function T(e){let t=D().resolve(process.cwd(),e.projectName);d.existsSync(t)&&(P(`Directory ${e.projectName} already exists.`),process.exit(1)),b(`Creating project in ${t}...`),d.mkdirSync(t);let s=[],a={name:e.projectName,version:"0.0.0",private:!0,type:"module",packageManager:`${e.packageManager}@latest`,scripts:{dev:"ts"===e.language?"tsx watch src/index.ts":"node --watch src/index.js",build:"ts"===e.language?"tsc":void 0,start:"ts"===e.language?"node dist/index.js":"node src/index.js"},dependencies:{express:"latest"},devDependencies:{..."ts"===e.language?{"@types/node":"latest","@types/express":"latest"}:{}}};"rest-swagger"===e.apiType&&(Object.assign(a.dependencies,{"swagger-ui-express":"latest",zod:"latest","@asteasolutions/zod-to-openapi":"latest"}),"ts"===e.language&&Object.assign(a.devDependencies,{"@types/swagger-ui-express":"latest"})),"jwt"===e.auth&&(Object.assign(a.dependencies,{jsonwebtoken:"latest"}),"ts"===e.language&&Object.assign(a.devDependencies,{"@types/jsonwebtoken":"latest"})),"none"!==e.templateEngine&&(Object.assign(a.dependencies,{[e.templateEngine]:"latest"}),"ts"===e.language&&Object.assign(a.devDependencies,{[`@types/${e.templateEngine}`]:"latest"})),d.writeJsonSync(D().join(t,"package.json"),a,{spaces:2});let w=D().join(t,"src");d.mkdirSync(w),e.language;let y={projectRoot:t,projectName:e.projectName,isTs:"ts"===e.language,language:e.language};await M(n,y,t,a,s),await M(l,y,t,a,s),"rest-swagger"===e.apiType&&await M(g,y,t,a,s),"none"!==e.database&&await M(i,y,t,a,s,{database:e.database}),"jwt"===e.auth&&await M(o,y,t,a,[]),"none"!==e.templateEngine&&await M(u,y,t,a,s,{templateEngine:e.templateEngine});let f=s.join("\n")+"\n";d.writeFileSync(D().join(t,".env"),f),d.writeFileSync(D().join(t,".env.example"),f);let v=`import 'dotenv/config';
2
+ import express${"ts"===e.language?", { Request, Response }":""} from 'express';
3
3
  import cors from 'cors';
4
4
  import helmet from 'helmet';
5
5
  import path from 'path';
@@ -39,15 +39,15 @@ app.use(express.static(path.join(__dirname, 'public')));
39
39
 
40
40
  `,"rest-swagger"===e.apiType&&(v+=`app.use('/docs', swaggerRouter);
41
41
  `),"jwt"===e.auth&&(v+=`app.use('/auth', authRouter);
42
- `),v+=`app.get('/', (req, res) => {
42
+ `),v+=`app.get('/', (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
43
43
  ${"none"!==e.templateEngine?`res.render('index', { title: 'Express App', message: 'Hello from ${e.templateEngine.toUpperCase()}!' });`:"res.json({ status: 'ok', timestamp: new Date().toISOString() });"}
44
44
  });
45
45
 
46
- app.get('/health', (req, res) => {
46
+ app.get('/health', (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
47
47
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
48
48
  });
49
49
  `,"jwt"===e.auth&&(v+=`
50
- app.get('/protected', authenticateToken, (req, res) => {
50
+ app.get('/protected', authenticateToken, (req${"ts"===e.language?": Request":""}, res${"ts"===e.language?": Response":""}) => {
51
51
  res.json({ message: 'This is a protected route', user: (req as any).user });
52
52
  });
53
53
  `),v+=`
@@ -55,7 +55,7 @@ app.use(errorHandler);
55
55
 
56
56
  // Export app for testing
57
57
  export { app };
58
- `;let j=`
58
+ `;let h=`
59
59
  const server = app.listen(port, () => {
60
60
  logger.info(\`Server running on http://localhost:\${port}\`);
61
61
  });
@@ -73,17 +73,20 @@ process.on('SIGTERM', shutdown);
73
73
  process.on('SIGINT', shutdown);
74
74
  `;"ts"===e.language?v+=`
75
75
  if (import.meta.url === \`file://\${process.argv[1]}\`) {
76
- ${j}
76
+ ${h}
77
77
  }
78
78
  `:v+=`
79
79
  if (process.argv[1] === import.meta.filename) { // Node 20.11+
80
- ${j}
80
+ ${h}
81
81
  } else if (import.meta.url === \`file://\${process.argv[1]}\`) {
82
- ${j}
82
+ ${h}
83
83
  }
84
- `;let h="ts"===e.language?"index.ts":"index.js";g.writeFileSync(M().join(w,h),v),await O(c,f,t,d,u),await O(p,f,t,d,u),await O(n,f,t,d,u,{packageManager:e.packageManager,database:e.database}),await O(a,f,t,d,u,{packageManager:e.packageManager}),"ts"===e.language&&g.writeJsonSync(M().join(t,"tsconfig.json"),{compilerOptions:{target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",outDir:"./dist",rootDir:"./src",strict:!0,esModuleInterop:!0},include:["src/**/*"]},{spaces:2});let x=`node_modules
84
+ `;let j="ts"===e.language?"index.ts":"index.js";d.writeFileSync(D().join(w,j),v),await M(m,y,t,a,s),await M(c,y,t,a,s),await M(p,y,t,a,s,{packageManager:e.packageManager,database:e.database}),await M(r,y,t,a,s,{packageManager:e.packageManager}),"ts"===e.language&&d.writeJsonSync(D().join(t,"tsconfig.json"),{compilerOptions:{target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",outDir:"./dist",rootDir:"./src",strict:!0,esModuleInterop:!0,skipLibCheck:!0,forceConsistentCasingInFileNames:!0},include:["src/**/*"]},{spaces:2});let x=`node_modules
85
85
  dist
86
86
  .env
87
87
  .DS_Store
88
- `;g.writeFileSync(M().join(t,".gitignore"),x),D(`Project ${e.projectName} created successfully!`)}let L=d.object({projectName:d.string().min(1).regex(/^[a-z0-9-]+$/,"Project name must be kebab-case (lowercase letters, numbers, and hyphens)"),language:d.enum(["ts","js"]),architecture:d.enum(["feature","mvc"]),apiType:d.enum(["rest","rest-swagger"]),database:d.enum(["postgresql","mysql","mongodb","mongodb-prisma","none"]),auth:d.enum(["jwt","none"]),templateEngine:d.enum(["ejs","pug","none"]),packageManager:d.enum(["npm","pnpm","yarn","bun"])});async function I(){return await u([{type:"text",name:"projectName",message:"What is your project name?",initial:"my-express-app",validate:e=>{let t=L.shape.projectName.safeParse(e);return!!t.success||t.error.issues[0].message}},{type:"select",name:"language",message:"Select language",choices:[{title:"TypeScript (Recommended)",value:"ts"},{title:"JavaScript",value:"js"}],initial:0},{type:"select",name:"packageManager",message:"Select package manager",choices:[{title:"pnpm (Recommended)",value:"pnpm"},{title:"npm",value:"npm"},{title:"Yarn",value:"yarn"},{title:"Bun",value:"bun"}],initial:0},{type:"select",name:"architecture",message:"Select architecture",choices:[{title:"Feature-based (Recommended)",value:"feature",description:"Modules grouped by feature (e.g., users, posts)"},{title:"MVC",value:"mvc",description:"Classic Model-View-Controller structure"}],initial:0},{type:"select",name:"apiType",message:"Select API type",choices:[{title:"REST API + Swagger",value:"rest-swagger"},{title:"REST API (Basic)",value:"rest"}],initial:0},{type:"select",name:"database",message:"Select database",choices:[{title:"PostgreSQL (Prisma)",value:"postgresql"},{title:"MySQL (Prisma)",value:"mysql"},{title:"MongoDB (Prisma)",value:"mongodb-prisma"},{title:"MongoDB (Mongoose)",value:"mongodb"},{title:"None",value:"none"}],initial:0},{type:"select",name:"auth",message:"Select authentication",choices:[{title:"JWT (JSON Web Token)",value:"jwt"},{title:"None",value:"none"}],initial:0},{type:"select",name:"templateEngine",message:"Select template engine",choices:[{title:"EJS (Embedded JavaScript)",value:"ejs"},{title:"Pug (Jade)",value:"pug"},{title:"None (API only)",value:"none"}],initial:0}],{onCancel:()=>{T("Operation cancelled"),process.exit(1)}})}let F=new e("init").description("Initialize a new Express.js project").action(async()=>{let e=await I();await R(e)});async function _(e){let t=process.cwd(),s=M().join(t,"package.json");g.existsSync(s)||(T("No package.json found. Are you in the root of the project?"),process.exit(1));let a=g.readJsonSync(s),r=a.devDependencies&&a.devDependencies.typescript,o=r?"ts":"js",n=M().join(t,"src"),i=M().join(n,"controllers"),p=M().join(n,"routes"),l=M().join(t,"test");g.ensureDirSync(i),g.ensureDirSync(p),g.ensureDirSync(l);let c=e.charAt(0).toUpperCase()+e.slice(1),m=M().join(i,`${e.toLowerCase()}.controller.${o}`);g.existsSync(m)?N(`Controller ${m} already exists. Skipping.`):(g.writeFileSync(m,r?f(c):w(c)),E(`Created controller: src/controllers/${e.toLowerCase()}.controller.${o}`));let u=M().join(p,`${e.toLowerCase()}.routes.${o}`);g.existsSync(u)?N(`Route ${u} already exists. Skipping.`):(g.writeFileSync(u,r?v(c):y(c)),E(`Created route: src/routes/${e.toLowerCase()}.routes.${o}`));let d=M().join(l,`${e.toLowerCase()}.test.${o}`);g.existsSync(d)?N(`Test ${d} already exists. Skipping.`):(g.writeFileSync(d,r?h(c):j(c)),E(`Created test: test/${e.toLowerCase()}.test.${o}`)),D(`Feature ${e} generated successfully!`),E(`
89
- Don't forget to register the route in src/index.${o}:`),E(`import { ${e.toLowerCase()}Router } from './routes/${e.toLowerCase()}.routes';`),E(`app.use('/${e.toLowerCase()}s', ${e.toLowerCase()}Router);`)}let J=new e().name("generate").alias("g").description("Generate a new feature (controller, routes, test)").argument("<name>","Name of the feature (e.g. users, blogs)").action(async e=>{await _(e)}),q=new e().name("info").description("Print debugging information about your environment").action(async()=>{console.log(" System:"),await x.run({System:["OS","CPU","Memory","Shell"],Binaries:["Node","Yarn","npm","pnpm"],Utilities:["Git"],IDEs:["VSCode"],Browsers:["Chrome","Edge","Firefox","Safari"],npmPackages:["typescript","express","express-next"]},{console:!0,showNotFound:!0})}),H=b("https");var A=$.n(H);let B=new e().name("upgrade").description("Check for updates").action(async()=>{E("Checking for updates...");let e=k.rE,t=k.UU;try{var s;let a=await (s=t,new Promise(e=>{A().get(`https://registry.npmjs.org/${s}/latest`,t=>{let s="";t.on("data",e=>s+=e),t.on("end",()=>{try{let t=JSON.parse(s);e(t.version)}catch{e(null)}})}).on("error",()=>e(null))}));if(!a)return void N("Could not fetch latest version info.");a!==e?(E(`New version available: ${a} (current: ${e})`),E(`Run 'npm install -g ${t}' to update.`)):D("You are using the latest version.")}catch(e){T("Failed to check for updates.")}}),{rE:U}=k,G=new e;G.name("express-next").description("Production-grade CLI for Express.js applications").version(U),G.hook("preAction",()=>{E("Welcome to express-next CLI")}),G.addCommand(F),G.addCommand(J),G.addCommand(q),G.addCommand(B);var z=C.x;export{z as cli};
88
+ `;d.writeFileSync(D().join(t,".gitignore"),x),d.writeJsonSync(D().join(t,"package.json"),a,{spaces:2}),b("Installing dependencies...");try{let s=(e.packageManager,"install");C(317).execSync(`${e.packageManager} ${s}`,{cwd:t,stdio:"inherit"})}catch(e){N("Failed to install dependencies. Please run install manually.")}k(`Project ${e.projectName} created successfully!`),console.log(`
89
+ Next steps:`),console.log(` cd ${e.projectName}`),console.log(` ${e.packageManager} run dev`),"prisma-postgres"===e.database&&console.log(` ${e.packageManager} run db:init (To setup Prisma Postgres Managed DB)`),console.log(`
90
+ Happy Coding! 🚀
91
+ `)}let O=y.object({projectName:y.string().min(1).regex(/^[a-z0-9-]+$/,"Project name must be kebab-case (lowercase letters, numbers, and hyphens)"),language:y.enum(["ts","js"]),architecture:y.enum(["feature","mvc"]),apiType:y.enum(["rest","rest-swagger"]),database:y.enum(["postgresql","prisma-postgres","mysql","mongodb","none"]),auth:y.enum(["jwt","none"]),templateEngine:y.enum(["ejs","pug","none"]),packageManager:y.enum(["npm","pnpm","yarn","bun"])});async function L(){return await w([{type:"text",name:"projectName",message:"What is your project name?",initial:"my-express-app",validate:e=>{let t=O.shape.projectName.safeParse(e);return!!t.success||t.error.issues[0].message}},{type:"select",name:"language",message:"Select language",choices:[{title:"TypeScript (Recommended)",value:"ts"},{title:"JavaScript",value:"js"}],initial:0},{type:"select",name:"packageManager",message:"Select package manager",choices:[{title:"pnpm (Recommended)",value:"pnpm"},{title:"npm",value:"npm"},{title:"Yarn",value:"yarn"},{title:"Bun",value:"bun"}],initial:0},{type:"select",name:"architecture",message:"Select architecture",choices:[{title:"Feature-based (Recommended)",value:"feature",description:"Modules grouped by feature (e.g., users, posts)"},{title:"MVC",value:"mvc",description:"Classic Model-View-Controller structure"}],initial:0},{type:"select",name:"apiType",message:"Select API type",choices:[{title:"REST API + Swagger",value:"rest-swagger"},{title:"REST API (Basic)",value:"rest"}],initial:0},{type:"select",name:"database",message:"Select database",choices:[{title:"PostgreSQL (Prisma)",value:"postgresql"},{title:"PostgreSQL (Prisma Postgres Managed)",value:"prisma-postgres"},{title:"MySQL (Prisma)",value:"mysql"},{title:"MongoDB (Mongoose)",value:"mongodb"},{title:"None",value:"none"}],initial:0},{type:"select",name:"auth",message:"Select authentication",choices:[{title:"JWT (JSON Web Token)",value:"jwt"},{title:"None",value:"none"}],initial:0},{type:"select",name:"templateEngine",message:"Select template engine",choices:[{title:"EJS (Embedded JavaScript)",value:"ejs"},{title:"Pug (Jade)",value:"pug"},{title:"None (API only)",value:"none"}],initial:0}],{onCancel:()=>{P("Operation cancelled"),process.exit(1)}})}let I=new s("init").description("Initialize a new Express.js project").action(async()=>{let e=await L();await T(e)});async function F(e){let t=process.cwd(),s=D().join(t,"package.json");d.existsSync(s)||(P("No package.json found. Are you in the root of the project?"),process.exit(1));let a=d.readJsonSync(s),o=a.devDependencies&&a.devDependencies.typescript,r=o?"ts":"js",n=D().join(t,"src"),i=D().join(n,"controllers"),p=D().join(n,"routes"),l=D().join(t,"test");d.ensureDirSync(i),d.ensureDirSync(p),d.ensureDirSync(l);let c=e.charAt(0).toUpperCase()+e.slice(1),g=D().join(i,`${e.toLowerCase()}.controller.${r}`);d.existsSync(g)?N(`Controller ${g} already exists. Skipping.`):(d.writeFileSync(g,o?v(c):f(c)),b(`Created controller: src/controllers/${e.toLowerCase()}.controller.${r}`));let m=D().join(p,`${e.toLowerCase()}.routes.${r}`);d.existsSync(m)?N(`Route ${m} already exists. Skipping.`):(d.writeFileSync(m,o?j(c):h(c)),b(`Created route: src/routes/${e.toLowerCase()}.routes.${r}`));let u=D().join(l,`${e.toLowerCase()}.test.${r}`);d.existsSync(u)?N(`Test ${u} already exists. Skipping.`):(d.writeFileSync(u,o?S(c):x(c)),b(`Created test: test/${e.toLowerCase()}.test.${r}`)),k(`Feature ${e} generated successfully!`),b(`
92
+ Don't forget to register the route in src/index.${r}:`),b(`import { ${e.toLowerCase()}Router } from './routes/${e.toLowerCase()}.routes';`),b(`app.use('/${e.toLowerCase()}s', ${e.toLowerCase()}Router);`)}let q=new s().name("generate").alias("g").description("Generate a new feature (controller, routes, test)").argument("<name>","Name of the feature (e.g. users, blogs)").action(async e=>{await F(e)}),_=new s().name("info").description("Print debugging information about your environment").action(async()=>{console.log(" System:"),await $.run({System:["OS","CPU","Memory","Shell"],Binaries:["Node","Yarn","npm","pnpm"],Utilities:["Git"],IDEs:["VSCode"],Browsers:["Chrome","Edge","Firefox","Safari"],npmPackages:["typescript","express","express-tool"]},{console:!0,showNotFound:!0})}),J=t("https");var H=C.n(J);let A=new s().name("upgrade").description("Check for updates").action(async()=>{b("Checking for updates...");let t=e.rE,s=e.UU;try{var a;let e=await (a=s,new Promise(e=>{H().get(`https://registry.npmjs.org/${a}/latest`,t=>{let s="";t.on("data",e=>s+=e),t.on("end",()=>{try{let t=JSON.parse(s);e(t.version)}catch{e(null)}})}).on("error",()=>e(null))}));if(!e)return void N("Could not fetch latest version info.");e!==t?(b(`New version available: ${e} (current: ${t})`),b(`Run 'npm install -g ${s}' to update.`)):k("You are using the latest version.")}catch(e){P("Failed to check for updates.")}}),{rE:B}=e,U=new s;U.name("express-tool").description("Production-grade CLI for Express.js applications").version(B),U.hook("preAction",()=>{b("Welcome to express-tool CLI")}),U.addCommand(I),U.addCommand(q),U.addCommand(_),U.addCommand(A)})();var N=E.x;export{N as cli};
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/utils/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAK3D,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,GAAG,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,aAAa,CAAC,EAAE,GAAG,sDA8CpB"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/utils/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAK3D,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,GAAG,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,aAAa,CAAC,EAAE,GAAG,sDA6DpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@express-tool/cli",
3
- "version": "0.0.1",
3
+ "version": "1.0.0",
4
4
  "description": "Production-grade CLI for Express.js applications",
5
5
  "keywords": [
6
6
  "express",
@@ -19,11 +19,11 @@
19
19
  ],
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+https://github.com/iam-mustak-ak/express-next.git"
22
+ "url": "git+https://github.com/iam-mustak-ak/express-tool.git"
23
23
  },
24
- "homepage": "https://github.com/iam-mustak-ak/express-next",
24
+ "homepage": "https://github.com/iam-mustak-ak/express-tool",
25
25
  "bugs": {
26
- "url": "https://github.com/iam-mustak-ak/express-next/issues"
26
+ "url": "https://github.com/iam-mustak-ak/express-tool/issues"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
@@ -41,18 +41,18 @@
41
41
  "picocolors": "^1.1.1",
42
42
  "prompts": "^2.4.2",
43
43
  "zod": "^4.3.6",
44
- "@express-tool/core": "0.0.1",
45
- "@express-tool/plugin-auth": "0.0.1",
46
- "@express-tool/plugin-swagger": "0.0.1",
47
- "@express-tool/plugin-views": "0.0.1",
48
- "@express-tool/plugin-database": "0.0.1",
49
- "@express-tool/plugin-testing": "0.0.1",
50
- "@express-tool/plugin-common": "0.0.1",
51
- "@express-tool/plugin-middleware": "0.0.1",
52
- "@express-tool/plugin-docker": "0.0.1",
53
- "@express-tool/plugin-quality": "0.0.1",
54
- "@express-tool/plugin-resource": "0.0.1",
55
- "@express-tool/plugin-ci": "0.0.1"
44
+ "@express-tool/core": "1.0.0",
45
+ "@express-tool/plugin-database": "1.0.0",
46
+ "@express-tool/plugin-auth": "1.0.0",
47
+ "@express-tool/plugin-views": "1.0.0",
48
+ "@express-tool/plugin-middleware": "1.0.0",
49
+ "@express-tool/plugin-common": "1.0.0",
50
+ "@express-tool/plugin-swagger": "1.0.0",
51
+ "@express-tool/plugin-testing": "1.0.0",
52
+ "@express-tool/plugin-docker": "1.0.0",
53
+ "@express-tool/plugin-ci": "1.0.0",
54
+ "@express-tool/plugin-quality": "1.0.0",
55
+ "@express-tool/plugin-resource": "1.0.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@rsbuild/core": "^1.7.3",