@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 +39 -15
- package/dist/bin.js +15 -12
- package/dist/commands/init.generator.d.ts.map +1 -1
- package/dist/commands/init.prompts.d.ts +1 -1
- package/dist/index.js +15 -12
- package/dist/utils/plugin.d.ts.map +1 -1
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
# 🚀 Express
|
|
3
|
+
# 🚀 Express Tool CLI
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@express-tool/cli)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](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-
|
|
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-
|
|
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-
|
|
45
|
+
pnpm add -g @express-tool/cli
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### Yarn
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
yarn global add express-
|
|
51
|
+
yarn global add @express-tool/cli
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
### Bun
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
bun add -g express-
|
|
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-
|
|
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-
|
|
123
|
+
express-tool generate <resource-name>
|
|
100
124
|
# or shorcut
|
|
101
|
-
express-
|
|
125
|
+
express-tool g <resource-name>
|
|
102
126
|
```
|
|
103
127
|
|
|
104
128
|
**Example:**
|
|
105
129
|
|
|
106
130
|
```bash
|
|
107
|
-
express-
|
|
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-
|
|
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-
|
|
166
|
+
express-tool upgrade
|
|
143
167
|
```
|
|
144
168
|
|
|
145
169
|
---
|
|
146
170
|
|
|
147
171
|
## 📂 Project Structure
|
|
148
172
|
|
|
149
|
-
A typical project created with
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
${
|
|
77
|
+
${h}
|
|
78
78
|
}
|
|
79
79
|
`:v+=`
|
|
80
80
|
if (process.argv[1] === import.meta.filename) { // Node 20.11+
|
|
81
|
-
${
|
|
81
|
+
${h}
|
|
82
82
|
} else if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
83
|
-
${
|
|
83
|
+
${h}
|
|
84
84
|
}
|
|
85
|
-
`;let
|
|
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),
|
|
90
|
-
|
|
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,
|
|
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{
|
|
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
|
|
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
|
-
${
|
|
76
|
+
${h}
|
|
77
77
|
}
|
|
78
78
|
`:v+=`
|
|
79
79
|
if (process.argv[1] === import.meta.filename) { // Node 20.11+
|
|
80
|
-
${
|
|
80
|
+
${h}
|
|
81
81
|
} else if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
82
|
-
${
|
|
82
|
+
${h}
|
|
83
83
|
}
|
|
84
|
-
`;let
|
|
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
|
-
`;
|
|
89
|
-
|
|
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,
|
|
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
|
|
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-
|
|
22
|
+
"url": "git+https://github.com/iam-mustak-ak/express-tool.git"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.com/iam-mustak-ak/express-
|
|
24
|
+
"homepage": "https://github.com/iam-mustak-ak/express-tool",
|
|
25
25
|
"bugs": {
|
|
26
|
-
"url": "https://github.com/iam-mustak-ak/express-
|
|
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
|
|
45
|
-
"@express-tool/plugin-
|
|
46
|
-
"@express-tool/plugin-
|
|
47
|
-
"@express-tool/plugin-views": "0.0
|
|
48
|
-
"@express-tool/plugin-
|
|
49
|
-
"@express-tool/plugin-
|
|
50
|
-
"@express-tool/plugin-
|
|
51
|
-
"@express-tool/plugin-
|
|
52
|
-
"@express-tool/plugin-docker": "0.0
|
|
53
|
-
"@express-tool/plugin-
|
|
54
|
-
"@express-tool/plugin-
|
|
55
|
-
"@express-tool/plugin-
|
|
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",
|