@diagramers/cli 1.0.23 → 1.0.25

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.
@@ -1,117 +0,0 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import * as glob from 'glob';
4
- import chalk from 'chalk';
5
-
6
- export interface UpdateOptions {
7
- force?: boolean;
8
- backup?: boolean;
9
- }
10
-
11
- export class ProjectUpdater {
12
- private currentProjectPath: string;
13
-
14
- constructor() {
15
- this.currentProjectPath = process.cwd();
16
- }
17
-
18
- async update(options: UpdateOptions): Promise<void> {
19
- // Check if we're in a valid project directory
20
- if (!await this.isValidProject()) {
21
- throw new Error('Not a valid project directory. Please run this command from your project root.');
22
- }
23
-
24
- // Create backup if requested
25
- if (options.backup) {
26
- await this.createBackup();
27
- }
28
-
29
- // Get list of files that can be updated
30
- const updateableFiles = await this.getUpdateableFiles();
31
-
32
- // Check for conflicts
33
- const conflicts = await this.checkConflicts(updateableFiles);
34
-
35
- if (conflicts.length > 0 && !options.force) {
36
- console.log(chalk.yellow('⚠️ Conflicts detected in the following files:'));
37
- conflicts.forEach(file => console.log(chalk.yellow(` - ${file}`)));
38
- console.log(chalk.yellow('Use --force to overwrite these files'));
39
- throw new Error('Update aborted due to conflicts');
40
- }
41
-
42
- // Perform the update
43
- await this.performUpdate(updateableFiles);
44
-
45
- console.log(chalk.green('✅ Project updated successfully!'));
46
- }
47
-
48
- private async isValidProject(): Promise<boolean> {
49
- const packageJsonPath = path.join(this.currentProjectPath, 'package.json');
50
- const mainTsPath = path.join(this.currentProjectPath, 'main.ts');
51
-
52
- return await fs.pathExists(packageJsonPath) && await fs.pathExists(mainTsPath);
53
- }
54
-
55
- private async createBackup(): Promise<void> {
56
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
57
- const backupPath = path.join(this.currentProjectPath, `backup-${timestamp}`);
58
-
59
- await fs.copy(this.currentProjectPath, backupPath, {
60
- filter: (src) => {
61
- const relativePath = path.relative(this.currentProjectPath, src);
62
- return !relativePath.startsWith('node_modules') &&
63
- !relativePath.startsWith('.git') &&
64
- !relativePath.startsWith('backup-');
65
- }
66
- });
67
-
68
- console.log(chalk.blue(`📦 Backup created at: ${backupPath}`));
69
- }
70
-
71
- private async getUpdateableFiles(): Promise<string[]> {
72
- // For now, we'll update specific files that are commonly modified in templates
73
- const updateableFiles = [
74
- 'src/helpers/dbcontext.ts',
75
- 'src/helpers/result.ts',
76
- 'src/helpers/enums.ts',
77
- 'src/config/index.ts',
78
- 'src/config/development.ts',
79
- 'src/config/staging.ts',
80
- 'src/config/production.ts',
81
- 'src/server/index.ts',
82
- 'webpack.config.js',
83
- 'tsconfig.json'
84
- ];
85
-
86
- return updateableFiles.filter(file => fs.existsSync(path.join(this.currentProjectPath, file)));
87
- }
88
-
89
- private async checkConflicts(files: string[]): Promise<string[]> {
90
- const conflicts: string[] = [];
91
-
92
- for (const file of files) {
93
- const projectPath = path.join(this.currentProjectPath, file);
94
-
95
- if (await fs.pathExists(projectPath)) {
96
- // For now, we'll consider all files as potentially conflicting
97
- // In a real implementation, you'd compare with the template version
98
- conflicts.push(file);
99
- }
100
- }
101
-
102
- return conflicts;
103
- }
104
-
105
- private async performUpdate(files: string[]): Promise<void> {
106
- console.log(chalk.blue('📝 Updating project files...'));
107
-
108
- // For now, we'll just report what would be updated
109
- // In a real implementation, you'd copy from the latest template
110
- for (const file of files) {
111
- console.log(chalk.green(`✅ Would update: ${file}`));
112
- }
113
-
114
- console.log(chalk.yellow('⚠️ Update mechanism is being improved.'));
115
- console.log(chalk.yellow(' For now, manual updates are recommended.'));
116
- }
117
- }
@@ -1,203 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
-
4
- export type RelationType = 'one-to-one' | 'one-to-many' | 'many-to-many';
5
-
6
- export async function generateRelation(table1: string, table2: string, relationType: RelationType = 'one-to-one'): Promise<void> {
7
- // Validate table names
8
- if (!table1 || !table2 || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table1) || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(table2)) {
9
- throw new Error('Invalid table names. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
10
- }
11
-
12
- const table1Capitalized = table1.charAt(0).toUpperCase() + table1.slice(1);
13
- const table2Capitalized = table2.charAt(0).toUpperCase() + table2.slice(1);
14
- const currentDir = process.cwd();
15
-
16
- // Check for required API project structure
17
- const requiredDirs = ['src/entities', 'src/schemas'];
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
- // Check if both tables exist
24
- const table1EntityPath = path.join(currentDir, 'src/entities', `${table1}.ts`);
25
- const table2EntityPath = path.join(currentDir, 'src/entities', `${table2}.ts`);
26
- const table1SchemaPath = path.join(currentDir, 'src/schemas', `${table1}.ts`);
27
- const table2SchemaPath = path.join(currentDir, 'src/schemas', `${table2}.ts`);
28
-
29
- if (!fs.existsSync(table1EntityPath) || !fs.existsSync(table2EntityPath)) {
30
- throw new Error(`Both tables must exist before creating relationships. Missing: ${!fs.existsSync(table1EntityPath) ? table1 : ''} ${!fs.existsSync(table2EntityPath) ? table2 : ''}`);
31
- }
32
-
33
- console.log(`🔗 Creating ${relationType} relationship between ${table1} and ${table2}...`);
34
-
35
- // Update entities
36
- console.log('📝 Updating entities...');
37
- updateEntity(table1EntityPath, table1Capitalized, table2Capitalized, relationType, 'forward');
38
- updateEntity(table2EntityPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
39
-
40
- // Update schemas
41
- console.log('📋 Updating schemas...');
42
- updateSchema(table1SchemaPath, table1Capitalized, table2Capitalized, relationType, 'forward');
43
- updateSchema(table2SchemaPath, table2Capitalized, table1Capitalized, relationType, 'reverse');
44
-
45
- console.log('✅ Relationship created successfully!');
46
- console.log(`🔗 ${table1} ↔ ${table2} (${relationType})`);
47
- }
48
-
49
- function updateEntity(entityPath: string, tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): void {
50
- let entityContent = fs.readFileSync(entityPath, 'utf8');
51
-
52
- // Add import for the related interface
53
- const importStatement = `import { I${relatedTableCapitalized} } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
54
- if (!entityContent.includes(importStatement)) {
55
- // Find the last import statement and add after it
56
- const importRegex = /import.*from.*['"];?\s*$/gm;
57
- const matches = [...entityContent.matchAll(importRegex)];
58
- if (matches.length > 0) {
59
- const lastImport = matches[matches.length - 1];
60
- const insertIndex = lastImport.index! + lastImport[0].length;
61
- entityContent = entityContent.slice(0, insertIndex) + '\n' + importStatement + entityContent.slice(insertIndex);
62
- }
63
- }
64
-
65
- // Add relationship fields based on type
66
- const interfaceRegex = /export interface I\w+ extends mongoose\.Document \{([^}]*)\}/s;
67
- const match = entityContent.match(interfaceRegex);
68
-
69
- if (match) {
70
- const interfaceContent = match[1];
71
- const newFields = generateEntityFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
72
-
73
- // Add new fields before the closing brace
74
- const updatedInterfaceContent = interfaceContent.trim() + '\n ' + newFields;
75
- entityContent = entityContent.replace(interfaceRegex, `export interface I${tableCapitalized} extends mongoose.Document {$1${updatedInterfaceContent}\n}`);
76
- }
77
-
78
- fs.writeFileSync(entityPath, entityContent);
79
- }
80
-
81
- function updateSchema(schemaPath: string, tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): void {
82
- let schemaContent = fs.readFileSync(schemaPath, 'utf8');
83
-
84
- // Add import for the related schema
85
- const importStatement = `import { ${relatedTableCapitalized}Entity } from './${direction === 'forward' ? relatedTableCapitalized.toLowerCase() : relatedTableCapitalized.toLowerCase()}';`;
86
- if (!schemaContent.includes(importStatement)) {
87
- // Find the last import statement and add after it
88
- const importRegex = /import.*from.*['"];?\s*$/gm;
89
- const matches = [...schemaContent.matchAll(importRegex)];
90
- if (matches.length > 0) {
91
- const lastImport = matches[matches.length - 1];
92
- const insertIndex = lastImport.index! + lastImport[0].length;
93
- schemaContent = schemaContent.slice(0, insertIndex) + '\n' + importStatement + schemaContent.slice(insertIndex);
94
- }
95
- }
96
-
97
- // Add schema fields based on relationship type
98
- const schemaRegex = /export const \w+Schema = new mongoose\.Schema\(([^)]*),/s;
99
- const match = schemaContent.match(schemaRegex);
100
-
101
- if (match) {
102
- const schemaFields = match[1];
103
- const newFields = generateSchemaFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
104
-
105
- // Add new fields before the closing brace
106
- const updatedSchemaFields = schemaFields.trim() + '\n ' + newFields;
107
- schemaContent = schemaContent.replace(schemaRegex, `export const ${tableCapitalized.toLowerCase()}Schema = new mongoose.Schema(${updatedSchemaFields},`);
108
- }
109
-
110
- // Add virtual fields and population methods
111
- const modelRegex = /export const \w+Entity = mongoose\.model<.*>\(.*\);?\s*$/;
112
- const virtualFields = generateVirtualFields(tableCapitalized, relatedTableCapitalized, relationType, direction);
113
-
114
- if (virtualFields) {
115
- schemaContent = schemaContent.replace(modelRegex, `${virtualFields}\n\n$&`);
116
- }
117
-
118
- fs.writeFileSync(schemaPath, schemaContent);
119
- }
120
-
121
- function generateEntityFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
122
- switch (relationType) {
123
- case 'one-to-one':
124
- if (direction === 'forward') {
125
- return `_${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
126
- } else {
127
- return `_${tableCapitalized.toLowerCase()}Id: ObjectId,\n ${tableCapitalized.toLowerCase()}?: I${tableCapitalized}`;
128
- }
129
-
130
- case 'one-to-many':
131
- if (direction === 'forward') {
132
- return `_${relatedTableCapitalized.toLowerCase()}Id: ObjectId,\n ${relatedTableCapitalized.toLowerCase()}?: I${relatedTableCapitalized}`;
133
- } else {
134
- return `${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
135
- }
136
-
137
- case 'many-to-many':
138
- if (direction === 'forward') {
139
- return `_${relatedTableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${relatedTableCapitalized.toLowerCase()}s?: I${relatedTableCapitalized}[]`;
140
- } else {
141
- return `_${tableCapitalized.toLowerCase()}Ids: ObjectId[],\n ${tableCapitalized.toLowerCase()}s?: I${tableCapitalized}[]`;
142
- }
143
-
144
- default:
145
- return '';
146
- }
147
- }
148
-
149
- function generateSchemaFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
150
- switch (relationType) {
151
- case 'one-to-one':
152
- if (direction === 'forward') {
153
- return `_${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
154
- } else {
155
- return `_${tableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}',\n required: false\n }`;
156
- }
157
-
158
- case 'one-to-many':
159
- if (direction === 'forward') {
160
- return `_${relatedTableCapitalized.toLowerCase()}Id: {\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}',\n required: false\n }`;
161
- } else {
162
- return ''; // No field needed for reverse one-to-many
163
- }
164
-
165
- case 'many-to-many':
166
- if (direction === 'forward') {
167
- return `_${relatedTableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${relatedTableCapitalized.toLowerCase()}'\n }]`;
168
- } else {
169
- return `_${tableCapitalized.toLowerCase()}Ids: [{\n type: mongoose.SchemaTypes.ObjectId,\n ref: '${tableCapitalized.toLowerCase()}'\n }]`;
170
- }
171
-
172
- default:
173
- return '';
174
- }
175
- }
176
-
177
- function generateVirtualFields(tableCapitalized: string, relatedTableCapitalized: string, relationType: RelationType, direction: 'forward' | 'reverse'): string {
178
- switch (relationType) {
179
- case 'one-to-one':
180
- if (direction === 'forward') {
181
- return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '_${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
182
- } else {
183
- return `// Virtual populate for ${tableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '_${tableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
184
- }
185
-
186
- case 'one-to-many':
187
- if (direction === 'forward') {
188
- return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '_${relatedTableCapitalized.toLowerCase()}Id',\n foreignField: '_id',\n justOne: true\n});`;
189
- } else {
190
- return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '_id',\n foreignField: '_${tableCapitalized.toLowerCase()}Id'\n});`;
191
- }
192
-
193
- case 'many-to-many':
194
- if (direction === 'forward') {
195
- return `// Virtual populate for ${relatedTableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${relatedTableCapitalized.toLowerCase()}s', {\n ref: '${relatedTableCapitalized.toLowerCase()}',\n localField: '_${relatedTableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
196
- } else {
197
- return `// Virtual populate for ${tableCapitalized.toLowerCase()}s\n${tableCapitalized.toLowerCase()}Schema.virtual('${tableCapitalized.toLowerCase()}s', {\n ref: '${tableCapitalized.toLowerCase()}',\n localField: '_${tableCapitalized.toLowerCase()}Ids',\n foreignField: '_id'\n});`;
198
- }
199
-
200
- default:
201
- return '';
202
- }
203
- }
@@ -1,114 +0,0 @@
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
- }
@@ -1,166 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
-
4
- export async function processTemplate(projectName: string): Promise<void> {
5
- if (!projectName) {
6
- throw new Error('Project name is required');
7
- }
8
-
9
- const currentDir = process.cwd();
10
-
11
- // Check for required API project structure
12
- const requiredDirs = [
13
- 'src/entities',
14
- 'src/schemas',
15
- 'src/services',
16
- 'src/controllers',
17
- 'src/routes'
18
- ];
19
- const missingDirs = requiredDirs.filter(dir => !fs.existsSync(path.join(currentDir, dir)));
20
- if (missingDirs.length > 0) {
21
- throw new Error(`This command should be run from a diagramers API project. Missing directories: ${missingDirs.join(', ')}`);
22
- }
23
-
24
- // Convert project name to database-friendly format
25
- const dbName = projectName
26
- .toLowerCase()
27
- .replace(/[^a-zA-Z0-9]/g, '_')
28
- .replace(/_+/g, '_')
29
- .replace(/^_|_$/g, '');
30
-
31
- console.log(`🗄️ Database name will be: ${dbName}`);
32
-
33
- // Process configuration files
34
- console.log('📝 Updating configuration files...');
35
-
36
- // Update development config
37
- const devConfigPath = path.join(currentDir, 'src/config/development.ts');
38
- if (fs.existsSync(devConfigPath)) {
39
- let devConfig = fs.readFileSync(devConfigPath, 'utf8');
40
- devConfig = devConfig.replace(
41
- /mongodb:\/\/127\.0\.0\.1:27017\/[^,\s]+/g,
42
- `mongodb://127.0.0.1:27017/${dbName}-development`
43
- );
44
- fs.writeFileSync(devConfigPath, devConfig);
45
- console.log(' ✅ Updated development.ts');
46
- }
47
-
48
- // Update staging config
49
- const stagingConfigPath = path.join(currentDir, 'src/config/staging.ts');
50
- if (fs.existsSync(stagingConfigPath)) {
51
- let stagingConfig = fs.readFileSync(stagingConfigPath, 'utf8');
52
- stagingConfig = stagingConfig.replace(
53
- /sendifier-staging/g,
54
- `${dbName}-staging`
55
- );
56
- fs.writeFileSync(stagingConfigPath, stagingConfig);
57
- console.log(' ✅ Updated staging.ts');
58
- }
59
-
60
- // Update production config
61
- const prodConfigPath = path.join(currentDir, 'src/config/production.ts');
62
- if (fs.existsSync(prodConfigPath)) {
63
- let prodConfig = fs.readFileSync(prodConfigPath, 'utf8');
64
- prodConfig = prodConfig.replace(
65
- /sendifier-production/g,
66
- `${dbName}-production`
67
- );
68
- fs.writeFileSync(prodConfigPath, prodConfig);
69
- console.log(' ✅ Updated production.ts');
70
- }
71
-
72
- // Update package.json
73
- const packageJsonPath = path.join(currentDir, 'package.json');
74
- if (fs.existsSync(packageJsonPath)) {
75
- let packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
76
- packageJsonContent = packageJsonContent.replace(
77
- /"name":\s*"@diagramers\/api"/g,
78
- `"name": "${projectName}"`
79
- );
80
- packageJsonContent = packageJsonContent.replace(
81
- /"description":\s*"Diagramers API - A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io"/g,
82
- `"description": "${projectName} - API project"`
83
- );
84
- fs.writeFileSync(packageJsonPath, packageJsonContent);
85
- console.log(' ✅ Updated package.json');
86
- }
87
-
88
- // Update README.md
89
- const readmePath = path.join(currentDir, 'README.md');
90
- if (fs.existsSync(readmePath)) {
91
- let readmeContent = fs.readFileSync(readmePath, 'utf8');
92
- readmeContent = readmeContent.replace(
93
- /# @diagramers\/api/g,
94
- `# ${projectName}`
95
- );
96
- readmeContent = readmeContent.replace(
97
- /A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io\./g,
98
- `${projectName} - API project.`
99
- );
100
- fs.writeFileSync(readmePath, readmeContent);
101
- console.log(' ✅ Updated README.md');
102
- }
103
-
104
- // Create .env file template
105
- console.log('📄 Creating .env template...');
106
- const envTemplate = generateEnvTemplate(dbName);
107
- fs.writeFileSync(path.join(currentDir, '.env.example'), envTemplate);
108
-
109
- console.log('✅ Template processing completed!');
110
- console.log('');
111
- console.log('📋 Summary:');
112
- console.log(` Project Name: ${projectName}`);
113
- console.log(` Database Name: ${dbName}`);
114
- console.log(` Development DB: ${dbName}-development`);
115
- console.log(` Staging DB: ${dbName}-staging`);
116
- console.log(` Production DB: ${dbName}-production`);
117
- console.log('');
118
- console.log('🚀 Next steps:');
119
- console.log(' 1. Copy .env.example to .env and configure your environment variables');
120
- console.log(' 2. Install dependencies: npm install');
121
- console.log(' 3. Build the project: npm run build:dev');
122
- console.log(' 4. Start the server: npm run serve');
123
- }
124
-
125
- function generateEnvTemplate(dbName: string): string {
126
- return `# Environment Configuration
127
- NODE_ENV=development
128
-
129
- # Server Configuration
130
- PORT=4000
131
- HOST=localhost
132
-
133
- # Database Configuration
134
- MONGODB_URI=mongodb://127.0.0.1:27017/${dbName}-development
135
-
136
- # Firebase Configuration
137
- FIREBASE_API_KEY=your-api-key
138
- FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
139
- FIREBASE_PROJECT_ID=your-project-id
140
- FIREBASE_STORAGE_BUCKET=your-project.appspot.com
141
- FIREBASE_MESSAGING_SENDER_ID=your-sender-id
142
- FIREBASE_APP_ID=your-app-id
143
-
144
- # JWT Configuration
145
- JWT_SECRET=your-jwt-secret-key
146
-
147
- # Twilio Configuration (for SMS)
148
- TWILIO_ACCOUNT_SID=your-account-sid
149
- TWILIO_AUTH_TOKEN=your-auth-token
150
-
151
- # Email Configuration
152
- SMTP_HOST=smtp.gmail.com
153
- SMTP_PORT=587
154
- SMTP_USER=your-email@gmail.com
155
- SMTP_PASS=your-app-password
156
-
157
- # Internal API Configuration
158
- INTERNAL_REQUEST_HEADER_VALUE=your-secret-header-value
159
-
160
- # Optional Configuration
161
- BASE_SITE_URL=http://localhost:3000
162
- LOCAL_API_TUNNEL_URL=https://your-ngrok-url.ngrok-free.app
163
- LOCAL_UI_TUNNEL_URL=https://your-ui-ngrok-url.ngrok-free.app
164
- BACKUP_DATABASES_FOLDER_PATH=/path/to/backup/folder
165
- EXTERNAL_HTTP_REQUEST_TIMEOUT=5000`;
166
- }