@express-tool/cli 0.0.1
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/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +90 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.generator.d.ts +2 -0
- package/dist/commands/generate.generator.d.ts.map +1 -0
- package/dist/commands/info.d.ts +3 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.generator.d.ts +3 -0
- package/dist/commands/init.generator.d.ts.map +1 -0
- package/dist/commands/init.prompts.d.ts +41 -0
- package/dist/commands/init.prompts.d.ts.map +1 -0
- package/dist/commands/upgrade.d.ts +3 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/plugin.d.ts +3 -0
- package/dist/utils/plugin.d.ts.map +1 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mustak Ahmed Khan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ๐ Express Next CLI
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/express-next)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](http://makeapullrequest.com)
|
|
8
|
+
|
|
9
|
+
</div>
|
|
10
|
+
|
|
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.
|
|
13
|
+
|
|
14
|
+
## โจ Features
|
|
15
|
+
|
|
16
|
+
- **Language Support**: First-class TypeScript support (recommended) or modern JavaScript (ES Modules).
|
|
17
|
+
- **Architecture**: Choose between **Feature-based** (great for scalability) or Classic **MVC**.
|
|
18
|
+
- **Database Integration**:
|
|
19
|
+
- **Prisma ORM**: PostgreSQL, MySQL, MongoDB.
|
|
20
|
+
- **Mongoose**: Native MongoDB support.
|
|
21
|
+
- **Authentication**: Built-in simple JWT authentication boilerplate.
|
|
22
|
+
- **API Documentation**: Automatic Swagger/OpenAPI options.
|
|
23
|
+
- **Package Managers**: Support for `npm`, `pnpm`, `yarn`, and `bun`.
|
|
24
|
+
- **Production Ready**:
|
|
25
|
+
- ๐ณ Docker & Docker Compose setup included.
|
|
26
|
+
- ๐งช Testing with Vitest + Supertest.
|
|
27
|
+
- ๐งน Linting & Formatting (ESLint + Prettier + Husky).
|
|
28
|
+
- ๐ Structured logging with Pino.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## ๐ฆ Installation
|
|
33
|
+
|
|
34
|
+
Install globally via your preferred package manager:
|
|
35
|
+
|
|
36
|
+
### npm
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g express-next
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### pnpm (Recommended)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add -g express-next
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Yarn
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
yarn global add express-next
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Bun
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bun add -g express-next
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## ๐ Usage
|
|
63
|
+
|
|
64
|
+
### 1. Initialize a New Project
|
|
65
|
+
|
|
66
|
+
The `init` command launches an interactive wizard to configure your new application.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
express-next init
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Interactive Prompts:**
|
|
73
|
+
|
|
74
|
+
1. **Project Name**: Name of your project directory (kebab-case).
|
|
75
|
+
2. **Language**: `TypeScript` (Recommended) or `JavaScript`.
|
|
76
|
+
3. **Architecture**:
|
|
77
|
+
- `Feature-based`: Groups files by domain feature (e.g., `src/modules/users/`).
|
|
78
|
+
- `MVC`: Classic layering (`src/controllers`, `src/routes`, `src/models`).
|
|
79
|
+
4. **API Type**:
|
|
80
|
+
- `REST API + Swagger`: Includes setup for auto-generated API docs.
|
|
81
|
+
- `REST API (Basic)`: Simple setup without documentation tools.
|
|
82
|
+
5. **Database**:
|
|
83
|
+
- `PostgreSQL (Prisma)`
|
|
84
|
+
- `MySQL (Prisma)`
|
|
85
|
+
- `MongoDB (Prisma)`
|
|
86
|
+
- `MongoDB (Mongoose)`
|
|
87
|
+
- `None`
|
|
88
|
+
6. **Package Manager**: Select `npm`, `pnpm`, `yarn`, or `bun`.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### 2. Generate Resources (`generate` or `g`)
|
|
93
|
+
|
|
94
|
+
Quickly scaffold new resources (features) into your existing application. This command respects your project's language (TS/JS).
|
|
95
|
+
|
|
96
|
+
**Syntax:**
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
express-next generate <resource-name>
|
|
100
|
+
# or shorcut
|
|
101
|
+
express-next g <resource-name>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Example:**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
express-next g blogs
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Output:**
|
|
111
|
+
This will create the following files (example for a `blogs` feature):
|
|
112
|
+
|
|
113
|
+
- ๐ `src/controllers/blogs.controller.ts` (CRUD handlers)
|
|
114
|
+
- ๐ฃ๏ธ `src/routes/blogs.routes.ts` (Router definition)
|
|
115
|
+
- ๐งช `test/blogs.test.ts` (Integration tests)
|
|
116
|
+
|
|
117
|
+
**After Generation:**
|
|
118
|
+
The CLI will print instructions on how to register the new route in your `src/index.ts` (or `app.ts`):
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { blogsRouter } from './routes/blogs.routes.js';
|
|
122
|
+
app.use('/blogs', blogsRouter);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 3. Utility Commands
|
|
128
|
+
|
|
129
|
+
#### Check Environment
|
|
130
|
+
|
|
131
|
+
View debugging information about your local environment. useful for reporting issues.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
express-next info
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Update CLI
|
|
138
|
+
|
|
139
|
+
Check for updates or self-update the CLI tool.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
express-next upgrade
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## ๐ Project Structure
|
|
148
|
+
|
|
149
|
+
A typical project created with `express-next` looks like this:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
my-express-app/
|
|
153
|
+
โโโ ๐ณ .dockerignore
|
|
154
|
+
โโโ โ๏ธ .env
|
|
155
|
+
โโโ โ๏ธ .eslintrc.json
|
|
156
|
+
โโโ ๐ .github/ # CI/CD Workflows
|
|
157
|
+
โโโ ๐ .gitignore
|
|
158
|
+
โโโ ๐
.prettierrc
|
|
159
|
+
โโโ ๐ณ docker-compose.yml
|
|
160
|
+
โโโ ๐ณ Dockerfile
|
|
161
|
+
โโโ ๐ฆ package.json
|
|
162
|
+
โโโ ๐ README.md
|
|
163
|
+
โโโ ๐ tsconfig.json # (If TypeScript)
|
|
164
|
+
โโโ ๐งช vitest.config.ts
|
|
165
|
+
โโโ src/
|
|
166
|
+
โ โโโ ๐ controllers/ # Route handlers
|
|
167
|
+
โ โโโ ๐ middleware/ # Custom middleware (auth, validation, error)
|
|
168
|
+
โ โโโ ๐ models/ # Database models (Mongoose schemas)
|
|
169
|
+
โ โโโ ๐ routes/ # Route definitions
|
|
170
|
+
โ โโโ ๐ utils/ # Utility functions and Logger
|
|
171
|
+
โ โโโ ๐ index.ts # Application entry point
|
|
172
|
+
โ โโโ ๐ app.test.ts # App setup tests
|
|
173
|
+
โโโ prisma/ # (If Prisma selected)
|
|
174
|
+
โโโ ๐ schema.prisma
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## ๐ป Local Development
|
|
178
|
+
|
|
179
|
+
If you want to contribute to the project or run it from source, please check out our [Development Guide](./DEVELOPMENT.md).
|
|
180
|
+
|
|
181
|
+
## ๐ค Contributing
|
|
182
|
+
|
|
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).
|
|
184
|
+
|
|
185
|
+
## ๐ License
|
|
186
|
+
|
|
187
|
+
MIT ยฉ Mustak Ahmed Khan
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
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';
|
|
4
|
+
import cors from 'cors';
|
|
5
|
+
import helmet from 'helmet';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import pinoHttp from 'pino-http';
|
|
8
|
+
import { rateLimit } from 'express-rate-limit';
|
|
9
|
+
import { logger } from './utils/logger';
|
|
10
|
+
import { errorHandler } from './middleware/errorHandler';
|
|
11
|
+
${"mongodb"===e.database?"import { connectDB } from './lib/db';":""}
|
|
12
|
+
`;"jwt"===e.auth&&(v+=`import { authRouter } from './routes/auth';
|
|
13
|
+
import { authenticateToken } from './middleware/auth';
|
|
14
|
+
`),"rest-swagger"===e.apiType&&(v+=`import { swaggerRouter } from './docs/index';
|
|
15
|
+
`),v+=`
|
|
16
|
+
const app = express();
|
|
17
|
+
const port = process.env.PORT || 3000;
|
|
18
|
+
|
|
19
|
+
app.use(helmet());
|
|
20
|
+
app.use(cors());
|
|
21
|
+
app.use(express.json());
|
|
22
|
+
app.use(pinoHttp({ logger }));
|
|
23
|
+
|
|
24
|
+
const limiter = rateLimit({
|
|
25
|
+
windowMs: 15 * 60 * 1000,
|
|
26
|
+
limit: 100,
|
|
27
|
+
standardHeaders: 'draft-7',
|
|
28
|
+
legacyHeaders: false,
|
|
29
|
+
});
|
|
30
|
+
app.use(limiter);
|
|
31
|
+
|
|
32
|
+
${"mongodb"===e.database?"connectDB();":""}
|
|
33
|
+
|
|
34
|
+
// View Engine Setup
|
|
35
|
+
${"none"!==e.templateEngine?`
|
|
36
|
+
app.set('views', path.join(__dirname, 'views'));
|
|
37
|
+
app.set('view engine', '${e.templateEngine}');
|
|
38
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
39
|
+
`:""}
|
|
40
|
+
|
|
41
|
+
`,"rest-swagger"===e.apiType&&(v+=`app.use('/docs', swaggerRouter);
|
|
42
|
+
`),"jwt"===e.auth&&(v+=`app.use('/auth', authRouter);
|
|
43
|
+
`),v+=`app.get('/', (req, res) => {
|
|
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
|
+
});
|
|
46
|
+
|
|
47
|
+
app.get('/health', (req, res) => {
|
|
48
|
+
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
49
|
+
});
|
|
50
|
+
`,"jwt"===e.auth&&(v+=`
|
|
51
|
+
app.get('/protected', authenticateToken, (req, res) => {
|
|
52
|
+
res.json({ message: 'This is a protected route', user: (req as any).user });
|
|
53
|
+
});
|
|
54
|
+
`),v+=`
|
|
55
|
+
app.use(errorHandler);
|
|
56
|
+
|
|
57
|
+
// Export app for testing
|
|
58
|
+
export { app };
|
|
59
|
+
`;let j=`
|
|
60
|
+
const server = app.listen(port, () => {
|
|
61
|
+
logger.info(\`Server running on http://localhost:\${port}\`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Graceful Shutdown
|
|
65
|
+
const shutdown = () => {
|
|
66
|
+
logger.info('SIGTERM signal received: closing HTTP server');
|
|
67
|
+
server.close(() => {
|
|
68
|
+
logger.info('HTTP server closed');
|
|
69
|
+
process.exit(0);
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
process.on('SIGTERM', shutdown);
|
|
74
|
+
process.on('SIGINT', shutdown);
|
|
75
|
+
`;"ts"===e.language?v+=`
|
|
76
|
+
if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
77
|
+
${j}
|
|
78
|
+
}
|
|
79
|
+
`:v+=`
|
|
80
|
+
if (process.argv[1] === import.meta.filename) { // Node 20.11+
|
|
81
|
+
${j}
|
|
82
|
+
} else if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
83
|
+
${j}
|
|
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
|
|
86
|
+
dist
|
|
87
|
+
.env
|
|
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);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,QAAQ,SAOjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.generator.d.ts","sourceRoot":"","sources":["../../src/commands/generate.generator.ts"],"names":[],"mappings":"AAgBA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,iBA6DlD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,IAAI,SAmBb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,WAAW,SAKpB,CAAC"}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const initOptionsSchema: z.ZodObject<{
|
|
3
|
+
projectName: z.ZodString;
|
|
4
|
+
language: z.ZodEnum<{
|
|
5
|
+
ts: "ts";
|
|
6
|
+
js: "js";
|
|
7
|
+
}>;
|
|
8
|
+
architecture: z.ZodEnum<{
|
|
9
|
+
feature: "feature";
|
|
10
|
+
mvc: "mvc";
|
|
11
|
+
}>;
|
|
12
|
+
apiType: z.ZodEnum<{
|
|
13
|
+
rest: "rest";
|
|
14
|
+
"rest-swagger": "rest-swagger";
|
|
15
|
+
}>;
|
|
16
|
+
database: z.ZodEnum<{
|
|
17
|
+
postgresql: "postgresql";
|
|
18
|
+
mysql: "mysql";
|
|
19
|
+
mongodb: "mongodb";
|
|
20
|
+
"mongodb-prisma": "mongodb-prisma";
|
|
21
|
+
none: "none";
|
|
22
|
+
}>;
|
|
23
|
+
auth: z.ZodEnum<{
|
|
24
|
+
none: "none";
|
|
25
|
+
jwt: "jwt";
|
|
26
|
+
}>;
|
|
27
|
+
templateEngine: z.ZodEnum<{
|
|
28
|
+
none: "none";
|
|
29
|
+
ejs: "ejs";
|
|
30
|
+
pug: "pug";
|
|
31
|
+
}>;
|
|
32
|
+
packageManager: z.ZodEnum<{
|
|
33
|
+
npm: "npm";
|
|
34
|
+
pnpm: "pnpm";
|
|
35
|
+
yarn: "yarn";
|
|
36
|
+
bun: "bun";
|
|
37
|
+
}>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
export type InitOptions = z.infer<typeof initOptionsSchema>;
|
|
40
|
+
export declare function promptInitOptions(): Promise<InitOptions>;
|
|
41
|
+
//# sourceMappingURL=init.prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.prompts.d.ts","sourceRoot":"","sources":["../../src/commands/init.prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAe5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC,CAuG9D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,OAAO,SAwBhB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,GAAG,SAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
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';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
import helmet from 'helmet';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import pinoHttp from 'pino-http';
|
|
7
|
+
import { rateLimit } from 'express-rate-limit';
|
|
8
|
+
import { logger } from './utils/logger';
|
|
9
|
+
import { errorHandler } from './middleware/errorHandler';
|
|
10
|
+
${"mongodb"===e.database?"import { connectDB } from './lib/db';":""}
|
|
11
|
+
`;"jwt"===e.auth&&(v+=`import { authRouter } from './routes/auth';
|
|
12
|
+
import { authenticateToken } from './middleware/auth';
|
|
13
|
+
`),"rest-swagger"===e.apiType&&(v+=`import { swaggerRouter } from './docs/index';
|
|
14
|
+
`),v+=`
|
|
15
|
+
const app = express();
|
|
16
|
+
const port = process.env.PORT || 3000;
|
|
17
|
+
|
|
18
|
+
app.use(helmet());
|
|
19
|
+
app.use(cors());
|
|
20
|
+
app.use(express.json());
|
|
21
|
+
app.use(pinoHttp({ logger }));
|
|
22
|
+
|
|
23
|
+
const limiter = rateLimit({
|
|
24
|
+
windowMs: 15 * 60 * 1000,
|
|
25
|
+
limit: 100,
|
|
26
|
+
standardHeaders: 'draft-7',
|
|
27
|
+
legacyHeaders: false,
|
|
28
|
+
});
|
|
29
|
+
app.use(limiter);
|
|
30
|
+
|
|
31
|
+
${"mongodb"===e.database?"connectDB();":""}
|
|
32
|
+
|
|
33
|
+
// View Engine Setup
|
|
34
|
+
${"none"!==e.templateEngine?`
|
|
35
|
+
app.set('views', path.join(__dirname, 'views'));
|
|
36
|
+
app.set('view engine', '${e.templateEngine}');
|
|
37
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
38
|
+
`:""}
|
|
39
|
+
|
|
40
|
+
`,"rest-swagger"===e.apiType&&(v+=`app.use('/docs', swaggerRouter);
|
|
41
|
+
`),"jwt"===e.auth&&(v+=`app.use('/auth', authRouter);
|
|
42
|
+
`),v+=`app.get('/', (req, res) => {
|
|
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
|
+
});
|
|
45
|
+
|
|
46
|
+
app.get('/health', (req, res) => {
|
|
47
|
+
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
48
|
+
});
|
|
49
|
+
`,"jwt"===e.auth&&(v+=`
|
|
50
|
+
app.get('/protected', authenticateToken, (req, res) => {
|
|
51
|
+
res.json({ message: 'This is a protected route', user: (req as any).user });
|
|
52
|
+
});
|
|
53
|
+
`),v+=`
|
|
54
|
+
app.use(errorHandler);
|
|
55
|
+
|
|
56
|
+
// Export app for testing
|
|
57
|
+
export { app };
|
|
58
|
+
`;let j=`
|
|
59
|
+
const server = app.listen(port, () => {
|
|
60
|
+
logger.info(\`Server running on http://localhost:\${port}\`);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Graceful Shutdown
|
|
64
|
+
const shutdown = () => {
|
|
65
|
+
logger.info('SIGTERM signal received: closing HTTP server');
|
|
66
|
+
server.close(() => {
|
|
67
|
+
logger.info('HTTP server closed');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
process.on('SIGTERM', shutdown);
|
|
73
|
+
process.on('SIGINT', shutdown);
|
|
74
|
+
`;"ts"===e.language?v+=`
|
|
75
|
+
if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
76
|
+
${j}
|
|
77
|
+
}
|
|
78
|
+
`:v+=`
|
|
79
|
+
if (process.argv[1] === import.meta.filename) { // Node 20.11+
|
|
80
|
+
${j}
|
|
81
|
+
} else if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
82
|
+
${j}
|
|
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
|
|
85
|
+
dist
|
|
86
|
+
.env
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;gBACL,MAAM;mBACH,MAAM;gBACT,MAAM;iBACL,MAAM;CACpB,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Plugin, PluginContext } from '@express-tool/core';
|
|
2
|
+
export declare function executePlugin(plugin: Plugin, context: PluginContext, targetDir: string, packageJson: any, envVars: string[], pluginOptions?: any): Promise<import("@express-tool/core").PluginAction>;
|
|
3
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@express-tool/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Production-grade CLI for Express.js applications",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"express",
|
|
7
|
+
"cli",
|
|
8
|
+
"generator",
|
|
9
|
+
"scaffold",
|
|
10
|
+
"typescript",
|
|
11
|
+
"prisma",
|
|
12
|
+
"mongodb"
|
|
13
|
+
],
|
|
14
|
+
"author": "Mustak Ahmed Khan",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/iam-mustak-ak/express-next.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/iam-mustak-ak/express-next",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/iam-mustak-ak/express-next/issues"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"type": "module",
|
|
32
|
+
"main": "dist/index.js",
|
|
33
|
+
"types": "dist/index.d.ts",
|
|
34
|
+
"bin": {
|
|
35
|
+
"express-tool": "./dist/bin.js"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"commander": "^14.0.3",
|
|
39
|
+
"envinfo": "^7.21.0",
|
|
40
|
+
"fs-extra": "^11.3.3",
|
|
41
|
+
"picocolors": "^1.1.1",
|
|
42
|
+
"prompts": "^2.4.2",
|
|
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"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@rsbuild/core": "^1.7.3",
|
|
59
|
+
"@rsbuild/plugin-type-check": "^1.3.3",
|
|
60
|
+
"@types/envinfo": "^7.8.4",
|
|
61
|
+
"@types/fs-extra": "^11.0.4",
|
|
62
|
+
"@types/node": "^25.2.1",
|
|
63
|
+
"@types/prompts": "^2.4.9",
|
|
64
|
+
"eslint": "^8.57.1",
|
|
65
|
+
"typescript": "^5.9.3"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "rsbuild build && tsc -b --force --emitDeclarationOnly",
|
|
69
|
+
"dev": "rsbuild build --watch",
|
|
70
|
+
"start": "node dist/bin.js",
|
|
71
|
+
"lint": "eslint . --max-warnings 0",
|
|
72
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
73
|
+
}
|
|
74
|
+
}
|