simpledi-app-generator 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/cli.js +3 -4
- package/dist/cli.js.map +1 -1
- package/dist/create_module.d.ts.map +1 -1
- package/dist/create_module.js +6 -0
- package/dist/create_module.js.map +1 -1
- package/dist/generate_crud_use_cases.d.ts +2 -0
- package/dist/generate_crud_use_cases.d.ts.map +1 -0
- package/dist/generate_crud_use_cases.js +1111 -0
- package/dist/generate_crud_use_cases.js.map +1 -0
- package/package.json +1 -1
- package/user-guide.md +16 -4
package/README.md
CHANGED
|
@@ -20,11 +20,11 @@ npm link
|
|
|
20
20
|
|
|
21
21
|
## Commands
|
|
22
22
|
|
|
23
|
-
| Command | Description
|
|
24
|
-
| ---------------------------------------- |
|
|
25
|
-
| `simpledi new <name>` | Create a new simple-di project
|
|
26
|
-
| `simpledi module <entity>` | Generate a
|
|
27
|
-
| `simpledi use-case <name> [imports=...]` | Generate a use case with routes
|
|
23
|
+
| Command | Description |
|
|
24
|
+
| ---------------------------------------- | ------------------------------------- |
|
|
25
|
+
| `simpledi new <name>` | Create a new simple-di project |
|
|
26
|
+
| `simpledi module <entity>` | Generate a module with CRUD use cases |
|
|
27
|
+
| `simpledi use-case <name> [imports=...]` | Generate a use case with routes |
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
@@ -35,13 +35,13 @@ cd my-app
|
|
|
35
35
|
bun install
|
|
36
36
|
|
|
37
37
|
# Add your DATABASE_URL to .env.development
|
|
38
|
-
# Generate entities
|
|
38
|
+
# Generate entities (includes CRUD use cases!)
|
|
39
39
|
simpledi module user
|
|
40
40
|
simpledi module blog-post
|
|
41
41
|
|
|
42
|
-
# Generate use cases
|
|
43
|
-
simpledi use-case get-
|
|
44
|
-
simpledi use-case
|
|
42
|
+
# Generate custom use cases
|
|
43
|
+
simpledi use-case get-dashboard-stats imports=user,blog-post
|
|
44
|
+
simpledi use-case publish-post imports=blog-post
|
|
45
45
|
|
|
46
46
|
# Run
|
|
47
47
|
bun run dev
|
package/dist/cli.js
CHANGED
|
@@ -11,15 +11,14 @@ simpledi - Simple DI App Generator
|
|
|
11
11
|
|
|
12
12
|
Usage:
|
|
13
13
|
simpledi new <project-name> Create a new simple-di project
|
|
14
|
-
simpledi module <entity-name> Generate a module
|
|
14
|
+
simpledi module <entity-name> Generate a module with CRUD use cases
|
|
15
15
|
simpledi use-case <name> [imports=mod1,mod2,...] Generate a use case in current project
|
|
16
16
|
|
|
17
17
|
Examples:
|
|
18
18
|
simpledi new my-app
|
|
19
19
|
simpledi module user
|
|
20
|
-
simpledi
|
|
21
|
-
simpledi use-case
|
|
22
|
-
simpledi use-case create-user imports=CoreModule,ConfigModule
|
|
20
|
+
simpledi use-case get-dashboard-stats
|
|
21
|
+
simpledi use-case publish-post imports=blog-post
|
|
23
22
|
`);
|
|
24
23
|
}
|
|
25
24
|
function parseImports(args) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAErB,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAErB,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAab,CAAC,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,IAAc;IAClC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAChD,OAAO,UAAU;iBACd,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,UAAU,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,KAAK;YACR,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBACjD,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;gBACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM;QAER,KAAK,QAAQ;YACX,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;gBAChD,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;gBACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM;QAER,KAAK,UAAU;YACb,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBAClD,OAAO,CAAC,KAAK,CACX,yDAAyD,CAC1D,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACnC,MAAM;QAER;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;YAC7C,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_module.d.ts","sourceRoot":"","sources":["../src/create_module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create_module.d.ts","sourceRoot":"","sources":["../src/create_module.ts"],"names":[],"mappings":"AAaA,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ajE"}
|
package/dist/create_module.js
CHANGED
|
@@ -2,6 +2,7 @@ import { mkdir, writeFile, readFile } from 'fs/promises';
|
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import { toPascalCase, toCamelCase, toKebabCase, toSnakeCase, toUpperSnakeCase, pluralize, } from './lib/stringUtils.js';
|
|
5
|
+
import { generateCrudUseCases } from './generate_crud_use_cases.js';
|
|
5
6
|
export async function createModule(rawName) {
|
|
6
7
|
if (!rawName) {
|
|
7
8
|
throw new Error('Entity name is required');
|
|
@@ -62,8 +63,11 @@ export type ${EntityName}SchemaType = typeof ${entityName}Schema;
|
|
|
62
63
|
// Zod validation schemas
|
|
63
64
|
export const ${EntityName}InsertSchema = createInsertSchema(${entityName}Schema).merge(
|
|
64
65
|
baseZod${EntityName}Schema.partial({
|
|
66
|
+
id: true,
|
|
65
67
|
createdAt: true,
|
|
68
|
+
createdBy: true,
|
|
66
69
|
updatedAt: true,
|
|
70
|
+
updatedBy: true,
|
|
67
71
|
deletedAt: true,
|
|
68
72
|
deleted: true,
|
|
69
73
|
})
|
|
@@ -403,5 +407,7 @@ describe('${EntityName}Repository', () => {
|
|
|
403
407
|
console.warn('Warning: src/core/CoreModule.ts not found');
|
|
404
408
|
}
|
|
405
409
|
console.log('\n✅ Module generation complete!');
|
|
410
|
+
// Generate CRUD use cases
|
|
411
|
+
await generateCrudUseCases(EntityName, entityName, kebabName, srcDir);
|
|
406
412
|
}
|
|
407
413
|
//# sourceMappingURL=create_module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_module.js","sourceRoot":"","sources":["../src/create_module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,SAAS,GACV,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"create_module.js","sourceRoot":"","sources":["../src/create_module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB;IAC1D,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB;IACzD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB;IACzD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB;IACzD,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB;IAC/D,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB;IAE1D,OAAO,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,UAAU,SAAS,EAAE,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAErD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,aAAa,SAAS,iBAAiB,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,iBAAiB;IAEjB,+CAA+C;IAC/C,MAAM,oBAAoB,GAAG;;;sBAGT,UAAU;;;cAGlB,UAAU,qCAAqC,UAAU;CACtE,CAAC;IAEA,iBAAiB;IACjB,MAAM,aAAa,GAAG;;;;;;;kBAON,UAAU,2BAA2B,UAAU;;;eAGlD,UAAU,kBAAkB,SAAS;;;eAGrC,UAAU,2BAA2B,UAAU;;;;;;;kBAO5C,UAAU,yBAAyB,UAAU;;;;;cAKjD,UAAU,uBAAuB,UAAU;;;eAG1C,UAAU,qCAAqC,UAAU;WAC7D,UAAU;;;;;;;;;;;eAWN,UAAU,qCAAqC,UAAU;WAC7D,UAAU;;;eAGN,UAAU,qCAAqC,UAAU;WAC7D,UAAU;;CAEpB,CAAC;IAEA,4BAA4B;IAC5B,MAAM,YAAY,GAAG;gBACP,UAAU,8BAA8B,UAAU;;eAEnD,UAAU,6BAA6B,UAAU;;oBAE5C,UAAU,kCAAkC,UAAU;;;CAGzE,CAAC;IAEA,2BAA2B;IAC3B,MAAM,WAAW,GAAG;;IAElB,UAAU;UACJ,UAAU;aACP,UAAU;WACZ,UAAU,gBAAgB,UAAU,wBAAwB,UAAU;gBACjE,UAAU,8BAA8B,UAAU;;;;oBAI9C,UAAU;eACf,UAAU;2BACE,UAAU,cAAc,UAAU;gBAC7C,UAAU;;;YAGd,UAAU;;;sCAGgB,UAAU;kCACd,UAAU;;uBAErB,UAAU;;;yCAGQ,UAAU;kCACjB,UAAU;;uBAErB,UAAU;;;CAGhC,CAAC;IAEA,iCAAiC;IACjC,MAAM,iBAAiB,GAAG;WACjB,UAAU,oCAAoC,UAAU;WACxD,UAAU,wBAAwB,UAAU;;;;eAIxC,UAAU;;;;iBAIR,UAAU;kBACT,UAAU;;;;CAI3B,CAAC;IAEA,yBAAyB;IACzB,MAAM,eAAe,GAAG;gBACV,UAAU,8BAA8B,UAAU;;eAEnD,UAAU,0BAA0B,UAAU;;oBAEzC,UAAU,4BAA4B,UAAU;;;CAGnE,CAAC;IAEA,wBAAwB;IACxB,MAAM,cAAc,GAAG;gBACT,UAAU,8BAA8B,UAAU;;IAE9D,UAAU;UACJ,UAAU;aACP,UAAU;;IAEnB,UAAU;UACJ,UAAU;aACP,UAAU;;IAEnB,UAAU;IACV,UAAU;IACV,UAAU;YACF,UAAU;;;oBAGF,UAAU;eACf,UAAU;wBACD,UAAU;gBAClB,UAAU;;;cAGZ,UAAU;uBACD,UAAU,gBAAgB,UAAU;;;QAGnD,UAAU;QACV,UAAU;QACV,UAAU;QACV,UAAU;;;;CAIjB,CAAC;IAEA,8BAA8B;IAC9B,MAAM,oBAAoB,GAAG;WACpB,UAAU,qBAAqB,UAAU;WACzC,UAAU,8BAA8B,UAAU;WAClD,UAAU,iCAAiC,UAAU;;eAEjD,UAAU;cACX,UAAU;;;iBAGP,UAAU;kBACT,UAAU;;;;CAI3B,CAAC;IAEA,uBAAuB;IACvB,MAAM,iBAAiB,GAAG;WACjB,UAAU,8BAA8B,UAAU;WAClD,UAAU,2BAA2B,UAAU;;eAE3C,UAAU;cACX,UAAU,qBAAqB,UAAU;;CAEtD,CAAC;IAEA,iCAAiC;IACjC,MAAM,WAAW,GAAG;WACX,UAAU,wBAAwB,UAAU;;;;;;;WAO5C,UAAU,oCAAoC,UAAU;;;;;YAKvD,UAAU;QACd,UAAU,eAAe,UAAU;;;;gCAIX,UAAU;;;;;;;YAO9B,UAAU;;;;qBAID,UAAU;sBACT,UAAU;;;;;;;;;UAStB,UAAU;;;;;;;MAOd,UAAU,uBAAuB,UAAU,eAAe,UAAU;;;;;;gCAM1C,UAAU;;;;;;;;aAQ7B,UAAU;;;CAGtB,CAAC;IAEA,cAAc;IACd,MAAM,KAAK,GAAG;QACZ,EAAE,IAAI,EAAE,UAAU,UAAU,WAAW,EAAE,OAAO,EAAE,oBAAoB,EAAE;QACxE,EAAE,IAAI,EAAE,GAAG,UAAU,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE;QACpD,EAAE,IAAI,EAAE,IAAI,UAAU,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE;QAC9D,EAAE,IAAI,EAAE,GAAG,UAAU,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE;QAC5D,EAAE,IAAI,EAAE,GAAG,UAAU,qBAAqB,EAAE,OAAO,EAAE,iBAAiB,EAAE;QACxE,EAAE,IAAI,EAAE,IAAI,UAAU,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE;QAC9D,EAAE,IAAI,EAAE,GAAG,UAAU,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE;QAC5D,EAAE,IAAI,EAAE,GAAG,UAAU,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,EAAE;QACxE,EAAE,IAAI,EAAE,GAAG,UAAU,WAAW,EAAE,OAAO,EAAE,iBAAiB,EAAE;QAC9D,EAAE,IAAI,EAAE,GAAG,UAAU,oBAAoB,EAAE,OAAO,EAAE,WAAW,EAAE;KAClE,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,oBAAoB;IAEpB,mBAAmB;IACnB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,eAAe,GAAG,6BAA6B,SAAS,IAAI,UAAU,IAAI,CAAC;QACjF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,KAAK,eAAe,IAAI,CAAC;YACpC,MAAM,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACnD,CAAC;IAED,4BAA4B;IAC5B,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC1D,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/B,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,eAAe,GAAG,YAAY,UAAU,oBAAoB,SAAS,IAAI,UAAU,UAAU,CAAC;QAEpG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,aAAa;YACb,gDAAgD;YAChD,MAAM,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACvD,IAAI,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC3B,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;gBAC7D,OAAO;oBACL,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC;wBACnC,eAAe;wBACf,IAAI;wBACJ,OAAO,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC;YAC7C,CAAC;YAED,uBAAuB;YACvB,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACxD,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC7B,MAAM,UAAU,GAAG,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC;gBAC3D,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;gBAClB,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACjD,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;wBAAE,KAAK,EAAE,CAAC;oBAChC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;wBAAE,KAAK,EAAE,CAAC;oBAChC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;wBAChB,QAAQ,GAAG,CAAC,CAAC;wBACb,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;oBACpB,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;oBACzD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,CAAC;wBAClD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;wBACpC,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;wBAC/C,MAAM,SAAS,GACb,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtD,wBAAwB;wBACxB,MAAM,SAAS,GAAG,GAAG,SAAS,SAAS,UAAU,SAAS,CAAC;wBAE3D,OAAO;4BACL,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBACnE,MAAM,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;wBACzC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;oBAChD,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CACV,4EAA4E,CAC7E,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,iFAAiF;gBACjF,MAAM,YAAY,GAAG,gBAAgB,CAAC;gBACtC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;oBACjD,IAAI,KAAK,GAAG,CAAC,CAAC;oBACd,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;oBAClB,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACjD,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;4BAAE,KAAK,EAAE,CAAC;wBAChC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;4BAAE,KAAK,EAAE,CAAC;wBAChC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;4BAChB,QAAQ,GAAG,CAAC,CAAC;4BACb,MAAM;wBACR,CAAC;oBACH,CAAC;oBACD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;wBACpB,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;wBACzD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,CAAC;4BAClD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;4BACpC,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;4BAC/C,MAAM,SAAS,GACb,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;4BACtD,MAAM,SAAS,GAAG,GAAG,SAAS,SAAS,UAAU,SAAS,CAAC;4BAC3D,OAAO;gCACL,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;oCAC1B,SAAS;oCACT,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;4BAC1B,MAAM,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;4BACzC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;wBAChD,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CACV,wDAAwD,CACzD,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,0BAA0B;IAC1B,MAAM,oBAAoB,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate_crud_use_cases.d.ts","sourceRoot":"","sources":["../src/generate_crud_use_cases.ts"],"names":[],"mappings":"AAoBA,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAsCf"}
|
|
@@ -0,0 +1,1111 @@
|
|
|
1
|
+
import { mkdir, writeFile, readFile } from 'fs/promises';
|
|
2
|
+
import { join, resolve } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { toPascalCase, toCamelCase, toKebabCase, toUpperSnakeCase, pluralize, } from './lib/stringUtils.js';
|
|
5
|
+
export async function generateCrudUseCases(EntityName, entityName, kebabName, srcDir) {
|
|
6
|
+
const TOKEN_BASE = toUpperSnakeCase(entityName);
|
|
7
|
+
const pluralKebab = pluralize(kebabName);
|
|
8
|
+
const pluralPascal = toPascalCase(pluralKebab);
|
|
9
|
+
const config = {
|
|
10
|
+
EntityName,
|
|
11
|
+
entityName,
|
|
12
|
+
kebabName,
|
|
13
|
+
TOKEN_BASE,
|
|
14
|
+
pluralKebab,
|
|
15
|
+
pluralPascal,
|
|
16
|
+
};
|
|
17
|
+
const useCaseBaseDir = resolve(srcDir, 'use-case', kebabName);
|
|
18
|
+
await mkdir(useCaseBaseDir, { recursive: true });
|
|
19
|
+
// Generate each CRUD use case
|
|
20
|
+
await generateCreateUseCase(useCaseBaseDir, config);
|
|
21
|
+
await generateUpdateUseCase(useCaseBaseDir, config);
|
|
22
|
+
await generateGetUseCase(useCaseBaseDir, config);
|
|
23
|
+
await generateListUseCase(useCaseBaseDir, config);
|
|
24
|
+
await generateDeleteUseCase(useCaseBaseDir, config);
|
|
25
|
+
// Generate aggregator module
|
|
26
|
+
await generateUseCaseAggregatorModule(useCaseBaseDir, config);
|
|
27
|
+
// Auto-register in UseCaseModule.ts
|
|
28
|
+
await registerInUseCaseModule(srcDir, config);
|
|
29
|
+
// Phase 3: Generate Scaffolded E2E Tests
|
|
30
|
+
await generateCreateE2ETest(useCaseBaseDir, config);
|
|
31
|
+
await generateUpdateE2ETest(useCaseBaseDir, config);
|
|
32
|
+
await generateGetE2ETest(useCaseBaseDir, config);
|
|
33
|
+
await generateListE2ETest(useCaseBaseDir, config);
|
|
34
|
+
await generateDeleteE2ETest(useCaseBaseDir, config);
|
|
35
|
+
console.log(`\n✅ CRUD use cases generated for ${EntityName}!`);
|
|
36
|
+
}
|
|
37
|
+
// ============ CREATE USE CASE ============
|
|
38
|
+
async function generateCreateUseCase(baseDir, config) {
|
|
39
|
+
const { EntityName, entityName, kebabName, TOKEN_BASE, pluralKebab } = config;
|
|
40
|
+
const useCaseName = `Create${EntityName}`;
|
|
41
|
+
const useCaseDir = join(baseDir, `create-${kebabName}`);
|
|
42
|
+
const inputsDir = join(useCaseDir, 'inputs');
|
|
43
|
+
const outputsDir = join(useCaseDir, 'outputs');
|
|
44
|
+
await mkdir(useCaseDir, { recursive: true });
|
|
45
|
+
await mkdir(inputsDir, { recursive: true });
|
|
46
|
+
await mkdir(outputsDir, { recursive: true });
|
|
47
|
+
// Input
|
|
48
|
+
const inputContent = `import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
49
|
+
|
|
50
|
+
export type ${useCaseName}Input = Omit<${EntityName}Interface, 'id' | 'createdAt' | 'updatedAt' | 'deleted' | 'deletedAt'>;
|
|
51
|
+
`;
|
|
52
|
+
// Success Output
|
|
53
|
+
const successContent = `import { SuccessfullOperation } from '@root/lib';
|
|
54
|
+
import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
55
|
+
|
|
56
|
+
export type ${useCaseName}Payload = ${EntityName}Interface;
|
|
57
|
+
|
|
58
|
+
export class ${useCaseName}Success extends SuccessfullOperation {
|
|
59
|
+
constructor(
|
|
60
|
+
result: ${useCaseName}Payload,
|
|
61
|
+
message: string = '${EntityName} created successfully',
|
|
62
|
+
) {
|
|
63
|
+
super(message);
|
|
64
|
+
this.result = result;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
// Failure Output
|
|
69
|
+
const failureContent = `import { FailedOperation } from '@root/lib';
|
|
70
|
+
|
|
71
|
+
export class ${useCaseName}Failure extends FailedOperation {
|
|
72
|
+
constructor(message: string = 'Failed to create ${EntityName}') {
|
|
73
|
+
super(message);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
// Use Case
|
|
78
|
+
const useCaseContent = `import { Inject, Module, Service } from '@kanian77/simple-di';
|
|
79
|
+
import { ${useCaseName}Success, type ${useCaseName}Payload } from './outputs/${useCaseName}Success';
|
|
80
|
+
import type { IUseCase } from '../../IUseCase';
|
|
81
|
+
import type { ${useCaseName}Input } from './inputs/${useCaseName}Input';
|
|
82
|
+
import { ${EntityName}Module } from '@root/core/${kebabName}/${EntityName}Module';
|
|
83
|
+
import { ${TOKEN_BASE}_SERVICE_INTERFACE, type I${EntityName}Service } from '@root/core/${kebabName}/I${EntityName}Service';
|
|
84
|
+
|
|
85
|
+
export const ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN = '${toUpperSnakeCase(useCaseName)}_USE_CASE';
|
|
86
|
+
|
|
87
|
+
@Service({
|
|
88
|
+
token: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
89
|
+
lifecycle: 'transient',
|
|
90
|
+
})
|
|
91
|
+
export class ${useCaseName} implements IUseCase {
|
|
92
|
+
constructor(
|
|
93
|
+
@Inject(${TOKEN_BASE}_SERVICE_INTERFACE)
|
|
94
|
+
private readonly ${entityName}Service: I${EntityName}Service,
|
|
95
|
+
) {}
|
|
96
|
+
|
|
97
|
+
async execute(input: ${useCaseName}Input): Promise<${useCaseName}Success> {
|
|
98
|
+
const created = await this.${entityName}Service.create(input);
|
|
99
|
+
return new ${useCaseName}Success(created as ${useCaseName}Payload);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const ${useCaseName}Module = new Module({
|
|
104
|
+
imports: [${EntityName}Module],
|
|
105
|
+
providers: [
|
|
106
|
+
{
|
|
107
|
+
provide: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
108
|
+
useClass: ${useCaseName},
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
`;
|
|
113
|
+
// Routes
|
|
114
|
+
const routesContent = `import { Hono } from 'hono';
|
|
115
|
+
import { StatusCodes } from 'http-status-codes';
|
|
116
|
+
import { inject } from '@kanian77/simple-di';
|
|
117
|
+
import { ${useCaseName}, ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN } from './${useCaseName}';
|
|
118
|
+
import { ${useCaseName}Failure } from './outputs/${useCaseName}Failure';
|
|
119
|
+
import { ${EntityName}InsertSchema } from '@root/core/${kebabName}/${EntityName}';
|
|
120
|
+
import { authGuard, roleGuard, getContextUser } from '@root/middlewares';
|
|
121
|
+
import { AdminRoleEnum } from '@root/lib';
|
|
122
|
+
|
|
123
|
+
const ${toCamelCase(useCaseName)}Routes = new Hono();
|
|
124
|
+
const ${toCamelCase(useCaseName)}RoutesPath = '/${pluralKebab}';
|
|
125
|
+
|
|
126
|
+
${toCamelCase(useCaseName)}Routes.post(
|
|
127
|
+
${toCamelCase(useCaseName)}RoutesPath,
|
|
128
|
+
authGuard(),
|
|
129
|
+
roleGuard([AdminRoleEnum.ADMIN]),
|
|
130
|
+
async (c) => {
|
|
131
|
+
try {
|
|
132
|
+
const rawInput = await c.req.json();
|
|
133
|
+
const user = getContextUser(c);
|
|
134
|
+
if (user) {
|
|
135
|
+
rawInput.createdBy = user.id;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const input = ${EntityName}InsertSchema.parse(rawInput);
|
|
139
|
+
const useCase = inject<${useCaseName}>(${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN);
|
|
140
|
+
const result = await useCase.execute(input);
|
|
141
|
+
return c.json(result, StatusCodes.CREATED);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.error('Error in ${toCamelCase(useCaseName)}Routes:', e);
|
|
144
|
+
return c.json(
|
|
145
|
+
new ${useCaseName}Failure('Internal Server Error'),
|
|
146
|
+
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
export { ${toCamelCase(useCaseName)}Routes as Route, ${toCamelCase(useCaseName)}RoutesPath as Path };
|
|
153
|
+
`;
|
|
154
|
+
await writeFile(join(inputsDir, `${useCaseName}Input.ts`), inputContent);
|
|
155
|
+
await writeFile(join(outputsDir, `${useCaseName}Success.ts`), successContent);
|
|
156
|
+
await writeFile(join(outputsDir, `${useCaseName}Failure.ts`), failureContent);
|
|
157
|
+
await writeFile(join(useCaseDir, `${useCaseName}.ts`), useCaseContent);
|
|
158
|
+
await writeFile(join(useCaseDir, `${toCamelCase(useCaseName)}Routes.ts`), routesContent);
|
|
159
|
+
console.log(`Created: create-${kebabName}/ use case`);
|
|
160
|
+
}
|
|
161
|
+
// ============ UPDATE USE CASE ============
|
|
162
|
+
async function generateUpdateUseCase(baseDir, config) {
|
|
163
|
+
const { EntityName, entityName, kebabName, TOKEN_BASE, pluralKebab } = config;
|
|
164
|
+
const useCaseName = `Update${EntityName}`;
|
|
165
|
+
const useCaseDir = join(baseDir, `update-${kebabName}`);
|
|
166
|
+
const inputsDir = join(useCaseDir, 'inputs');
|
|
167
|
+
const outputsDir = join(useCaseDir, 'outputs');
|
|
168
|
+
await mkdir(useCaseDir, { recursive: true });
|
|
169
|
+
await mkdir(inputsDir, { recursive: true });
|
|
170
|
+
await mkdir(outputsDir, { recursive: true });
|
|
171
|
+
// Input
|
|
172
|
+
const inputContent = `import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
173
|
+
|
|
174
|
+
export interface ${useCaseName}Input {
|
|
175
|
+
id: string;
|
|
176
|
+
data: Partial<Omit<${EntityName}Interface, 'id' | 'createdAt' | 'updatedAt'>>;
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
// Success Output
|
|
180
|
+
const successContent = `import { SuccessfullOperation } from '@root/lib';
|
|
181
|
+
import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
182
|
+
|
|
183
|
+
export type ${useCaseName}Payload = ${EntityName}Interface;
|
|
184
|
+
|
|
185
|
+
export class ${useCaseName}Success extends SuccessfullOperation {
|
|
186
|
+
constructor(
|
|
187
|
+
result: ${useCaseName}Payload,
|
|
188
|
+
message: string = '${EntityName} updated successfully',
|
|
189
|
+
) {
|
|
190
|
+
super(message);
|
|
191
|
+
this.result = result;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
`;
|
|
195
|
+
// Failure Output
|
|
196
|
+
const failureContent = `import { FailedOperation } from '@root/lib';
|
|
197
|
+
|
|
198
|
+
export class ${useCaseName}Failure extends FailedOperation {
|
|
199
|
+
constructor(message: string = 'Failed to update ${EntityName}') {
|
|
200
|
+
super(message);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
// Use Case
|
|
205
|
+
const useCaseContent = `import { Inject, Module, Service } from '@kanian77/simple-di';
|
|
206
|
+
import { ${useCaseName}Success, type ${useCaseName}Payload } from './outputs/${useCaseName}Success';
|
|
207
|
+
import type { IUseCase } from '../../IUseCase';
|
|
208
|
+
import type { ${useCaseName}Input } from './inputs/${useCaseName}Input';
|
|
209
|
+
import { ${EntityName}Module } from '@root/core/${kebabName}/${EntityName}Module';
|
|
210
|
+
import { ${TOKEN_BASE}_SERVICE_INTERFACE, type I${EntityName}Service } from '@root/core/${kebabName}/I${EntityName}Service';
|
|
211
|
+
|
|
212
|
+
export const ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN = '${toUpperSnakeCase(useCaseName)}_USE_CASE';
|
|
213
|
+
|
|
214
|
+
@Service({
|
|
215
|
+
token: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
216
|
+
lifecycle: 'transient',
|
|
217
|
+
})
|
|
218
|
+
export class ${useCaseName} implements IUseCase {
|
|
219
|
+
constructor(
|
|
220
|
+
@Inject(${TOKEN_BASE}_SERVICE_INTERFACE)
|
|
221
|
+
private readonly ${entityName}Service: I${EntityName}Service,
|
|
222
|
+
) {}
|
|
223
|
+
|
|
224
|
+
async execute(input: ${useCaseName}Input): Promise<${useCaseName}Success> {
|
|
225
|
+
const updated = await this.${entityName}Service.update(input.id, input.data);
|
|
226
|
+
return new ${useCaseName}Success(updated as ${useCaseName}Payload);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export const ${useCaseName}Module = new Module({
|
|
231
|
+
imports: [${EntityName}Module],
|
|
232
|
+
providers: [
|
|
233
|
+
{
|
|
234
|
+
provide: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
235
|
+
useClass: ${useCaseName},
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
`;
|
|
240
|
+
// Routes
|
|
241
|
+
const routesContent = `import { Hono } from 'hono';
|
|
242
|
+
import { StatusCodes } from 'http-status-codes';
|
|
243
|
+
import { inject } from '@kanian77/simple-di';
|
|
244
|
+
import { ${useCaseName}, ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN } from './${useCaseName}';
|
|
245
|
+
import { ${useCaseName}Failure } from './outputs/${useCaseName}Failure';
|
|
246
|
+
import type { ${useCaseName}Input } from './inputs/${useCaseName}Input';
|
|
247
|
+
import { ${EntityName}UpdateSchema } from '@root/core/${kebabName}/${EntityName}';
|
|
248
|
+
import { authGuard, roleGuard, getContextUser } from '@root/middlewares';
|
|
249
|
+
import { AdminRoleEnum } from '@root/lib';
|
|
250
|
+
|
|
251
|
+
const ${toCamelCase(useCaseName)}Routes = new Hono();
|
|
252
|
+
const ${toCamelCase(useCaseName)}RoutesPath = '/${pluralKebab}/:id';
|
|
253
|
+
|
|
254
|
+
${toCamelCase(useCaseName)}Routes.put(
|
|
255
|
+
${toCamelCase(useCaseName)}RoutesPath,
|
|
256
|
+
authGuard(),
|
|
257
|
+
roleGuard([AdminRoleEnum.ADMIN]),
|
|
258
|
+
async (c) => {
|
|
259
|
+
try {
|
|
260
|
+
const id = c.req.param('id');
|
|
261
|
+
const rawBody = await c.req.json();
|
|
262
|
+
|
|
263
|
+
const user = getContextUser(c);
|
|
264
|
+
if (user) {
|
|
265
|
+
rawBody.updatedBy = user.id;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const data = ${EntityName}UpdateSchema.parse(rawBody);
|
|
269
|
+
const input: ${useCaseName}Input = { id, data };
|
|
270
|
+
const useCase = inject<${useCaseName}>(${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN);
|
|
271
|
+
const result = await useCase.execute(input);
|
|
272
|
+
return c.json(result, StatusCodes.OK);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
console.error('Error in ${toCamelCase(useCaseName)}Routes:', e);
|
|
275
|
+
return c.json(
|
|
276
|
+
new ${useCaseName}Failure('Internal Server Error'),
|
|
277
|
+
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
export { ${toCamelCase(useCaseName)}Routes as Route, ${toCamelCase(useCaseName)}RoutesPath as Path };
|
|
284
|
+
`;
|
|
285
|
+
await writeFile(join(inputsDir, `${useCaseName}Input.ts`), inputContent);
|
|
286
|
+
await writeFile(join(outputsDir, `${useCaseName}Success.ts`), successContent);
|
|
287
|
+
await writeFile(join(outputsDir, `${useCaseName}Failure.ts`), failureContent);
|
|
288
|
+
await writeFile(join(useCaseDir, `${useCaseName}.ts`), useCaseContent);
|
|
289
|
+
await writeFile(join(useCaseDir, `${toCamelCase(useCaseName)}Routes.ts`), routesContent);
|
|
290
|
+
console.log(`Created: update-${kebabName}/ use case`);
|
|
291
|
+
}
|
|
292
|
+
// ============ GET USE CASE ============
|
|
293
|
+
async function generateGetUseCase(baseDir, config) {
|
|
294
|
+
const { EntityName, entityName, kebabName, TOKEN_BASE, pluralKebab } = config;
|
|
295
|
+
const useCaseName = `Get${EntityName}`;
|
|
296
|
+
const useCaseDir = join(baseDir, `get-${kebabName}`);
|
|
297
|
+
const outputsDir = join(useCaseDir, 'outputs');
|
|
298
|
+
await mkdir(useCaseDir, { recursive: true });
|
|
299
|
+
await mkdir(outputsDir, { recursive: true });
|
|
300
|
+
// Success Output
|
|
301
|
+
const successContent = `import { SuccessfullOperation } from '@root/lib';
|
|
302
|
+
import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
303
|
+
|
|
304
|
+
export type ${useCaseName}Payload = ${EntityName}Interface;
|
|
305
|
+
|
|
306
|
+
export class ${useCaseName}Success extends SuccessfullOperation {
|
|
307
|
+
constructor(
|
|
308
|
+
result: ${useCaseName}Payload,
|
|
309
|
+
message: string = '${EntityName} retrieved successfully',
|
|
310
|
+
) {
|
|
311
|
+
super(message);
|
|
312
|
+
this.result = result;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
`;
|
|
316
|
+
// Failure Output
|
|
317
|
+
const failureContent = `import { FailedOperation } from '@root/lib';
|
|
318
|
+
|
|
319
|
+
export class ${useCaseName}Failure extends FailedOperation {
|
|
320
|
+
constructor(message: string = 'Failed to get ${EntityName}') {
|
|
321
|
+
super(message);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
`;
|
|
325
|
+
// Use Case
|
|
326
|
+
const useCaseContent = `import { Inject, Module, Service } from '@kanian77/simple-di';
|
|
327
|
+
import { ${useCaseName}Success, type ${useCaseName}Payload } from './outputs/${useCaseName}Success';
|
|
328
|
+
import type { IUseCase } from '../../IUseCase';
|
|
329
|
+
import { ${EntityName}Module } from '@root/core/${kebabName}/${EntityName}Module';
|
|
330
|
+
import { ${TOKEN_BASE}_SERVICE_INTERFACE, type I${EntityName}Service } from '@root/core/${kebabName}/I${EntityName}Service';
|
|
331
|
+
|
|
332
|
+
export const ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN = '${toUpperSnakeCase(useCaseName)}_USE_CASE';
|
|
333
|
+
|
|
334
|
+
@Service({
|
|
335
|
+
token: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
336
|
+
lifecycle: 'transient',
|
|
337
|
+
})
|
|
338
|
+
export class ${useCaseName} implements IUseCase {
|
|
339
|
+
constructor(
|
|
340
|
+
@Inject(${TOKEN_BASE}_SERVICE_INTERFACE)
|
|
341
|
+
private readonly ${entityName}Service: I${EntityName}Service,
|
|
342
|
+
) {}
|
|
343
|
+
|
|
344
|
+
async execute(id: string): Promise<${useCaseName}Success> {
|
|
345
|
+
const entity = await this.${entityName}Service.findById(id);
|
|
346
|
+
return new ${useCaseName}Success(entity as ${useCaseName}Payload);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export const ${useCaseName}Module = new Module({
|
|
351
|
+
imports: [${EntityName}Module],
|
|
352
|
+
providers: [
|
|
353
|
+
{
|
|
354
|
+
provide: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
355
|
+
useClass: ${useCaseName},
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
});
|
|
359
|
+
`;
|
|
360
|
+
// Routes
|
|
361
|
+
const routesContent = `import { Hono } from 'hono';
|
|
362
|
+
import { StatusCodes } from 'http-status-codes';
|
|
363
|
+
import { inject } from '@kanian77/simple-di';
|
|
364
|
+
import { ${useCaseName}, ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN } from './${useCaseName}';
|
|
365
|
+
import { ${useCaseName}Failure } from './outputs/${useCaseName}Failure';
|
|
366
|
+
|
|
367
|
+
const ${toCamelCase(useCaseName)}Routes = new Hono();
|
|
368
|
+
const ${toCamelCase(useCaseName)}RoutesPath = '/${pluralKebab}/:id';
|
|
369
|
+
|
|
370
|
+
${toCamelCase(useCaseName)}Routes.get(${toCamelCase(useCaseName)}RoutesPath, async (c) => {
|
|
371
|
+
try {
|
|
372
|
+
const id = c.req.param('id');
|
|
373
|
+
const useCase = inject<${useCaseName}>(${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN);
|
|
374
|
+
const result = await useCase.execute(id);
|
|
375
|
+
return c.json(result, StatusCodes.OK);
|
|
376
|
+
} catch (e) {
|
|
377
|
+
console.error('Error in ${toCamelCase(useCaseName)}Routes:', e);
|
|
378
|
+
return c.json(
|
|
379
|
+
new ${useCaseName}Failure('Internal Server Error'),
|
|
380
|
+
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
export { ${toCamelCase(useCaseName)}Routes as Route, ${toCamelCase(useCaseName)}RoutesPath as Path };
|
|
386
|
+
`;
|
|
387
|
+
await writeFile(join(outputsDir, `${useCaseName}Success.ts`), successContent);
|
|
388
|
+
await writeFile(join(outputsDir, `${useCaseName}Failure.ts`), failureContent);
|
|
389
|
+
await writeFile(join(useCaseDir, `${useCaseName}.ts`), useCaseContent);
|
|
390
|
+
await writeFile(join(useCaseDir, `${toCamelCase(useCaseName)}Routes.ts`), routesContent);
|
|
391
|
+
console.log(`Created: get-${kebabName}/ use case`);
|
|
392
|
+
}
|
|
393
|
+
// ============ LIST USE CASE ============
|
|
394
|
+
async function generateListUseCase(baseDir, config) {
|
|
395
|
+
const { EntityName, entityName, kebabName, TOKEN_BASE, pluralPascal, pluralKebab, } = config;
|
|
396
|
+
const useCaseName = `List${pluralPascal}`;
|
|
397
|
+
const useCaseDir = join(baseDir, `list-${config.pluralKebab}`);
|
|
398
|
+
const outputsDir = join(useCaseDir, 'outputs');
|
|
399
|
+
await mkdir(useCaseDir, { recursive: true });
|
|
400
|
+
await mkdir(outputsDir, { recursive: true });
|
|
401
|
+
// Success Output
|
|
402
|
+
const successContent = `import { SuccessfullOperation } from '@root/lib';
|
|
403
|
+
import type { ${EntityName}Interface } from '@root/core/${kebabName}/baseZod${EntityName}Schema';
|
|
404
|
+
|
|
405
|
+
export type ${useCaseName}Payload = ${EntityName}Interface[];
|
|
406
|
+
|
|
407
|
+
export class ${useCaseName}Success extends SuccessfullOperation {
|
|
408
|
+
constructor(
|
|
409
|
+
result: ${useCaseName}Payload,
|
|
410
|
+
message: string = '${pluralPascal} retrieved successfully',
|
|
411
|
+
) {
|
|
412
|
+
super(message);
|
|
413
|
+
this.result = result;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`;
|
|
417
|
+
// Failure Output
|
|
418
|
+
const failureContent = `import { FailedOperation } from '@root/lib';
|
|
419
|
+
|
|
420
|
+
export class ${useCaseName}Failure extends FailedOperation {
|
|
421
|
+
constructor(message: string = 'Failed to list ${pluralPascal}') {
|
|
422
|
+
super(message);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
`;
|
|
426
|
+
// Use Case
|
|
427
|
+
const useCaseContent = `import { Inject, Module, Service } from '@kanian77/simple-di';
|
|
428
|
+
import { ${useCaseName}Success, type ${useCaseName}Payload } from './outputs/${useCaseName}Success';
|
|
429
|
+
import type { IUseCase } from '../../IUseCase';
|
|
430
|
+
import { ${EntityName}Module } from '@root/core/${kebabName}/${EntityName}Module';
|
|
431
|
+
import { ${TOKEN_BASE}_SERVICE_INTERFACE, type I${EntityName}Service } from '@root/core/${kebabName}/I${EntityName}Service';
|
|
432
|
+
|
|
433
|
+
export const ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN = '${toUpperSnakeCase(useCaseName)}_USE_CASE';
|
|
434
|
+
|
|
435
|
+
@Service({
|
|
436
|
+
token: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
437
|
+
lifecycle: 'transient',
|
|
438
|
+
})
|
|
439
|
+
export class ${useCaseName} implements IUseCase {
|
|
440
|
+
constructor(
|
|
441
|
+
@Inject(${TOKEN_BASE}_SERVICE_INTERFACE)
|
|
442
|
+
private readonly ${entityName}Service: I${EntityName}Service,
|
|
443
|
+
) {}
|
|
444
|
+
|
|
445
|
+
async execute(): Promise<${useCaseName}Success> {
|
|
446
|
+
const entities = await this.${entityName}Service.findAll();
|
|
447
|
+
return new ${useCaseName}Success(entities as ${useCaseName}Payload);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export const ${useCaseName}Module = new Module({
|
|
452
|
+
imports: [${EntityName}Module],
|
|
453
|
+
providers: [
|
|
454
|
+
{
|
|
455
|
+
provide: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
456
|
+
useClass: ${useCaseName},
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
});
|
|
460
|
+
`;
|
|
461
|
+
// Routes
|
|
462
|
+
const routesContent = `import { Hono } from 'hono';
|
|
463
|
+
import { StatusCodes } from 'http-status-codes';
|
|
464
|
+
import { inject } from '@kanian77/simple-di';
|
|
465
|
+
import { ${useCaseName}, ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN } from './${useCaseName}';
|
|
466
|
+
import { ${useCaseName}Failure } from './outputs/${useCaseName}Failure';
|
|
467
|
+
|
|
468
|
+
const ${toCamelCase(useCaseName)}Routes = new Hono();
|
|
469
|
+
const ${toCamelCase(useCaseName)}RoutesPath = '/${pluralKebab}';
|
|
470
|
+
|
|
471
|
+
${toCamelCase(useCaseName)}Routes.get(${toCamelCase(useCaseName)}RoutesPath, async (c) => {
|
|
472
|
+
try {
|
|
473
|
+
const useCase = inject<${useCaseName}>(${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN);
|
|
474
|
+
const result = await useCase.execute();
|
|
475
|
+
return c.json(result, StatusCodes.OK);
|
|
476
|
+
} catch (e) {
|
|
477
|
+
console.error('Error in ${toCamelCase(useCaseName)}Routes:', e);
|
|
478
|
+
return c.json(
|
|
479
|
+
new ${useCaseName}Failure('Internal Server Error'),
|
|
480
|
+
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
export { ${toCamelCase(useCaseName)}Routes as Route, ${toCamelCase(useCaseName)}RoutesPath as Path };
|
|
486
|
+
`;
|
|
487
|
+
await writeFile(join(outputsDir, `${useCaseName}Success.ts`), successContent);
|
|
488
|
+
await writeFile(join(outputsDir, `${useCaseName}Failure.ts`), failureContent);
|
|
489
|
+
await writeFile(join(useCaseDir, `${useCaseName}.ts`), useCaseContent);
|
|
490
|
+
await writeFile(join(useCaseDir, `${toCamelCase(useCaseName)}Routes.ts`), routesContent);
|
|
491
|
+
console.log(`Created: list-${config.pluralKebab}/ use case`);
|
|
492
|
+
}
|
|
493
|
+
// ============ DELETE USE CASE ============
|
|
494
|
+
async function generateDeleteUseCase(baseDir, config) {
|
|
495
|
+
const { EntityName, entityName, kebabName, TOKEN_BASE, pluralKebab } = config;
|
|
496
|
+
const useCaseName = `Delete${EntityName}`;
|
|
497
|
+
const useCaseDir = join(baseDir, `delete-${kebabName}`);
|
|
498
|
+
const outputsDir = join(useCaseDir, 'outputs');
|
|
499
|
+
await mkdir(useCaseDir, { recursive: true });
|
|
500
|
+
await mkdir(outputsDir, { recursive: true });
|
|
501
|
+
// Success Output
|
|
502
|
+
const successContent = `import { SuccessfullOperation } from '@root/lib';
|
|
503
|
+
|
|
504
|
+
export type ${useCaseName}Payload = { id: string; deleted: boolean; softDelete: boolean };
|
|
505
|
+
|
|
506
|
+
export class ${useCaseName}Success extends SuccessfullOperation {
|
|
507
|
+
constructor(
|
|
508
|
+
result: ${useCaseName}Payload,
|
|
509
|
+
message: string = '${EntityName} deleted successfully',
|
|
510
|
+
) {
|
|
511
|
+
super(message);
|
|
512
|
+
this.result = result;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
516
|
+
// Failure Output
|
|
517
|
+
const failureContent = `import { FailedOperation } from '@root/lib';
|
|
518
|
+
|
|
519
|
+
export class ${useCaseName}Failure extends FailedOperation {
|
|
520
|
+
constructor(message: string = 'Failed to delete ${EntityName}') {
|
|
521
|
+
super(message);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
`;
|
|
525
|
+
// Use Case
|
|
526
|
+
const useCaseContent = `import { Inject, Module, Service } from '@kanian77/simple-di';
|
|
527
|
+
import { ${useCaseName}Success, type ${useCaseName}Payload } from './outputs/${useCaseName}Success';
|
|
528
|
+
import type { IUseCase } from '../../IUseCase';
|
|
529
|
+
import { ${EntityName}Module } from '@root/core/${kebabName}/${EntityName}Module';
|
|
530
|
+
import { ${TOKEN_BASE}_SERVICE_INTERFACE, type I${EntityName}Service } from '@root/core/${kebabName}/I${EntityName}Service';
|
|
531
|
+
|
|
532
|
+
export const ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN = '${toUpperSnakeCase(useCaseName)}_USE_CASE';
|
|
533
|
+
|
|
534
|
+
@Service({
|
|
535
|
+
token: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
536
|
+
lifecycle: 'transient',
|
|
537
|
+
})
|
|
538
|
+
export class ${useCaseName} implements IUseCase {
|
|
539
|
+
constructor(
|
|
540
|
+
@Inject(${TOKEN_BASE}_SERVICE_INTERFACE)
|
|
541
|
+
private readonly ${entityName}Service: I${EntityName}Service,
|
|
542
|
+
) {}
|
|
543
|
+
|
|
544
|
+
async execute(id: string, softDelete: boolean = true): Promise<${useCaseName}Success> {
|
|
545
|
+
await this.${entityName}Service.delete(id, softDelete);
|
|
546
|
+
const result: ${useCaseName}Payload = { id, deleted: true, softDelete };
|
|
547
|
+
return new ${useCaseName}Success(result);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export const ${useCaseName}Module = new Module({
|
|
552
|
+
imports: [${EntityName}Module],
|
|
553
|
+
providers: [
|
|
554
|
+
{
|
|
555
|
+
provide: ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN,
|
|
556
|
+
useClass: ${useCaseName},
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
});
|
|
560
|
+
`;
|
|
561
|
+
// Routes
|
|
562
|
+
const routesContent = `import { Hono } from 'hono';
|
|
563
|
+
import { StatusCodes } from 'http-status-codes';
|
|
564
|
+
import { inject } from '@kanian77/simple-di';
|
|
565
|
+
import { ${useCaseName}, ${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN } from './${useCaseName}';
|
|
566
|
+
import { ${useCaseName}Failure } from './outputs/${useCaseName}Failure';
|
|
567
|
+
import { authGuard, roleGuard } from '@root/middlewares';
|
|
568
|
+
import { AdminRoleEnum } from '@root/lib';
|
|
569
|
+
|
|
570
|
+
const ${toCamelCase(useCaseName)}Routes = new Hono();
|
|
571
|
+
const ${toCamelCase(useCaseName)}RoutesPath = '/${pluralKebab}/:id';
|
|
572
|
+
|
|
573
|
+
${toCamelCase(useCaseName)}Routes.delete(
|
|
574
|
+
${toCamelCase(useCaseName)}RoutesPath,
|
|
575
|
+
authGuard(),
|
|
576
|
+
roleGuard([AdminRoleEnum.ADMIN]),
|
|
577
|
+
async (c) => {
|
|
578
|
+
try {
|
|
579
|
+
const id = c.req.param('id');
|
|
580
|
+
|
|
581
|
+
let softDelete = true;
|
|
582
|
+
try {
|
|
583
|
+
const body = await c.req.json();
|
|
584
|
+
if (typeof body.softDelete === 'boolean') {
|
|
585
|
+
softDelete = body.softDelete;
|
|
586
|
+
}
|
|
587
|
+
} catch (e) {
|
|
588
|
+
// Body is likely empty, default to softDelete = true
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const useCase = inject<${useCaseName}>(${toUpperSnakeCase(useCaseName)}_USE_CASE_TOKEN);
|
|
592
|
+
const result = await useCase.execute(id, softDelete);
|
|
593
|
+
return c.json(result, StatusCodes.OK);
|
|
594
|
+
} catch (e) {
|
|
595
|
+
console.error('Error in ${toCamelCase(useCaseName)}Routes:', e);
|
|
596
|
+
return c.json(
|
|
597
|
+
new ${useCaseName}Failure('Internal Server Error'),
|
|
598
|
+
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
export { ${toCamelCase(useCaseName)}Routes as Route, ${toCamelCase(useCaseName)}RoutesPath as Path };
|
|
605
|
+
`;
|
|
606
|
+
await writeFile(join(outputsDir, `${useCaseName}Success.ts`), successContent);
|
|
607
|
+
await writeFile(join(outputsDir, `${useCaseName}Failure.ts`), failureContent);
|
|
608
|
+
await writeFile(join(useCaseDir, `${useCaseName}.ts`), useCaseContent);
|
|
609
|
+
await writeFile(join(useCaseDir, `${toCamelCase(useCaseName)}Routes.ts`), routesContent);
|
|
610
|
+
console.log(`Created: delete-${kebabName}/ use case`);
|
|
611
|
+
}
|
|
612
|
+
// ============ AGGREGATOR MODULE ============
|
|
613
|
+
async function generateUseCaseAggregatorModule(baseDir, config) {
|
|
614
|
+
const { EntityName, kebabName, pluralPascal, pluralKebab } = config;
|
|
615
|
+
const content = `import { Module } from '@kanian77/simple-di';
|
|
616
|
+
import { Create${EntityName}Module } from './create-${kebabName}/Create${EntityName}';
|
|
617
|
+
import { Update${EntityName}Module } from './update-${kebabName}/Update${EntityName}';
|
|
618
|
+
import { Get${EntityName}Module } from './get-${kebabName}/Get${EntityName}';
|
|
619
|
+
import { List${pluralPascal}Module } from './list-${pluralKebab}/List${pluralPascal}';
|
|
620
|
+
import { Delete${EntityName}Module } from './delete-${kebabName}/Delete${EntityName}';
|
|
621
|
+
|
|
622
|
+
export const ${EntityName}UseCaseModule = new Module({
|
|
623
|
+
imports: [
|
|
624
|
+
Create${EntityName}Module,
|
|
625
|
+
Update${EntityName}Module,
|
|
626
|
+
Get${EntityName}Module,
|
|
627
|
+
List${pluralPascal}Module,
|
|
628
|
+
Delete${EntityName}Module,
|
|
629
|
+
],
|
|
630
|
+
});
|
|
631
|
+
`;
|
|
632
|
+
await writeFile(join(baseDir, `${EntityName}UseCaseModule.ts`), content);
|
|
633
|
+
console.log(`Created: ${kebabName}/${EntityName}UseCaseModule.ts`);
|
|
634
|
+
}
|
|
635
|
+
// ============ REGISTER IN UseCaseModule.ts ============
|
|
636
|
+
async function registerInUseCaseModule(srcDir, config) {
|
|
637
|
+
const { EntityName, kebabName } = config;
|
|
638
|
+
const useCaseModulePath = join(srcDir, 'use-case', 'UseCaseModule.ts');
|
|
639
|
+
if (!existsSync(useCaseModulePath)) {
|
|
640
|
+
console.warn('Warning: src/use-case/UseCaseModule.ts not found');
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
let content = await readFile(useCaseModulePath, 'utf8');
|
|
644
|
+
const importStatement = `import { ${EntityName}UseCaseModule } from './${kebabName}/${EntityName}UseCaseModule';`;
|
|
645
|
+
if (content.includes(`${EntityName}UseCaseModule`)) {
|
|
646
|
+
return; // Already registered
|
|
647
|
+
}
|
|
648
|
+
// Add import after last import
|
|
649
|
+
const lastImportIndex = content.lastIndexOf('import ');
|
|
650
|
+
if (lastImportIndex !== -1) {
|
|
651
|
+
const nextLineIndex = content.indexOf('\n', lastImportIndex);
|
|
652
|
+
content =
|
|
653
|
+
content.slice(0, nextLineIndex + 1) +
|
|
654
|
+
importStatement +
|
|
655
|
+
'\n' +
|
|
656
|
+
content.slice(nextLineIndex + 1);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
content = importStatement + '\n' + content;
|
|
660
|
+
}
|
|
661
|
+
// Add to imports array
|
|
662
|
+
const importsRegex = /imports:\s*\[/g;
|
|
663
|
+
const match = importsRegex.exec(content);
|
|
664
|
+
if (match) {
|
|
665
|
+
const arrayStart = match.index + match[0].length;
|
|
666
|
+
let depth = 1;
|
|
667
|
+
let endIndex = -1;
|
|
668
|
+
for (let i = arrayStart; i < content.length; i++) {
|
|
669
|
+
if (content[i] === '[')
|
|
670
|
+
depth++;
|
|
671
|
+
if (content[i] === ']')
|
|
672
|
+
depth--;
|
|
673
|
+
if (depth === 0) {
|
|
674
|
+
endIndex = i;
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (endIndex !== -1) {
|
|
679
|
+
const arrayContent = content.slice(arrayStart, endIndex);
|
|
680
|
+
if (!arrayContent.includes(`${EntityName}UseCaseModule`)) {
|
|
681
|
+
const trimmed = arrayContent.trim();
|
|
682
|
+
const hasTrailingComma = trimmed.endsWith(',');
|
|
683
|
+
const separator = trimmed.length > 0 && !hasTrailingComma ? ', ' : '';
|
|
684
|
+
const insertion = `${separator}${EntityName}UseCaseModule`;
|
|
685
|
+
content =
|
|
686
|
+
content.slice(0, endIndex) + insertion + content.slice(endIndex);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
await writeFile(useCaseModulePath, content);
|
|
691
|
+
console.log(`Updated: src/use-case/UseCaseModule.ts`);
|
|
692
|
+
}
|
|
693
|
+
// ============ E2E TESTS GENERATION ============
|
|
694
|
+
async function generateCreateE2ETest(baseDir, config) {
|
|
695
|
+
const { EntityName, kebabName, pluralKebab } = config;
|
|
696
|
+
const useCaseDir = join(baseDir, `create-${kebabName}`);
|
|
697
|
+
const testContent = `import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
|
|
698
|
+
import { EnvFileNames, UserRoleEnum, UserTypeEnum } from '@root/lib';
|
|
699
|
+
import { bootstrap, inject, Module } from '@kanian77/simple-di';
|
|
700
|
+
import { UseCaseModule } from '@root/use-case/UseCaseModule';
|
|
701
|
+
import { getConfigModule } from 'config/getConfigModule';
|
|
702
|
+
import { getDbModule } from 'db/getDbModule';
|
|
703
|
+
import { CoreModule } from '@root/core/CoreModule';
|
|
704
|
+
import { DB_SERVICE, type DbService } from 'db/DbService';
|
|
705
|
+
import { APP, AppModule } from '@root/AppModule';
|
|
706
|
+
import type { Hono } from 'hono';
|
|
707
|
+
import * as schema from '@root/schema';
|
|
708
|
+
import { eq } from 'drizzle-orm';
|
|
709
|
+
import { getTestServer, type TestServer } from '@root/lib/functions/getTestServer';
|
|
710
|
+
|
|
711
|
+
describe('Create${EntityName} e2e', () => {
|
|
712
|
+
let dbService: DbService;
|
|
713
|
+
let server: TestServer;
|
|
714
|
+
let app: Hono;
|
|
715
|
+
|
|
716
|
+
beforeAll(async () => {
|
|
717
|
+
const TestModule = new Module({
|
|
718
|
+
imports: [
|
|
719
|
+
AppModule,
|
|
720
|
+
getConfigModule(EnvFileNames.TESTING),
|
|
721
|
+
getDbModule(),
|
|
722
|
+
CoreModule,
|
|
723
|
+
UseCaseModule,
|
|
724
|
+
],
|
|
725
|
+
});
|
|
726
|
+
bootstrap(TestModule);
|
|
727
|
+
dbService = inject<DbService>(DB_SERVICE);
|
|
728
|
+
app = inject<Hono>(APP);
|
|
729
|
+
server = await getTestServer(app);
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
afterAll(async () => {
|
|
733
|
+
await dbService.getDb().delete(schema.${kebabName.replace(/-/g, '')}Schema).execute();
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
it('fails if unauthenticated', async () => {
|
|
737
|
+
const req = await server.client.request('/${pluralKebab}', {
|
|
738
|
+
method: 'POST',
|
|
739
|
+
body: JSON.stringify({ /* TODO: Add valid payload */ }),
|
|
740
|
+
headers: { 'Content-Type': 'application/json' },
|
|
741
|
+
});
|
|
742
|
+
expect(req.status).toBe(401);
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
it('fails with fake generated ID for createdBy', async () => {
|
|
746
|
+
const { token } = await server.createSignedUpUser({
|
|
747
|
+
userType: UserTypeEnum.ADMIN,
|
|
748
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
// Attempting to forge createdBy should be overwritten by the backend Context Injection
|
|
752
|
+
const maliciousPayload = {
|
|
753
|
+
// TODO: Add required payload properties
|
|
754
|
+
createdBy: 'fake-malicious-id'
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
const req = await server.client.request('/${pluralKebab}', {
|
|
758
|
+
method: 'POST',
|
|
759
|
+
body: JSON.stringify(maliciousPayload),
|
|
760
|
+
headers: {
|
|
761
|
+
'Content-Type': 'application/json',
|
|
762
|
+
Authorization: \`Bearer \${token}\`,
|
|
763
|
+
},
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
expect(req.status).toBe(201);
|
|
767
|
+
const body: any = await req.json();
|
|
768
|
+
|
|
769
|
+
// Verify creation succeeded but createdBy was securely overwritten
|
|
770
|
+
expect(body.result.createdBy).not.toBe('fake-malicious-id');
|
|
771
|
+
|
|
772
|
+
// Direct DB check
|
|
773
|
+
const row = await dbService.getDb().query.${kebabName.replace(/-/g, '')}Schema.findFirst({
|
|
774
|
+
where: eq(schema.${kebabName.replace(/-/g, '')}Schema.id, body.result.id)
|
|
775
|
+
});
|
|
776
|
+
expect(row).toBeDefined();
|
|
777
|
+
expect(row!.createdBy).not.toBe('fake-malicious-id');
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
`;
|
|
781
|
+
await writeFile(join(useCaseDir, `Create${EntityName}.e2e.spec.ts`), testContent);
|
|
782
|
+
}
|
|
783
|
+
async function generateUpdateE2ETest(baseDir, config) {
|
|
784
|
+
const { EntityName, kebabName, pluralKebab } = config;
|
|
785
|
+
const useCaseDir = join(baseDir, `update-${kebabName}`);
|
|
786
|
+
const testContent = `import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
|
|
787
|
+
import { EnvFileNames, UserRoleEnum, UserTypeEnum } from '@root/lib';
|
|
788
|
+
import { bootstrap, inject, Module } from '@kanian77/simple-di';
|
|
789
|
+
import { UseCaseModule } from '@root/use-case/UseCaseModule';
|
|
790
|
+
import { getConfigModule } from 'config/getConfigModule';
|
|
791
|
+
import { getDbModule } from 'db/getDbModule';
|
|
792
|
+
import { CoreModule } from '@root/core/CoreModule';
|
|
793
|
+
import { DB_SERVICE, type DbService } from 'db/DbService';
|
|
794
|
+
import { APP, AppModule } from '@root/AppModule';
|
|
795
|
+
import type { Hono } from 'hono';
|
|
796
|
+
import * as schema from '@root/schema';
|
|
797
|
+
import { eq } from 'drizzle-orm';
|
|
798
|
+
import { getTestServer, type TestServer } from '@root/lib/functions/getTestServer';
|
|
799
|
+
|
|
800
|
+
describe('Update${EntityName} e2e', () => {
|
|
801
|
+
let dbService: DbService;
|
|
802
|
+
let server: TestServer;
|
|
803
|
+
let app: Hono;
|
|
804
|
+
let targetId: string;
|
|
805
|
+
|
|
806
|
+
beforeAll(async () => {
|
|
807
|
+
const TestModule = new Module({
|
|
808
|
+
imports: [
|
|
809
|
+
AppModule,
|
|
810
|
+
getConfigModule(EnvFileNames.TESTING),
|
|
811
|
+
getDbModule(),
|
|
812
|
+
CoreModule,
|
|
813
|
+
UseCaseModule,
|
|
814
|
+
],
|
|
815
|
+
});
|
|
816
|
+
bootstrap(TestModule);
|
|
817
|
+
dbService = inject<DbService>(DB_SERVICE);
|
|
818
|
+
app = inject<Hono>(APP);
|
|
819
|
+
server = await getTestServer(app);
|
|
820
|
+
|
|
821
|
+
// TODO: Seed a target entity here and save targetId
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
afterAll(async () => {
|
|
825
|
+
await dbService.getDb().delete(schema.${kebabName.replace(/-/g, '')}Schema).execute();
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('fails if unauthenticated', async () => {
|
|
829
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetId}\`, {
|
|
830
|
+
method: 'PUT',
|
|
831
|
+
body: JSON.stringify({ /* TODO: valid update payload */ }),
|
|
832
|
+
headers: { 'Content-Type': 'application/json' },
|
|
833
|
+
});
|
|
834
|
+
expect(req.status).toBe(401);
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
it('successfully updates and overrides updatedBy context', async () => {
|
|
838
|
+
const { token } = await server.createSignedUpUser({
|
|
839
|
+
userType: UserTypeEnum.ADMIN,
|
|
840
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
const payload = {
|
|
844
|
+
// TODO: Add properties to update
|
|
845
|
+
updatedBy: 'hacker-id' // Should be discarded
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetId}\`, {
|
|
849
|
+
method: 'PUT',
|
|
850
|
+
body: JSON.stringify(payload),
|
|
851
|
+
headers: {
|
|
852
|
+
'Content-Type': 'application/json',
|
|
853
|
+
Authorization: \`Bearer \${token}\`,
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
expect(req.status).toBe(200);
|
|
858
|
+
const body: any = await req.json();
|
|
859
|
+
|
|
860
|
+
expect(body.result.updatedBy).not.toBe('hacker-id');
|
|
861
|
+
|
|
862
|
+
const row = await dbService.getDb().query.${kebabName.replace(/-/g, '')}Schema.findFirst({
|
|
863
|
+
where: eq(schema.${kebabName.replace(/-/g, '')}Schema.id, targetId)
|
|
864
|
+
});
|
|
865
|
+
expect(row!.updatedBy).not.toBe('hacker-id');
|
|
866
|
+
});
|
|
867
|
+
});
|
|
868
|
+
`;
|
|
869
|
+
await writeFile(join(useCaseDir, `Update${EntityName}.e2e.spec.ts`), testContent);
|
|
870
|
+
}
|
|
871
|
+
async function generateGetE2ETest(baseDir, config) {
|
|
872
|
+
const { EntityName, kebabName, pluralKebab } = config;
|
|
873
|
+
const useCaseDir = join(baseDir, `get-${kebabName}`);
|
|
874
|
+
const testContent = `import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
|
|
875
|
+
import { EnvFileNames, UserRoleEnum, UserTypeEnum } from '@root/lib';
|
|
876
|
+
import { bootstrap, inject, Module } from '@kanian77/simple-di';
|
|
877
|
+
import { UseCaseModule } from '@root/use-case/UseCaseModule';
|
|
878
|
+
import { getConfigModule } from 'config/getConfigModule';
|
|
879
|
+
import { getDbModule } from 'db/getDbModule';
|
|
880
|
+
import { CoreModule } from '@root/core/CoreModule';
|
|
881
|
+
import { DB_SERVICE, type DbService } from 'db/DbService';
|
|
882
|
+
import { APP, AppModule } from '@root/AppModule';
|
|
883
|
+
import type { Hono } from 'hono';
|
|
884
|
+
import * as schema from '@root/schema';
|
|
885
|
+
import { getTestServer, type TestServer } from '@root/lib/functions/getTestServer';
|
|
886
|
+
|
|
887
|
+
describe('Get${EntityName} e2e', () => {
|
|
888
|
+
let dbService: DbService;
|
|
889
|
+
let server: TestServer;
|
|
890
|
+
let app: Hono;
|
|
891
|
+
let targetId: string;
|
|
892
|
+
|
|
893
|
+
beforeAll(async () => {
|
|
894
|
+
const TestModule = new Module({
|
|
895
|
+
imports: [
|
|
896
|
+
AppModule,
|
|
897
|
+
getConfigModule(EnvFileNames.TESTING),
|
|
898
|
+
getDbModule(),
|
|
899
|
+
CoreModule,
|
|
900
|
+
UseCaseModule,
|
|
901
|
+
],
|
|
902
|
+
});
|
|
903
|
+
bootstrap(TestModule);
|
|
904
|
+
dbService = inject<DbService>(DB_SERVICE);
|
|
905
|
+
app = inject<Hono>(APP);
|
|
906
|
+
server = await getTestServer(app);
|
|
907
|
+
|
|
908
|
+
// TODO: Seed an entity here and assign targetId
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
afterAll(async () => {
|
|
912
|
+
await dbService.getDb().delete(schema.${kebabName.replace(/-/g, '')}Schema).execute();
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
it('fails if unauthenticated (assuming route requires auth)', async () => {
|
|
916
|
+
// Note: Adjust depending on whether the GET route should be public or private
|
|
917
|
+
// const req = await server.client.request(\`/\${pluralKebab}/\${targetId}\`);
|
|
918
|
+
// expect(req.status).toBe(401);
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
it('retrieves the entity', async () => {
|
|
922
|
+
const { token } = await server.createSignedUpUser({
|
|
923
|
+
userType: UserTypeEnum.ADMIN,
|
|
924
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetId}\`, {
|
|
928
|
+
method: 'GET',
|
|
929
|
+
headers: {
|
|
930
|
+
Authorization: \`Bearer \${token}\`,
|
|
931
|
+
},
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
expect(req.status).toBe(200);
|
|
935
|
+
const body: any = await req.json();
|
|
936
|
+
expect(body.result.id).toBe(targetId);
|
|
937
|
+
});
|
|
938
|
+
});
|
|
939
|
+
`;
|
|
940
|
+
await writeFile(join(useCaseDir, `Get${EntityName}.e2e.spec.ts`), testContent);
|
|
941
|
+
}
|
|
942
|
+
async function generateListE2ETest(baseDir, config) {
|
|
943
|
+
const { EntityName, kebabName, pluralKebab, pluralPascal } = config;
|
|
944
|
+
const useCaseDir = join(baseDir, `list-${pluralKebab}`);
|
|
945
|
+
const testContent = `import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
|
|
946
|
+
import { EnvFileNames, UserRoleEnum, UserTypeEnum } from '@root/lib';
|
|
947
|
+
import { bootstrap, inject, Module } from '@kanian77/simple-di';
|
|
948
|
+
import { UseCaseModule } from '@root/use-case/UseCaseModule';
|
|
949
|
+
import { getConfigModule } from 'config/getConfigModule';
|
|
950
|
+
import { getDbModule } from 'db/getDbModule';
|
|
951
|
+
import { CoreModule } from '@root/core/CoreModule';
|
|
952
|
+
import { DB_SERVICE, type DbService } from 'db/DbService';
|
|
953
|
+
import { APP, AppModule } from '@root/AppModule';
|
|
954
|
+
import type { Hono } from 'hono';
|
|
955
|
+
import * as schema from '@root/schema';
|
|
956
|
+
import { getTestServer, type TestServer } from '@root/lib/functions/getTestServer';
|
|
957
|
+
|
|
958
|
+
describe('List${pluralPascal} e2e', () => {
|
|
959
|
+
let dbService: DbService;
|
|
960
|
+
let server: TestServer;
|
|
961
|
+
let app: Hono;
|
|
962
|
+
|
|
963
|
+
beforeAll(async () => {
|
|
964
|
+
const TestModule = new Module({
|
|
965
|
+
imports: [
|
|
966
|
+
AppModule,
|
|
967
|
+
getConfigModule(EnvFileNames.TESTING),
|
|
968
|
+
getDbModule(),
|
|
969
|
+
CoreModule,
|
|
970
|
+
UseCaseModule,
|
|
971
|
+
],
|
|
972
|
+
});
|
|
973
|
+
bootstrap(TestModule);
|
|
974
|
+
dbService = inject<DbService>(DB_SERVICE);
|
|
975
|
+
app = inject<Hono>(APP);
|
|
976
|
+
server = await getTestServer(app);
|
|
977
|
+
|
|
978
|
+
// TODO: Seed multiple entities here
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
afterAll(async () => {
|
|
982
|
+
await dbService.getDb().delete(schema.${kebabName.replace(/-/g, '')}Schema).execute();
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
it('lists entities successfully', async () => {
|
|
986
|
+
const { token } = await server.createSignedUpUser({
|
|
987
|
+
userType: UserTypeEnum.ADMIN,
|
|
988
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
const req = await server.client.request('/${pluralKebab}', {
|
|
992
|
+
method: 'GET',
|
|
993
|
+
headers: {
|
|
994
|
+
Authorization: \`Bearer \${token}\`,
|
|
995
|
+
},
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
expect(req.status).toBe(200);
|
|
999
|
+
const body: any = await req.json();
|
|
1000
|
+
expect(Array.isArray(body.result)).toBe(true);
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
`;
|
|
1004
|
+
await writeFile(join(useCaseDir, `List${pluralPascal}.e2e.spec.ts`), testContent);
|
|
1005
|
+
}
|
|
1006
|
+
async function generateDeleteE2ETest(baseDir, config) {
|
|
1007
|
+
const { EntityName, kebabName, pluralKebab } = config;
|
|
1008
|
+
const useCaseDir = join(baseDir, `delete-${kebabName}`);
|
|
1009
|
+
const testContent = `import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
|
|
1010
|
+
import { EnvFileNames, UserRoleEnum, UserTypeEnum } from '@root/lib';
|
|
1011
|
+
import { bootstrap, inject, Module } from '@kanian77/simple-di';
|
|
1012
|
+
import { UseCaseModule } from '@root/use-case/UseCaseModule';
|
|
1013
|
+
import { getConfigModule } from 'config/getConfigModule';
|
|
1014
|
+
import { getDbModule } from 'db/getDbModule';
|
|
1015
|
+
import { CoreModule } from '@root/core/CoreModule';
|
|
1016
|
+
import { DB_SERVICE, type DbService } from 'db/DbService';
|
|
1017
|
+
import { APP, AppModule } from '@root/AppModule';
|
|
1018
|
+
import type { Hono } from 'hono';
|
|
1019
|
+
import * as schema from '@root/schema';
|
|
1020
|
+
import { eq } from 'drizzle-orm';
|
|
1021
|
+
import { getTestServer, type TestServer } from '@root/lib/functions/getTestServer';
|
|
1022
|
+
|
|
1023
|
+
describe('Delete${EntityName} e2e', () => {
|
|
1024
|
+
let dbService: DbService;
|
|
1025
|
+
let server: TestServer;
|
|
1026
|
+
let app: Hono;
|
|
1027
|
+
let targetIdSoft: string;
|
|
1028
|
+
let targetIdHard: string;
|
|
1029
|
+
|
|
1030
|
+
beforeAll(async () => {
|
|
1031
|
+
const TestModule = new Module({
|
|
1032
|
+
imports: [
|
|
1033
|
+
AppModule,
|
|
1034
|
+
getConfigModule(EnvFileNames.TESTING),
|
|
1035
|
+
getDbModule(),
|
|
1036
|
+
CoreModule,
|
|
1037
|
+
UseCaseModule,
|
|
1038
|
+
],
|
|
1039
|
+
});
|
|
1040
|
+
bootstrap(TestModule);
|
|
1041
|
+
dbService = inject<DbService>(DB_SERVICE);
|
|
1042
|
+
app = inject<Hono>(APP);
|
|
1043
|
+
server = await getTestServer(app);
|
|
1044
|
+
|
|
1045
|
+
// TODO: Seed two entities, assign to targetIdSoft and targetIdHard
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
afterAll(async () => {
|
|
1049
|
+
await dbService.getDb().delete(schema.${kebabName.replace(/-/g, '')}Schema).execute();
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
it('fails if unauthenticated', async () => {
|
|
1053
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetIdSoft}\`, {
|
|
1054
|
+
method: 'DELETE',
|
|
1055
|
+
});
|
|
1056
|
+
expect(req.status).toBe(401);
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
it('soft deletes by default', async () => {
|
|
1060
|
+
const { token } = await server.createSignedUpUser({
|
|
1061
|
+
userType: UserTypeEnum.ADMIN,
|
|
1062
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetIdSoft}\`, {
|
|
1066
|
+
method: 'DELETE',
|
|
1067
|
+
headers: {
|
|
1068
|
+
Authorization: \`Bearer \${token}\`,
|
|
1069
|
+
},
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
expect(req.status).toBe(200);
|
|
1073
|
+
|
|
1074
|
+
// Direct DB check for soft delete
|
|
1075
|
+
const row = await dbService.getDb().query.${kebabName.replace(/-/g, '')}Schema.findFirst({
|
|
1076
|
+
where: eq(schema.${kebabName.replace(/-/g, '')}Schema.id, targetIdSoft)
|
|
1077
|
+
});
|
|
1078
|
+
expect(row).toBeDefined();
|
|
1079
|
+
expect(row!.deleted).toBe(true);
|
|
1080
|
+
expect(row!.deletedAt).not.toBeNull();
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
it('hard deletes when flag is false', async () => {
|
|
1084
|
+
const { token } = await server.createSignedUpUser({
|
|
1085
|
+
userType: UserTypeEnum.ADMIN,
|
|
1086
|
+
role: UserRoleEnum.AUTHENTICATED,
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
const req = await server.client.request(\`/\${pluralKebab}/\${targetIdHard}\`, {
|
|
1090
|
+
method: 'DELETE',
|
|
1091
|
+
body: JSON.stringify({ softDelete: false }),
|
|
1092
|
+
headers: {
|
|
1093
|
+
'Content-Type': 'application/json',
|
|
1094
|
+
Authorization: \`Bearer \${token}\`,
|
|
1095
|
+
},
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
expect(req.status).toBe(200);
|
|
1099
|
+
|
|
1100
|
+
// Direct DB check for physical row missing
|
|
1101
|
+
const row = await dbService.getDb().query.${kebabName.replace(/-/g, '')}Schema.findFirst({
|
|
1102
|
+
where: eq(schema.${kebabName.replace(/-/g, '')}Schema.id, targetIdHard)
|
|
1103
|
+
});
|
|
1104
|
+
expect(row).toBeUndefined();
|
|
1105
|
+
});
|
|
1106
|
+
});
|
|
1107
|
+
`;
|
|
1108
|
+
await writeFile(join(useCaseDir, `Delete${EntityName}.e2e.spec.ts`), testContent);
|
|
1109
|
+
}
|
|
1110
|
+
// END ROUTES
|
|
1111
|
+
//# sourceMappingURL=generate_crud_use_cases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate_crud_use_cases.js","sourceRoot":"","sources":["../src/generate_crud_use_cases.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/user-guide.md
CHANGED
|
@@ -73,24 +73,36 @@ simpledi module blog-post
|
|
|
73
73
|
| `<Entity>Module.ts` | Main module (combines all) |
|
|
74
74
|
| `<Entity>Repository.spec.ts` | Test file |
|
|
75
75
|
|
|
76
|
+
**Generated Use Cases** in `src/use-case/<entity-name>/`:
|
|
77
|
+
|
|
78
|
+
| Use Case | Route | Method |
|
|
79
|
+
| ---------------- | ------ | -------- |
|
|
80
|
+
| `Create<Entity>` | `/` | `POST` |
|
|
81
|
+
| `Update<Entity>` | `/:id` | `PUT` |
|
|
82
|
+
| `Get<Entity>` | `/:id` | `GET` |
|
|
83
|
+
| `List<Entity>s` | `/` | `GET` |
|
|
84
|
+
| `Delete<Entity>` | `/:id` | `DELETE` |
|
|
85
|
+
|
|
76
86
|
**Auto-registration:**
|
|
77
87
|
|
|
78
88
|
- Adds export to `src/schema.ts`
|
|
79
89
|
- Adds module to `src/core/CoreModule.ts`
|
|
90
|
+
- Adds use case module to `src/use-case/UseCaseModule.ts`
|
|
91
|
+
- Registers routes in `src/main.routes.ts`
|
|
80
92
|
|
|
81
93
|
---
|
|
82
94
|
|
|
83
95
|
### `simpledi use-case <name> [imports=entity1,entity2,...]`
|
|
84
96
|
|
|
85
|
-
Generates a use case with routes and typed outputs.
|
|
97
|
+
Generates a custom use case with routes and typed outputs.
|
|
86
98
|
|
|
87
99
|
```bash
|
|
88
100
|
# Simple use case
|
|
89
|
-
simpledi use-case get-
|
|
101
|
+
simpledi use-case get-dashboard-stats
|
|
90
102
|
|
|
91
103
|
# Use case with module imports
|
|
92
|
-
simpledi use-case
|
|
93
|
-
simpledi use-case
|
|
104
|
+
simpledi use-case publish-post imports=blog-post
|
|
105
|
+
simpledi use-case assign-role imports=user
|
|
94
106
|
```
|
|
95
107
|
|
|
96
108
|
**Generated files** in `src/use-case/<name>/`:
|