@gravito/scaffold 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1361 -1642
- package/dist/index.d.cts +378 -308
- package/dist/index.d.ts +378 -308
- package/dist/index.js +1360 -1642
- package/package.json +7 -5
- package/templates/common/Dockerfile.hbs +25 -0
- package/templates/common/env.example.hbs +13 -0
- package/templates/common/gitignore.hbs +10 -0
- package/templates/common/tsconfig.json.hbs +22 -0
- package/templates/features/otel/package.json +6 -6
- package/templates/features/redis/package.json +4 -4
- package/templates/overlays/core/package.json +4 -4
- package/templates/overlays/enterprise/package.json +6 -6
- package/templates/overlays/scale/package.json +5 -5
- package/templates/scripts/check-dependencies.ts.hbs +142 -0
- package/templates/scripts/check.sh.hbs +55 -0
- package/templates/scripts/pre-commit.sh.hbs +58 -0
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
BaseGenerator: () => BaseGenerator,
|
|
34
34
|
CleanArchitectureGenerator: () => CleanArchitectureGenerator,
|
|
35
35
|
DddGenerator: () => DddGenerator,
|
|
36
|
+
DependencyValidator: () => DependencyValidator,
|
|
36
37
|
EnterpriseMvcGenerator: () => EnterpriseMvcGenerator,
|
|
37
38
|
EnvironmentDetector: () => EnvironmentDetector,
|
|
38
39
|
FileMerger: () => FileMerger,
|
|
@@ -44,6 +45,147 @@ __export(index_exports, {
|
|
|
44
45
|
});
|
|
45
46
|
module.exports = __toCommonJS(index_exports);
|
|
46
47
|
|
|
48
|
+
// src/DependencyValidator.ts
|
|
49
|
+
var DependencyValidator = class _DependencyValidator {
|
|
50
|
+
/**
|
|
51
|
+
* Driver 到 Package 的映射規則
|
|
52
|
+
*/
|
|
53
|
+
static DRIVER_DEPENDENCIES = [
|
|
54
|
+
{
|
|
55
|
+
driver: "redis",
|
|
56
|
+
requiredPackages: ["@gravito/ion"],
|
|
57
|
+
description: "Redis cache/queue driver requires @gravito/ion"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
driver: "postgresql",
|
|
61
|
+
requiredPackages: ["@gravito/atlas", "pg"],
|
|
62
|
+
description: "PostgreSQL driver requires @gravito/atlas and pg"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
driver: "mysql",
|
|
66
|
+
requiredPackages: ["@gravito/atlas", "mysql2"],
|
|
67
|
+
description: "MySQL driver requires @gravito/atlas and mysql2"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
driver: "sqlite",
|
|
71
|
+
requiredPackages: ["@gravito/atlas", "better-sqlite3"],
|
|
72
|
+
description: "SQLite driver requires @gravito/atlas and better-sqlite3"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
driver: "s3",
|
|
76
|
+
requiredPackages: ["@gravito/stasis", "@aws-sdk/client-s3"],
|
|
77
|
+
description: "S3 storage driver requires @gravito/stasis and AWS SDK"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
driver: "r2",
|
|
81
|
+
requiredPackages: ["@gravito/stasis", "@aws-sdk/client-s3"],
|
|
82
|
+
description: "R2 storage driver requires @gravito/stasis and AWS SDK"
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* Feature 衝突規則
|
|
87
|
+
*/
|
|
88
|
+
static CONFLICTS = [
|
|
89
|
+
{
|
|
90
|
+
features: ["postgres", "mysql", "sqlite"],
|
|
91
|
+
reason: "\u4E0D\u80FD\u540C\u6642\u4F7F\u7528\u591A\u500B\u8CC7\u6599\u5EAB driver (PostgreSQL, MySQL, SQLite)"
|
|
92
|
+
}
|
|
93
|
+
];
|
|
94
|
+
/**
|
|
95
|
+
* Feature 依賴映射
|
|
96
|
+
*/
|
|
97
|
+
static FEATURE_DEPENDENCIES = {
|
|
98
|
+
stream: ["@gravito/beam"],
|
|
99
|
+
monitor: ["@gravito/spectrum"],
|
|
100
|
+
graphql: ["@gravito/constellation"]
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* 驗證 Profile 配置
|
|
104
|
+
*
|
|
105
|
+
* @param config - Profile 配置
|
|
106
|
+
* @param packageJson - 專案的 package.json 內容
|
|
107
|
+
* @returns 驗證結果
|
|
108
|
+
*/
|
|
109
|
+
validate(config, packageJson) {
|
|
110
|
+
const errors = [];
|
|
111
|
+
const warnings = [];
|
|
112
|
+
this.validateDriverDependencies(config, packageJson, errors);
|
|
113
|
+
this.validateFeatureConflicts(config, errors);
|
|
114
|
+
this.validateFeatureDependencies(config, packageJson, warnings);
|
|
115
|
+
return {
|
|
116
|
+
valid: errors.length === 0,
|
|
117
|
+
errors,
|
|
118
|
+
warnings
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 驗證 driver 依賴
|
|
123
|
+
*/
|
|
124
|
+
validateDriverDependencies(config, packageJson, errors) {
|
|
125
|
+
for (const [service, driver] of Object.entries(config.drivers)) {
|
|
126
|
+
const rule = _DependencyValidator.DRIVER_DEPENDENCIES.find((r) => r.driver === driver);
|
|
127
|
+
if (rule) {
|
|
128
|
+
for (const pkg of rule.requiredPackages) {
|
|
129
|
+
if (!this.hasPackage(packageJson, pkg)) {
|
|
130
|
+
errors.push(`\u7F3A\u5C11\u4F9D\u8CF4: ${pkg} (${service} driver '${driver}' \u6240\u9700)`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 驗證 feature 衝突
|
|
138
|
+
*/
|
|
139
|
+
validateFeatureConflicts(config, errors) {
|
|
140
|
+
for (const conflict of _DependencyValidator.CONFLICTS) {
|
|
141
|
+
const conflictingFeatures = conflict.features.filter((f) => config.features.includes(f));
|
|
142
|
+
if (conflictingFeatures.length > 1) {
|
|
143
|
+
errors.push(`Feature \u885D\u7A81: ${conflictingFeatures.join(", ")} - ${conflict.reason}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 驗證 feature 依賴
|
|
149
|
+
*/
|
|
150
|
+
validateFeatureDependencies(config, packageJson, warnings) {
|
|
151
|
+
for (const feature of config.features) {
|
|
152
|
+
const requiredPackages = _DependencyValidator.FEATURE_DEPENDENCIES[feature];
|
|
153
|
+
if (requiredPackages) {
|
|
154
|
+
for (const pkg of requiredPackages) {
|
|
155
|
+
if (!this.hasPackage(packageJson, pkg)) {
|
|
156
|
+
warnings.push(`Feature "${feature}" \u9700\u8981 ${pkg}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 檢查 package.json 是否包含指定 package
|
|
164
|
+
*/
|
|
165
|
+
hasPackage(packageJson, packageName) {
|
|
166
|
+
return packageJson.dependencies?.[packageName] !== void 0 || packageJson.devDependencies?.[packageName] !== void 0;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 建議安裝缺失的依賴
|
|
170
|
+
*
|
|
171
|
+
* @param result - 驗證結果
|
|
172
|
+
* @returns 安裝命令建議
|
|
173
|
+
*/
|
|
174
|
+
static suggestInstallCommand(result) {
|
|
175
|
+
if (result.errors.length === 0) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const missingPackages = result.errors.map((err) => {
|
|
179
|
+
const match = err.match(/缺少依賴: ([@\w/-]+)/);
|
|
180
|
+
return match ? match[1] : null;
|
|
181
|
+
}).filter((pkg) => pkg !== null);
|
|
182
|
+
if (missingPackages.length === 0) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
return `bun add ${missingPackages.join(" ")}`;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
47
189
|
// src/EnvironmentDetector.ts
|
|
48
190
|
var EnvironmentDetector = class {
|
|
49
191
|
detect() {
|
|
@@ -144,12 +286,52 @@ ${overlay}`;
|
|
|
144
286
|
};
|
|
145
287
|
|
|
146
288
|
// src/generators/BaseGenerator.ts
|
|
147
|
-
var
|
|
148
|
-
var
|
|
289
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
290
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
149
291
|
|
|
150
|
-
// src/
|
|
292
|
+
// src/utils/FileUtilities.ts
|
|
151
293
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
152
294
|
var import_node_path = __toESM(require("path"), 1);
|
|
295
|
+
var FileUtilities = class _FileUtilities {
|
|
296
|
+
static async walk(dir) {
|
|
297
|
+
const files = await import_promises.default.readdir(dir);
|
|
298
|
+
const paths = [];
|
|
299
|
+
for (const file of files) {
|
|
300
|
+
const filePath = import_node_path.default.join(dir, file);
|
|
301
|
+
const stat = await import_promises.default.stat(filePath);
|
|
302
|
+
if (stat.isDirectory()) {
|
|
303
|
+
paths.push(...await _FileUtilities.walk(filePath));
|
|
304
|
+
} else {
|
|
305
|
+
paths.push(filePath);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return paths;
|
|
309
|
+
}
|
|
310
|
+
static async writeFile(basePath, relativePath, content, fileMerger, log) {
|
|
311
|
+
const fullPath = import_node_path.default.resolve(basePath, relativePath);
|
|
312
|
+
await import_promises.default.mkdir(import_node_path.default.dirname(fullPath), { recursive: true });
|
|
313
|
+
let finalContent = content;
|
|
314
|
+
try {
|
|
315
|
+
const existingContent = await import_promises.default.readFile(fullPath, "utf-8");
|
|
316
|
+
finalContent = fileMerger.merge(relativePath, existingContent, content);
|
|
317
|
+
if (finalContent !== content) {
|
|
318
|
+
log?.(`\u{1F504} Merged file: ${relativePath}`);
|
|
319
|
+
}
|
|
320
|
+
} catch {
|
|
321
|
+
}
|
|
322
|
+
await import_promises.default.writeFile(fullPath, finalContent, "utf-8");
|
|
323
|
+
log?.(`\u{1F4C4} Created file: ${relativePath}`);
|
|
324
|
+
return fullPath;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// src/utils/TemplateManager.ts
|
|
329
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
330
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
331
|
+
|
|
332
|
+
// src/generators/StubGenerator.ts
|
|
333
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
334
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
153
335
|
var import_handlebars = __toESM(require("handlebars"), 1);
|
|
154
336
|
var StubGenerator = class {
|
|
155
337
|
config;
|
|
@@ -238,16 +420,16 @@ var StubGenerator = class {
|
|
|
238
420
|
* @returns Path to the generated file
|
|
239
421
|
*/
|
|
240
422
|
async generate(stubName, outputPath, variables = {}) {
|
|
241
|
-
const stubPath =
|
|
242
|
-
const template = await
|
|
423
|
+
const stubPath = import_node_path2.default.resolve(this.config.stubsDir, stubName);
|
|
424
|
+
const template = await import_promises2.default.readFile(stubPath, "utf-8");
|
|
243
425
|
const compiled = this.handlebars.compile(template);
|
|
244
426
|
const content = compiled({
|
|
245
427
|
...this.config.defaultVariables,
|
|
246
428
|
...variables
|
|
247
429
|
});
|
|
248
|
-
const fullOutputPath =
|
|
249
|
-
await
|
|
250
|
-
await
|
|
430
|
+
const fullOutputPath = import_node_path2.default.resolve(this.config.outputDir, outputPath);
|
|
431
|
+
await import_promises2.default.mkdir(import_node_path2.default.dirname(fullOutputPath), { recursive: true });
|
|
432
|
+
await import_promises2.default.writeFile(fullOutputPath, content, "utf-8");
|
|
251
433
|
return fullOutputPath;
|
|
252
434
|
}
|
|
253
435
|
/**
|
|
@@ -299,41 +481,57 @@ var StubGenerator = class {
|
|
|
299
481
|
}
|
|
300
482
|
};
|
|
301
483
|
|
|
302
|
-
// src/
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
484
|
+
// src/utils/TemplateManager.ts
|
|
485
|
+
var TemplateManager = class {
|
|
486
|
+
stubGenerator;
|
|
487
|
+
constructor(templatesDir) {
|
|
488
|
+
this.stubGenerator = new StubGenerator({
|
|
489
|
+
stubsDir: templatesDir,
|
|
490
|
+
outputDir: ""
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
render(template, context) {
|
|
494
|
+
return this.stubGenerator.render(template, context);
|
|
495
|
+
}
|
|
496
|
+
async applyOverlay(sourceDir, targetDir, context, fileMerger, log) {
|
|
497
|
+
const createdFiles = [];
|
|
498
|
+
try {
|
|
499
|
+
await import_promises3.default.access(sourceDir);
|
|
500
|
+
} catch {
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
const files = await FileUtilities.walk(sourceDir);
|
|
504
|
+
for (const filePath of files) {
|
|
505
|
+
const relativePath = import_node_path3.default.relative(sourceDir, filePath);
|
|
506
|
+
let content = await import_promises3.default.readFile(filePath, "utf-8");
|
|
507
|
+
try {
|
|
508
|
+
content = this.render(content, context);
|
|
509
|
+
} catch {
|
|
510
|
+
}
|
|
511
|
+
const fullPath = await FileUtilities.writeFile(
|
|
512
|
+
targetDir,
|
|
513
|
+
relativePath,
|
|
514
|
+
content,
|
|
515
|
+
fileMerger,
|
|
516
|
+
log
|
|
517
|
+
);
|
|
518
|
+
createdFiles.push(fullPath);
|
|
313
519
|
}
|
|
520
|
+
return createdFiles;
|
|
314
521
|
}
|
|
315
|
-
|
|
316
|
-
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// src/generators/BaseGenerator.ts
|
|
317
525
|
var BaseGenerator = class {
|
|
318
526
|
config;
|
|
319
|
-
|
|
527
|
+
templateManager;
|
|
320
528
|
fileMerger;
|
|
321
529
|
filesCreated = [];
|
|
322
530
|
constructor(config) {
|
|
323
531
|
this.config = config;
|
|
324
|
-
this.
|
|
325
|
-
stubsDir: config.templatesDir,
|
|
326
|
-
outputDir: ""
|
|
327
|
-
// Set per-generation
|
|
328
|
-
});
|
|
532
|
+
this.templateManager = new TemplateManager(config.templatesDir);
|
|
329
533
|
this.fileMerger = new FileMerger();
|
|
330
534
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Generate the project scaffold.
|
|
333
|
-
*
|
|
334
|
-
* @param context - Generator context
|
|
335
|
-
* @returns Array of created file paths
|
|
336
|
-
*/
|
|
337
535
|
async generate(context) {
|
|
338
536
|
this.filesCreated = [];
|
|
339
537
|
const structure = this.getDirectoryStructure(context);
|
|
@@ -343,50 +541,73 @@ var BaseGenerator = class {
|
|
|
343
541
|
await this.applyFeatureOverlays(context);
|
|
344
542
|
return this.filesCreated;
|
|
345
543
|
}
|
|
346
|
-
/**
|
|
347
|
-
* Create directory structure recursively.
|
|
348
|
-
*/
|
|
349
544
|
async createStructure(basePath, nodes, context) {
|
|
350
545
|
for (const node of nodes) {
|
|
351
|
-
const fullPath =
|
|
546
|
+
const fullPath = import_node_path4.default.resolve(basePath, node.name);
|
|
352
547
|
if (node.type === "directory") {
|
|
353
|
-
await
|
|
548
|
+
await import_promises4.default.mkdir(fullPath, { recursive: true });
|
|
354
549
|
this.log(`\u{1F4C1} Created directory: ${node.name}`);
|
|
355
550
|
if (node.children) {
|
|
356
551
|
await this.createStructure(fullPath, node.children, context);
|
|
357
552
|
}
|
|
358
553
|
} else {
|
|
359
|
-
await
|
|
554
|
+
await import_promises4.default.mkdir(import_node_path4.default.dirname(fullPath), { recursive: true });
|
|
555
|
+
let content = "";
|
|
360
556
|
if (node.template) {
|
|
361
|
-
const templatePath = import_node_path2.default.resolve(this.config.templatesDir, node.template);
|
|
362
557
|
try {
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
|
|
558
|
+
const templatePath = import_node_path4.default.resolve(this.config.templatesDir, node.template);
|
|
559
|
+
const template = await import_promises4.default.readFile(templatePath, "utf-8");
|
|
560
|
+
content = this.templateManager.render(template, context);
|
|
366
561
|
} catch {
|
|
367
|
-
|
|
562
|
+
content = node.content ?? "";
|
|
368
563
|
}
|
|
369
|
-
} else if (node.content) {
|
|
370
|
-
await import_promises2.default.writeFile(fullPath, node.content, "utf-8");
|
|
371
564
|
} else {
|
|
372
|
-
|
|
565
|
+
content = node.content ?? "";
|
|
373
566
|
}
|
|
374
|
-
|
|
375
|
-
|
|
567
|
+
const relativePath = import_node_path4.default.relative(context.targetDir, fullPath);
|
|
568
|
+
const writtenPath = await FileUtilities.writeFile(
|
|
569
|
+
context.targetDir,
|
|
570
|
+
relativePath,
|
|
571
|
+
content,
|
|
572
|
+
this.fileMerger,
|
|
573
|
+
(msg) => this.log(msg)
|
|
574
|
+
);
|
|
575
|
+
this.filesCreated.push(writtenPath);
|
|
376
576
|
}
|
|
377
577
|
}
|
|
378
578
|
}
|
|
379
|
-
/**
|
|
380
|
-
* Generate common files (package.json, .env, etc.)
|
|
381
|
-
*/
|
|
382
579
|
async generateCommonFiles(context) {
|
|
580
|
+
const commonDir = import_node_path4.default.resolve(this.config.templatesDir, "common");
|
|
581
|
+
const extendedContext = {
|
|
582
|
+
...context,
|
|
583
|
+
entrypoint: context.architecture === "ddd" ? "dist/main.js" : "dist/bootstrap.js",
|
|
584
|
+
dbConnection: context.profile === "core" ? "sqlite" : "postgres"
|
|
585
|
+
};
|
|
586
|
+
await this.generateFileFromTemplate(
|
|
587
|
+
commonDir,
|
|
588
|
+
"env.example.hbs",
|
|
589
|
+
".env.example",
|
|
590
|
+
extendedContext
|
|
591
|
+
);
|
|
592
|
+
await this.generateFileFromTemplate(commonDir, "env.example.hbs", ".env", extendedContext);
|
|
593
|
+
await this.generateFileFromTemplate(commonDir, "gitignore.hbs", ".gitignore", extendedContext);
|
|
594
|
+
await this.generateFileFromTemplate(
|
|
595
|
+
commonDir,
|
|
596
|
+
"tsconfig.json.hbs",
|
|
597
|
+
"tsconfig.json",
|
|
598
|
+
extendedContext
|
|
599
|
+
);
|
|
600
|
+
await this.generateFileFromTemplate(commonDir, "Dockerfile.hbs", "Dockerfile", extendedContext);
|
|
383
601
|
await this.writeFile(context.targetDir, "package.json", this.generatePackageJson(context));
|
|
384
|
-
await this.writeFile(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
602
|
+
await this.writeFile(
|
|
603
|
+
context.targetDir,
|
|
604
|
+
".dockerignore",
|
|
605
|
+
`node_modules
|
|
606
|
+
dist
|
|
607
|
+
.git
|
|
608
|
+
.env
|
|
609
|
+
`
|
|
610
|
+
);
|
|
390
611
|
await this.writeFile(
|
|
391
612
|
context.targetDir,
|
|
392
613
|
"ARCHITECTURE.md",
|
|
@@ -395,104 +616,74 @@ var BaseGenerator = class {
|
|
|
395
616
|
await this.generateCheckScripts(context);
|
|
396
617
|
await this.generateSkills(context);
|
|
397
618
|
}
|
|
398
|
-
|
|
399
|
-
* Copy AI Skills to the project
|
|
400
|
-
*/
|
|
401
|
-
async generateSkills(context) {
|
|
402
|
-
const skillsDir = import_node_path2.default.resolve(this.config.templatesDir, "skills");
|
|
403
|
-
const targetSkillsDir = import_node_path2.default.join(".skills");
|
|
619
|
+
async generateFileFromTemplate(tplDir, tplName, targetName, context) {
|
|
404
620
|
try {
|
|
405
|
-
await
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
for (const filePath of files) {
|
|
411
|
-
const relativePath = import_node_path2.default.relative(skillsDir, filePath);
|
|
412
|
-
const targetPath = import_node_path2.default.join(targetSkillsDir, relativePath);
|
|
413
|
-
let content = await import_promises2.default.readFile(filePath, "utf-8");
|
|
414
|
-
try {
|
|
415
|
-
content = this.stubGenerator.render(content, context);
|
|
416
|
-
} catch {
|
|
417
|
-
}
|
|
418
|
-
await this.writeFile(context.targetDir, targetPath, content);
|
|
621
|
+
const template = await import_promises4.default.readFile(import_node_path4.default.join(tplDir, tplName), "utf-8");
|
|
622
|
+
const content = this.templateManager.render(template, context);
|
|
623
|
+
await this.writeFile(context.targetDir, targetName, content);
|
|
624
|
+
} catch (e) {
|
|
625
|
+
this.log(`\u26A0\uFE0F Failed to generate ${targetName}: ${e}`);
|
|
419
626
|
}
|
|
420
627
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
628
|
+
async generateSkills(context) {
|
|
629
|
+
const skillsDir = import_node_path4.default.resolve(this.config.templatesDir, "skills");
|
|
630
|
+
const created = await this.templateManager.applyOverlay(
|
|
631
|
+
skillsDir,
|
|
632
|
+
import_node_path4.default.join(context.targetDir, ".skills"),
|
|
633
|
+
context,
|
|
634
|
+
this.fileMerger,
|
|
635
|
+
(msg) => this.log(msg)
|
|
636
|
+
);
|
|
637
|
+
this.filesCreated.push(...created);
|
|
638
|
+
}
|
|
424
639
|
async applyOverlays(context) {
|
|
425
640
|
const profile = context.profile;
|
|
426
|
-
if (
|
|
427
|
-
|
|
428
|
-
|
|
641
|
+
if (profile) {
|
|
642
|
+
const overlayDir = import_node_path4.default.resolve(this.config.templatesDir, "overlays", profile);
|
|
643
|
+
await this.copyOverlayDirectory(overlayDir, context);
|
|
644
|
+
}
|
|
429
645
|
}
|
|
430
|
-
/**
|
|
431
|
-
* Apply feature-specific overlays
|
|
432
|
-
*/
|
|
433
646
|
async applyFeatureOverlays(context) {
|
|
434
647
|
const features = context.features || [];
|
|
435
648
|
for (const feature of features) {
|
|
436
|
-
const overlayDir =
|
|
649
|
+
const overlayDir = import_node_path4.default.resolve(this.config.templatesDir, "features", feature);
|
|
437
650
|
await this.copyOverlayDirectory(overlayDir, context);
|
|
438
651
|
}
|
|
439
652
|
}
|
|
440
|
-
/**
|
|
441
|
-
* Helper to copy/merge an overlay directory into the target
|
|
442
|
-
*/
|
|
443
653
|
async copyOverlayDirectory(sourceDir, context) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
let content = await import_promises2.default.readFile(filePath, "utf-8");
|
|
453
|
-
try {
|
|
454
|
-
content = this.stubGenerator.render(content, context);
|
|
455
|
-
} catch {
|
|
456
|
-
}
|
|
457
|
-
await this.writeFile(context.targetDir, relativePath, content);
|
|
458
|
-
}
|
|
654
|
+
const created = await this.templateManager.applyOverlay(
|
|
655
|
+
sourceDir,
|
|
656
|
+
context.targetDir,
|
|
657
|
+
context,
|
|
658
|
+
this.fileMerger,
|
|
659
|
+
(msg) => this.log(msg)
|
|
660
|
+
);
|
|
661
|
+
this.filesCreated.push(...created);
|
|
459
662
|
}
|
|
460
|
-
/**
|
|
461
|
-
* Write a file and track it.
|
|
462
|
-
*/
|
|
463
663
|
async writeFile(basePath, relativePath, content) {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
} catch {
|
|
474
|
-
}
|
|
475
|
-
await import_promises2.default.writeFile(fullPath, finalContent, "utf-8");
|
|
476
|
-
this.filesCreated.push(fullPath);
|
|
477
|
-
this.log(`\u{1F4C4} Created file: ${relativePath}`);
|
|
664
|
+
const writtenPath = await FileUtilities.writeFile(
|
|
665
|
+
basePath,
|
|
666
|
+
relativePath,
|
|
667
|
+
content,
|
|
668
|
+
this.fileMerger,
|
|
669
|
+
(msg) => this.log(msg)
|
|
670
|
+
);
|
|
671
|
+
this.filesCreated.push(writtenPath);
|
|
478
672
|
}
|
|
479
|
-
/**
|
|
480
|
-
* Generate package.json content.
|
|
481
|
-
*/
|
|
482
673
|
generatePackageJson(context) {
|
|
483
674
|
const profile = context.profile || "core";
|
|
484
|
-
const
|
|
675
|
+
const deps = {
|
|
485
676
|
"@gravito/core": "^1.0.0-beta.5",
|
|
486
677
|
"@gravito/atlas": "^1.0.0-beta.5",
|
|
487
678
|
"@gravito/plasma": "^1.0.0-beta.5",
|
|
488
679
|
"@gravito/stream": "^1.0.0-beta.5"
|
|
489
680
|
};
|
|
490
681
|
if (profile === "enterprise" || profile === "scale") {
|
|
491
|
-
|
|
492
|
-
|
|
682
|
+
deps["@gravito/quasar"] = "^1.0.0-beta.5";
|
|
683
|
+
deps["@gravito/horizon"] = "^1.0.0-beta.5";
|
|
493
684
|
}
|
|
494
685
|
if (context.withSpectrum) {
|
|
495
|
-
|
|
686
|
+
deps["@gravito/spectrum"] = "^1.0.0-beta.5";
|
|
496
687
|
}
|
|
497
688
|
const pkg = {
|
|
498
689
|
name: context.nameKebabCase,
|
|
@@ -503,717 +694,426 @@ var BaseGenerator = class {
|
|
|
503
694
|
build: "bun build ./src/bootstrap.ts --outdir ./dist --target bun",
|
|
504
695
|
start: "bun run dist/bootstrap.js",
|
|
505
696
|
test: "bun test",
|
|
506
|
-
typecheck: "tsc --noEmit",
|
|
507
|
-
|
|
508
|
-
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
509
|
-
validate: "bun run check && bun run check:deps",
|
|
510
|
-
precommit: "bun run validate",
|
|
511
|
-
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
512
|
-
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
697
|
+
typecheck: "bun tsc --noEmit",
|
|
698
|
+
validate: "bun run typecheck && bun run test"
|
|
513
699
|
},
|
|
514
|
-
dependencies:
|
|
515
|
-
devDependencies: {
|
|
516
|
-
"bun-types": "latest",
|
|
517
|
-
typescript: "^5.0.0"
|
|
518
|
-
}
|
|
700
|
+
dependencies: deps,
|
|
701
|
+
devDependencies: { "bun-types": "latest", typescript: "^5.9.3" }
|
|
519
702
|
};
|
|
520
703
|
return JSON.stringify(pkg, null, 2);
|
|
521
704
|
}
|
|
705
|
+
async generateCheckScripts(context) {
|
|
706
|
+
const scriptsDir = import_node_path4.default.resolve(context.targetDir, "scripts");
|
|
707
|
+
await import_promises4.default.mkdir(scriptsDir, { recursive: true });
|
|
708
|
+
const templatesDir = import_node_path4.default.resolve(this.config.templatesDir, "scripts");
|
|
709
|
+
await this.generateFileFromTemplate(
|
|
710
|
+
templatesDir,
|
|
711
|
+
"check-dependencies.ts.hbs",
|
|
712
|
+
"scripts/check-dependencies.ts",
|
|
713
|
+
context
|
|
714
|
+
);
|
|
715
|
+
await this.generateFileFromTemplate(templatesDir, "check.sh.hbs", "scripts/check.sh", context);
|
|
716
|
+
await this.generateFileFromTemplate(
|
|
717
|
+
templatesDir,
|
|
718
|
+
"pre-commit.sh.hbs",
|
|
719
|
+
"scripts/pre-commit.sh",
|
|
720
|
+
context
|
|
721
|
+
);
|
|
722
|
+
await this.writeFile(
|
|
723
|
+
context.targetDir,
|
|
724
|
+
"CHECK_SYSTEM.md",
|
|
725
|
+
"# Project Check System\n\nRun `bun run validate` to check everything.\n"
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
log(message) {
|
|
729
|
+
if (this.config.verbose) {
|
|
730
|
+
console.log(message);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
static createContext(name, targetDir, architecture, packageManager = "bun", extra = {}) {
|
|
734
|
+
const toPascalCase = (str) => str.replace(/([a-z])([A-Z])/g, "$1 $2").split(/[-_ ]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
735
|
+
const toCamelCase = (str) => {
|
|
736
|
+
const pascal = toPascalCase(str);
|
|
737
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
738
|
+
};
|
|
739
|
+
const toSnakeCase = (str) => str.replace(/([a-z])([A-Z])/g, "$1_$2").split(/[-_ ]+/).map((word) => word.toLowerCase()).join("_");
|
|
740
|
+
const toKebabCase = (str) => str.replace(/([a-z])([A-Z])/g, "$1-$2").split(/[-_ ]+/).map((word) => word.toLowerCase()).join("-");
|
|
741
|
+
return {
|
|
742
|
+
name,
|
|
743
|
+
namePascalCase: toPascalCase(name),
|
|
744
|
+
nameCamelCase: toCamelCase(name),
|
|
745
|
+
nameSnakeCase: toSnakeCase(name),
|
|
746
|
+
nameKebabCase: toKebabCase(name),
|
|
747
|
+
targetDir,
|
|
748
|
+
architecture,
|
|
749
|
+
packageManager,
|
|
750
|
+
year: (/* @__PURE__ */ new Date()).getFullYear().toString(),
|
|
751
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
752
|
+
...extra
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// src/utils/ConfigGenerator.ts
|
|
758
|
+
var ConfigGenerator = class {
|
|
522
759
|
/**
|
|
523
|
-
* Generate
|
|
760
|
+
* Generate app configuration (simple version for Clean Architecture)
|
|
524
761
|
*/
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
COPY package.json bun.lockb /temp/dev/
|
|
534
|
-
RUN cd /temp/dev && bun install --frozen-lockfile
|
|
535
|
-
|
|
536
|
-
# Build application
|
|
537
|
-
FROM base AS build
|
|
538
|
-
COPY --from=install /temp/dev/node_modules node_modules
|
|
539
|
-
COPY . .
|
|
540
|
-
ENV NODE_ENV=production
|
|
541
|
-
RUN bun run build
|
|
542
|
-
|
|
543
|
-
# Final production image
|
|
544
|
-
FROM base AS release
|
|
545
|
-
COPY --from=build /usr/src/app/${entrypoint} index.js
|
|
546
|
-
COPY --from=build /usr/src/app/package.json .
|
|
547
|
-
|
|
548
|
-
# Create a non-root user for security
|
|
549
|
-
USER bun
|
|
550
|
-
EXPOSE 3000/tcp
|
|
551
|
-
ENTRYPOINT [ "bun", "run", "index.js" ]
|
|
762
|
+
static generateSimpleAppConfig(context) {
|
|
763
|
+
return `export default {
|
|
764
|
+
name: process.env.APP_NAME ?? '${context.name}',
|
|
765
|
+
env: process.env.APP_ENV ?? 'development',
|
|
766
|
+
debug: process.env.APP_DEBUG === 'true',
|
|
767
|
+
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
768
|
+
key: process.env.APP_KEY,
|
|
769
|
+
}
|
|
552
770
|
`;
|
|
553
771
|
}
|
|
554
772
|
/**
|
|
555
|
-
* Generate
|
|
773
|
+
* Generate app configuration (detailed version for Enterprise MVC)
|
|
556
774
|
*/
|
|
557
|
-
|
|
558
|
-
return
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
*.log
|
|
563
|
-
.vscode
|
|
564
|
-
.idea
|
|
565
|
-
tests
|
|
566
|
-
`;
|
|
567
|
-
}
|
|
775
|
+
static generateDetailedAppConfig(context) {
|
|
776
|
+
return `/**
|
|
777
|
+
* Application Configuration
|
|
778
|
+
*/
|
|
779
|
+
export default {
|
|
568
780
|
/**
|
|
569
|
-
*
|
|
781
|
+
* Application name
|
|
570
782
|
*/
|
|
571
|
-
|
|
572
|
-
const profile = context.profile || "core";
|
|
573
|
-
let envContent = `# ============================================================================
|
|
574
|
-
# Application Configuration
|
|
575
|
-
# ============================================================================
|
|
576
|
-
|
|
577
|
-
APP_NAME=${context.name}
|
|
578
|
-
APP_ENV=development
|
|
579
|
-
APP_DEBUG=true
|
|
580
|
-
APP_URL=http://localhost:3000
|
|
581
|
-
APP_KEY=
|
|
582
|
-
|
|
583
|
-
# ============================================================================
|
|
584
|
-
# Database Configuration
|
|
585
|
-
# ============================================================================
|
|
586
|
-
|
|
587
|
-
# Database Connection (sqlite, postgres, mysql)
|
|
588
|
-
DB_CONNECTION=${profile === "core" ? "sqlite" : "postgres"}
|
|
589
|
-
|
|
590
|
-
# SQLite Configuration (when DB_CONNECTION=sqlite)
|
|
591
|
-
DB_DATABASE=database/database.sqlite
|
|
592
|
-
|
|
593
|
-
# PostgreSQL Configuration (when DB_CONNECTION=postgres)
|
|
594
|
-
${profile !== "core" ? `DB_HOST=127.0.0.1
|
|
595
|
-
DB_PORT=5432
|
|
596
|
-
DB_DATABASE=${context.name}
|
|
597
|
-
DB_USERNAME=postgres
|
|
598
|
-
DB_PASSWORD=
|
|
599
|
-
DB_SSLMODE=prefer` : `# DB_HOST=127.0.0.1
|
|
600
|
-
# DB_PORT=5432
|
|
601
|
-
# DB_DATABASE=${context.name}
|
|
602
|
-
# DB_USERNAME=postgres
|
|
603
|
-
# DB_PASSWORD=
|
|
604
|
-
# DB_SSLMODE=prefer`}
|
|
605
|
-
|
|
606
|
-
# MySQL Configuration (when DB_CONNECTION=mysql)
|
|
607
|
-
# DB_HOST=127.0.0.1
|
|
608
|
-
# DB_PORT=3306
|
|
609
|
-
# DB_DATABASE=${context.name}
|
|
610
|
-
# DB_USERNAME=root
|
|
611
|
-
# DB_PASSWORD=
|
|
612
|
-
|
|
613
|
-
# ============================================================================
|
|
614
|
-
# Redis Configuration (@gravito/plasma)
|
|
615
|
-
# ============================================================================
|
|
616
|
-
|
|
617
|
-
# Default Redis Connection
|
|
618
|
-
REDIS_CONNECTION=default
|
|
619
|
-
REDIS_HOST=127.0.0.1
|
|
620
|
-
REDIS_PORT=6379
|
|
621
|
-
REDIS_PASSWORD=
|
|
622
|
-
REDIS_DB=0
|
|
623
|
-
|
|
624
|
-
# Redis Connection Options
|
|
625
|
-
REDIS_CONNECT_TIMEOUT=10000
|
|
626
|
-
REDIS_COMMAND_TIMEOUT=5000
|
|
627
|
-
REDIS_KEY_PREFIX=
|
|
628
|
-
REDIS_MAX_RETRIES=3
|
|
629
|
-
REDIS_RETRY_DELAY=1000
|
|
630
|
-
|
|
631
|
-
# Cache-specific Redis Connection (optional, falls back to default)
|
|
632
|
-
# REDIS_CACHE_HOST=127.0.0.1
|
|
633
|
-
# REDIS_CACHE_PORT=6379
|
|
634
|
-
# REDIS_CACHE_PASSWORD=
|
|
635
|
-
REDIS_CACHE_DB=1
|
|
636
|
-
|
|
637
|
-
# Queue-specific Redis Connection (optional, falls back to default)
|
|
638
|
-
# REDIS_QUEUE_HOST=127.0.0.1
|
|
639
|
-
# REDIS_QUEUE_PORT=6379
|
|
640
|
-
# REDIS_QUEUE_PASSWORD=
|
|
641
|
-
REDIS_QUEUE_DB=2
|
|
642
|
-
|
|
643
|
-
# ============================================================================
|
|
644
|
-
# Cache Configuration (@gravito/stasis)
|
|
645
|
-
# ============================================================================
|
|
646
|
-
|
|
647
|
-
# Cache Driver (memory, file, redis)
|
|
648
|
-
CACHE_DRIVER=${profile === "core" ? "memory" : "redis"}
|
|
649
|
-
|
|
650
|
-
# File Cache Path (when CACHE_DRIVER=file)
|
|
651
|
-
CACHE_PATH=storage/framework/cache
|
|
652
|
-
|
|
653
|
-
# Redis Cache Configuration (when CACHE_DRIVER=redis)
|
|
654
|
-
REDIS_CACHE_CONNECTION=cache
|
|
655
|
-
REDIS_CACHE_PREFIX=cache:
|
|
656
|
-
|
|
657
|
-
# ============================================================================
|
|
658
|
-
# Queue Configuration (@gravito/stream)
|
|
659
|
-
# ============================================================================
|
|
660
|
-
|
|
661
|
-
# Queue Connection (sync, memory, database, redis, kafka, sqs, rabbitmq)
|
|
662
|
-
QUEUE_CONNECTION=${profile === "core" ? "sync" : "redis"}
|
|
663
|
-
|
|
664
|
-
# Database Queue Configuration (when QUEUE_CONNECTION=database)
|
|
665
|
-
QUEUE_TABLE=jobs
|
|
666
|
-
|
|
667
|
-
# Redis Queue Configuration (when QUEUE_CONNECTION=redis)
|
|
668
|
-
REDIS_PREFIX=queue:
|
|
669
|
-
|
|
670
|
-
`;
|
|
671
|
-
if (profile === "enterprise" || profile === "scale") {
|
|
672
|
-
envContent += `# Kafka Queue Configuration (when QUEUE_CONNECTION=kafka)
|
|
673
|
-
# KAFKA_BROKERS=localhost:9092
|
|
674
|
-
# KAFKA_CONSUMER_GROUP_ID=gravito-workers
|
|
675
|
-
# KAFKA_CLIENT_ID=${context.name}
|
|
676
|
-
|
|
677
|
-
# AWS SQS Queue Configuration (when QUEUE_CONNECTION=sqs)
|
|
678
|
-
# AWS_REGION=us-east-1
|
|
679
|
-
# SQS_QUEUE_URL_PREFIX=
|
|
680
|
-
# SQS_VISIBILITY_TIMEOUT=30
|
|
681
|
-
# SQS_WAIT_TIME_SECONDS=20
|
|
682
|
-
|
|
683
|
-
# RabbitMQ Queue Configuration (when QUEUE_CONNECTION=rabbitmq)
|
|
684
|
-
# RABBITMQ_URL=amqp://localhost
|
|
685
|
-
# RABBITMQ_EXCHANGE=gravito.events
|
|
686
|
-
# RABBITMQ_EXCHANGE_TYPE=fanout
|
|
687
|
-
|
|
688
|
-
`;
|
|
689
|
-
}
|
|
690
|
-
envContent += `# ============================================================================
|
|
691
|
-
# Logging Configuration
|
|
692
|
-
# ============================================================================
|
|
783
|
+
name: process.env.APP_NAME ?? '${context.name}',
|
|
693
784
|
|
|
694
|
-
LOG_LEVEL=debug
|
|
695
|
-
`;
|
|
696
|
-
return envContent;
|
|
697
|
-
}
|
|
698
785
|
/**
|
|
699
|
-
*
|
|
786
|
+
* Application environment
|
|
700
787
|
*/
|
|
701
|
-
|
|
702
|
-
return `# Dependencies
|
|
703
|
-
node_modules/
|
|
704
|
-
|
|
705
|
-
# Build output
|
|
706
|
-
dist/
|
|
707
|
-
|
|
708
|
-
# Environment
|
|
709
|
-
.env
|
|
710
|
-
.env.local
|
|
711
|
-
.env.*.local
|
|
712
|
-
|
|
713
|
-
# IDE
|
|
714
|
-
.idea/
|
|
715
|
-
.vscode/
|
|
716
|
-
*.swp
|
|
717
|
-
*.swo
|
|
718
|
-
|
|
719
|
-
# System
|
|
720
|
-
.DS_Store
|
|
721
|
-
Thumbs.db
|
|
788
|
+
env: process.env.APP_ENV ?? 'development',
|
|
722
789
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
790
|
+
/**
|
|
791
|
+
* Application port
|
|
792
|
+
*/
|
|
793
|
+
port: Number.parseInt(process.env.PORT ?? '3000', 10),
|
|
726
794
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
795
|
+
/**
|
|
796
|
+
* View directory
|
|
797
|
+
*/
|
|
798
|
+
VIEW_DIR: process.env.VIEW_DIR ?? 'src/views',
|
|
730
799
|
|
|
731
|
-
# Coverage
|
|
732
|
-
coverage/
|
|
733
|
-
`;
|
|
734
|
-
}
|
|
735
800
|
/**
|
|
736
|
-
*
|
|
801
|
+
* Debug mode
|
|
737
802
|
*/
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
compilerOptions: {
|
|
741
|
-
target: "ESNext",
|
|
742
|
-
module: "ESNext",
|
|
743
|
-
moduleResolution: "bundler",
|
|
744
|
-
esModuleInterop: true,
|
|
745
|
-
strict: true,
|
|
746
|
-
skipLibCheck: true,
|
|
747
|
-
declaration: true,
|
|
748
|
-
experimentalDecorators: true,
|
|
749
|
-
emitDecoratorMetadata: true,
|
|
750
|
-
types: ["bun-types"],
|
|
751
|
-
outDir: "./dist",
|
|
752
|
-
rootDir: "./src",
|
|
753
|
-
baseUrl: ".",
|
|
754
|
-
paths: {
|
|
755
|
-
"@/*": ["./src/*"]
|
|
756
|
-
}
|
|
757
|
-
},
|
|
758
|
-
include: ["src/**/*"],
|
|
759
|
-
exclude: ["node_modules", "dist"]
|
|
760
|
-
};
|
|
761
|
-
return JSON.stringify(config, null, 2);
|
|
762
|
-
}
|
|
803
|
+
debug: process.env.APP_DEBUG === 'true',
|
|
804
|
+
|
|
763
805
|
/**
|
|
764
|
-
*
|
|
806
|
+
* Application URL
|
|
765
807
|
*/
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
await import_promises2.default.mkdir(scriptsDir, { recursive: true });
|
|
769
|
-
await this.writeFile(
|
|
770
|
-
scriptsDir,
|
|
771
|
-
"check-dependencies.ts",
|
|
772
|
-
this.generateCheckDependenciesScript()
|
|
773
|
-
);
|
|
774
|
-
await this.writeFile(scriptsDir, "check.sh", this.generateCheckShellScript());
|
|
775
|
-
await this.writeFile(scriptsDir, "pre-commit.sh", this.generatePreCommitScript());
|
|
776
|
-
await this.writeFile(context.targetDir, "CHECK_SYSTEM.md", this.generateCheckSystemDoc(context));
|
|
777
|
-
}
|
|
808
|
+
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
809
|
+
|
|
778
810
|
/**
|
|
779
|
-
*
|
|
811
|
+
* Timezone
|
|
780
812
|
*/
|
|
781
|
-
|
|
782
|
-
return `/**
|
|
783
|
-
* \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5\u8173\u672C
|
|
784
|
-
*
|
|
785
|
-
* \u6AA2\u67E5 package.json \u4E2D\u7684\u5957\u4EF6\u662F\u5426\u70BA\u6700\u65B0\u7A69\u5B9A\u7248\u672C
|
|
786
|
-
* \u4E26\u63D0\u4F9B\u66F4\u65B0\u5EFA\u8B70
|
|
787
|
-
*/
|
|
813
|
+
timezone: 'UTC',
|
|
788
814
|
|
|
789
|
-
|
|
790
|
-
|
|
815
|
+
/**
|
|
816
|
+
* Locale
|
|
817
|
+
*/
|
|
818
|
+
locale: 'en',
|
|
791
819
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
interface PackageInfo {
|
|
798
|
-
name: string
|
|
799
|
-
current: string
|
|
800
|
-
latest: string
|
|
801
|
-
outdated: boolean
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const colors = {
|
|
805
|
-
reset: '\\x1b[0m',
|
|
806
|
-
green: '\\x1b[32m',
|
|
807
|
-
yellow: '\\x1b[33m',
|
|
808
|
-
red: '\\x1b[31m',
|
|
809
|
-
blue: '\\x1b[36m',
|
|
810
|
-
}
|
|
820
|
+
/**
|
|
821
|
+
* Fallback locale
|
|
822
|
+
*/
|
|
823
|
+
fallbackLocale: 'en',
|
|
811
824
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
825
|
+
/**
|
|
826
|
+
* Encryption key
|
|
827
|
+
*/
|
|
828
|
+
key: process.env.APP_KEY,
|
|
815
829
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
} catch {
|
|
823
|
-
return null
|
|
824
|
-
}
|
|
825
|
-
}
|
|
830
|
+
/**
|
|
831
|
+
* Service providers to register
|
|
832
|
+
*/
|
|
833
|
+
providers: [
|
|
834
|
+
// Framework providers
|
|
835
|
+
// 'RouteServiceProvider',
|
|
826
836
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
837
|
+
// Application providers
|
|
838
|
+
// 'AppServiceProvider',
|
|
839
|
+
],
|
|
830
840
|
}
|
|
831
|
-
|
|
832
|
-
async function checkPackage(
|
|
833
|
-
name: string,
|
|
834
|
-
currentVersion: string
|
|
835
|
-
): Promise<PackageInfo | null> {
|
|
836
|
-
// \u8DF3\u904E\u672C\u5730\u9023\u7D50\u7684\u5957\u4EF6
|
|
837
|
-
if (currentVersion.startsWith('link:') || currentVersion.startsWith('workspace:')) {
|
|
838
|
-
return null
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
const current = parseVersion(currentVersion)
|
|
842
|
-
const latest = await getLatestVersion(name)
|
|
843
|
-
|
|
844
|
-
if (!latest) {
|
|
845
|
-
return null
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
return {
|
|
849
|
-
name,
|
|
850
|
-
current,
|
|
851
|
-
latest,
|
|
852
|
-
outdated: current !== latest,
|
|
841
|
+
`;
|
|
853
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Generate database configuration (simple version)
|
|
845
|
+
*/
|
|
846
|
+
static generateSimpleDatabaseConfig() {
|
|
847
|
+
return `export default {
|
|
848
|
+
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
849
|
+
connections: {
|
|
850
|
+
sqlite: {
|
|
851
|
+
driver: 'sqlite',
|
|
852
|
+
database: process.env.DB_DATABASE ?? 'database/database.sqlite',
|
|
853
|
+
},
|
|
854
|
+
},
|
|
854
855
|
}
|
|
855
|
-
|
|
856
|
-
async function main() {
|
|
857
|
-
log('\\n=== \u76F8\u4F9D\u5957\u4EF6\u7248\u672C\u6AA2\u67E5 ===\\n', 'blue')
|
|
858
|
-
|
|
859
|
-
const packageJsonPath = join(process.cwd(), 'package.json')
|
|
860
|
-
const packageJson: PackageJson = JSON.parse(
|
|
861
|
-
readFileSync(packageJsonPath, 'utf-8')
|
|
862
|
-
)
|
|
863
|
-
|
|
864
|
-
const allDependencies = {
|
|
865
|
-
...packageJson.dependencies,
|
|
866
|
-
...packageJson.devDependencies,
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
log(\`\u6AA2\u67E5 \${Object.keys(allDependencies).length} \u500B\u5957\u4EF6...\\n\`, 'yellow')
|
|
870
|
-
|
|
871
|
-
const results: PackageInfo[] = []
|
|
872
|
-
const outdated: PackageInfo[] = []
|
|
873
|
-
const upToDate: PackageInfo[] = []
|
|
874
|
-
|
|
875
|
-
// \u6AA2\u67E5\u6240\u6709\u5957\u4EF6
|
|
876
|
-
for (const [name, version] of Object.entries(allDependencies)) {
|
|
877
|
-
const info = await checkPackage(name, version)
|
|
878
|
-
if (info) {
|
|
879
|
-
results.push(info)
|
|
880
|
-
if (info.outdated) {
|
|
881
|
-
outdated.push(info)
|
|
882
|
-
} else {
|
|
883
|
-
upToDate.push(info)
|
|
884
|
-
}
|
|
885
|
-
}
|
|
856
|
+
`;
|
|
886
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
* Generate database configuration (detailed version)
|
|
860
|
+
*/
|
|
861
|
+
static generateDetailedDatabaseConfig() {
|
|
862
|
+
return `/**
|
|
863
|
+
* Database Configuration
|
|
864
|
+
*/
|
|
865
|
+
export default {
|
|
866
|
+
/**
|
|
867
|
+
* Default connection
|
|
868
|
+
*/
|
|
869
|
+
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
887
870
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
871
|
+
/**
|
|
872
|
+
* Database connections
|
|
873
|
+
*/
|
|
874
|
+
connections: {
|
|
875
|
+
sqlite: {
|
|
876
|
+
driver: 'sqlite',
|
|
877
|
+
database: process.env.DB_DATABASE ?? 'database/database.sqlite',
|
|
878
|
+
},
|
|
895
879
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
880
|
+
mysql: {
|
|
881
|
+
driver: 'mysql',
|
|
882
|
+
host: process.env.DB_HOST ?? 'localhost',
|
|
883
|
+
port: Number(process.env.DB_PORT ?? 3306),
|
|
884
|
+
database: process.env.DB_DATABASE ?? 'forge',
|
|
885
|
+
username: process.env.DB_USERNAME ?? 'forge',
|
|
886
|
+
password: process.env.DB_PASSWORD ?? '',
|
|
887
|
+
},
|
|
902
888
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
889
|
+
postgres: {
|
|
890
|
+
driver: 'postgres',
|
|
891
|
+
host: process.env.DB_HOST ?? 'localhost',
|
|
892
|
+
port: Number(process.env.DB_PORT ?? 5432),
|
|
893
|
+
database: process.env.DB_DATABASE ?? 'forge',
|
|
894
|
+
username: process.env.DB_USERNAME ?? 'forge',
|
|
895
|
+
password: process.env.DB_PASSWORD ?? '',
|
|
896
|
+
},
|
|
897
|
+
},
|
|
908
898
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
899
|
+
/**
|
|
900
|
+
* Migration settings
|
|
901
|
+
*/
|
|
902
|
+
migrations: {
|
|
903
|
+
table: 'migrations',
|
|
904
|
+
path: 'database/migrations',
|
|
905
|
+
},
|
|
906
|
+
}
|
|
907
|
+
`;
|
|
917
908
|
}
|
|
909
|
+
/**
|
|
910
|
+
* Generate auth configuration
|
|
911
|
+
*/
|
|
912
|
+
static generateAuthConfig() {
|
|
913
|
+
return `export default {
|
|
914
|
+
defaults: { guard: 'web' },
|
|
915
|
+
guards: {
|
|
916
|
+
web: { driver: 'session', provider: 'users' },
|
|
917
|
+
api: { driver: 'token', provider: 'users' },
|
|
918
|
+
},
|
|
918
919
|
}
|
|
919
|
-
|
|
920
|
-
main().catch((error) => {
|
|
921
|
-
log(\`\\n\u932F\u8AA4: \${error.message}\`, 'red')
|
|
922
|
-
process.exit(1)
|
|
923
|
-
})
|
|
924
920
|
`;
|
|
925
921
|
}
|
|
926
922
|
/**
|
|
927
|
-
* Generate
|
|
923
|
+
* Generate cache configuration
|
|
928
924
|
*/
|
|
929
|
-
|
|
930
|
-
return
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
# \u984F\u8272\u5B9A\u7FA9
|
|
938
|
-
GREEN='\\033[0;32m'
|
|
939
|
-
YELLOW='\\033[1;33m'
|
|
940
|
-
RED='\\033[0;31m'
|
|
941
|
-
BLUE='\\033[0;34m'
|
|
942
|
-
NC='\\033[0m' # No Color
|
|
943
|
-
|
|
944
|
-
echo -e "\${BLUE}=== \u5C08\u6848\u6AA2\u67E5 ===\${NC}\\n"
|
|
945
|
-
|
|
946
|
-
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
947
|
-
if [ ! -f "package.json" ]; then
|
|
948
|
-
echo -e "\${RED}\u932F\u8AA4: \u8ACB\u5728\u5C08\u6848\u6839\u76EE\u9304\u57F7\u884C\u6B64\u8173\u672C\${NC}"
|
|
949
|
-
exit 1
|
|
950
|
-
fi
|
|
951
|
-
|
|
952
|
-
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
953
|
-
if ! command -v bun &> /dev/null; then
|
|
954
|
-
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
955
|
-
exit 1
|
|
956
|
-
fi
|
|
957
|
-
|
|
958
|
-
# 1. \u985E\u578B\u6AA2\u67E5
|
|
959
|
-
echo -e "\${YELLOW}[1/3] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
960
|
-
if bun run typecheck; then
|
|
961
|
-
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
962
|
-
else
|
|
963
|
-
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
964
|
-
exit 1
|
|
965
|
-
fi
|
|
966
|
-
|
|
967
|
-
# 2. \u57F7\u884C\u6E2C\u8A66
|
|
968
|
-
echo -e "\${YELLOW}[2/3] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
969
|
-
if bun test; then
|
|
970
|
-
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
971
|
-
else
|
|
972
|
-
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
973
|
-
exit 1
|
|
974
|
-
fi
|
|
975
|
-
|
|
976
|
-
# 3. \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C\uFF08\u53EF\u9078\uFF0C\u56E0\u70BA\u9700\u8981\u7DB2\u8DEF\u9023\u7DDA\uFF09
|
|
977
|
-
echo -e "\${YELLOW}[3/3] \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C...\${NC}"
|
|
978
|
-
if bun run check:deps; then
|
|
979
|
-
echo -e "\${GREEN}\u2713 \u4F9D\u8CF4\u6AA2\u67E5\u5B8C\u6210\${NC}\\n"
|
|
980
|
-
else
|
|
981
|
-
echo -e "\${YELLOW}\u26A0 \u4F9D\u8CF4\u6AA2\u67E5\u6709\u8B66\u544A\uFF08\u67D0\u4E9B\u5957\u4EF6\u53EF\u80FD\u9700\u8981\u66F4\u65B0\uFF09\${NC}\\n"
|
|
982
|
-
fi
|
|
983
|
-
|
|
984
|
-
echo -e "\${GREEN}=== \u6240\u6709\u6AA2\u67E5\u5B8C\u6210 ===\${NC}"
|
|
925
|
+
static generateCacheConfig() {
|
|
926
|
+
return `export default {
|
|
927
|
+
default: process.env.CACHE_DRIVER ?? 'memory',
|
|
928
|
+
stores: {
|
|
929
|
+
memory: { driver: 'memory' },
|
|
930
|
+
},
|
|
931
|
+
}
|
|
985
932
|
`;
|
|
986
933
|
}
|
|
987
934
|
/**
|
|
988
|
-
* Generate
|
|
935
|
+
* Generate logging configuration
|
|
989
936
|
*/
|
|
990
|
-
|
|
991
|
-
return
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
# ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
998
|
-
# \u6216
|
|
999
|
-
# cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1000
|
-
# chmod +x .git/hooks/pre-commit
|
|
1001
|
-
|
|
1002
|
-
set -e
|
|
1003
|
-
|
|
1004
|
-
# \u984F\u8272\u5B9A\u7FA9
|
|
1005
|
-
GREEN='\\033[0;32m'
|
|
1006
|
-
YELLOW='\\033[1;33m'
|
|
1007
|
-
RED='\\033[0;31m'
|
|
1008
|
-
BLUE='\\033[0;34m'
|
|
1009
|
-
NC='\\033[0m' # No Color
|
|
1010
|
-
|
|
1011
|
-
echo -e "\${BLUE}=== Pre-commit \u6AA2\u67E5 ===\${NC}\\n"
|
|
1012
|
-
|
|
1013
|
-
# \u5207\u63DB\u5230\u5C08\u6848\u6839\u76EE\u9304
|
|
1014
|
-
cd "$(git rev-parse --show-toplevel)"
|
|
1015
|
-
|
|
1016
|
-
# \u6AA2\u67E5\u662F\u5426\u5728\u6B63\u78BA\u7684\u76EE\u9304
|
|
1017
|
-
if [ ! -f "package.json" ]; then
|
|
1018
|
-
echo -e "\${RED}\u932F\u8AA4: \u627E\u4E0D\u5230 package.json\${NC}"
|
|
1019
|
-
exit 1
|
|
1020
|
-
fi
|
|
1021
|
-
|
|
1022
|
-
# \u6AA2\u67E5 Bun \u662F\u5426\u5B89\u88DD
|
|
1023
|
-
if ! command -v bun &> /dev/null; then
|
|
1024
|
-
echo -e "\${RED}\u932F\u8AA4: \u672A\u627E\u5230 bun\uFF0C\u8ACB\u5148\u5B89\u88DD Bun\${NC}"
|
|
1025
|
-
exit 1
|
|
1026
|
-
fi
|
|
1027
|
-
|
|
1028
|
-
# 1. \u985E\u578B\u6AA2\u67E5\uFF08\u5FEB\u901F\u6AA2\u67E5\uFF09
|
|
1029
|
-
echo -e "\${YELLOW}[1/2] \u57F7\u884C\u985E\u578B\u6AA2\u67E5...\${NC}"
|
|
1030
|
-
if bun run typecheck; then
|
|
1031
|
-
echo -e "\${GREEN}\u2713 \u985E\u578B\u6AA2\u67E5\u901A\u904E\${NC}\\n"
|
|
1032
|
-
else
|
|
1033
|
-
echo -e "\${RED}\u2717 \u985E\u578B\u6AA2\u67E5\u5931\u6557\${NC}"
|
|
1034
|
-
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u985E\u578B\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
1035
|
-
exit 1
|
|
1036
|
-
fi
|
|
1037
|
-
|
|
1038
|
-
# 2. \u57F7\u884C\u6E2C\u8A66\uFF08\u53EF\u9078\uFF0C\u5982\u679C\u6E2C\u8A66\u6642\u9593\u8F03\u9577\u53EF\u4EE5\u8A3B\u89E3\u6389\uFF09
|
|
1039
|
-
echo -e "\${YELLOW}[2/2] \u57F7\u884C\u6E2C\u8A66...\${NC}"
|
|
1040
|
-
if bun test; then
|
|
1041
|
-
echo -e "\${GREEN}\u2713 \u6E2C\u8A66\u901A\u904E\${NC}\\n"
|
|
1042
|
-
else
|
|
1043
|
-
echo -e "\${RED}\u2717 \u6E2C\u8A66\u5931\u6557\${NC}"
|
|
1044
|
-
echo -e "\${YELLOW}\u63D0\u793A: \u8ACB\u4FEE\u6B63\u6E2C\u8A66\u932F\u8AA4\u5F8C\u518D\u63D0\u4EA4\${NC}"
|
|
1045
|
-
exit 1
|
|
1046
|
-
fi
|
|
1047
|
-
|
|
1048
|
-
echo -e "\${GREEN}=== Pre-commit \u6AA2\u67E5\u901A\u904E ===\${NC}\\n"
|
|
937
|
+
static generateLoggingConfig() {
|
|
938
|
+
return `export default {
|
|
939
|
+
default: process.env.LOG_CHANNEL ?? 'console',
|
|
940
|
+
channels: {
|
|
941
|
+
console: { driver: 'console', level: process.env.LOG_LEVEL ?? 'debug' },
|
|
942
|
+
},
|
|
943
|
+
}
|
|
1049
944
|
`;
|
|
1050
945
|
}
|
|
1051
946
|
/**
|
|
1052
|
-
* Generate
|
|
947
|
+
* Generate view configuration
|
|
1053
948
|
*/
|
|
1054
|
-
|
|
1055
|
-
return
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
bun run validate
|
|
1064
|
-
\`\`\`
|
|
1065
|
-
|
|
1066
|
-
### \u57F7\u884C\u55AE\u9805\u6AA2\u67E5
|
|
1067
|
-
\`\`\`bash
|
|
1068
|
-
# \u985E\u578B\u6AA2\u67E5
|
|
1069
|
-
bun run typecheck
|
|
1070
|
-
|
|
1071
|
-
# \u6E2C\u8A66
|
|
1072
|
-
bun run test
|
|
1073
|
-
|
|
1074
|
-
# \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1075
|
-
bun run check:deps
|
|
1076
|
-
\`\`\`
|
|
1077
|
-
|
|
1078
|
-
## \u53EF\u7528\u547D\u4EE4
|
|
1079
|
-
|
|
1080
|
-
### Package.json \u8173\u672C
|
|
1081
|
-
|
|
1082
|
-
| \u547D\u4EE4 | \u8AAA\u660E |
|
|
1083
|
-
|------|------|
|
|
1084
|
-
| \`bun run typecheck\` | TypeScript \u985E\u578B\u6AA2\u67E5 |
|
|
1085
|
-
| \`bun run test\` | \u57F7\u884C\u6240\u6709\u6E2C\u8A66 |
|
|
1086
|
-
| \`bun run check\` | \u985E\u578B\u6AA2\u67E5 + \u6E2C\u8A66 |
|
|
1087
|
-
| \`bun run check:deps\` | \u6AA2\u67E5\u4F9D\u8CF4\u7248\u672C |
|
|
1088
|
-
| \`bun run validate\` | \u5B8C\u6574\u9A57\u8B49\uFF08\u985E\u578B + \u6E2C\u8A66 + \u4F9D\u8CF4\uFF09 |
|
|
1089
|
-
| \`bun run precommit\` | \u7B49\u540C\u65BC \`validate\` |
|
|
1090
|
-
|
|
1091
|
-
### Shell \u8173\u672C
|
|
1092
|
-
|
|
1093
|
-
| \u8173\u672C | \u8AAA\u660E |
|
|
1094
|
-
|------|------|
|
|
1095
|
-
| \`./scripts/check.sh\` | \u5B8C\u6574\u5C08\u6848\u6AA2\u67E5\uFF08Shell \u7248\u672C\uFF09 |
|
|
1096
|
-
| \`./scripts/pre-commit.sh\` | Pre-commit hook \u8173\u672C |
|
|
1097
|
-
|
|
1098
|
-
## Pre-commit Hook\uFF08\u63A8\u85A6\uFF09
|
|
1099
|
-
|
|
1100
|
-
\u5B89\u88DD pre-commit hook \u5F8C\uFF0C\u6BCF\u6B21 \`git commit\` \u524D\u6703\u81EA\u52D5\u57F7\u884C\u6AA2\u67E5\uFF1A
|
|
1101
|
-
|
|
1102
|
-
\`\`\`bash
|
|
1103
|
-
# \u5B89\u88DD pre-commit hook
|
|
1104
|
-
ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1105
|
-
|
|
1106
|
-
# \u6216\u4F7F\u7528\u8907\u88FD\u65B9\u5F0F
|
|
1107
|
-
cp scripts/pre-commit.sh .git/hooks/pre-commit
|
|
1108
|
-
chmod +x .git/hooks/pre-commit
|
|
1109
|
-
\`\`\`
|
|
1110
|
-
|
|
1111
|
-
**\u529F\u80FD\uFF1A**
|
|
1112
|
-
- \u2705 \u81EA\u52D5\u57F7\u884C\u985E\u578B\u6AA2\u67E5
|
|
1113
|
-
- \u2705 \u81EA\u52D5\u57F7\u884C\u6E2C\u8A66
|
|
1114
|
-
- \u274C \u6AA2\u67E5\u5931\u6557\u6642\u963B\u6B62\u63D0\u4EA4
|
|
949
|
+
static generateViewConfig() {
|
|
950
|
+
return `/**
|
|
951
|
+
* View Configuration
|
|
952
|
+
*/
|
|
953
|
+
export default {
|
|
954
|
+
/**
|
|
955
|
+
* View engine
|
|
956
|
+
*/
|
|
957
|
+
engine: 'html',
|
|
1115
958
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
959
|
+
/**
|
|
960
|
+
* View directory
|
|
961
|
+
*/
|
|
962
|
+
path: 'src/views',
|
|
1120
963
|
|
|
1121
|
-
|
|
964
|
+
/**
|
|
965
|
+
* Cache views in production
|
|
966
|
+
*/
|
|
967
|
+
cache: process.env.NODE_ENV === 'production',
|
|
968
|
+
}
|
|
969
|
+
`;
|
|
970
|
+
}
|
|
971
|
+
};
|
|
1122
972
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
973
|
+
// src/utils/ServiceProviderGenerator.ts
|
|
974
|
+
var ServiceProviderGenerator = class {
|
|
975
|
+
/**
|
|
976
|
+
* Generate App Service Provider
|
|
977
|
+
*/
|
|
978
|
+
static generateAppServiceProvider(context, architectureName) {
|
|
979
|
+
return `/**
|
|
980
|
+
* App Service Provider
|
|
981
|
+
*/
|
|
1126
982
|
|
|
1127
|
-
|
|
1128
|
-
- \u57F7\u884C\u6240\u6709\u55AE\u5143\u6E2C\u8A66\u548C\u6574\u5408\u6E2C\u8A66
|
|
1129
|
-
- \u78BA\u4FDD\u6E2C\u8A66\u901A\u904E
|
|
983
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1130
984
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
985
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
986
|
+
register(_container: Container): void {
|
|
987
|
+
// Register application services
|
|
988
|
+
}
|
|
1135
989
|
|
|
1136
|
-
|
|
990
|
+
boot(_core: PlanetCore): void {
|
|
991
|
+
console.log('${context.name} (${architectureName}) booted!')
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
`;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Generate Middleware Provider
|
|
998
|
+
*/
|
|
999
|
+
static generateMiddlewareProvider() {
|
|
1000
|
+
return `/**
|
|
1001
|
+
* Middleware Service Provider
|
|
1002
|
+
*/
|
|
1137
1003
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1004
|
+
import {
|
|
1005
|
+
ServiceProvider,
|
|
1006
|
+
type Container,
|
|
1007
|
+
type PlanetCore,
|
|
1008
|
+
bodySizeLimit,
|
|
1009
|
+
securityHeaders,
|
|
1010
|
+
} from '@gravito/core'
|
|
1143
1011
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
2. \u6B63\u5E38\u958B\u767C\u548C\u63D0\u4EA4
|
|
1147
|
-
3. \u6AA2\u67E5\u6703\u81EA\u52D5\u57F7\u884C
|
|
1148
|
-
4. \u5982\u6709\u554F\u984C\uFF0C\u4FEE\u6B63\u5F8C\u91CD\u65B0\u63D0\u4EA4
|
|
1012
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
1013
|
+
register(_container: Container): void {}
|
|
1149
1014
|
|
|
1150
|
-
|
|
1015
|
+
boot(core: PlanetCore): void {
|
|
1016
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
1151
1017
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
\u251C\u2500\u2500 scripts/
|
|
1156
|
-
\u2502 \u251C\u2500\u2500 check.sh # \u5B8C\u6574\u6AA2\u67E5\u8173\u672C\uFF08Shell\uFF09
|
|
1157
|
-
\u2502 \u251C\u2500\u2500 check-dependencies.ts # \u4F9D\u8CF4\u7248\u672C\u6AA2\u67E5
|
|
1158
|
-
\u2502 \u2514\u2500\u2500 pre-commit.sh # Pre-commit hook
|
|
1159
|
-
\u2514\u2500\u2500 CHECK_SYSTEM.md # \u672C\u6587\u4EF6
|
|
1160
|
-
\`\`\`
|
|
1018
|
+
core.adapter.use('*', securityHeaders({
|
|
1019
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
1020
|
+
}))
|
|
1161
1021
|
|
|
1162
|
-
|
|
1022
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
1163
1023
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1024
|
+
core.logger.info('\u{1F6E1}\uFE0F Middleware registered')
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
`;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Generate Route Provider
|
|
1031
|
+
*/
|
|
1032
|
+
static generateRouteProvider(routePath = "../../routes/api", importType = "default") {
|
|
1033
|
+
const importStatement = importType === "default" ? `import routes from '${routePath}'` : `import { registerApiRoutes } from '${routePath}'`;
|
|
1034
|
+
const routeCall = importType === "default" ? "routes(core.router)" : "registerApiRoutes(core.router)";
|
|
1035
|
+
return `/**
|
|
1036
|
+
* Route Service Provider
|
|
1037
|
+
*/
|
|
1167
1038
|
|
|
1168
|
-
|
|
1039
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1040
|
+
${importStatement}
|
|
1169
1041
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
2. \u4FEE\u6B63\u554F\u984C
|
|
1173
|
-
3. \u91CD\u65B0\u57F7\u884C\u6AA2\u67E5
|
|
1042
|
+
export class RouteProvider extends ServiceProvider {
|
|
1043
|
+
register(_container: Container): void {}
|
|
1174
1044
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1045
|
+
boot(core: PlanetCore): void {
|
|
1046
|
+
${routeCall}
|
|
1047
|
+
core.logger.info('\u{1F6E4}\uFE0F Routes registered')
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
`;
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Generate Providers Index
|
|
1054
|
+
*/
|
|
1055
|
+
static generateProvidersIndex(providers = ["AppServiceProvider", "MiddlewareProvider", "RouteProvider"]) {
|
|
1056
|
+
const exports2 = providers.map((p) => `export { ${p} } from './${p}'`).join("\n");
|
|
1057
|
+
return `/**
|
|
1058
|
+
* Application Service Providers
|
|
1059
|
+
*/
|
|
1180
1060
|
|
|
1181
|
-
|
|
1182
|
-
\`\`\`bash
|
|
1183
|
-
rm .git/hooks/pre-commit
|
|
1184
|
-
\`\`\`
|
|
1061
|
+
${exports2}
|
|
1185
1062
|
`;
|
|
1186
1063
|
}
|
|
1187
1064
|
/**
|
|
1188
|
-
*
|
|
1065
|
+
* Generate Repository Service Provider
|
|
1189
1066
|
*/
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1067
|
+
static generateRepositoryServiceProvider(repositories = [], additionalServices = []) {
|
|
1068
|
+
const repositoryRegistrations = repositories.map((repo) => ` container.singleton('${repo}', () => new ${repo}())`).join("\n");
|
|
1069
|
+
const serviceRegistrations = additionalServices.map((service) => ` container.singleton('${service}', () => new ${service}())`).join("\n");
|
|
1070
|
+
const imports = [
|
|
1071
|
+
...repositories.map(
|
|
1072
|
+
(repo) => `import { ${repo} } from '../Persistence/Repositories/${repo}'`
|
|
1073
|
+
),
|
|
1074
|
+
...additionalServices.map(
|
|
1075
|
+
(service) => `import { ${service} } from '../ExternalServices/${service}'`
|
|
1076
|
+
)
|
|
1077
|
+
].join("\n");
|
|
1078
|
+
return `/**
|
|
1079
|
+
* Repository Service Provider
|
|
1080
|
+
*
|
|
1081
|
+
* Binds repository interfaces to implementations.
|
|
1082
|
+
*/
|
|
1083
|
+
|
|
1084
|
+
import { ServiceProvider, type Container } from '@gravito/core'
|
|
1085
|
+
${imports}
|
|
1086
|
+
|
|
1087
|
+
export class RepositoryServiceProvider extends ServiceProvider {
|
|
1088
|
+
register(container: Container): void {
|
|
1089
|
+
${repositoryRegistrations || " // Bind repositories here"}
|
|
1090
|
+
${serviceRegistrations || " // Bind external services here"}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
`;
|
|
1194
1094
|
}
|
|
1195
1095
|
/**
|
|
1196
|
-
*
|
|
1096
|
+
* Generate Database Provider
|
|
1197
1097
|
*/
|
|
1198
|
-
static
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1098
|
+
static generateDatabaseProvider() {
|
|
1099
|
+
return `/**
|
|
1100
|
+
* Database Service Provider
|
|
1101
|
+
*/
|
|
1102
|
+
|
|
1103
|
+
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1104
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
1105
|
+
|
|
1106
|
+
export class DatabaseProvider extends ServiceProvider {
|
|
1107
|
+
register(_container: Container): void {
|
|
1108
|
+
// Register database connections
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
boot(core: PlanetCore): void {
|
|
1112
|
+
// Initialize database
|
|
1113
|
+
core.logger.info('\u{1F5C4}\uFE0F Database initialized')
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
`;
|
|
1217
1117
|
}
|
|
1218
1118
|
};
|
|
1219
1119
|
|
|
@@ -1467,57 +1367,22 @@ var CleanArchitectureGenerator = class extends BaseGenerator {
|
|
|
1467
1367
|
];
|
|
1468
1368
|
}
|
|
1469
1369
|
// ─────────────────────────────────────────────────────────────
|
|
1470
|
-
// Config Generators (
|
|
1370
|
+
// Config Generators (using shared ConfigGenerator)
|
|
1471
1371
|
// ─────────────────────────────────────────────────────────────
|
|
1472
1372
|
generateAppConfig(context) {
|
|
1473
|
-
return
|
|
1474
|
-
name: process.env.APP_NAME ?? '${context.name}',
|
|
1475
|
-
env: process.env.APP_ENV ?? 'development',
|
|
1476
|
-
debug: process.env.APP_DEBUG === 'true',
|
|
1477
|
-
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
1478
|
-
key: process.env.APP_KEY,
|
|
1479
|
-
}
|
|
1480
|
-
`;
|
|
1373
|
+
return ConfigGenerator.generateSimpleAppConfig(context);
|
|
1481
1374
|
}
|
|
1482
1375
|
generateDatabaseConfig() {
|
|
1483
|
-
return
|
|
1484
|
-
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
1485
|
-
connections: {
|
|
1486
|
-
sqlite: {
|
|
1487
|
-
driver: 'sqlite',
|
|
1488
|
-
database: process.env.DB_DATABASE ?? 'database/database.sqlite',
|
|
1489
|
-
},
|
|
1490
|
-
},
|
|
1491
|
-
}
|
|
1492
|
-
`;
|
|
1376
|
+
return ConfigGenerator.generateSimpleDatabaseConfig();
|
|
1493
1377
|
}
|
|
1494
1378
|
generateAuthConfig() {
|
|
1495
|
-
return
|
|
1496
|
-
defaults: { guard: 'web' },
|
|
1497
|
-
guards: {
|
|
1498
|
-
web: { driver: 'session', provider: 'users' },
|
|
1499
|
-
api: { driver: 'token', provider: 'users' },
|
|
1500
|
-
},
|
|
1501
|
-
}
|
|
1502
|
-
`;
|
|
1379
|
+
return ConfigGenerator.generateAuthConfig();
|
|
1503
1380
|
}
|
|
1504
1381
|
generateCacheConfig() {
|
|
1505
|
-
return
|
|
1506
|
-
default: process.env.CACHE_DRIVER ?? 'memory',
|
|
1507
|
-
stores: {
|
|
1508
|
-
memory: { driver: 'memory' },
|
|
1509
|
-
},
|
|
1510
|
-
}
|
|
1511
|
-
`;
|
|
1382
|
+
return ConfigGenerator.generateCacheConfig();
|
|
1512
1383
|
}
|
|
1513
1384
|
generateLoggingConfig() {
|
|
1514
|
-
return
|
|
1515
|
-
default: process.env.LOG_CHANNEL ?? 'console',
|
|
1516
|
-
channels: {
|
|
1517
|
-
console: { driver: 'console', level: process.env.LOG_LEVEL ?? 'debug' },
|
|
1518
|
-
},
|
|
1519
|
-
}
|
|
1520
|
-
`;
|
|
1385
|
+
return ConfigGenerator.generateLoggingConfig();
|
|
1521
1386
|
}
|
|
1522
1387
|
generateUserEntity() {
|
|
1523
1388
|
return `/**
|
|
@@ -1816,132 +1681,59 @@ export class UserRepository implements IUserRepository {
|
|
|
1816
1681
|
|
|
1817
1682
|
async delete(id: string): Promise<void> {
|
|
1818
1683
|
users.delete(id)
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
async findAll(): Promise<User[]> {
|
|
1822
|
-
return Array.from(users.values())
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
async exists(id: string): Promise<boolean> {
|
|
1826
|
-
return users.has(id)
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
`;
|
|
1830
|
-
}
|
|
1831
|
-
generateMailService() {
|
|
1832
|
-
return `/**
|
|
1833
|
-
* Mail Service Implementation
|
|
1834
|
-
*/
|
|
1835
|
-
|
|
1836
|
-
import type { IMailService, MailMessage } from '../../Application/Interfaces/IMailService'
|
|
1837
|
-
|
|
1838
|
-
export class MailService implements IMailService {
|
|
1839
|
-
async send(message: MailMessage): Promise<void> {
|
|
1840
|
-
// TODO: Implement actual email sending
|
|
1841
|
-
console.log(\`[Mail] Sending to \${message.to}: \${message.subject}\`)
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
`;
|
|
1845
|
-
}
|
|
1846
|
-
generateAppServiceProvider(context) {
|
|
1847
|
-
return `/**
|
|
1848
|
-
* App Service Provider
|
|
1849
|
-
*/
|
|
1850
|
-
|
|
1851
|
-
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
1852
|
-
|
|
1853
|
-
export class AppServiceProvider extends ServiceProvider {
|
|
1854
|
-
register(_container: Container): void {
|
|
1855
|
-
// Register application services
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
boot(_core: PlanetCore): void {
|
|
1859
|
-
console.log('${context.name} (Clean Architecture) booted!')
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
`;
|
|
1863
|
-
}
|
|
1864
|
-
generateRepositoryServiceProvider() {
|
|
1865
|
-
return `/**
|
|
1866
|
-
* Repository Service Provider
|
|
1867
|
-
*
|
|
1868
|
-
* Binds repository interfaces to implementations.
|
|
1869
|
-
*/
|
|
1870
|
-
|
|
1871
|
-
import { ServiceProvider, type Container } from '@gravito/core'
|
|
1872
|
-
import { UserRepository } from '../Persistence/Repositories/UserRepository'
|
|
1873
|
-
import { MailService } from '../ExternalServices/MailService'
|
|
1874
|
-
|
|
1875
|
-
export class RepositoryServiceProvider extends ServiceProvider {
|
|
1876
|
-
register(container: Container): void {
|
|
1877
|
-
// Bind repositories
|
|
1878
|
-
container.singleton('userRepository', () => new UserRepository())
|
|
1879
|
-
|
|
1880
|
-
// Bind external services
|
|
1881
|
-
container.singleton('mailService', () => new MailService())
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
`;
|
|
1885
|
-
}
|
|
1886
|
-
generateProvidersIndex() {
|
|
1887
|
-
return `/**
|
|
1888
|
-
* Application Service Providers
|
|
1889
|
-
*/
|
|
1890
|
-
|
|
1891
|
-
export { AppServiceProvider } from './AppServiceProvider'
|
|
1892
|
-
export { RepositoryServiceProvider } from './RepositoryServiceProvider'
|
|
1893
|
-
export { MiddlewareProvider } from './MiddlewareProvider'
|
|
1894
|
-
export { RouteProvider } from './RouteProvider'
|
|
1895
|
-
`;
|
|
1896
|
-
}
|
|
1897
|
-
generateMiddlewareProvider() {
|
|
1898
|
-
return `/**
|
|
1899
|
-
* Middleware Service Provider
|
|
1900
|
-
*/
|
|
1901
|
-
|
|
1902
|
-
import {
|
|
1903
|
-
ServiceProvider,
|
|
1904
|
-
type Container,
|
|
1905
|
-
type PlanetCore,
|
|
1906
|
-
bodySizeLimit,
|
|
1907
|
-
securityHeaders,
|
|
1908
|
-
} from '@gravito/core'
|
|
1909
|
-
|
|
1910
|
-
export class MiddlewareProvider extends ServiceProvider {
|
|
1911
|
-
register(_container: Container): void {}
|
|
1912
|
-
|
|
1913
|
-
boot(core: PlanetCore): void {
|
|
1914
|
-
const isDev = process.env.NODE_ENV !== 'production'
|
|
1915
|
-
|
|
1916
|
-
core.adapter.use('*', securityHeaders({
|
|
1917
|
-
contentSecurityPolicy: isDev ? false : undefined,
|
|
1918
|
-
}))
|
|
1684
|
+
}
|
|
1919
1685
|
|
|
1920
|
-
|
|
1686
|
+
async findAll(): Promise<User[]> {
|
|
1687
|
+
return Array.from(users.values())
|
|
1688
|
+
}
|
|
1921
1689
|
|
|
1922
|
-
|
|
1690
|
+
async exists(id: string): Promise<boolean> {
|
|
1691
|
+
return users.has(id)
|
|
1923
1692
|
}
|
|
1924
1693
|
}
|
|
1925
1694
|
`;
|
|
1926
1695
|
}
|
|
1927
|
-
|
|
1696
|
+
generateMailService() {
|
|
1928
1697
|
return `/**
|
|
1929
|
-
*
|
|
1698
|
+
* Mail Service Implementation
|
|
1930
1699
|
*/
|
|
1931
1700
|
|
|
1932
|
-
import {
|
|
1933
|
-
import { registerApiRoutes } from '../../Interface/Http/Routes/api'
|
|
1934
|
-
|
|
1935
|
-
export class RouteProvider extends ServiceProvider {
|
|
1936
|
-
register(_container: Container): void {}
|
|
1701
|
+
import type { IMailService, MailMessage } from '../../Application/Interfaces/IMailService'
|
|
1937
1702
|
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1703
|
+
export class MailService implements IMailService {
|
|
1704
|
+
async send(message: MailMessage): Promise<void> {
|
|
1705
|
+
// TODO: Implement actual email sending
|
|
1706
|
+
console.log(\`[Mail] Sending to \${message.to}: \${message.subject}\`)
|
|
1941
1707
|
}
|
|
1942
1708
|
}
|
|
1943
1709
|
`;
|
|
1944
1710
|
}
|
|
1711
|
+
generateAppServiceProvider(context) {
|
|
1712
|
+
return ServiceProviderGenerator.generateAppServiceProvider(context, "Clean Architecture");
|
|
1713
|
+
}
|
|
1714
|
+
generateRepositoryServiceProvider() {
|
|
1715
|
+
return ServiceProviderGenerator.generateRepositoryServiceProvider(
|
|
1716
|
+
["UserRepository"],
|
|
1717
|
+
["MailService"]
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
generateProvidersIndex() {
|
|
1721
|
+
return ServiceProviderGenerator.generateProvidersIndex([
|
|
1722
|
+
"AppServiceProvider",
|
|
1723
|
+
"RepositoryServiceProvider",
|
|
1724
|
+
"MiddlewareProvider",
|
|
1725
|
+
"RouteProvider"
|
|
1726
|
+
]);
|
|
1727
|
+
}
|
|
1728
|
+
generateMiddlewareProvider() {
|
|
1729
|
+
return ServiceProviderGenerator.generateMiddlewareProvider();
|
|
1730
|
+
}
|
|
1731
|
+
generateRouteProvider() {
|
|
1732
|
+
return ServiceProviderGenerator.generateRouteProvider(
|
|
1733
|
+
"../../Interface/Http/Routes/api",
|
|
1734
|
+
"named"
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1945
1737
|
// ─────────────────────────────────────────────────────────────
|
|
1946
1738
|
// Interface Layer
|
|
1947
1739
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -2163,7 +1955,7 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
2163
1955
|
build: "bun build ./src/bootstrap.ts --outdir ./dist --target bun",
|
|
2164
1956
|
start: "bun run dist/bootstrap.js",
|
|
2165
1957
|
test: "bun test",
|
|
2166
|
-
typecheck: "tsc --noEmit",
|
|
1958
|
+
typecheck: "bun tsc --noEmit",
|
|
2167
1959
|
check: "bun run typecheck && bun run test",
|
|
2168
1960
|
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2169
1961
|
validate: "bun run check && bun run check:deps",
|
|
@@ -2178,107 +1970,16 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
2178
1970
|
},
|
|
2179
1971
|
devDependencies: {
|
|
2180
1972
|
"bun-types": "latest",
|
|
2181
|
-
typescript: "^5.
|
|
1973
|
+
typescript: "^5.9.3"
|
|
2182
1974
|
}
|
|
2183
1975
|
};
|
|
2184
1976
|
return JSON.stringify(pkg, null, 2);
|
|
2185
1977
|
}
|
|
2186
1978
|
};
|
|
2187
1979
|
|
|
2188
|
-
// src/generators/
|
|
2189
|
-
var
|
|
2190
|
-
|
|
2191
|
-
return "ddd";
|
|
2192
|
-
}
|
|
2193
|
-
get displayName() {
|
|
2194
|
-
return "Domain-Driven Design (DDD)";
|
|
2195
|
-
}
|
|
2196
|
-
get description() {
|
|
2197
|
-
return "Full DDD with Bounded Contexts, Aggregates, and Event-Driven patterns";
|
|
2198
|
-
}
|
|
2199
|
-
getDirectoryStructure(context) {
|
|
2200
|
-
return [
|
|
2201
|
-
{
|
|
2202
|
-
type: "directory",
|
|
2203
|
-
name: "config",
|
|
2204
|
-
children: [
|
|
2205
|
-
{ type: "file", name: "app.ts", content: this.generateAppConfig(context) },
|
|
2206
|
-
{ type: "file", name: "database.ts", content: this.generateDatabaseConfig() },
|
|
2207
|
-
{ type: "file", name: "modules.ts", content: this.generateModulesConfig() },
|
|
2208
|
-
{ type: "file", name: "cache.ts", content: this.generateCacheConfig() },
|
|
2209
|
-
{ type: "file", name: "logging.ts", content: this.generateLoggingConfig() }
|
|
2210
|
-
]
|
|
2211
|
-
},
|
|
2212
|
-
{
|
|
2213
|
-
type: "directory",
|
|
2214
|
-
name: "src",
|
|
2215
|
-
children: [
|
|
2216
|
-
// Bootstrap - Application startup and configuration
|
|
2217
|
-
this.generateBootstrapDirectory(context),
|
|
2218
|
-
// Shared - Cross-module shared components
|
|
2219
|
-
this.generateShared(),
|
|
2220
|
-
// Modules - Bounded Contexts
|
|
2221
|
-
{
|
|
2222
|
-
type: "directory",
|
|
2223
|
-
name: "Modules",
|
|
2224
|
-
children: [
|
|
2225
|
-
this.generateModule("Ordering", context),
|
|
2226
|
-
this.generateModule("Catalog", context)
|
|
2227
|
-
]
|
|
2228
|
-
},
|
|
2229
|
-
{ type: "file", name: "main.ts", content: this.generateMainEntry(context) }
|
|
2230
|
-
]
|
|
2231
|
-
},
|
|
2232
|
-
{
|
|
2233
|
-
type: "directory",
|
|
2234
|
-
name: "tests",
|
|
2235
|
-
children: [
|
|
2236
|
-
{
|
|
2237
|
-
type: "directory",
|
|
2238
|
-
name: "Modules",
|
|
2239
|
-
children: [
|
|
2240
|
-
{
|
|
2241
|
-
type: "directory",
|
|
2242
|
-
name: "Ordering",
|
|
2243
|
-
children: [
|
|
2244
|
-
{
|
|
2245
|
-
type: "directory",
|
|
2246
|
-
name: "Unit",
|
|
2247
|
-
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2248
|
-
},
|
|
2249
|
-
{
|
|
2250
|
-
type: "directory",
|
|
2251
|
-
name: "Integration",
|
|
2252
|
-
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2253
|
-
}
|
|
2254
|
-
]
|
|
2255
|
-
},
|
|
2256
|
-
{
|
|
2257
|
-
type: "directory",
|
|
2258
|
-
name: "Catalog",
|
|
2259
|
-
children: [
|
|
2260
|
-
{
|
|
2261
|
-
type: "directory",
|
|
2262
|
-
name: "Unit",
|
|
2263
|
-
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2264
|
-
}
|
|
2265
|
-
]
|
|
2266
|
-
}
|
|
2267
|
-
]
|
|
2268
|
-
},
|
|
2269
|
-
{
|
|
2270
|
-
type: "directory",
|
|
2271
|
-
name: "Shared",
|
|
2272
|
-
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2273
|
-
}
|
|
2274
|
-
]
|
|
2275
|
-
}
|
|
2276
|
-
];
|
|
2277
|
-
}
|
|
2278
|
-
// ─────────────────────────────────────────────────────────────
|
|
2279
|
-
// Bootstrap Directory
|
|
2280
|
-
// ─────────────────────────────────────────────────────────────
|
|
2281
|
-
generateBootstrapDirectory(context) {
|
|
1980
|
+
// src/generators/ddd/BootstrapGenerator.ts
|
|
1981
|
+
var BootstrapGenerator = class {
|
|
1982
|
+
generate(context) {
|
|
2282
1983
|
return {
|
|
2283
1984
|
type: "directory",
|
|
2284
1985
|
name: "Bootstrap",
|
|
@@ -2290,60 +1991,227 @@ var DddGenerator = class extends BaseGenerator {
|
|
|
2290
1991
|
]
|
|
2291
1992
|
};
|
|
2292
1993
|
}
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
{
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
1994
|
+
generateConfigDirectory(context) {
|
|
1995
|
+
return {
|
|
1996
|
+
type: "directory",
|
|
1997
|
+
name: "config",
|
|
1998
|
+
children: [
|
|
1999
|
+
{ type: "file", name: "app.ts", content: this.generateAppConfig(context) },
|
|
2000
|
+
{ type: "file", name: "database.ts", content: this.generateDatabaseConfig() },
|
|
2001
|
+
{ type: "file", name: "modules.ts", content: this.generateModulesConfig() },
|
|
2002
|
+
{ type: "file", name: "cache.ts", content: this.generateCacheConfig() },
|
|
2003
|
+
{ type: "file", name: "logging.ts", content: this.generateLoggingConfig() }
|
|
2004
|
+
]
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
generateMainEntry(_context) {
|
|
2008
|
+
return `/**
|
|
2009
|
+
* Application Entry Point
|
|
2010
|
+
*
|
|
2011
|
+
* Start the HTTP server.
|
|
2012
|
+
*/
|
|
2013
|
+
|
|
2014
|
+
import { createApp } from './Bootstrap/app'
|
|
2015
|
+
|
|
2016
|
+
const app = await createApp()
|
|
2017
|
+
|
|
2018
|
+
export default app.liftoff()
|
|
2019
|
+
`;
|
|
2020
|
+
}
|
|
2021
|
+
generateBootstrapApp(_context) {
|
|
2022
|
+
return `/**
|
|
2023
|
+
* Application Bootstrap
|
|
2024
|
+
*
|
|
2025
|
+
* Central configuration and initialization using the ServiceProvider pattern.
|
|
2026
|
+
*
|
|
2027
|
+
* Lifecycle:
|
|
2028
|
+
* 1. Configure: Load app config and orbits
|
|
2029
|
+
* 2. Boot: Initialize PlanetCore
|
|
2030
|
+
* 3. Register Providers: Bind services to container
|
|
2031
|
+
* 4. Bootstrap: Boot all providers
|
|
2032
|
+
*/
|
|
2033
|
+
|
|
2034
|
+
import { defineConfig, PlanetCore } from '@gravito/core'
|
|
2035
|
+
import { OrbitAtlas } from '@gravito/atlas'
|
|
2036
|
+
import appConfig from '../../config/app'
|
|
2037
|
+
import { registerProviders } from './providers'
|
|
2038
|
+
import { registerRoutes } from './routes'
|
|
2039
|
+
|
|
2040
|
+
export async function createApp(): Promise<PlanetCore> {
|
|
2041
|
+
// 1. Configure
|
|
2042
|
+
const config = defineConfig({
|
|
2043
|
+
config: appConfig,
|
|
2044
|
+
orbits: [new OrbitAtlas()],
|
|
2045
|
+
})
|
|
2046
|
+
|
|
2047
|
+
// 2. Boot Core
|
|
2048
|
+
const core = await PlanetCore.boot(config)
|
|
2049
|
+
core.registerGlobalErrorHandlers()
|
|
2050
|
+
|
|
2051
|
+
// 3. Register Providers
|
|
2052
|
+
await registerProviders(core)
|
|
2053
|
+
|
|
2054
|
+
// 4. Bootstrap All Providers
|
|
2055
|
+
await core.bootstrap()
|
|
2056
|
+
|
|
2057
|
+
// Register routes after bootstrap
|
|
2058
|
+
registerRoutes(core.router)
|
|
2059
|
+
|
|
2060
|
+
return core
|
|
2061
|
+
}
|
|
2062
|
+
`;
|
|
2063
|
+
}
|
|
2064
|
+
generateProvidersRegistry(_context) {
|
|
2065
|
+
return `/**
|
|
2066
|
+
* Service Providers Registry
|
|
2067
|
+
*
|
|
2068
|
+
* Register all service providers here.
|
|
2069
|
+
* Include both global and module-specific providers.
|
|
2070
|
+
*/
|
|
2071
|
+
|
|
2072
|
+
import {
|
|
2073
|
+
ServiceProvider,
|
|
2074
|
+
type Container,
|
|
2075
|
+
type PlanetCore,
|
|
2076
|
+
bodySizeLimit,
|
|
2077
|
+
securityHeaders,
|
|
2078
|
+
} from '@gravito/core'
|
|
2079
|
+
import { OrderingServiceProvider } from '../Modules/Ordering/Infrastructure/Providers/OrderingServiceProvider'
|
|
2080
|
+
import { CatalogServiceProvider } from '../Modules/Catalog/Infrastructure/Providers/CatalogServiceProvider'
|
|
2081
|
+
|
|
2082
|
+
/**
|
|
2083
|
+
* Middleware Provider - Global middleware registration
|
|
2084
|
+
*/
|
|
2085
|
+
export class MiddlewareProvider extends ServiceProvider {
|
|
2086
|
+
register(_container: Container): void {}
|
|
2087
|
+
|
|
2088
|
+
boot(core: PlanetCore): void {
|
|
2089
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
2090
|
+
|
|
2091
|
+
core.adapter.use('*', securityHeaders({
|
|
2092
|
+
contentSecurityPolicy: isDev ? false : undefined,
|
|
2093
|
+
}))
|
|
2094
|
+
|
|
2095
|
+
core.adapter.use('*', bodySizeLimit(10 * 1024 * 1024))
|
|
2096
|
+
|
|
2097
|
+
core.logger.info('\u{1F6E1}\uFE0F Global middleware registered')
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
export async function registerProviders(core: PlanetCore): Promise<void> {
|
|
2102
|
+
// Global Providers
|
|
2103
|
+
core.register(new MiddlewareProvider())
|
|
2104
|
+
|
|
2105
|
+
// Module Providers
|
|
2106
|
+
core.register(new OrderingServiceProvider())
|
|
2107
|
+
core.register(new CatalogServiceProvider())
|
|
2108
|
+
|
|
2109
|
+
// Add more providers as needed
|
|
2110
|
+
}
|
|
2111
|
+
`;
|
|
2112
|
+
}
|
|
2113
|
+
generateEventsRegistry() {
|
|
2114
|
+
return `/**
|
|
2115
|
+
* Domain Events Registry
|
|
2116
|
+
*
|
|
2117
|
+
* Register all domain event handlers here.
|
|
2118
|
+
*/
|
|
2119
|
+
|
|
2120
|
+
import { EventDispatcher } from '../Shared/Infrastructure/EventBus/EventDispatcher'
|
|
2121
|
+
|
|
2122
|
+
export function registerEvents(dispatcher: EventDispatcher): void {
|
|
2123
|
+
// Register event handlers
|
|
2124
|
+
// dispatcher.subscribe('ordering.created', async (event) => { ... })
|
|
2125
|
+
}
|
|
2126
|
+
`;
|
|
2127
|
+
}
|
|
2128
|
+
generateRoutesRegistry(_context) {
|
|
2129
|
+
return `/**
|
|
2130
|
+
* Routes Registry
|
|
2131
|
+
*
|
|
2132
|
+
* Register all module routes here.
|
|
2133
|
+
*/
|
|
2134
|
+
|
|
2135
|
+
export function registerRoutes(router: any): void {
|
|
2136
|
+
// Health check
|
|
2137
|
+
router.get('/health', (c: any) => c.json({ status: 'healthy' }))
|
|
2138
|
+
|
|
2139
|
+
// Ordering module
|
|
2140
|
+
router.get('/api/orders', (c: any) => c.json({ message: 'Order list' }))
|
|
2141
|
+
router.post('/api/orders', (c: any) => c.json({ message: 'Order created' }, 201))
|
|
2142
|
+
|
|
2143
|
+
// Catalog module
|
|
2144
|
+
router.get('/api/products', (c: any) => c.json({ message: 'Product list' }))
|
|
2145
|
+
}
|
|
2146
|
+
`;
|
|
2147
|
+
}
|
|
2148
|
+
generateModulesConfig() {
|
|
2149
|
+
return `/**
|
|
2150
|
+
* Modules Configuration
|
|
2151
|
+
*
|
|
2152
|
+
* Define module boundaries and their dependencies.
|
|
2153
|
+
*/
|
|
2154
|
+
|
|
2155
|
+
export default {
|
|
2156
|
+
modules: {
|
|
2157
|
+
ordering: {
|
|
2158
|
+
name: 'Ordering',
|
|
2159
|
+
description: 'Order management module',
|
|
2160
|
+
prefix: '/api/orders',
|
|
2315
2161
|
},
|
|
2316
|
-
{
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
{
|
|
2321
|
-
type: "directory",
|
|
2322
|
-
name: "EventBus",
|
|
2323
|
-
children: [
|
|
2324
|
-
{
|
|
2325
|
-
type: "file",
|
|
2326
|
-
name: "EventDispatcher.ts",
|
|
2327
|
-
content: this.generateEventDispatcher()
|
|
2328
|
-
}
|
|
2329
|
-
]
|
|
2330
|
-
}
|
|
2331
|
-
]
|
|
2162
|
+
catalog: {
|
|
2163
|
+
name: 'Catalog',
|
|
2164
|
+
description: 'Product catalog module',
|
|
2165
|
+
prefix: '/api/products',
|
|
2332
2166
|
},
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
};
|
|
2167
|
+
},
|
|
2168
|
+
|
|
2169
|
+
// Module dependencies
|
|
2170
|
+
dependencies: {
|
|
2171
|
+
ordering: ['catalog'], // Ordering depends on Catalog
|
|
2172
|
+
},
|
|
2173
|
+
}
|
|
2174
|
+
`;
|
|
2342
2175
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2176
|
+
generateAppConfig(context) {
|
|
2177
|
+
return `export default {
|
|
2178
|
+
name: process.env.APP_NAME ?? '${context.name}',
|
|
2179
|
+
env: process.env.APP_ENV ?? 'development',
|
|
2180
|
+
port: Number.parseInt(process.env.PORT ?? '3000', 10),
|
|
2181
|
+
VIEW_DIR: process.env.VIEW_DIR ?? 'src/views',
|
|
2182
|
+
debug: process.env.APP_DEBUG === 'true',
|
|
2183
|
+
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
2184
|
+
}
|
|
2185
|
+
`;
|
|
2186
|
+
}
|
|
2187
|
+
generateDatabaseConfig() {
|
|
2188
|
+
return `export default {
|
|
2189
|
+
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
2190
|
+
connections: {
|
|
2191
|
+
sqlite: { driver: 'sqlite', database: 'database/database.sqlite' },
|
|
2192
|
+
},
|
|
2193
|
+
}
|
|
2194
|
+
`;
|
|
2195
|
+
}
|
|
2196
|
+
generateCacheConfig() {
|
|
2197
|
+
return `export default {
|
|
2198
|
+
default: process.env.CACHE_DRIVER ?? 'memory',
|
|
2199
|
+
stores: { memory: { driver: 'memory' } },
|
|
2200
|
+
}
|
|
2201
|
+
`;
|
|
2202
|
+
}
|
|
2203
|
+
generateLoggingConfig() {
|
|
2204
|
+
return `export default {
|
|
2205
|
+
default: 'console',
|
|
2206
|
+
channels: { console: { driver: 'console', level: 'debug' } },
|
|
2207
|
+
}
|
|
2208
|
+
`;
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2211
|
+
|
|
2212
|
+
// src/generators/ddd/ModuleGenerator.ts
|
|
2213
|
+
var ModuleGenerator = class {
|
|
2214
|
+
generate(name, context) {
|
|
2347
2215
|
return {
|
|
2348
2216
|
type: "directory",
|
|
2349
2217
|
name,
|
|
@@ -2488,175 +2356,224 @@ var DddGenerator = class extends BaseGenerator {
|
|
|
2488
2356
|
]
|
|
2489
2357
|
};
|
|
2490
2358
|
}
|
|
2491
|
-
|
|
2492
|
-
// Bootstrap File Generators
|
|
2493
|
-
// ─────────────────────────────────────────────────────────────
|
|
2494
|
-
generateBootstrapApp(_context) {
|
|
2359
|
+
generateAggregate(name) {
|
|
2495
2360
|
return `/**
|
|
2496
|
-
*
|
|
2497
|
-
*
|
|
2498
|
-
* Central configuration and initialization using the ServiceProvider pattern.
|
|
2499
|
-
*
|
|
2500
|
-
* Lifecycle:
|
|
2501
|
-
* 1. Configure: Load app config and orbits
|
|
2502
|
-
* 2. Boot: Initialize PlanetCore
|
|
2503
|
-
* 3. Register Providers: Bind services to container
|
|
2504
|
-
* 4. Bootstrap: Boot all providers
|
|
2361
|
+
* ${name} Aggregate Root
|
|
2505
2362
|
*/
|
|
2506
2363
|
|
|
2507
|
-
import {
|
|
2508
|
-
import {
|
|
2509
|
-
import
|
|
2510
|
-
import {
|
|
2511
|
-
import { registerRoutes } from './routes'
|
|
2364
|
+
import { AggregateRoot } from '@gravito/enterprise'
|
|
2365
|
+
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2366
|
+
import { ${name}Created } from '../../Events/${name}Created'
|
|
2367
|
+
import { ${name}Status } from './${name}Status'
|
|
2512
2368
|
|
|
2513
|
-
export
|
|
2514
|
-
//
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
})
|
|
2369
|
+
export interface ${name}Props {
|
|
2370
|
+
// Add properties here
|
|
2371
|
+
status: ${name}Status
|
|
2372
|
+
createdAt: Date
|
|
2373
|
+
}
|
|
2519
2374
|
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
core.registerGlobalErrorHandlers()
|
|
2375
|
+
export class ${name} extends AggregateRoot<Id> {
|
|
2376
|
+
private props: ${name}Props
|
|
2523
2377
|
|
|
2524
|
-
|
|
2525
|
-
|
|
2378
|
+
private constructor(id: Id, props: ${name}Props) {
|
|
2379
|
+
super(id)
|
|
2380
|
+
this.props = props
|
|
2381
|
+
}
|
|
2526
2382
|
|
|
2527
|
-
|
|
2528
|
-
|
|
2383
|
+
static create(id: Id): ${name} {
|
|
2384
|
+
const aggregate = new ${name}(id, {
|
|
2385
|
+
status: ${name}Status.PENDING,
|
|
2386
|
+
createdAt: new Date(),
|
|
2387
|
+
})
|
|
2529
2388
|
|
|
2530
|
-
|
|
2531
|
-
registerRoutes(core.router)
|
|
2389
|
+
aggregate.addDomainEvent(new ${name}Created(id.value))
|
|
2532
2390
|
|
|
2533
|
-
|
|
2391
|
+
return aggregate
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
get status(): ${name}Status {
|
|
2395
|
+
return this.props.status
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
// Add domain methods here
|
|
2534
2399
|
}
|
|
2535
2400
|
`;
|
|
2536
2401
|
}
|
|
2537
|
-
|
|
2402
|
+
generateAggregateStatus(name) {
|
|
2538
2403
|
return `/**
|
|
2539
|
-
*
|
|
2540
|
-
*
|
|
2541
|
-
* Register all service providers here.
|
|
2542
|
-
* Include both global and module-specific providers.
|
|
2404
|
+
* ${name} Status
|
|
2543
2405
|
*/
|
|
2544
2406
|
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2407
|
+
export enum ${name}Status {
|
|
2408
|
+
PENDING = 'pending',
|
|
2409
|
+
ACTIVE = 'active',
|
|
2410
|
+
COMPLETED = 'completed',
|
|
2411
|
+
CANCELLED = 'cancelled',
|
|
2412
|
+
}
|
|
2413
|
+
`;
|
|
2414
|
+
}
|
|
2415
|
+
generateCreatedEvent(name) {
|
|
2416
|
+
return `/**
|
|
2417
|
+
* ${name} Created Event
|
|
2418
|
+
*/
|
|
2554
2419
|
|
|
2555
|
-
|
|
2556
|
-
|
|
2420
|
+
import { DomainEvent } from '@gravito/enterprise'
|
|
2421
|
+
|
|
2422
|
+
export class ${name}Created extends DomainEvent {
|
|
2423
|
+
constructor(public readonly ${name.toLowerCase()}Id: string) {
|
|
2424
|
+
super()
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
override get eventName(): string {
|
|
2428
|
+
return '${name.toLowerCase()}.created'
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
get aggregateId(): string {
|
|
2432
|
+
return this.${name.toLowerCase()}Id
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
`;
|
|
2436
|
+
}
|
|
2437
|
+
generateRepositoryInterface(name) {
|
|
2438
|
+
return `/**
|
|
2439
|
+
* ${name} Repository Interface
|
|
2557
2440
|
*/
|
|
2558
|
-
export class MiddlewareProvider extends ServiceProvider {
|
|
2559
|
-
register(_container: Container): void {}
|
|
2560
2441
|
|
|
2561
|
-
|
|
2562
|
-
|
|
2442
|
+
import { Repository } from '@gravito/enterprise'
|
|
2443
|
+
import type { ${name} } from '../Aggregates/${name}/${name}'
|
|
2444
|
+
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2563
2445
|
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2446
|
+
export interface I${name}Repository extends Repository<${name}, Id> {
|
|
2447
|
+
// Add specific methods for this repository if needed
|
|
2448
|
+
}
|
|
2449
|
+
`;
|
|
2450
|
+
}
|
|
2451
|
+
generateCommand(name) {
|
|
2452
|
+
return `/**
|
|
2453
|
+
* Create ${name} Command
|
|
2454
|
+
*/
|
|
2567
2455
|
|
|
2568
|
-
|
|
2456
|
+
import { Command } from '@gravito/enterprise'
|
|
2569
2457
|
|
|
2570
|
-
|
|
2458
|
+
export class Create${name}Command extends Command {
|
|
2459
|
+
constructor(
|
|
2460
|
+
// Add command properties
|
|
2461
|
+
public readonly id?: string
|
|
2462
|
+
) {
|
|
2463
|
+
super()
|
|
2571
2464
|
}
|
|
2572
2465
|
}
|
|
2466
|
+
`;
|
|
2467
|
+
}
|
|
2468
|
+
generateCommandHandler(name) {
|
|
2469
|
+
return `/**
|
|
2470
|
+
* Create ${name} Handler
|
|
2471
|
+
*/
|
|
2573
2472
|
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2473
|
+
import { CommandHandler } from '@gravito/enterprise'
|
|
2474
|
+
import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
|
|
2475
|
+
import { ${name} } from '../../../Domain/Aggregates/${name}/${name}'
|
|
2476
|
+
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2477
|
+
import type { Create${name}Command } from './Create${name}Command'
|
|
2577
2478
|
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
core.register(new CatalogServiceProvider())
|
|
2479
|
+
export class Create${name}Handler implements CommandHandler<Create${name}Command, string> {
|
|
2480
|
+
constructor(private repository: I${name}Repository) {}
|
|
2581
2481
|
|
|
2582
|
-
|
|
2482
|
+
async handle(command: Create${name}Command): Promise<string> {
|
|
2483
|
+
const id = command.id ? Id.from(command.id) : Id.create()
|
|
2484
|
+
const aggregate = ${name}.create(id)
|
|
2485
|
+
|
|
2486
|
+
await this.repository.save(aggregate)
|
|
2487
|
+
|
|
2488
|
+
return id.value
|
|
2489
|
+
}
|
|
2583
2490
|
}
|
|
2584
2491
|
`;
|
|
2585
2492
|
}
|
|
2586
|
-
|
|
2493
|
+
generateQuery(name) {
|
|
2587
2494
|
return `/**
|
|
2588
|
-
*
|
|
2589
|
-
*
|
|
2590
|
-
* Register all domain event handlers here.
|
|
2495
|
+
* Get ${name} By Id Query
|
|
2591
2496
|
*/
|
|
2592
2497
|
|
|
2593
|
-
import {
|
|
2498
|
+
import { Query } from '@gravito/enterprise'
|
|
2594
2499
|
|
|
2595
|
-
export
|
|
2596
|
-
|
|
2597
|
-
|
|
2500
|
+
export class Get${name}ByIdQuery extends Query {
|
|
2501
|
+
constructor(public readonly id: string) {
|
|
2502
|
+
super()
|
|
2503
|
+
}
|
|
2598
2504
|
}
|
|
2599
2505
|
`;
|
|
2600
2506
|
}
|
|
2601
|
-
|
|
2507
|
+
generateQueryHandler(name) {
|
|
2602
2508
|
return `/**
|
|
2603
|
-
*
|
|
2604
|
-
*
|
|
2605
|
-
* Register all module routes here.
|
|
2509
|
+
* Get ${name} By Id Handler
|
|
2606
2510
|
*/
|
|
2607
2511
|
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2512
|
+
import { QueryHandler } from '@gravito/enterprise'
|
|
2513
|
+
import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
|
|
2514
|
+
import type { ${name}DTO } from '../../DTOs/${name}DTO'
|
|
2515
|
+
import type { Get${name}ByIdQuery } from './Get${name}ByIdQuery'
|
|
2611
2516
|
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
router.post('/api/orders', (c: any) => c.json({ message: 'Order created' }, 201))
|
|
2517
|
+
export class Get${name}ByIdHandler implements QueryHandler<Get${name}ByIdQuery, ${name}DTO | null> {
|
|
2518
|
+
constructor(private repository: I${name}Repository) {}
|
|
2615
2519
|
|
|
2616
|
-
|
|
2617
|
-
|
|
2520
|
+
async handle(query: Get${name}ByIdQuery): Promise<${name}DTO | null> {
|
|
2521
|
+
const aggregate = await this.repository.findById(query.id as any) // Simplified for demo
|
|
2522
|
+
if (!aggregate) return null
|
|
2523
|
+
|
|
2524
|
+
return {
|
|
2525
|
+
id: aggregate.id.value,
|
|
2526
|
+
status: aggregate.status,
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2618
2529
|
}
|
|
2619
2530
|
`;
|
|
2620
2531
|
}
|
|
2621
|
-
|
|
2532
|
+
generateDTO(name) {
|
|
2622
2533
|
return `/**
|
|
2623
|
-
*
|
|
2624
|
-
*
|
|
2625
|
-
* Start the HTTP server.
|
|
2534
|
+
* ${name} DTO
|
|
2626
2535
|
*/
|
|
2627
2536
|
|
|
2628
|
-
import {
|
|
2629
|
-
|
|
2630
|
-
const app = await createApp()
|
|
2537
|
+
import type { ${name}Status } from '../../Domain/Aggregates/${name}/${name}Status'
|
|
2631
2538
|
|
|
2632
|
-
export
|
|
2539
|
+
export interface ${name}DTO {
|
|
2540
|
+
id: string
|
|
2541
|
+
status: ${name}Status
|
|
2542
|
+
// Add more fields
|
|
2543
|
+
}
|
|
2633
2544
|
`;
|
|
2634
2545
|
}
|
|
2635
|
-
|
|
2546
|
+
generateRepository(name) {
|
|
2636
2547
|
return `/**
|
|
2637
|
-
*
|
|
2638
|
-
*
|
|
2639
|
-
* Define module boundaries and their dependencies.
|
|
2548
|
+
* ${name} Repository Implementation
|
|
2640
2549
|
*/
|
|
2641
2550
|
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
name: 'Ordering',
|
|
2646
|
-
description: 'Order management module',
|
|
2647
|
-
prefix: '/api/orders',
|
|
2648
|
-
},
|
|
2649
|
-
catalog: {
|
|
2650
|
-
name: 'Catalog',
|
|
2651
|
-
description: 'Product catalog module',
|
|
2652
|
-
prefix: '/api/products',
|
|
2653
|
-
},
|
|
2654
|
-
},
|
|
2551
|
+
import type { ${name} } from '../../Domain/Aggregates/${name}/${name}'
|
|
2552
|
+
import type { I${name}Repository } from '../../Domain/Repositories/I${name}Repository'
|
|
2553
|
+
import type { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2655
2554
|
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2555
|
+
const store = new Map<string, ${name}>()
|
|
2556
|
+
|
|
2557
|
+
export class ${name}Repository implements I${name}Repository {
|
|
2558
|
+
async findById(id: Id): Promise<${name} | null> {
|
|
2559
|
+
return store.get(id.value) ?? null
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
async save(aggregate: ${name}): Promise<void> {
|
|
2563
|
+
store.set(aggregate.id.value, aggregate)
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
async delete(id: Id): Promise<void> {
|
|
2567
|
+
store.delete(id.value)
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
async findAll(): Promise<${name}[]> {
|
|
2571
|
+
return Array.from(store.values())
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
async exists(id: Id): Promise<boolean> {
|
|
2575
|
+
return store.has(id.value)
|
|
2576
|
+
}
|
|
2660
2577
|
}
|
|
2661
2578
|
`;
|
|
2662
2579
|
}
|
|
@@ -2679,78 +2596,57 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
2679
2596
|
}
|
|
2680
2597
|
`;
|
|
2681
2598
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2599
|
+
};
|
|
2600
|
+
|
|
2601
|
+
// src/generators/ddd/SharedKernelGenerator.ts
|
|
2602
|
+
var SharedKernelGenerator = class {
|
|
2603
|
+
generate() {
|
|
2604
|
+
return {
|
|
2605
|
+
type: "directory",
|
|
2606
|
+
name: "Shared",
|
|
2607
|
+
children: [
|
|
2608
|
+
{
|
|
2609
|
+
type: "directory",
|
|
2610
|
+
name: "Domain",
|
|
2611
|
+
children: [
|
|
2612
|
+
{
|
|
2613
|
+
type: "directory",
|
|
2614
|
+
name: "ValueObjects",
|
|
2615
|
+
children: [
|
|
2616
|
+
{ type: "file", name: "Id.ts", content: this.generateIdValueObject() },
|
|
2617
|
+
{ type: "file", name: "Money.ts", content: this.generateMoneyValueObject() },
|
|
2618
|
+
{ type: "file", name: "Email.ts", content: this.generateEmailValueObject() }
|
|
2619
|
+
]
|
|
2620
|
+
}
|
|
2621
|
+
]
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
type: "directory",
|
|
2625
|
+
name: "Infrastructure",
|
|
2626
|
+
children: [
|
|
2627
|
+
{
|
|
2628
|
+
type: "directory",
|
|
2629
|
+
name: "EventBus",
|
|
2630
|
+
children: [
|
|
2631
|
+
{
|
|
2632
|
+
type: "file",
|
|
2633
|
+
name: "EventDispatcher.ts",
|
|
2634
|
+
content: this.generateEventDispatcher()
|
|
2635
|
+
}
|
|
2636
|
+
]
|
|
2637
|
+
}
|
|
2638
|
+
]
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
type: "directory",
|
|
2642
|
+
name: "Exceptions",
|
|
2643
|
+
children: [
|
|
2644
|
+
{ type: "file", name: "Handler.ts", content: this.generateExceptionHandler() }
|
|
2645
|
+
]
|
|
2646
|
+
}
|
|
2647
|
+
]
|
|
2711
2648
|
};
|
|
2712
|
-
return JSON.stringify(pkg, null, 2);
|
|
2713
|
-
}
|
|
2714
|
-
// ─────────────────────────────────────────────────────────────
|
|
2715
|
-
// Config Generators
|
|
2716
|
-
// ─────────────────────────────────────────────────────────────
|
|
2717
|
-
generateAppConfig(context) {
|
|
2718
|
-
return `export default {
|
|
2719
|
-
name: process.env.APP_NAME ?? '${context.name}',
|
|
2720
|
-
env: process.env.APP_ENV ?? 'development',
|
|
2721
|
-
port: Number.parseInt(process.env.PORT ?? '3000', 10),
|
|
2722
|
-
VIEW_DIR: process.env.VIEW_DIR ?? 'src/views',
|
|
2723
|
-
debug: process.env.APP_DEBUG === 'true',
|
|
2724
|
-
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
2725
|
-
}
|
|
2726
|
-
`;
|
|
2727
|
-
}
|
|
2728
|
-
generateDatabaseConfig() {
|
|
2729
|
-
return `export default {
|
|
2730
|
-
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
2731
|
-
connections: {
|
|
2732
|
-
sqlite: { driver: 'sqlite', database: 'database/database.sqlite' },
|
|
2733
|
-
},
|
|
2734
|
-
}
|
|
2735
|
-
`;
|
|
2736
|
-
}
|
|
2737
|
-
generateCacheConfig() {
|
|
2738
|
-
return `export default {
|
|
2739
|
-
default: process.env.CACHE_DRIVER ?? 'memory',
|
|
2740
|
-
stores: { memory: { driver: 'memory' } },
|
|
2741
|
-
}
|
|
2742
|
-
`;
|
|
2743
|
-
}
|
|
2744
|
-
generateLoggingConfig() {
|
|
2745
|
-
return `export default {
|
|
2746
|
-
default: 'console',
|
|
2747
|
-
channels: { console: { driver: 'console', level: 'debug' } },
|
|
2748
|
-
}
|
|
2749
|
-
`;
|
|
2750
2649
|
}
|
|
2751
|
-
// ─────────────────────────────────────────────────────────────
|
|
2752
|
-
// Shared Kernel Files
|
|
2753
|
-
// ─────────────────────────────────────────────────────────────
|
|
2754
2650
|
generateIdValueObject() {
|
|
2755
2651
|
return `/**
|
|
2756
2652
|
* ID Value Object
|
|
@@ -2898,239 +2794,142 @@ export class EventDispatcher {
|
|
|
2898
2794
|
}
|
|
2899
2795
|
`;
|
|
2900
2796
|
}
|
|
2901
|
-
|
|
2902
|
-
// Bounded Context Templates
|
|
2903
|
-
// ─────────────────────────────────────────────────────────────
|
|
2904
|
-
generateAggregate(name) {
|
|
2905
|
-
return `/**
|
|
2906
|
-
* ${name} Aggregate Root
|
|
2907
|
-
*/
|
|
2908
|
-
|
|
2909
|
-
import { AggregateRoot } from '@gravito/enterprise'
|
|
2910
|
-
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2911
|
-
import { ${name}Created } from '../../Events/${name}Created'
|
|
2912
|
-
import { ${name}Status } from './${name}Status'
|
|
2913
|
-
|
|
2914
|
-
export interface ${name}Props {
|
|
2915
|
-
// Add properties here
|
|
2916
|
-
status: ${name}Status
|
|
2917
|
-
createdAt: Date
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
export class ${name} extends AggregateRoot<Id> {
|
|
2921
|
-
private props: ${name}Props
|
|
2922
|
-
|
|
2923
|
-
private constructor(id: Id, props: ${name}Props) {
|
|
2924
|
-
super(id)
|
|
2925
|
-
this.props = props
|
|
2926
|
-
}
|
|
2927
|
-
|
|
2928
|
-
static create(id: Id): ${name} {
|
|
2929
|
-
const aggregate = new ${name}(id, {
|
|
2930
|
-
status: ${name}Status.PENDING,
|
|
2931
|
-
createdAt: new Date(),
|
|
2932
|
-
})
|
|
2933
|
-
|
|
2934
|
-
aggregate.addDomainEvent(new ${name}Created(id.value))
|
|
2935
|
-
|
|
2936
|
-
return aggregate
|
|
2937
|
-
}
|
|
2938
|
-
|
|
2939
|
-
get status(): ${name}Status {
|
|
2940
|
-
return this.props.status
|
|
2941
|
-
}
|
|
2942
|
-
|
|
2943
|
-
// Add domain methods here
|
|
2944
|
-
}
|
|
2945
|
-
`;
|
|
2946
|
-
}
|
|
2947
|
-
generateAggregateStatus(name) {
|
|
2948
|
-
return `/**
|
|
2949
|
-
* ${name} Status
|
|
2950
|
-
*/
|
|
2951
|
-
|
|
2952
|
-
export enum ${name}Status {
|
|
2953
|
-
PENDING = 'pending',
|
|
2954
|
-
ACTIVE = 'active',
|
|
2955
|
-
COMPLETED = 'completed',
|
|
2956
|
-
CANCELLED = 'cancelled',
|
|
2957
|
-
}
|
|
2958
|
-
`;
|
|
2959
|
-
}
|
|
2960
|
-
generateCreatedEvent(name) {
|
|
2961
|
-
return `/**
|
|
2962
|
-
* ${name} Created Event
|
|
2963
|
-
*/
|
|
2964
|
-
|
|
2965
|
-
import { DomainEvent } from '@gravito/enterprise'
|
|
2966
|
-
|
|
2967
|
-
export class ${name}Created extends DomainEvent {
|
|
2968
|
-
constructor(public readonly ${name.toLowerCase()}Id: string) {
|
|
2969
|
-
super()
|
|
2970
|
-
}
|
|
2971
|
-
|
|
2972
|
-
override get eventName(): string {
|
|
2973
|
-
return '${name.toLowerCase()}.created'
|
|
2974
|
-
}
|
|
2975
|
-
|
|
2976
|
-
get aggregateId(): string {
|
|
2977
|
-
return this.${name.toLowerCase()}Id
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
`;
|
|
2981
|
-
}
|
|
2982
|
-
generateRepositoryInterface(name) {
|
|
2983
|
-
return `/**
|
|
2984
|
-
* ${name} Repository Interface
|
|
2985
|
-
*/
|
|
2986
|
-
|
|
2987
|
-
import { Repository } from '@gravito/enterprise'
|
|
2988
|
-
import type { ${name} } from '../Aggregates/${name}/${name}'
|
|
2989
|
-
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
2990
|
-
|
|
2991
|
-
export interface I${name}Repository extends Repository<${name}, Id> {
|
|
2992
|
-
// Add specific methods for this repository if needed
|
|
2993
|
-
}
|
|
2994
|
-
`;
|
|
2995
|
-
}
|
|
2996
|
-
generateCommand(name) {
|
|
2997
|
-
return `/**
|
|
2998
|
-
* Create ${name} Command
|
|
2999
|
-
*/
|
|
3000
|
-
|
|
3001
|
-
import { Command } from '@gravito/enterprise'
|
|
3002
|
-
|
|
3003
|
-
export class Create${name}Command extends Command {
|
|
3004
|
-
constructor(
|
|
3005
|
-
// Add command properties
|
|
3006
|
-
public readonly id?: string
|
|
3007
|
-
) {
|
|
3008
|
-
super()
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
`;
|
|
3012
|
-
}
|
|
3013
|
-
generateCommandHandler(name) {
|
|
3014
|
-
return `/**
|
|
3015
|
-
* Create ${name} Handler
|
|
3016
|
-
*/
|
|
3017
|
-
|
|
3018
|
-
import { CommandHandler } from '@gravito/enterprise'
|
|
3019
|
-
import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
|
|
3020
|
-
import { ${name} } from '../../../Domain/Aggregates/${name}/${name}'
|
|
3021
|
-
import { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
3022
|
-
import type { Create${name}Command } from './Create${name}Command'
|
|
3023
|
-
|
|
3024
|
-
export class Create${name}Handler implements CommandHandler<Create${name}Command, string> {
|
|
3025
|
-
constructor(private repository: I${name}Repository) {}
|
|
3026
|
-
|
|
3027
|
-
async handle(command: Create${name}Command): Promise<string> {
|
|
3028
|
-
const id = command.id ? Id.from(command.id) : Id.create()
|
|
3029
|
-
const aggregate = ${name}.create(id)
|
|
3030
|
-
|
|
3031
|
-
await this.repository.save(aggregate)
|
|
3032
|
-
|
|
3033
|
-
return id.value
|
|
3034
|
-
}
|
|
3035
|
-
}
|
|
3036
|
-
`;
|
|
3037
|
-
}
|
|
3038
|
-
generateQuery(name) {
|
|
3039
|
-
return `/**
|
|
3040
|
-
* Get ${name} By Id Query
|
|
3041
|
-
*/
|
|
3042
|
-
|
|
3043
|
-
import { Query } from '@gravito/enterprise'
|
|
3044
|
-
|
|
3045
|
-
export class Get${name}ByIdQuery extends Query {
|
|
3046
|
-
constructor(public readonly id: string) {
|
|
3047
|
-
super()
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
`;
|
|
3051
|
-
}
|
|
3052
|
-
generateQueryHandler(name) {
|
|
3053
|
-
return `/**
|
|
3054
|
-
* Get ${name} By Id Handler
|
|
3055
|
-
*/
|
|
3056
|
-
|
|
3057
|
-
import { QueryHandler } from '@gravito/enterprise'
|
|
3058
|
-
import type { I${name}Repository } from '../../../Domain/Repositories/I${name}Repository'
|
|
3059
|
-
import type { ${name}DTO } from '../../DTOs/${name}DTO'
|
|
3060
|
-
import type { Get${name}ByIdQuery } from './Get${name}ByIdQuery'
|
|
3061
|
-
|
|
3062
|
-
export class Get${name}ByIdHandler implements QueryHandler<Get${name}ByIdQuery, ${name}DTO | null> {
|
|
3063
|
-
constructor(private repository: I${name}Repository) {}
|
|
3064
|
-
|
|
3065
|
-
async handle(query: Get${name}ByIdQuery): Promise<${name}DTO | null> {
|
|
3066
|
-
const aggregate = await this.repository.findById(query.id as any) // Simplified for demo
|
|
3067
|
-
if (!aggregate) return null
|
|
3068
|
-
|
|
3069
|
-
return {
|
|
3070
|
-
id: aggregate.id.value,
|
|
3071
|
-
status: aggregate.status,
|
|
3072
|
-
}
|
|
3073
|
-
}
|
|
3074
|
-
}
|
|
3075
|
-
`;
|
|
3076
|
-
}
|
|
3077
|
-
generateDTO(name) {
|
|
2797
|
+
generateExceptionHandler() {
|
|
3078
2798
|
return `/**
|
|
3079
|
-
*
|
|
2799
|
+
* Exception Handler
|
|
3080
2800
|
*/
|
|
3081
2801
|
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
export interface ${name}DTO {
|
|
3085
|
-
id: string
|
|
3086
|
-
status: ${name}Status
|
|
3087
|
-
// Add more fields
|
|
2802
|
+
export function report(error: unknown): void {
|
|
2803
|
+
console.error('[Exception]', error)
|
|
3088
2804
|
}
|
|
3089
2805
|
`;
|
|
3090
2806
|
}
|
|
3091
|
-
|
|
3092
|
-
return `/**
|
|
3093
|
-
* ${name} Repository Implementation
|
|
3094
|
-
*/
|
|
3095
|
-
|
|
3096
|
-
import type { ${name} } from '../../Domain/Aggregates/${name}/${name}'
|
|
3097
|
-
import type { I${name}Repository } from '../../Domain/Repositories/I${name}Repository'
|
|
3098
|
-
import type { Id } from '../../../../../Shared/Domain/ValueObjects/Id'
|
|
3099
|
-
|
|
3100
|
-
const store = new Map<string, ${name}>()
|
|
3101
|
-
|
|
3102
|
-
export class ${name}Repository implements I${name}Repository {
|
|
3103
|
-
async findById(id: Id): Promise<${name} | null> {
|
|
3104
|
-
return store.get(id.value) ?? null
|
|
3105
|
-
}
|
|
2807
|
+
};
|
|
3106
2808
|
|
|
3107
|
-
|
|
3108
|
-
|
|
2809
|
+
// src/generators/DddGenerator.ts
|
|
2810
|
+
var DddGenerator = class extends BaseGenerator {
|
|
2811
|
+
moduleGenerator;
|
|
2812
|
+
sharedKernelGenerator;
|
|
2813
|
+
bootstrapGenerator;
|
|
2814
|
+
constructor(config) {
|
|
2815
|
+
super(config);
|
|
2816
|
+
this.moduleGenerator = new ModuleGenerator();
|
|
2817
|
+
this.sharedKernelGenerator = new SharedKernelGenerator();
|
|
2818
|
+
this.bootstrapGenerator = new BootstrapGenerator();
|
|
3109
2819
|
}
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
store.delete(id.value)
|
|
2820
|
+
get architectureType() {
|
|
2821
|
+
return "ddd";
|
|
3113
2822
|
}
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
return Array.from(store.values())
|
|
2823
|
+
get displayName() {
|
|
2824
|
+
return "Domain-Driven Design (DDD)";
|
|
3117
2825
|
}
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
return store.has(id.value)
|
|
2826
|
+
get description() {
|
|
2827
|
+
return "Full DDD with Bounded Contexts, Aggregates, and Event-Driven patterns";
|
|
3121
2828
|
}
|
|
3122
|
-
|
|
3123
|
-
|
|
2829
|
+
getDirectoryStructure(context) {
|
|
2830
|
+
return [
|
|
2831
|
+
this.bootstrapGenerator.generateConfigDirectory(context),
|
|
2832
|
+
{
|
|
2833
|
+
type: "directory",
|
|
2834
|
+
name: "src",
|
|
2835
|
+
children: [
|
|
2836
|
+
// Bootstrap - Application startup and configuration
|
|
2837
|
+
this.bootstrapGenerator.generate(context),
|
|
2838
|
+
// Shared - Cross-module shared components
|
|
2839
|
+
this.sharedKernelGenerator.generate(),
|
|
2840
|
+
// Modules - Bounded Contexts
|
|
2841
|
+
{
|
|
2842
|
+
type: "directory",
|
|
2843
|
+
name: "Modules",
|
|
2844
|
+
children: [
|
|
2845
|
+
this.moduleGenerator.generate("Ordering", context),
|
|
2846
|
+
this.moduleGenerator.generate("Catalog", context)
|
|
2847
|
+
]
|
|
2848
|
+
},
|
|
2849
|
+
{
|
|
2850
|
+
type: "file",
|
|
2851
|
+
name: "main.ts",
|
|
2852
|
+
content: this.bootstrapGenerator.generateMainEntry(context)
|
|
2853
|
+
}
|
|
2854
|
+
]
|
|
2855
|
+
},
|
|
2856
|
+
{
|
|
2857
|
+
type: "directory",
|
|
2858
|
+
name: "tests",
|
|
2859
|
+
children: [
|
|
2860
|
+
{
|
|
2861
|
+
type: "directory",
|
|
2862
|
+
name: "Modules",
|
|
2863
|
+
children: [
|
|
2864
|
+
{
|
|
2865
|
+
type: "directory",
|
|
2866
|
+
name: "Ordering",
|
|
2867
|
+
children: [
|
|
2868
|
+
{
|
|
2869
|
+
type: "directory",
|
|
2870
|
+
name: "Unit",
|
|
2871
|
+
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2872
|
+
},
|
|
2873
|
+
{
|
|
2874
|
+
type: "directory",
|
|
2875
|
+
name: "Integration",
|
|
2876
|
+
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2877
|
+
}
|
|
2878
|
+
]
|
|
2879
|
+
},
|
|
2880
|
+
{
|
|
2881
|
+
type: "directory",
|
|
2882
|
+
name: "Catalog",
|
|
2883
|
+
children: [
|
|
2884
|
+
{
|
|
2885
|
+
type: "directory",
|
|
2886
|
+
name: "Unit",
|
|
2887
|
+
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2888
|
+
}
|
|
2889
|
+
]
|
|
2890
|
+
}
|
|
2891
|
+
]
|
|
2892
|
+
},
|
|
2893
|
+
{
|
|
2894
|
+
type: "directory",
|
|
2895
|
+
name: "Shared",
|
|
2896
|
+
children: [{ type: "file", name: ".gitkeep", content: "" }]
|
|
2897
|
+
}
|
|
2898
|
+
]
|
|
2899
|
+
}
|
|
2900
|
+
];
|
|
3124
2901
|
}
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
2902
|
+
/**
|
|
2903
|
+
* Override package.json for DDD architecture (uses main.ts instead of bootstrap.ts)
|
|
2904
|
+
*/
|
|
2905
|
+
generatePackageJson(context) {
|
|
2906
|
+
const pkg = {
|
|
2907
|
+
name: context.nameKebabCase,
|
|
2908
|
+
version: "0.1.0",
|
|
2909
|
+
type: "module",
|
|
2910
|
+
scripts: {
|
|
2911
|
+
dev: "bun run --watch src/main.ts",
|
|
2912
|
+
build: "bun build ./src/main.ts --outdir ./dist --target bun",
|
|
2913
|
+
start: "bun run dist/main.js",
|
|
2914
|
+
test: "bun test",
|
|
2915
|
+
typecheck: "bun tsc --noEmit",
|
|
2916
|
+
check: "bun run typecheck && bun run test",
|
|
2917
|
+
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
2918
|
+
validate: "bun run check && bun run check:deps",
|
|
2919
|
+
precommit: "bun run validate",
|
|
2920
|
+
"docker:build": `docker build -t ${context.nameKebabCase} .`,
|
|
2921
|
+
"docker:run": `docker run -it -p 3000:3000 ${context.nameKebabCase}`
|
|
2922
|
+
},
|
|
2923
|
+
dependencies: {
|
|
2924
|
+
"@gravito/core": "^1.0.0-beta.5",
|
|
2925
|
+
"@gravito/enterprise": "workspace:*"
|
|
2926
|
+
},
|
|
2927
|
+
devDependencies: {
|
|
2928
|
+
"bun-types": "latest",
|
|
2929
|
+
typescript: "^5.9.3"
|
|
2930
|
+
}
|
|
2931
|
+
};
|
|
2932
|
+
return JSON.stringify(pkg, null, 2);
|
|
3134
2933
|
}
|
|
3135
2934
|
generateArchitectureDoc(context) {
|
|
3136
2935
|
return `# ${context.name} - DDD Architecture Guide
|
|
@@ -3359,123 +3158,13 @@ var EnterpriseMvcGenerator = class extends BaseGenerator {
|
|
|
3359
3158
|
];
|
|
3360
3159
|
}
|
|
3361
3160
|
// ─────────────────────────────────────────────────────────────
|
|
3362
|
-
// Config Generators
|
|
3161
|
+
// Config Generators (using shared ConfigGenerator)
|
|
3363
3162
|
// ─────────────────────────────────────────────────────────────
|
|
3364
3163
|
generateAppConfig(context) {
|
|
3365
|
-
return
|
|
3366
|
-
* Application Configuration
|
|
3367
|
-
*/
|
|
3368
|
-
export default {
|
|
3369
|
-
/**
|
|
3370
|
-
* Application name
|
|
3371
|
-
*/
|
|
3372
|
-
name: process.env.APP_NAME ?? '${context.name}',
|
|
3373
|
-
|
|
3374
|
-
/**
|
|
3375
|
-
* Application environment
|
|
3376
|
-
*/
|
|
3377
|
-
env: process.env.APP_ENV ?? 'development',
|
|
3378
|
-
|
|
3379
|
-
/**
|
|
3380
|
-
* Application port
|
|
3381
|
-
*/
|
|
3382
|
-
port: Number.parseInt(process.env.PORT ?? '3000', 10),
|
|
3383
|
-
|
|
3384
|
-
/**
|
|
3385
|
-
* View directory
|
|
3386
|
-
*/
|
|
3387
|
-
VIEW_DIR: process.env.VIEW_DIR ?? 'src/views',
|
|
3388
|
-
|
|
3389
|
-
/**
|
|
3390
|
-
* Debug mode
|
|
3391
|
-
*/
|
|
3392
|
-
debug: process.env.APP_DEBUG === 'true',
|
|
3393
|
-
|
|
3394
|
-
/**
|
|
3395
|
-
* Application URL
|
|
3396
|
-
*/
|
|
3397
|
-
url: process.env.APP_URL ?? 'http://localhost:3000',
|
|
3398
|
-
|
|
3399
|
-
/**
|
|
3400
|
-
* Timezone
|
|
3401
|
-
*/
|
|
3402
|
-
timezone: 'UTC',
|
|
3403
|
-
|
|
3404
|
-
/**
|
|
3405
|
-
* Locale
|
|
3406
|
-
*/
|
|
3407
|
-
locale: 'en',
|
|
3408
|
-
|
|
3409
|
-
/**
|
|
3410
|
-
* Fallback locale
|
|
3411
|
-
*/
|
|
3412
|
-
fallbackLocale: 'en',
|
|
3413
|
-
|
|
3414
|
-
/**
|
|
3415
|
-
* Encryption key
|
|
3416
|
-
*/
|
|
3417
|
-
key: process.env.APP_KEY,
|
|
3418
|
-
|
|
3419
|
-
/**
|
|
3420
|
-
* Service providers to register
|
|
3421
|
-
*/
|
|
3422
|
-
providers: [
|
|
3423
|
-
// Framework providers
|
|
3424
|
-
// 'RouteServiceProvider',
|
|
3425
|
-
|
|
3426
|
-
// Application providers
|
|
3427
|
-
// 'AppServiceProvider',
|
|
3428
|
-
],
|
|
3429
|
-
}
|
|
3430
|
-
`;
|
|
3164
|
+
return ConfigGenerator.generateDetailedAppConfig(context);
|
|
3431
3165
|
}
|
|
3432
3166
|
generateDatabaseConfig() {
|
|
3433
|
-
return
|
|
3434
|
-
* Database Configuration
|
|
3435
|
-
*/
|
|
3436
|
-
export default {
|
|
3437
|
-
/**
|
|
3438
|
-
* Default connection
|
|
3439
|
-
*/
|
|
3440
|
-
default: process.env.DB_CONNECTION ?? 'sqlite',
|
|
3441
|
-
|
|
3442
|
-
/**
|
|
3443
|
-
* Database connections
|
|
3444
|
-
*/
|
|
3445
|
-
connections: {
|
|
3446
|
-
sqlite: {
|
|
3447
|
-
driver: 'sqlite',
|
|
3448
|
-
database: process.env.DB_DATABASE ?? 'database/database.sqlite',
|
|
3449
|
-
},
|
|
3450
|
-
|
|
3451
|
-
mysql: {
|
|
3452
|
-
driver: 'mysql',
|
|
3453
|
-
host: process.env.DB_HOST ?? 'localhost',
|
|
3454
|
-
port: Number(process.env.DB_PORT ?? 3306),
|
|
3455
|
-
database: process.env.DB_DATABASE ?? 'forge',
|
|
3456
|
-
username: process.env.DB_USERNAME ?? 'forge',
|
|
3457
|
-
password: process.env.DB_PASSWORD ?? '',
|
|
3458
|
-
},
|
|
3459
|
-
|
|
3460
|
-
postgres: {
|
|
3461
|
-
driver: 'postgres',
|
|
3462
|
-
host: process.env.DB_HOST ?? 'localhost',
|
|
3463
|
-
port: Number(process.env.DB_PORT ?? 5432),
|
|
3464
|
-
database: process.env.DB_DATABASE ?? 'forge',
|
|
3465
|
-
username: process.env.DB_USERNAME ?? 'forge',
|
|
3466
|
-
password: process.env.DB_PASSWORD ?? '',
|
|
3467
|
-
},
|
|
3468
|
-
},
|
|
3469
|
-
|
|
3470
|
-
/**
|
|
3471
|
-
* Migration settings
|
|
3472
|
-
*/
|
|
3473
|
-
migrations: {
|
|
3474
|
-
table: 'migrations',
|
|
3475
|
-
path: 'database/migrations',
|
|
3476
|
-
},
|
|
3477
|
-
}
|
|
3478
|
-
`;
|
|
3167
|
+
return ConfigGenerator.generateDetailedDatabaseConfig();
|
|
3479
3168
|
}
|
|
3480
3169
|
generateAuthConfig() {
|
|
3481
3170
|
return `/**
|
|
@@ -3758,33 +3447,6 @@ export class AppServiceProvider extends ServiceProvider {
|
|
|
3758
3447
|
console.log('${context.name} application booted!')
|
|
3759
3448
|
}
|
|
3760
3449
|
}
|
|
3761
|
-
`;
|
|
3762
|
-
}
|
|
3763
|
-
generateRouteServiceProvider(_context) {
|
|
3764
|
-
return `/**
|
|
3765
|
-
* Route Service Provider
|
|
3766
|
-
*
|
|
3767
|
-
* Configures and registers application routes.
|
|
3768
|
-
*/
|
|
3769
|
-
|
|
3770
|
-
import { ServiceProvider, type Container, type PlanetCore } from '@gravito/core'
|
|
3771
|
-
import { registerRoutes } from '../routes'
|
|
3772
|
-
|
|
3773
|
-
export class RouteServiceProvider extends ServiceProvider {
|
|
3774
|
-
/**
|
|
3775
|
-
* Register any application services.
|
|
3776
|
-
*/
|
|
3777
|
-
register(_container: Container): void {
|
|
3778
|
-
// Routes are registered in boot
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
/**
|
|
3782
|
-
* Bootstrap any application services.
|
|
3783
|
-
*/
|
|
3784
|
-
boot(core: PlanetCore): void {
|
|
3785
|
-
registerRoutes(core.router)
|
|
3786
|
-
}
|
|
3787
|
-
}
|
|
3788
3450
|
`;
|
|
3789
3451
|
}
|
|
3790
3452
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -4455,11 +4117,9 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
4455
4117
|
module: "dist/index.mjs",
|
|
4456
4118
|
types: "dist/index.d.ts",
|
|
4457
4119
|
scripts: {
|
|
4458
|
-
build: "tsup src/index.ts --format
|
|
4120
|
+
build: "tsup src/index.ts --format esm --dts",
|
|
4459
4121
|
test: "bun test",
|
|
4460
|
-
typecheck: "tsc --noEmit"
|
|
4461
|
-
check: "bun run typecheck && bun run test",
|
|
4462
|
-
validate: "bun run check"
|
|
4122
|
+
typecheck: "bun tsc --noEmit"
|
|
4463
4123
|
},
|
|
4464
4124
|
dependencies: {
|
|
4465
4125
|
"@gravito/core": depVersion,
|
|
@@ -4468,8 +4128,12 @@ export class ${name}ServiceProvider extends ServiceProvider {
|
|
|
4468
4128
|
"@gravito/stasis": depVersion
|
|
4469
4129
|
},
|
|
4470
4130
|
devDependencies: {
|
|
4471
|
-
|
|
4472
|
-
typescript: "^5.
|
|
4131
|
+
"bun-types": "latest",
|
|
4132
|
+
typescript: "^5.9.3",
|
|
4133
|
+
tsup: "^8.0.0"
|
|
4134
|
+
},
|
|
4135
|
+
peerDependencies: {
|
|
4136
|
+
"@gravito/core": ">=1.0.0"
|
|
4473
4137
|
}
|
|
4474
4138
|
};
|
|
4475
4139
|
return JSON.stringify(pkg, null, 2);
|
|
@@ -4619,7 +4283,7 @@ var ProfileResolver = class _ProfileResolver {
|
|
|
4619
4283
|
};
|
|
4620
4284
|
|
|
4621
4285
|
// src/Scaffold.ts
|
|
4622
|
-
var
|
|
4286
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
4623
4287
|
|
|
4624
4288
|
// src/generators/ActionDomainGenerator.ts
|
|
4625
4289
|
var ActionDomainGenerator = class extends BaseGenerator {
|
|
@@ -4826,6 +4490,9 @@ var ActionDomainGenerator = class extends BaseGenerator {
|
|
|
4826
4490
|
|
|
4827
4491
|
import { Model, column } from '@gravito/atlas'
|
|
4828
4492
|
|
|
4493
|
+
/**
|
|
4494
|
+
* Represents a user in the system.
|
|
4495
|
+
*/
|
|
4829
4496
|
export class User extends Model {
|
|
4830
4497
|
static table = 'users'
|
|
4831
4498
|
|
|
@@ -4849,6 +4516,11 @@ export class User extends Model {
|
|
|
4849
4516
|
// ─────────────────────────────────────────────────────────────
|
|
4850
4517
|
// Action Generators
|
|
4851
4518
|
// ─────────────────────────────────────────────────────────────
|
|
4519
|
+
/**
|
|
4520
|
+
* Generates the base Action class source code.
|
|
4521
|
+
*
|
|
4522
|
+
* @returns The complete source code for the abstract Action class.
|
|
4523
|
+
*/
|
|
4852
4524
|
generateActionBase() {
|
|
4853
4525
|
return `/**
|
|
4854
4526
|
* Action Base Class
|
|
@@ -4865,6 +4537,11 @@ export abstract class Action<TInput = unknown, TOutput = unknown> {
|
|
|
4865
4537
|
}
|
|
4866
4538
|
`;
|
|
4867
4539
|
}
|
|
4540
|
+
/**
|
|
4541
|
+
* Generates the GetServerStatusAction source code.
|
|
4542
|
+
*
|
|
4543
|
+
* @returns The complete source code for the example action.
|
|
4544
|
+
*/
|
|
4868
4545
|
generateGetServerStatusAction() {
|
|
4869
4546
|
return `/**
|
|
4870
4547
|
* Get Server Status Action
|
|
@@ -4887,6 +4564,11 @@ export class GetServerStatusAction extends Action<void, ServerStatusResponse> {
|
|
|
4887
4564
|
// ─────────────────────────────────────────────────────────────
|
|
4888
4565
|
// Controller Generators
|
|
4889
4566
|
// ─────────────────────────────────────────────────────────────
|
|
4567
|
+
/**
|
|
4568
|
+
* Generates the Server Controller source code.
|
|
4569
|
+
*
|
|
4570
|
+
* @returns The complete source code for the ServerController class.
|
|
4571
|
+
*/
|
|
4890
4572
|
generateServerController() {
|
|
4891
4573
|
return `/**
|
|
4892
4574
|
* Server Controller
|
|
@@ -4914,6 +4596,11 @@ export class ServerController {
|
|
|
4914
4596
|
// ─────────────────────────────────────────────────────────────
|
|
4915
4597
|
// Type Generators
|
|
4916
4598
|
// ─────────────────────────────────────────────────────────────
|
|
4599
|
+
/**
|
|
4600
|
+
* Generates the ServerStatusResponse type definition.
|
|
4601
|
+
*
|
|
4602
|
+
* @returns The complete source code for the response interface.
|
|
4603
|
+
*/
|
|
4917
4604
|
generateServerStatusResponse() {
|
|
4918
4605
|
return `/**
|
|
4919
4606
|
* Server Status Response Type
|
|
@@ -4929,6 +4616,11 @@ export interface ServerStatusResponse {
|
|
|
4929
4616
|
// ─────────────────────────────────────────────────────────────
|
|
4930
4617
|
// Routes & Bootstrap
|
|
4931
4618
|
// ─────────────────────────────────────────────────────────────
|
|
4619
|
+
/**
|
|
4620
|
+
* Generates the API routes registration function.
|
|
4621
|
+
*
|
|
4622
|
+
* @returns The complete source code for the api.ts routes file.
|
|
4623
|
+
*/
|
|
4932
4624
|
generateApiRoutes() {
|
|
4933
4625
|
return `/**
|
|
4934
4626
|
* API Routes Registration
|
|
@@ -4947,6 +4639,12 @@ export function registerApiRoutes(router: Router) {
|
|
|
4947
4639
|
}
|
|
4948
4640
|
`;
|
|
4949
4641
|
}
|
|
4642
|
+
/**
|
|
4643
|
+
* Generates the App Service Provider source code.
|
|
4644
|
+
*
|
|
4645
|
+
* @param context - The generator context containing project details.
|
|
4646
|
+
* @returns The complete source code for AppServiceProvider.
|
|
4647
|
+
*/
|
|
4950
4648
|
generateAppServiceProvider(context) {
|
|
4951
4649
|
return `/**
|
|
4952
4650
|
* App Service Provider
|
|
@@ -4975,6 +4673,11 @@ export { MiddlewareProvider } from './MiddlewareProvider'
|
|
|
4975
4673
|
export { RouteProvider } from './RouteProvider'
|
|
4976
4674
|
`;
|
|
4977
4675
|
}
|
|
4676
|
+
/**
|
|
4677
|
+
* Generates the Middleware Service Provider source code.
|
|
4678
|
+
*
|
|
4679
|
+
* @returns The complete source code for MiddlewareProvider.
|
|
4680
|
+
*/
|
|
4978
4681
|
generateMiddlewareProvider() {
|
|
4979
4682
|
return `/**
|
|
4980
4683
|
* Middleware Service Provider
|
|
@@ -4999,6 +4702,11 @@ export class MiddlewareProvider extends ServiceProvider {
|
|
|
4999
4702
|
}
|
|
5000
4703
|
`;
|
|
5001
4704
|
}
|
|
4705
|
+
/**
|
|
4706
|
+
* Generates the Route Service Provider source code.
|
|
4707
|
+
*
|
|
4708
|
+
* @returns The complete source code for RouteProvider.
|
|
4709
|
+
*/
|
|
5002
4710
|
generateRouteProvider() {
|
|
5003
4711
|
return `/**
|
|
5004
4712
|
* Route Service Provider
|
|
@@ -5110,7 +4818,7 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
5110
4818
|
build: "bun build ./src/bootstrap.ts --outdir ./dist --target bun",
|
|
5111
4819
|
start: "bun run dist/bootstrap.js",
|
|
5112
4820
|
test: "bun test",
|
|
5113
|
-
typecheck: "tsc --noEmit",
|
|
4821
|
+
typecheck: "bun tsc --noEmit",
|
|
5114
4822
|
check: "bun run typecheck && bun run test",
|
|
5115
4823
|
"check:deps": "bun run scripts/check-dependencies.ts",
|
|
5116
4824
|
validate: "bun run check && bun run check:deps",
|
|
@@ -5124,7 +4832,7 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
5124
4832
|
},
|
|
5125
4833
|
devDependencies: {
|
|
5126
4834
|
"bun-types": "latest",
|
|
5127
|
-
typescript: "^5.
|
|
4835
|
+
typescript: "^5.9.3"
|
|
5128
4836
|
}
|
|
5129
4837
|
};
|
|
5130
4838
|
return JSON.stringify(pkg, null, 2);
|
|
@@ -5132,6 +4840,7 @@ Created with \u2764\uFE0F using Gravito Framework
|
|
|
5132
4840
|
};
|
|
5133
4841
|
|
|
5134
4842
|
// src/generators/StandaloneEngineGenerator.ts
|
|
4843
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
5135
4844
|
var StandaloneEngineGenerator = class extends BaseGenerator {
|
|
5136
4845
|
get architectureType() {
|
|
5137
4846
|
return "standalone-engine";
|
|
@@ -5163,9 +4872,16 @@ var StandaloneEngineGenerator = class extends BaseGenerator {
|
|
|
5163
4872
|
];
|
|
5164
4873
|
}
|
|
5165
4874
|
async generateCommonFiles(context) {
|
|
4875
|
+
const commonDir = import_node_path5.default.resolve(this.config.templatesDir, "common");
|
|
4876
|
+
const extendedContext = { ...context };
|
|
5166
4877
|
await this.writeFile(context.targetDir, "package.json", this.generatePackageJson(context));
|
|
5167
|
-
await this.
|
|
5168
|
-
|
|
4878
|
+
await this.generateFileFromTemplate(
|
|
4879
|
+
commonDir,
|
|
4880
|
+
"tsconfig.json.hbs",
|
|
4881
|
+
"tsconfig.json",
|
|
4882
|
+
extendedContext
|
|
4883
|
+
);
|
|
4884
|
+
await this.generateFileFromTemplate(commonDir, "gitignore.hbs", ".gitignore", extendedContext);
|
|
5169
4885
|
}
|
|
5170
4886
|
generatePackageJson(context) {
|
|
5171
4887
|
const pkg = {
|
|
@@ -5220,23 +4936,17 @@ A high-performance web application powered by Gravito Engine.
|
|
|
5220
4936
|
|
|
5221
4937
|
### Install Dependencies
|
|
5222
4938
|
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
\`\`\`
|
|
5226
|
-
|
|
4939
|
+
bun install
|
|
4940
|
+
|
|
5227
4941
|
### Run Development Server
|
|
5228
4942
|
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
\`\`\`
|
|
5232
|
-
|
|
4943
|
+
bun run dev
|
|
4944
|
+
|
|
5233
4945
|
### Production Build
|
|
5234
4946
|
|
|
5235
|
-
|
|
5236
|
-
bun run build
|
|
4947
|
+
bun run build
|
|
5237
4948
|
bun start
|
|
5238
|
-
|
|
5239
|
-
`;
|
|
4949
|
+
`;
|
|
5240
4950
|
}
|
|
5241
4951
|
};
|
|
5242
4952
|
|
|
@@ -5245,11 +4955,14 @@ var Scaffold = class {
|
|
|
5245
4955
|
templatesDir;
|
|
5246
4956
|
verbose;
|
|
5247
4957
|
constructor(options = {}) {
|
|
5248
|
-
this.templatesDir = options.templatesDir ??
|
|
4958
|
+
this.templatesDir = options.templatesDir ?? import_node_path6.default.resolve(__dirname, "../templates");
|
|
5249
4959
|
this.verbose = options.verbose ?? false;
|
|
5250
4960
|
}
|
|
5251
4961
|
/**
|
|
5252
|
-
*
|
|
4962
|
+
* Returns a list of all architectural patterns supported by the engine,
|
|
4963
|
+
* along with human-readable names and descriptions.
|
|
4964
|
+
*
|
|
4965
|
+
* @returns {Array<{type: ArchitectureType, name: string, description: string}>}
|
|
5253
4966
|
*/
|
|
5254
4967
|
getArchitectureTypes() {
|
|
5255
4968
|
return [
|
|
@@ -5286,11 +4999,16 @@ var Scaffold = class {
|
|
|
5286
4999
|
];
|
|
5287
5000
|
}
|
|
5288
5001
|
/**
|
|
5289
|
-
*
|
|
5002
|
+
* Orchestrates the complete project generation lifecycle.
|
|
5003
|
+
* This includes directory creation, file layout, profile resolution,
|
|
5004
|
+
* dependency mapping, and optional post-install hooks.
|
|
5005
|
+
*
|
|
5006
|
+
* @param {ScaffoldOptions} options - Detailed configuration for the new project.
|
|
5007
|
+
* @returns {Promise<ScaffoldResult>}
|
|
5290
5008
|
*/
|
|
5291
5009
|
async create(options) {
|
|
5292
5010
|
const generator = this.createGenerator(options.architecture);
|
|
5293
|
-
const
|
|
5011
|
+
const fs5 = await import("fs/promises");
|
|
5294
5012
|
const profileResolver = new ProfileResolver();
|
|
5295
5013
|
const profileConfig = profileResolver.resolve(options.profile, options.features);
|
|
5296
5014
|
const context = BaseGenerator.createContext(
|
|
@@ -5317,8 +5035,8 @@ var Scaffold = class {
|
|
|
5317
5035
|
// Default template for now, should come from options if applicable
|
|
5318
5036
|
"1.0.0"
|
|
5319
5037
|
);
|
|
5320
|
-
const lockPath =
|
|
5321
|
-
await
|
|
5038
|
+
const lockPath = import_node_path6.default.resolve(options.targetDir, "gravito.lock.json");
|
|
5039
|
+
await fs5.writeFile(lockPath, lockContent, "utf-8");
|
|
5322
5040
|
filesCreated.push(lockPath);
|
|
5323
5041
|
return {
|
|
5324
5042
|
success: true,
|
|
@@ -5377,6 +5095,7 @@ var Scaffold = class {
|
|
|
5377
5095
|
BaseGenerator,
|
|
5378
5096
|
CleanArchitectureGenerator,
|
|
5379
5097
|
DddGenerator,
|
|
5098
|
+
DependencyValidator,
|
|
5380
5099
|
EnterpriseMvcGenerator,
|
|
5381
5100
|
EnvironmentDetector,
|
|
5382
5101
|
FileMerger,
|