@diagramers/cli 1.0.16 → 1.0.17
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 +112 -8
- package/dist/commands/api.d.ts.map +1 -1
- package/dist/commands/api.js +16 -0
- package/dist/commands/api.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/table-generator.d.ts +2 -0
- package/dist/services/table-generator.d.ts.map +1 -0
- package/dist/services/table-generator.js +137 -0
- package/dist/services/table-generator.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/api.ts +16 -0
- package/src/index.ts +1 -0
- package/src/services/table-generator.ts +114 -0
package/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# @diagramers/cli
|
2
2
|
|
3
|
-
Command-line tools for managing Diagramers projects.
|
3
|
+
Command-line tools for managing Diagramers projects with comprehensive API development features.
|
4
4
|
|
5
5
|
## 🚀 Installation
|
6
6
|
|
@@ -55,6 +55,78 @@ diagramers extend --feature cron
|
|
55
55
|
diagramers extend --feature audit
|
56
56
|
```
|
57
57
|
|
58
|
+
### API-Specific Commands
|
59
|
+
|
60
|
+
The CLI provides powerful commands specifically for API development:
|
61
|
+
|
62
|
+
#### Generate Full Module
|
63
|
+
Creates a complete CRUD module with entity, schema, service, controller, and routes:
|
64
|
+
|
65
|
+
```bash
|
66
|
+
# Generate a complete product module
|
67
|
+
diagramers api generate:module product
|
68
|
+
|
69
|
+
# Generate a user profile module
|
70
|
+
diagramers api generate:module user_profile
|
71
|
+
```
|
72
|
+
|
73
|
+
**What it creates:**
|
74
|
+
- 📝 Entity interface (`src/entities/product.ts`)
|
75
|
+
- 📋 Mongoose schema (`src/schemas/product.ts`)
|
76
|
+
- 🔧 Service layer (`src/services/product-service.ts`)
|
77
|
+
- 🎮 Controller (`src/controllers/product-controller.ts`)
|
78
|
+
- 🛣️ Routes (`src/routes/product-routes.ts`)
|
79
|
+
- 🔄 Updates `dbcontext.ts` and `routes/index.ts`
|
80
|
+
|
81
|
+
#### Generate Database Table
|
82
|
+
Creates only the database layer (entity and schema) without API endpoints:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
# Generate a category table
|
86
|
+
diagramers api generate:table category
|
87
|
+
|
88
|
+
# Generate a settings table
|
89
|
+
diagramers api generate:table app_settings
|
90
|
+
```
|
91
|
+
|
92
|
+
**What it creates:**
|
93
|
+
- 📝 Entity interface (`src/entities/category.ts`)
|
94
|
+
- 📋 Mongoose schema (`src/schemas/category.ts`)
|
95
|
+
- 🔄 Updates `dbcontext.ts`
|
96
|
+
|
97
|
+
#### Process Template
|
98
|
+
Customize your API project template with a new name:
|
99
|
+
|
100
|
+
```bash
|
101
|
+
# Process template for a new project
|
102
|
+
diagramers api process:template my-custom-api
|
103
|
+
```
|
104
|
+
|
105
|
+
**What it updates:**
|
106
|
+
- 📦 Package.json name and description
|
107
|
+
- 📄 README.md title and description
|
108
|
+
- ⚙️ Configuration files (development, staging, production)
|
109
|
+
- 🗄️ Database names in config files
|
110
|
+
- 📄 Creates `.env.example` template
|
111
|
+
|
112
|
+
## 🎯 Use Cases
|
113
|
+
|
114
|
+
### When to use `generate:module`:
|
115
|
+
- Building full CRUD APIs
|
116
|
+
- Creating complete feature modules
|
117
|
+
- When you need both database and API endpoints
|
118
|
+
|
119
|
+
### When to use `generate:table`:
|
120
|
+
- Adding database tables without API endpoints
|
121
|
+
- Creating lookup/reference tables
|
122
|
+
- Building data models for internal use
|
123
|
+
- When you only need the database layer
|
124
|
+
|
125
|
+
### When to use `process:template`:
|
126
|
+
- Customizing a new API project
|
127
|
+
- Setting up project-specific configurations
|
128
|
+
- Preparing for deployment with custom names
|
129
|
+
|
58
130
|
## 🔧 Development
|
59
131
|
|
60
132
|
```bash
|
@@ -68,6 +140,9 @@ npm install
|
|
68
140
|
# Build the CLI
|
69
141
|
npm run build
|
70
142
|
|
143
|
+
# Run in development mode
|
144
|
+
npm run dev
|
145
|
+
|
71
146
|
# Link locally
|
72
147
|
npm link
|
73
148
|
|
@@ -75,16 +150,45 @@ npm link
|
|
75
150
|
diagramers --help
|
76
151
|
```
|
77
152
|
|
78
|
-
## 📚
|
153
|
+
## 📚 Examples
|
79
154
|
|
80
|
-
|
155
|
+
### Complete API Development Workflow
|
156
|
+
|
157
|
+
```bash
|
158
|
+
# 1. Initialize a new API project
|
159
|
+
diagramers init api my-ecommerce-api
|
81
160
|
|
82
|
-
|
161
|
+
# 2. Navigate to the project
|
162
|
+
cd my-ecommerce-api
|
83
163
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
164
|
+
# 3. Generate full modules for main entities
|
165
|
+
diagramers api generate:module product
|
166
|
+
diagramers api generate:module user
|
167
|
+
diagramers api generate:module order
|
168
|
+
|
169
|
+
# 4. Generate tables for supporting data
|
170
|
+
diagramers api generate:table category
|
171
|
+
diagramers api generate:table brand
|
172
|
+
diagramers api generate:table shipping_method
|
173
|
+
|
174
|
+
# 5. Process template for production
|
175
|
+
diagramers api process:template ecommerce-production
|
176
|
+
```
|
177
|
+
|
178
|
+
## 🛠️ Project Structure
|
179
|
+
|
180
|
+
After using the CLI, your API project will have:
|
181
|
+
|
182
|
+
```
|
183
|
+
src/
|
184
|
+
├── entities/ # TypeScript interfaces
|
185
|
+
├── schemas/ # Mongoose schemas
|
186
|
+
├── services/ # Business logic
|
187
|
+
├── controllers/ # Request handlers
|
188
|
+
├── routes/ # API endpoints
|
189
|
+
├── helpers/ # Utilities
|
190
|
+
└── config/ # Environment configs
|
191
|
+
```
|
88
192
|
|
89
193
|
## 📄 License
|
90
194
|
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,WAmD1C"}
|
package/dist/commands/api.js
CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.apiCommand = apiCommand;
|
7
7
|
const api_generator_1 = require("../services/api-generator");
|
8
|
+
const table_generator_1 = require("../services/table-generator");
|
8
9
|
const template_processor_1 = require("../services/template-processor");
|
9
10
|
const chalk_1 = __importDefault(require("chalk"));
|
10
11
|
function apiCommand(program) {
|
@@ -41,6 +42,21 @@ function apiCommand(program) {
|
|
41
42
|
process.exit(1);
|
42
43
|
}
|
43
44
|
});
|
45
|
+
// Generate table command
|
46
|
+
api
|
47
|
+
.command('generate:table <name>')
|
48
|
+
.description('Generate a new database table with entity and schema only')
|
49
|
+
.action(async (name) => {
|
50
|
+
try {
|
51
|
+
console.log(chalk_1.default.blue(`🚀 Generating table: ${name}`));
|
52
|
+
await (0, table_generator_1.generateTable)(name);
|
53
|
+
console.log(chalk_1.default.green(`✅ Table '${name}' generated successfully!`));
|
54
|
+
}
|
55
|
+
catch (error) {
|
56
|
+
console.error(chalk_1.default.red(`❌ Error generating table: ${error.message}`));
|
57
|
+
process.exit(1);
|
58
|
+
}
|
59
|
+
});
|
44
60
|
return api;
|
45
61
|
}
|
46
62
|
//# sourceMappingURL=api.js.map
|
package/dist/commands/api.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":";;;;;
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":";;;;;AAMA,gCAmDC;AAxDD,6DAA2D;AAC3D,iEAA4D;AAC5D,uEAAiE;AACjE,kDAA0B;AAE1B,SAAgB,UAAU,CAAC,OAAgB;IACzC,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,+CAA+C,CAAC,CAAC;IAEhE,0BAA0B;IAC1B,GAAG;SACA,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,4EAA4E,CAAC;SACzF,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;YACzD,MAAM,IAAA,8BAAc,EAAC,IAAI,CAAC,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,aAAa,IAAI,2BAA2B,CAAC,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,2BAA2B;IAC3B,GAAG;SACA,OAAO,CAAC,yBAAyB,CAAC;SAClC,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,uCAAuC,IAAI,EAAE,CAAC,CAAC,CAAC;YACvE,MAAM,IAAA,oCAAe,EAAC,IAAI,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,wCAAwC,IAAI,IAAI,CAAC,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,gCAAgC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,yBAAyB;IACzB,GAAG;SACA,OAAO,CAAC,uBAAuB,CAAC;SAChC,WAAW,CAAC,2DAA2D,CAAC;SACxE,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,MAAM,IAAA,+BAAa,EAAC,IAAI,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,YAAY,IAAI,2BAA2B,CAAC,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAClD,wCAA4C;AAG5C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,eAAe;AACf,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;AACrB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,gBAAU,EAAC,OAAO,CAAC,CAAC;AAEpB,gBAAgB;AAChB,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAClD,wCAA4C;AAG5C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,eAAe;AACf,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;AACrB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,gBAAU,EAAC,OAAO,CAAC,CAAC;AAEpB,gBAAgB;AAChB,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;;;;;;;;;CAS5B,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB,uCAAuC;AACvC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"table-generator.d.ts","sourceRoot":"","sources":["../../src/services/table-generator.ts"],"names":[],"mappings":"AAGA,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCpE"}
|
@@ -0,0 +1,137 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
19
|
+
var ownKeys = function(o) {
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
21
|
+
var ar = [];
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
23
|
+
return ar;
|
24
|
+
};
|
25
|
+
return ownKeys(o);
|
26
|
+
};
|
27
|
+
return function (mod) {
|
28
|
+
if (mod && mod.__esModule) return mod;
|
29
|
+
var result = {};
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
31
|
+
__setModuleDefault(result, mod);
|
32
|
+
return result;
|
33
|
+
};
|
34
|
+
})();
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
36
|
+
exports.generateTable = generateTable;
|
37
|
+
const fs = __importStar(require("fs"));
|
38
|
+
const path = __importStar(require("path"));
|
39
|
+
async function generateTable(tableName) {
|
40
|
+
// Validate table name
|
41
|
+
if (!tableName || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(tableName)) {
|
42
|
+
throw new Error('Invalid table name. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
|
43
|
+
}
|
44
|
+
const tableNameCapitalized = tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
45
|
+
const currentDir = process.cwd();
|
46
|
+
// Check for required API project structure
|
47
|
+
const requiredDirs = [
|
48
|
+
'src/entities',
|
49
|
+
'src/schemas'
|
50
|
+
];
|
51
|
+
const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
|
52
|
+
if (missingDirs.length > 0) {
|
53
|
+
throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
|
54
|
+
}
|
55
|
+
console.log('📝 Creating entity...');
|
56
|
+
const entityContent = generateEntityContent(tableName, tableNameCapitalized);
|
57
|
+
fs.writeFileSync(path.join(currentDir, 'src/entities', `${tableName}.ts`), entityContent);
|
58
|
+
console.log('📋 Creating schema...');
|
59
|
+
const schemaContent = generateSchemaContent(tableName, tableNameCapitalized);
|
60
|
+
fs.writeFileSync(path.join(currentDir, 'src/schemas', `${tableName}.ts`), schemaContent);
|
61
|
+
// Update dbcontext to include the new entity
|
62
|
+
updateDbContext(currentDir, tableName, tableNameCapitalized);
|
63
|
+
console.log('✅ Table generation completed!');
|
64
|
+
console.log(`📊 Entity: src/entities/${tableName}.ts`);
|
65
|
+
console.log(`📋 Schema: src/schemas/${tableName}.ts`);
|
66
|
+
console.log('🔄 dbcontext.ts updated');
|
67
|
+
}
|
68
|
+
function generateEntityContent(tableName, tableNameCapitalized) {
|
69
|
+
return `import * as mongoose from 'mongoose';
|
70
|
+
import { ObjectId } from "bson";
|
71
|
+
|
72
|
+
export interface I${tableNameCapitalized} extends mongoose.Document {
|
73
|
+
_id: ObjectId,
|
74
|
+
name: string,
|
75
|
+
description?: string,
|
76
|
+
status: number,
|
77
|
+
createdAt: Date,
|
78
|
+
updatedAt: Date
|
79
|
+
}`;
|
80
|
+
}
|
81
|
+
function generateSchemaContent(tableName, tableNameCapitalized) {
|
82
|
+
return `import * as mongoose from 'mongoose';
|
83
|
+
import { I${tableNameCapitalized} } from '../entities/${tableName}';
|
84
|
+
|
85
|
+
export const ${tableName}Schema = new mongoose.Schema(
|
86
|
+
{
|
87
|
+
name: {
|
88
|
+
type: mongoose.SchemaTypes.String,
|
89
|
+
required: true,
|
90
|
+
},
|
91
|
+
description: {
|
92
|
+
type: mongoose.SchemaTypes.String,
|
93
|
+
required: false,
|
94
|
+
},
|
95
|
+
status: {
|
96
|
+
type: mongoose.SchemaTypes.Number,
|
97
|
+
default: 1,
|
98
|
+
}
|
99
|
+
},
|
100
|
+
{ timestamps: true, suppressReservedKeysWarning: true },
|
101
|
+
);
|
102
|
+
|
103
|
+
export const ${tableNameCapitalized}Entity = mongoose.model<I${tableNameCapitalized}>('${tableName}', ${tableName}Schema);`;
|
104
|
+
}
|
105
|
+
function updateDbContext(currentDir, tableName, tableNameCapitalized) {
|
106
|
+
const dbcontextPath = path.join(currentDir, 'src/helpers/dbcontext.ts');
|
107
|
+
if (!fs.existsSync(dbcontextPath)) {
|
108
|
+
console.log('⚠️ dbcontext.ts not found, skipping dbcontext update');
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
let dbcontextContent = fs.readFileSync(dbcontextPath, 'utf8');
|
112
|
+
// Add import
|
113
|
+
const importStatement = `import { ${tableNameCapitalized}Entity } from '../schemas/${tableName}';`;
|
114
|
+
if (!dbcontextContent.includes(importStatement)) {
|
115
|
+
// Find the last import statement and add after it
|
116
|
+
const importRegex = /import.*from.*['"];?\s*$/gm;
|
117
|
+
const matches = [...dbcontextContent.matchAll(importRegex)];
|
118
|
+
if (matches.length > 0) {
|
119
|
+
const lastImport = matches[matches.length - 1];
|
120
|
+
const insertIndex = lastImport.index + lastImport[0].length;
|
121
|
+
dbcontextContent = dbcontextContent.slice(0, insertIndex) + '\n' + importStatement + dbcontextContent.slice(insertIndex);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
// Add to dbcontext object
|
125
|
+
const dbcontextObjectRegex = /export\s+default\s*\{([^}]*)\}/s;
|
126
|
+
const match = dbcontextContent.match(dbcontextObjectRegex);
|
127
|
+
if (match) {
|
128
|
+
const objectContent = match[1];
|
129
|
+
if (!objectContent.includes(`${tableNameCapitalized}Entity`)) {
|
130
|
+
const newObjectContent = objectContent.trim() + `,\n ${tableNameCapitalized}Entity`;
|
131
|
+
dbcontextContent = dbcontextContent.replace(dbcontextObjectRegex, `export default {$1${newObjectContent}\n}`);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
fs.writeFileSync(dbcontextPath, dbcontextContent);
|
135
|
+
console.log('📊 Updated dbcontext.ts');
|
136
|
+
}
|
137
|
+
//# sourceMappingURL=table-generator.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"table-generator.js","sourceRoot":"","sources":["../../src/services/table-generator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/commands/api.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Command } from 'commander';
|
2
2
|
import { generateModule } from '../services/api-generator';
|
3
|
+
import { generateTable } from '../services/table-generator';
|
3
4
|
import { processTemplate } from '../services/template-processor';
|
4
5
|
import chalk from 'chalk';
|
5
6
|
|
@@ -38,5 +39,20 @@ export function apiCommand(program: Command) {
|
|
38
39
|
}
|
39
40
|
});
|
40
41
|
|
42
|
+
// Generate table command
|
43
|
+
api
|
44
|
+
.command('generate:table <name>')
|
45
|
+
.description('Generate a new database table with entity and schema only')
|
46
|
+
.action(async (name: string) => {
|
47
|
+
try {
|
48
|
+
console.log(chalk.blue(`🚀 Generating table: ${name}`));
|
49
|
+
await generateTable(name);
|
50
|
+
console.log(chalk.green(`✅ Table '${name}' generated successfully!`));
|
51
|
+
} catch (error: any) {
|
52
|
+
console.error(chalk.red(`❌ Error generating table: ${error.message}`));
|
53
|
+
process.exit(1);
|
54
|
+
}
|
55
|
+
});
|
56
|
+
|
41
57
|
return api;
|
42
58
|
}
|
package/src/index.ts
CHANGED
@@ -0,0 +1,114 @@
|
|
1
|
+
import * as fs from 'fs';
|
2
|
+
import * as path from 'path';
|
3
|
+
|
4
|
+
export async function generateTable(tableName: string): Promise<void> {
|
5
|
+
// Validate table name
|
6
|
+
if (!tableName || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(tableName)) {
|
7
|
+
throw new Error('Invalid table name. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
|
8
|
+
}
|
9
|
+
|
10
|
+
const tableNameCapitalized = tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
11
|
+
const currentDir = process.cwd();
|
12
|
+
|
13
|
+
// Check for required API project structure
|
14
|
+
const requiredDirs = [
|
15
|
+
'src/entities',
|
16
|
+
'src/schemas'
|
17
|
+
];
|
18
|
+
const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
|
19
|
+
if (missingDirs.length > 0) {
|
20
|
+
throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
|
21
|
+
}
|
22
|
+
|
23
|
+
console.log('📝 Creating entity...');
|
24
|
+
const entityContent = generateEntityContent(tableName, tableNameCapitalized);
|
25
|
+
fs.writeFileSync(path.join(currentDir, 'src/entities', `${tableName}.ts`), entityContent);
|
26
|
+
|
27
|
+
console.log('📋 Creating schema...');
|
28
|
+
const schemaContent = generateSchemaContent(tableName, tableNameCapitalized);
|
29
|
+
fs.writeFileSync(path.join(currentDir, 'src/schemas', `${tableName}.ts`), schemaContent);
|
30
|
+
|
31
|
+
// Update dbcontext to include the new entity
|
32
|
+
updateDbContext(currentDir, tableName, tableNameCapitalized);
|
33
|
+
|
34
|
+
console.log('✅ Table generation completed!');
|
35
|
+
console.log(`📊 Entity: src/entities/${tableName}.ts`);
|
36
|
+
console.log(`📋 Schema: src/schemas/${tableName}.ts`);
|
37
|
+
console.log('🔄 dbcontext.ts updated');
|
38
|
+
}
|
39
|
+
|
40
|
+
function generateEntityContent(tableName: string, tableNameCapitalized: string): string {
|
41
|
+
return `import * as mongoose from 'mongoose';
|
42
|
+
import { ObjectId } from "bson";
|
43
|
+
|
44
|
+
export interface I${tableNameCapitalized} extends mongoose.Document {
|
45
|
+
_id: ObjectId,
|
46
|
+
name: string,
|
47
|
+
description?: string,
|
48
|
+
status: number,
|
49
|
+
createdAt: Date,
|
50
|
+
updatedAt: Date
|
51
|
+
}`;
|
52
|
+
}
|
53
|
+
|
54
|
+
function generateSchemaContent(tableName: string, tableNameCapitalized: string): string {
|
55
|
+
return `import * as mongoose from 'mongoose';
|
56
|
+
import { I${tableNameCapitalized} } from '../entities/${tableName}';
|
57
|
+
|
58
|
+
export const ${tableName}Schema = new mongoose.Schema(
|
59
|
+
{
|
60
|
+
name: {
|
61
|
+
type: mongoose.SchemaTypes.String,
|
62
|
+
required: true,
|
63
|
+
},
|
64
|
+
description: {
|
65
|
+
type: mongoose.SchemaTypes.String,
|
66
|
+
required: false,
|
67
|
+
},
|
68
|
+
status: {
|
69
|
+
type: mongoose.SchemaTypes.Number,
|
70
|
+
default: 1,
|
71
|
+
}
|
72
|
+
},
|
73
|
+
{ timestamps: true, suppressReservedKeysWarning: true },
|
74
|
+
);
|
75
|
+
|
76
|
+
export const ${tableNameCapitalized}Entity = mongoose.model<I${tableNameCapitalized}>('${tableName}', ${tableName}Schema);`;
|
77
|
+
}
|
78
|
+
|
79
|
+
function updateDbContext(currentDir: string, tableName: string, tableNameCapitalized: string): void {
|
80
|
+
const dbcontextPath = path.join(currentDir, 'src/helpers/dbcontext.ts');
|
81
|
+
if (!fs.existsSync(dbcontextPath)) {
|
82
|
+
console.log('⚠️ dbcontext.ts not found, skipping dbcontext update');
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
|
86
|
+
let dbcontextContent = fs.readFileSync(dbcontextPath, 'utf8');
|
87
|
+
|
88
|
+
// Add import
|
89
|
+
const importStatement = `import { ${tableNameCapitalized}Entity } from '../schemas/${tableName}';`;
|
90
|
+
if (!dbcontextContent.includes(importStatement)) {
|
91
|
+
// Find the last import statement and add after it
|
92
|
+
const importRegex = /import.*from.*['"];?\s*$/gm;
|
93
|
+
const matches = [...dbcontextContent.matchAll(importRegex)];
|
94
|
+
if (matches.length > 0) {
|
95
|
+
const lastImport = matches[matches.length - 1];
|
96
|
+
const insertIndex = lastImport.index! + lastImport[0].length;
|
97
|
+
dbcontextContent = dbcontextContent.slice(0, insertIndex) + '\n' + importStatement + dbcontextContent.slice(insertIndex);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
// Add to dbcontext object
|
102
|
+
const dbcontextObjectRegex = /export\s+default\s*\{([^}]*)\}/s;
|
103
|
+
const match = dbcontextContent.match(dbcontextObjectRegex);
|
104
|
+
if (match) {
|
105
|
+
const objectContent = match[1];
|
106
|
+
if (!objectContent.includes(`${tableNameCapitalized}Entity`)) {
|
107
|
+
const newObjectContent = objectContent.trim() + `,\n ${tableNameCapitalized}Entity`;
|
108
|
+
dbcontextContent = dbcontextContent.replace(dbcontextObjectRegex, `export default {$1${newObjectContent}\n}`);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
fs.writeFileSync(dbcontextPath, dbcontextContent);
|
113
|
+
console.log('📊 Updated dbcontext.ts');
|
114
|
+
}
|