zudojs-cli 2.1.1 → 2.1.3
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 +1 -1
- package/dist/src/bin/zudojs.js +1 -1
- package/dist/src/commands/generate.command.js +11 -16
- package/dist/src/constants/index.js +5 -1
- package/dist/src/constants/zudojsVersions.generated.js +37 -37
- package/dist/src/generators/command/command.generator.d.ts +7 -1
- package/dist/src/generators/command/command.generator.js +18 -44
- package/dist/src/generators/command/command.template.d.ts +24 -0
- package/dist/src/generators/command/command.template.js +78 -0
- package/dist/src/generators/command/index.d.ts +6 -0
- package/dist/src/generators/command/index.js +6 -0
- package/dist/src/generators/index.d.ts +0 -1
- package/dist/src/generators/index.js +0 -1
- package/dist/src/generators/infrastructure/infrastructure.generator.js +1 -1
- package/dist/src/generators/middleware/index.d.ts +2 -1
- package/dist/src/generators/middleware/index.js +2 -1
- package/dist/src/generators/middleware/middleware.generator.d.ts +28 -1
- package/dist/src/generators/middleware/middleware.generator.js +60 -15
- package/dist/src/generators/middleware/middleware.template.d.ts +21 -0
- package/dist/src/generators/middleware/middleware.template.js +35 -0
- package/dist/src/generators/query/index.d.ts +6 -0
- package/dist/src/generators/query/index.js +6 -0
- package/dist/src/generators/query/query.generator.d.ts +7 -1
- package/dist/src/generators/query/query.generator.js +19 -44
- package/dist/src/generators/query/query.template.d.ts +14 -0
- package/dist/src/generators/query/query.template.js +72 -0
- package/dist/src/generators/resource/resource.plan.d.ts +8 -2
- package/dist/src/generators/resource/resource.plan.js +10 -1
- package/dist/src/recipes/docker/docker.recipe.js +1 -1
- package/dist/src/recipes/docker/docker.refresh.js +1 -1
- package/dist/src/templates/resource/layers/resourceData.template.d.ts +1 -1
- package/dist/src/templates/resource/layers/resourceData.template.js +2 -1
- package/dist/src/templates/resource/layers/resourceRoutes.template.d.ts +1 -1
- package/dist/src/templates/resource/layers/resourceRoutes.template.js +6 -5
- package/dist/src/templates/resource/resource.names.d.ts +6 -0
- package/dist/src/templates/resource/resource.names.js +15 -0
- package/dist/src/templates/shared/dockerfile/dockerfile.install.d.ts +35 -0
- package/dist/src/templates/shared/dockerfile/dockerfile.install.js +89 -0
- package/dist/src/templates/shared/{dockerfile.template.d.ts → dockerfile/dockerfile.template.d.ts} +4 -2
- package/dist/src/templates/shared/{dockerfile.template.js → dockerfile/dockerfile.template.js} +17 -30
- package/dist/src/templates/shared/dockerfile/index.d.ts +6 -0
- package/dist/src/templates/shared/dockerfile/index.js +6 -0
- package/dist/src/templates/shared/index.d.ts +1 -1
- package/dist/src/templates/shared/index.js +1 -1
- package/dist/src/templates/shared/server.template.d.ts +7 -0
- package/dist/src/templates/shared/server.template.js +15 -3
- package/package.json +6 -6
- package/dist/src/generators/service/service.generator.d.ts +0 -12
- package/dist/src/generators/service/service.generator.js +0 -41
package/README.md
CHANGED
|
@@ -178,7 +178,7 @@ current directory.
|
|
|
178
178
|
| Option | Applies to | Description |
|
|
179
179
|
| ----------------- | ----------------------------- | ------------------------------------------------------------------ |
|
|
180
180
|
| `--module <name>` | every schematic but `module` | Generates inside `<root>/modules/<name>` instead of the schematic's default directory |
|
|
181
|
-
| `--service <name>`| microservice projects
|
|
181
|
+
| `--service <name>`| microservice projects | Selects the microservice app a schematic (including `command`/`query`) is written into |
|
|
182
182
|
| `--dry-run` | all | Lists the files without writing anything |
|
|
183
183
|
| `--force` | all | Overwrites files that already exist |
|
|
184
184
|
|
package/dist/src/bin/zudojs.js
CHANGED
|
@@ -178,7 +178,7 @@ app.register(createCommand({
|
|
|
178
178
|
{
|
|
179
179
|
name: "service",
|
|
180
180
|
short: "s",
|
|
181
|
-
description: "
|
|
181
|
+
description: "Microservice projects: the app to generate into (gateway or a service name). Elsewhere: a folder grouping CQRS commands/queries",
|
|
182
182
|
type: "string",
|
|
183
183
|
},
|
|
184
184
|
{
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
* backend lives, then places the schematic accordingly.
|
|
7
7
|
*/
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
-
import { generateService } from "../generators/service/service.generator.js";
|
|
10
9
|
import { generateModule } from "../generators/module/module.generator.js";
|
|
11
10
|
import { generateCommand } from "../generators/command/command.generator.js";
|
|
12
11
|
import { generateQuery } from "../generators/query/query.generator.js";
|
|
13
|
-
import { generateMiddleware } from "../generators/middleware/middleware.generator.js";
|
|
12
|
+
import { generateMiddleware, } from "../generators/middleware/middleware.generator.js";
|
|
14
13
|
import { generateEvent } from "../generators/event/event.generator.js";
|
|
15
14
|
import { generateJob } from "../generators/job/job.generator.js";
|
|
16
15
|
import { generateModel } from "../generators/model/model.generator.js";
|
|
@@ -53,10 +52,6 @@ function getArchitectureRoot(architecture, schematic, serviceName) {
|
|
|
53
52
|
}
|
|
54
53
|
return "src";
|
|
55
54
|
case "microservice":
|
|
56
|
-
if (schematic === "service") {
|
|
57
|
-
// A new service is a new app in the workspace.
|
|
58
|
-
return "apps/services";
|
|
59
|
-
}
|
|
60
55
|
// `--service <name>` selects which app the schematic belongs to.
|
|
61
56
|
// Without it the gateway app — the one app always generated — is used.
|
|
62
57
|
// Modules go to that app's src/modules, next to the scaffolded ones,
|
|
@@ -72,13 +67,6 @@ function getArchitectureRoot(architecture, schematic, serviceName) {
|
|
|
72
67
|
if (schematic === "module") {
|
|
73
68
|
return "src/modules";
|
|
74
69
|
}
|
|
75
|
-
if (schematic === "service") {
|
|
76
|
-
// The monolith template scaffolds `src/services/app.service.ts` and a
|
|
77
|
-
// `src/services/index.ts` barrel. Generating into `src/<name>/`
|
|
78
|
-
// instead left two conventions in one project, and the generated
|
|
79
|
-
// service was never exported from the barrel the template owns.
|
|
80
|
-
return "src/services";
|
|
81
|
-
}
|
|
82
70
|
return "src";
|
|
83
71
|
}
|
|
84
72
|
}
|
|
@@ -221,6 +209,15 @@ export async function runGenerateCommand(context) {
|
|
|
221
209
|
.map((step) => ` ${step}`)
|
|
222
210
|
.join("\n")}`);
|
|
223
211
|
},
|
|
212
|
+
onMiddlewareRegistered: (registration) => {
|
|
213
|
+
if (registration.registered) {
|
|
214
|
+
context.logger.info(`Registered in the middleware pipeline of ${registration.serverFile}.`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
context.logger.warn(`Could not register the middleware automatically (the zudojs:server-imports or zudojs:server-middleware markers are missing). Add:\n${registration.manualSteps
|
|
218
|
+
.map((step) => ` ${step}`)
|
|
219
|
+
.join("\n")}`);
|
|
220
|
+
},
|
|
224
221
|
}, cwd);
|
|
225
222
|
if (dryRun) {
|
|
226
223
|
context.logger.info(`Dry run: ${fileCount(result.length)} would be generated (nothing written):`);
|
|
@@ -254,8 +251,6 @@ async function runSchematic(schematic, name, options, cwd) {
|
|
|
254
251
|
// writing to `<basePath>/commands/<name>`.
|
|
255
252
|
const cqrsService = options.architecture === "microservice" ? undefined : options.service;
|
|
256
253
|
switch (schematic) {
|
|
257
|
-
case "service":
|
|
258
|
-
return await generateService({ name, basePath, dryRun }, cwd);
|
|
259
254
|
case "module":
|
|
260
255
|
return await generateModule({ name, feature: true, basePath, dryRun, onRegistered: options.onModuleRegistered }, cwd);
|
|
261
256
|
case "command":
|
|
@@ -263,7 +258,7 @@ async function runSchematic(schematic, name, options, cwd) {
|
|
|
263
258
|
case "query":
|
|
264
259
|
return await generateQuery({ name, ...(cqrsService ? { service: cqrsService } : {}), basePath, dryRun }, cwd);
|
|
265
260
|
case "middleware":
|
|
266
|
-
return await generateMiddleware({ name, basePath, dryRun }, cwd);
|
|
261
|
+
return await generateMiddleware({ name, basePath, dryRun, onRegistered: options.onMiddlewareRegistered }, cwd);
|
|
267
262
|
case "event":
|
|
268
263
|
return await generateEvent({ name, basePath, dryRun }, cwd);
|
|
269
264
|
case "job":
|
|
@@ -133,7 +133,11 @@ export const SCHEMA_CHOICES = Object.freeze([
|
|
|
133
133
|
label: "Resource",
|
|
134
134
|
hint: "DTO, repository, service, controller, CRUD routes and a test, registered",
|
|
135
135
|
},
|
|
136
|
-
{
|
|
136
|
+
{
|
|
137
|
+
value: "service",
|
|
138
|
+
label: "Service",
|
|
139
|
+
hint: "src/services/<name>.service.ts, plus its DTO and repository when missing",
|
|
140
|
+
},
|
|
137
141
|
{ value: "module", label: "Module" },
|
|
138
142
|
{ value: "command", label: "Command" },
|
|
139
143
|
{ value: "query", label: "Query" },
|
|
@@ -6,43 +6,43 @@
|
|
|
6
6
|
* Do not edit by hand; run `node scripts/generateZudojsVersions.mjs`.
|
|
7
7
|
*/
|
|
8
8
|
export const ZUDOJS_PACKAGE_VERSIONS = Object.freeze({
|
|
9
|
-
"@zudojs/adapters": "1.2.
|
|
10
|
-
"@zudojs/api": "1.2.
|
|
11
|
-
"@zudojs/auth": "1.3.
|
|
12
|
-
"@zudojs/auth-oauth": "1.2.
|
|
13
|
-
"@zudojs/cache": "1.2.
|
|
14
|
-
"@zudojs/config": "1.3.
|
|
15
|
-
"@zudojs/constants": "1.1.
|
|
16
|
-
"@zudojs/container": "1.2.
|
|
17
|
-
"@zudojs/core": "1.2.
|
|
18
|
-
"@zudojs/cqrs": "1.2.
|
|
19
|
-
"@zudojs/crypto": "1.3.
|
|
20
|
-
"@zudojs/database": "1.
|
|
21
|
-
"@zudojs/docs": "1.0.
|
|
22
|
-
"@zudojs/errors": "1.3.
|
|
23
|
-
"@zudojs/events": "1.3.
|
|
24
|
-
"@zudojs/feature-flags": "1.4.
|
|
25
|
-
"@zudojs/http": "1.4.
|
|
26
|
-
"@zudojs/lifecycle": "1.2.
|
|
27
|
-
"@zudojs/logger": "1.4.
|
|
28
|
-
"@zudojs/messaging": "1.2.
|
|
29
|
-
"@zudojs/middleware": "1.1.
|
|
30
|
-
"@zudojs/observability": "1.2.
|
|
31
|
-
"@zudojs/openapi": "1.5.
|
|
32
|
-
"@zudojs/permissions": "1.4.
|
|
33
|
-
"@zudojs/plugins": "1.3.
|
|
34
|
-
"@zudojs/queue": "1.
|
|
35
|
-
"@zudojs/rpc": "1.4.
|
|
36
|
-
"@zudojs/runtime": "1.3.
|
|
37
|
-
"@zudojs/scheduler": "1.2.
|
|
38
|
-
"@zudojs/schema": "1.2.
|
|
39
|
-
"@zudojs/security": "1.3.
|
|
40
|
-
"@zudojs/serialization": "1.2.
|
|
41
|
-
"@zudojs/storage": "1.2.
|
|
42
|
-
"@zudojs/tenancy": "1.3.
|
|
43
|
-
"@zudojs/testing": "1.2.
|
|
44
|
-
"@zudojs/transactions": "1.2.
|
|
9
|
+
"@zudojs/adapters": "1.2.3",
|
|
10
|
+
"@zudojs/api": "1.2.3",
|
|
11
|
+
"@zudojs/auth": "1.3.3",
|
|
12
|
+
"@zudojs/auth-oauth": "1.2.5",
|
|
13
|
+
"@zudojs/cache": "1.2.3",
|
|
14
|
+
"@zudojs/config": "1.3.3",
|
|
15
|
+
"@zudojs/constants": "1.1.4",
|
|
16
|
+
"@zudojs/container": "1.2.3",
|
|
17
|
+
"@zudojs/core": "1.2.4",
|
|
18
|
+
"@zudojs/cqrs": "1.2.3",
|
|
19
|
+
"@zudojs/crypto": "1.3.3",
|
|
20
|
+
"@zudojs/database": "1.4.0",
|
|
21
|
+
"@zudojs/docs": "1.0.6",
|
|
22
|
+
"@zudojs/errors": "1.3.2",
|
|
23
|
+
"@zudojs/events": "1.3.3",
|
|
24
|
+
"@zudojs/feature-flags": "1.4.2",
|
|
25
|
+
"@zudojs/http": "1.4.4",
|
|
26
|
+
"@zudojs/lifecycle": "1.2.3",
|
|
27
|
+
"@zudojs/logger": "1.4.3",
|
|
28
|
+
"@zudojs/messaging": "1.2.3",
|
|
29
|
+
"@zudojs/middleware": "1.1.2",
|
|
30
|
+
"@zudojs/observability": "1.2.3",
|
|
31
|
+
"@zudojs/openapi": "1.5.2",
|
|
32
|
+
"@zudojs/permissions": "1.4.3",
|
|
33
|
+
"@zudojs/plugins": "1.3.3",
|
|
34
|
+
"@zudojs/queue": "1.5.1",
|
|
35
|
+
"@zudojs/rpc": "1.4.3",
|
|
36
|
+
"@zudojs/runtime": "1.3.3",
|
|
37
|
+
"@zudojs/scheduler": "1.2.2",
|
|
38
|
+
"@zudojs/schema": "1.2.3",
|
|
39
|
+
"@zudojs/security": "1.3.3",
|
|
40
|
+
"@zudojs/serialization": "1.2.3",
|
|
41
|
+
"@zudojs/storage": "1.2.3",
|
|
42
|
+
"@zudojs/tenancy": "1.3.3",
|
|
43
|
+
"@zudojs/testing": "1.2.4",
|
|
44
|
+
"@zudojs/transactions": "1.2.2",
|
|
45
45
|
"@zudojs/types": "1.2.0",
|
|
46
|
-
"@zudojs/validation": "1.1.
|
|
46
|
+
"@zudojs/validation": "1.1.2",
|
|
47
47
|
});
|
|
48
48
|
//# sourceMappingURL=zudojsVersions.generated.js.map
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Command Generator
|
|
3
3
|
*
|
|
4
|
-
* Generates a CQRS command
|
|
4
|
+
* Generates a CQRS command, its handler and a barrel under
|
|
5
|
+
* `<basePath>[/<service>]/commands/<name>/`.
|
|
5
6
|
*/
|
|
7
|
+
/** Options for {@link generateCommand}. */
|
|
6
8
|
export interface GenerateCommandOptions {
|
|
7
9
|
readonly name: string;
|
|
8
10
|
readonly service?: string;
|
|
9
11
|
readonly basePath?: string;
|
|
10
12
|
readonly dryRun?: boolean;
|
|
11
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Writes `<name>.command.ts`, `<name>.handler.ts` and `index.ts`, and
|
|
16
|
+
* returns their paths (only the paths on a dry run).
|
|
17
|
+
*/
|
|
12
18
|
export declare function generateCommand(options: GenerateCommandOptions, cwd: string): Promise<string[]>;
|
|
13
19
|
//# sourceMappingURL=command.generator.d.ts.map
|
|
@@ -1,55 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Command Generator
|
|
3
3
|
*
|
|
4
|
-
* Generates a CQRS command
|
|
4
|
+
* Generates a CQRS command, its handler and a barrel under
|
|
5
|
+
* `<basePath>[/<service>]/commands/<name>/`.
|
|
5
6
|
*/
|
|
6
7
|
import { writeFileTree } from "../../utils/utils.fileSystem.js";
|
|
7
8
|
import { CLIGenerationError } from "../../errors/index.js";
|
|
8
|
-
import {
|
|
9
|
+
import { assertGeneratableName } from "../../utils/utils.name.js";
|
|
10
|
+
import { cqrsSchematicNames, renderCommandBarrel, renderCommandFile, renderCommandHandlerFile, } from "./command.template.js";
|
|
11
|
+
/**
|
|
12
|
+
* Writes `<name>.command.ts`, `<name>.handler.ts` and `index.ts`, and
|
|
13
|
+
* returns their paths (only the paths on a dry run).
|
|
14
|
+
*/
|
|
9
15
|
export async function generateCommand(options, cwd) {
|
|
10
|
-
const
|
|
11
|
-
const nameCamel = name
|
|
12
|
-
.replace(/-([a-z])/g, (_m, c) => c.toUpperCase())
|
|
13
|
-
.replace(/^./, (c) => c.toUpperCase());
|
|
14
|
-
const service = options.service;
|
|
16
|
+
const names = cqrsSchematicNames(assertGeneratableName(options.name, "command name"));
|
|
15
17
|
const basePath = options.basePath ?? "services";
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
const servicePath = service ? `${basePath}/${service}` : basePath;
|
|
18
|
+
// Without a service group the schematic goes directly under basePath:
|
|
19
|
+
// callers that resolved the owning app into basePath (the microservice
|
|
20
|
+
// layout) pass no service, so the path is not nested twice.
|
|
21
|
+
const servicePath = options.service ? `${basePath}/${options.service}` : basePath;
|
|
22
|
+
const dir = `${servicePath}/commands/${names.slug}`;
|
|
20
23
|
const files = {
|
|
21
|
-
[`${
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
readonly [key: string]: unknown;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class ${nameCamel}Command implements BaseCommand<${nameCamel}CommandPayload> {
|
|
28
|
-
readonly commandName = "${name}";
|
|
29
|
-
|
|
30
|
-
constructor(public readonly payload: ${nameCamel}CommandPayload) {}
|
|
31
|
-
}
|
|
32
|
-
`,
|
|
33
|
-
[`${servicePath}/commands/${name}/${name}.handler.ts`]: `import type { CommandHandler, CommandResult } from "@zudojs/cqrs";
|
|
34
|
-
import { createLogger } from "@zudojs/logger";
|
|
35
|
-
import { ${nameCamel}Command } from "./${name}.command.js";
|
|
36
|
-
|
|
37
|
-
export class ${nameCamel}CommandHandler implements CommandHandler<${nameCamel}Command> {
|
|
38
|
-
private readonly logger = createLogger({ name: "${name}-handler" });
|
|
39
|
-
|
|
40
|
-
async handle(command: ${nameCamel}Command): Promise<CommandResult> {
|
|
41
|
-
this.logger.info("Processing ${name} command", { payload: command.payload });
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
success: true,
|
|
45
|
-
data: { id: crypto.randomUUID(), ...command.payload },
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`,
|
|
50
|
-
[`${servicePath}/commands/${name}/index.ts`]: `export { ${nameCamel}Command } from "./${name}.command.js";
|
|
51
|
-
export { ${nameCamel}CommandHandler } from "./${name}.handler.js";
|
|
52
|
-
`,
|
|
24
|
+
[`${dir}/${names.slug}.command.ts`]: renderCommandFile(names),
|
|
25
|
+
[`${dir}/${names.slug}.handler.ts`]: renderCommandHandlerFile(names),
|
|
26
|
+
[`${dir}/index.ts`]: renderCommandBarrel(names),
|
|
53
27
|
};
|
|
54
28
|
if (options.dryRun) {
|
|
55
29
|
return Object.keys(files);
|
|
@@ -59,7 +33,7 @@ export { ${nameCamel}CommandHandler } from "./${name}.handler.js";
|
|
|
59
33
|
return Object.keys(files);
|
|
60
34
|
}
|
|
61
35
|
catch (error) {
|
|
62
|
-
throw new CLIGenerationError(`Failed to generate command: ${
|
|
36
|
+
throw new CLIGenerationError(`Failed to generate command: ${names.slug} in ${servicePath}`, error);
|
|
63
37
|
}
|
|
64
38
|
}
|
|
65
39
|
//# sourceMappingURL=command.generator.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zudojs-cli — Command schematic templates, written against the
|
|
3
|
+
* @zudojs/cqrs API: a `CommandOf` type built with `createCommand`, and a
|
|
4
|
+
* `CommandHandler` subclass (`commandType` + `execute`) registered on a
|
|
5
|
+
* `CommandBus`.
|
|
6
|
+
*/
|
|
7
|
+
/** Identifiers derived from a command name (`create-user`). */
|
|
8
|
+
export interface CqrsSchematicNames {
|
|
9
|
+
/** kebab-case: folder and file names (`create-user`). */
|
|
10
|
+
readonly slug: string;
|
|
11
|
+
/** PascalCase: class and type prefix, and the bus discriminator (`CreateUser`). */
|
|
12
|
+
readonly pascal: string;
|
|
13
|
+
/** UPPER_SNAKE: prefix of the discriminator constant (`CREATE_USER`). */
|
|
14
|
+
readonly constant: string;
|
|
15
|
+
}
|
|
16
|
+
/** Derives {@link CqrsSchematicNames} from an already validated slug. */
|
|
17
|
+
export declare function cqrsSchematicNames(slug: string): CqrsSchematicNames;
|
|
18
|
+
/** `<slug>.command.ts`: the discriminator, payload, command type and factory. */
|
|
19
|
+
export declare function renderCommandFile(n: CqrsSchematicNames): string;
|
|
20
|
+
/** `<slug>.handler.ts`: the handler class and its bus registration. */
|
|
21
|
+
export declare function renderCommandHandlerFile(n: CqrsSchematicNames): string;
|
|
22
|
+
/** `index.ts`: the command folder's barrel. */
|
|
23
|
+
export declare function renderCommandBarrel(n: CqrsSchematicNames): string;
|
|
24
|
+
//# sourceMappingURL=command.template.d.ts.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zudojs-cli — Command schematic templates, written against the
|
|
3
|
+
* @zudojs/cqrs API: a `CommandOf` type built with `createCommand`, and a
|
|
4
|
+
* `CommandHandler` subclass (`commandType` + `execute`) registered on a
|
|
5
|
+
* `CommandBus`.
|
|
6
|
+
*/
|
|
7
|
+
import { toPascalCase } from "../../utils/utils.name.js";
|
|
8
|
+
/** Derives {@link CqrsSchematicNames} from an already validated slug. */
|
|
9
|
+
export function cqrsSchematicNames(slug) {
|
|
10
|
+
return { slug, pascal: toPascalCase(slug), constant: slug.toUpperCase().replace(/-/g, "_") };
|
|
11
|
+
}
|
|
12
|
+
/** `<slug>.command.ts`: the discriminator, payload, command type and factory. */
|
|
13
|
+
export function renderCommandFile(n) {
|
|
14
|
+
const id = `${n.constant}_COMMAND`;
|
|
15
|
+
return `import { createCommand, type CommandOf } from "@zudojs/cqrs";
|
|
16
|
+
|
|
17
|
+
/** Discriminator the command bus routes ${n.pascal} commands on. */
|
|
18
|
+
export const ${id} = "${n.pascal}";
|
|
19
|
+
|
|
20
|
+
/** Data a ${n.pascal} command carries. Replace it with the fields the use case needs. */
|
|
21
|
+
export type ${n.pascal}CommandPayload = {
|
|
22
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** The ${n.pascal} command: \`{ type: "${n.pascal}", data }\`. */
|
|
26
|
+
export type ${n.pascal}Command = CommandOf<typeof ${id}, ${n.pascal}CommandPayload>;
|
|
27
|
+
|
|
28
|
+
/** Creates an immutable ${n.pascal} command. */
|
|
29
|
+
export function create${n.pascal}Command(payload: ${n.pascal}CommandPayload): ${n.pascal}Command {
|
|
30
|
+
return createCommand(${id}, payload);
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
34
|
+
/** `<slug>.handler.ts`: the handler class and its bus registration. */
|
|
35
|
+
export function renderCommandHandlerFile(n) {
|
|
36
|
+
const id = `${n.constant}_COMMAND`;
|
|
37
|
+
return `import { randomUUID } from "node:crypto";
|
|
38
|
+
|
|
39
|
+
import { CommandHandler, type CommandBus } from "@zudojs/cqrs";
|
|
40
|
+
|
|
41
|
+
import { ${id}, type ${n.pascal}Command } from "./${n.slug}.command.js";
|
|
42
|
+
|
|
43
|
+
/** What executing a ${n.pascal} command returns. */
|
|
44
|
+
export interface ${n.pascal}CommandResult {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Handles ${n.pascal} commands: put the write-side logic in \`execute\`. */
|
|
50
|
+
export class ${n.pascal}CommandHandler extends CommandHandler<${n.pascal}Command, ${n.pascal}CommandResult> {
|
|
51
|
+
public override readonly commandType = ${id};
|
|
52
|
+
|
|
53
|
+
public override async execute(command: ${n.pascal}Command): Promise<${n.pascal}CommandResult> {
|
|
54
|
+
return { id: randomUUID(), data: command.data };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Registers {@link ${n.pascal}CommandHandler} on a command bus.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const bus = register${n.pascal}Command(createCommandBus());
|
|
63
|
+
* const result = await bus.execute<${n.pascal}Command, ${n.pascal}CommandResult>(
|
|
64
|
+
* create${n.pascal}Command({ data: {} }),
|
|
65
|
+
* );
|
|
66
|
+
*/
|
|
67
|
+
export function register${n.pascal}Command(bus: CommandBus): CommandBus {
|
|
68
|
+
return bus.register(${id}, new ${n.pascal}CommandHandler());
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
/** `index.ts`: the command folder's barrel. */
|
|
73
|
+
export function renderCommandBarrel(n) {
|
|
74
|
+
return `export * from "./${n.slug}.command.js";
|
|
75
|
+
export * from "./${n.slug}.handler.js";
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=command.template.js.map
|
|
@@ -8,7 +8,6 @@ export { FullstackComposer } from "./fullstack/index.js";
|
|
|
8
8
|
export { IntegrationGenerator } from "./integration/index.js";
|
|
9
9
|
export { InfrastructureGenerator } from "./infrastructure/index.js";
|
|
10
10
|
export { generateModule } from "./module/module.generator.js";
|
|
11
|
-
export { generateService } from "./service/service.generator.js";
|
|
12
11
|
export { generateCommand } from "./command/command.generator.js";
|
|
13
12
|
export { generateQuery } from "./query/query.generator.js";
|
|
14
13
|
export { generateResource, resolveResourceLayout, planResource, RESOURCE_SCHEMATICS, } from "./resource/index.js";
|
|
@@ -8,7 +8,6 @@ export { FullstackComposer } from "./fullstack/index.js";
|
|
|
8
8
|
export { IntegrationGenerator } from "./integration/index.js";
|
|
9
9
|
export { InfrastructureGenerator } from "./infrastructure/index.js";
|
|
10
10
|
export { generateModule } from "./module/module.generator.js";
|
|
11
|
-
export { generateService } from "./service/service.generator.js";
|
|
12
11
|
export { generateCommand } from "./command/command.generator.js";
|
|
13
12
|
export { generateQuery } from "./query/query.generator.js";
|
|
14
13
|
export { generateResource, resolveResourceLayout, planResource, RESOURCE_SCHEMATICS, } from "./resource/index.js";
|
|
@@ -7,7 +7,7 @@ import { writeFileTree } from "../../utils/utils.fileSystem.js";
|
|
|
7
7
|
import { CLIValidationError } from "../../errors/index.js";
|
|
8
8
|
import { resolveDatabaseAdapter } from "../../adapters/databases/databaseAdapter.resolver.js";
|
|
9
9
|
import { resolveMicroserviceServices } from "../../templates/microservice/microservice.template.js";
|
|
10
|
-
import { renderAppPackageDockerfile, renderWorkspaceAppDockerfile, } from "../../templates/shared/dockerfile.
|
|
10
|
+
import { renderAppPackageDockerfile, renderWorkspaceAppDockerfile, } from "../../templates/shared/dockerfile/index.js";
|
|
11
11
|
const SERVICE_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
12
12
|
/**
|
|
13
13
|
* Database passwords are interpolated by compose from `.env`
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Middleware Generator
|
|
3
3
|
*/
|
|
4
|
-
export { generateMiddleware, type GenerateMiddlewareOptions, } from "./middleware.generator.js";
|
|
4
|
+
export { generateMiddleware, middlewareAppSrc, middlewareServerLines, type GenerateMiddlewareOptions, type MiddlewareRegistration, } from "./middleware.generator.js";
|
|
5
|
+
export { renderMiddlewareFile, type MiddlewareFileOptions } from "./middleware.template.js";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Middleware Generator
|
|
3
3
|
*/
|
|
4
|
-
export { generateMiddleware, } from "./middleware.generator.js";
|
|
4
|
+
export { generateMiddleware, middlewareAppSrc, middlewareServerLines, } from "./middleware.generator.js";
|
|
5
|
+
export { renderMiddlewareFile } from "./middleware.template.js";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,12 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Middleware Generator
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Writes `<basePath>/middlewares/<name>.middleware.ts` (an `HttpMiddleware`
|
|
5
|
+
* from @zudojs/http), exports it from the folder barrel and registers it in
|
|
6
|
+
* the app's `src/server.ts` between the `zudojs:server-imports` and
|
|
7
|
+
* `zudojs:server-middleware` markers. A server.ts missing either marker pair
|
|
8
|
+
* is left unchanged (no import without its registration) and the lines to
|
|
9
|
+
* add by hand are reported instead.
|
|
5
10
|
*/
|
|
6
11
|
export interface GenerateMiddlewareOptions {
|
|
7
12
|
readonly name: string;
|
|
8
13
|
readonly basePath: string;
|
|
9
14
|
readonly dryRun?: boolean;
|
|
15
|
+
/** Receives the registration outcome (e.g. lines to add by hand). */
|
|
16
|
+
readonly onRegistered?: (registration: MiddlewareRegistration) => void;
|
|
10
17
|
}
|
|
18
|
+
/** Outcome of registering a generated middleware in `server.ts`. */
|
|
19
|
+
export interface MiddlewareRegistration {
|
|
20
|
+
/** Whether server.ts now runs the middleware. */
|
|
21
|
+
readonly registered: boolean;
|
|
22
|
+
/** The server file it was (or should be) registered in. */
|
|
23
|
+
readonly serverFile: string;
|
|
24
|
+
/** Lines to add by hand when `registered` is false. */
|
|
25
|
+
readonly manualSteps: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The app source directory owning `basePath`: `src` for `src` and
|
|
29
|
+
* `src/modules/billing`, `apps/services/x/src` for a service.
|
|
30
|
+
*/
|
|
31
|
+
export declare function middlewareAppSrc(basePath: string): string;
|
|
32
|
+
/** The import and pipeline lines that register `factoryName` in server.ts. */
|
|
33
|
+
export declare function middlewareServerLines(basePath: string, factoryName: string): {
|
|
34
|
+
readonly serverFile: string;
|
|
35
|
+
readonly importLine: string;
|
|
36
|
+
readonly entryLine: string;
|
|
37
|
+
};
|
|
11
38
|
export declare function generateMiddleware(options: GenerateMiddlewareOptions, cwd: string): Promise<string[]>;
|
|
12
39
|
//# sourceMappingURL=middleware.generator.d.ts.map
|
|
@@ -1,29 +1,74 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* zudojs-cli — Middleware Generator
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Writes `<basePath>/middlewares/<name>.middleware.ts` (an `HttpMiddleware`
|
|
5
|
+
* from @zudojs/http), exports it from the folder barrel and registers it in
|
|
6
|
+
* the app's `src/server.ts` between the `zudojs:server-imports` and
|
|
7
|
+
* `zudojs:server-middleware` markers. A server.ts missing either marker pair
|
|
8
|
+
* is left unchanged (no import without its registration) and the lines to
|
|
9
|
+
* add by hand are reported instead.
|
|
5
10
|
*/
|
|
6
|
-
import {
|
|
11
|
+
import { posix } from "node:path";
|
|
12
|
+
import { CLIValidationError } from "../../errors/index.js";
|
|
13
|
+
import { mergeBarrelExport, writeFileTree } from "../../utils/utils.fileSystem.js";
|
|
7
14
|
import { normalizeName, toCamelCase } from "../../utils/utils.name.js";
|
|
15
|
+
import { MARKERS, applyMarkerEdits, conflictingImport, planMarkerEdits, } from "../../wiring/index.js";
|
|
16
|
+
import { renderMiddlewareFile } from "./middleware.template.js";
|
|
17
|
+
/**
|
|
18
|
+
* The app source directory owning `basePath`: `src` for `src` and
|
|
19
|
+
* `src/modules/billing`, `apps/services/x/src` for a service.
|
|
20
|
+
*/
|
|
21
|
+
export function middlewareAppSrc(basePath) {
|
|
22
|
+
return basePath.replace(/\/modules\/[^/]+$/, "");
|
|
23
|
+
}
|
|
24
|
+
/** The import and pipeline lines that register `factoryName` in server.ts. */
|
|
25
|
+
export function middlewareServerLines(basePath, factoryName) {
|
|
26
|
+
const appSrc = middlewareAppSrc(basePath);
|
|
27
|
+
const barrel = posix.relative(appSrc, `${basePath}/middlewares/index.js`);
|
|
28
|
+
return {
|
|
29
|
+
serverFile: `${appSrc}/server.ts`,
|
|
30
|
+
importLine: `import { ${factoryName} } from "./${barrel}";`,
|
|
31
|
+
entryLine: `${factoryName}(),`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
8
34
|
export async function generateMiddleware(options, cwd) {
|
|
9
35
|
const name = normalizeName(options.name);
|
|
10
|
-
const
|
|
36
|
+
const factoryName = `${toCamelCase(options.name)}Middleware`;
|
|
37
|
+
const lines = middlewareServerLines(options.basePath, factoryName);
|
|
38
|
+
const barrel = `${options.basePath}/middlewares/index.ts`;
|
|
39
|
+
const clash = conflictingImport(cwd, lines.serverFile, lines.importLine);
|
|
40
|
+
if (clash !== undefined) {
|
|
41
|
+
throw new CLIValidationError(`${lines.serverFile} already imports ${factoryName} (${clash.trim()}), so middleware "${name}" cannot be registered. Choose another name.`);
|
|
42
|
+
}
|
|
11
43
|
const files = {
|
|
12
|
-
[`${options.basePath}/middlewares/${name}.middleware.ts`]:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
await next();
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
`,
|
|
44
|
+
[`${options.basePath}/middlewares/${name}.middleware.ts`]: renderMiddlewareFile({
|
|
45
|
+
name,
|
|
46
|
+
factoryName,
|
|
47
|
+
serverFile: lines.serverFile,
|
|
48
|
+
}),
|
|
49
|
+
[barrel]: mergeBarrelExport(cwd, barrel, `export { ${factoryName} } from "./${name}.middleware.js";`),
|
|
22
50
|
};
|
|
51
|
+
const edits = [
|
|
52
|
+
{ file: lines.serverFile, marker: MARKERS.serverImports, line: lines.importLine },
|
|
53
|
+
{ file: lines.serverFile, marker: MARKERS.serverMiddleware, line: lines.entryLine },
|
|
54
|
+
];
|
|
55
|
+
const planned = planMarkerEdits(cwd, edits).outcome;
|
|
56
|
+
const registered = planned.manualSteps.length === 0;
|
|
23
57
|
if (options.dryRun) {
|
|
24
|
-
return Object.keys(files);
|
|
58
|
+
return [...Object.keys(files), ...(registered ? planned.edited : [])];
|
|
25
59
|
}
|
|
26
60
|
await writeFileTree(cwd, files);
|
|
27
|
-
|
|
61
|
+
const edited = registered ? (await applyMarkerEdits(cwd, edits)).edited : [];
|
|
62
|
+
options.onRegistered?.({
|
|
63
|
+
registered,
|
|
64
|
+
serverFile: lines.serverFile,
|
|
65
|
+
manualSteps: registered
|
|
66
|
+
? []
|
|
67
|
+
: [
|
|
68
|
+
`In ${lines.serverFile}: ${lines.importLine}`,
|
|
69
|
+
`In ${lines.serverFile}: add ${lines.entryLine} to the middlewares list of the HttpMiddlewarePipeline, before dispatch`,
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
return [...Object.keys(files), ...edited];
|
|
28
73
|
}
|
|
29
74
|
//# sourceMappingURL=middleware.generator.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zudojs-cli — Generated `<name>.middleware.ts`.
|
|
3
|
+
*
|
|
4
|
+
* `generate middleware` used to write
|
|
5
|
+
* `(ctx: unknown, next: () => Promise<void>) => Promise<void>`: registering
|
|
6
|
+
* it in the server pipeline failed tsc with TS2322, and because it returned
|
|
7
|
+
* nothing the response produced by `next()` was dropped. The file is now a
|
|
8
|
+
* real `HttpMiddleware` from @zudojs/http that returns `next()`'s response.
|
|
9
|
+
*/
|
|
10
|
+
/** Options for {@link renderMiddlewareFile}. */
|
|
11
|
+
export interface MiddlewareFileOptions {
|
|
12
|
+
/** Normalized (kebab-case) name, e.g. `request-timer`. */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** Factory function name, e.g. `requestTimerMiddleware`. */
|
|
15
|
+
readonly factoryName: string;
|
|
16
|
+
/** Where the factory is registered, e.g. `src/server.ts`. */
|
|
17
|
+
readonly serverFile: string;
|
|
18
|
+
}
|
|
19
|
+
/** Renders the middleware source file. */
|
|
20
|
+
export declare function renderMiddlewareFile(options: MiddlewareFileOptions): string;
|
|
21
|
+
//# sourceMappingURL=middleware.template.d.ts.map
|