zudojs-cli 1.2.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/dist/src/adapters/frontend/flutter.adapter.d.ts +9 -0
- package/dist/src/adapters/frontend/flutter.adapter.js +16 -1
- package/dist/src/bin/zudojs.js +16 -5
- package/dist/src/cliApplication/cliApplication.builtins.d.ts +4 -0
- package/dist/src/cliApplication/cliApplication.builtins.js +28 -9
- package/dist/src/cliApplication/cliApplication.core.d.ts +8 -0
- package/dist/src/cliApplication/cliApplication.core.js +45 -5
- package/dist/src/cliApplication/cliApplication.help.d.ts +17 -0
- package/dist/src/cliApplication/cliApplication.help.js +94 -0
- package/dist/src/cliApplication/cliApplication.logger.js +4 -4
- package/dist/src/cliCommand/cliCommand.validator.js +22 -0
- package/dist/src/cliConstant/cliConstant.value.d.ts +18 -12
- package/dist/src/cliConstant/cliConstant.value.js +25 -19
- package/dist/src/cliError/cliError.argument.js +2 -2
- package/dist/src/cliError/cliError.base.js +28 -5
- package/dist/src/cliError/cliError.command.js +5 -2
- package/dist/src/cliError/cliError.execution.js +3 -3
- package/dist/src/cliParser/cliParser.core.js +11 -5
- package/dist/src/cliParser/cliParser.helper.d.ts +11 -0
- package/dist/src/cliParser/cliParser.helper.js +19 -0
- package/dist/src/cliParser/cliParser.longOption.js +4 -4
- package/dist/src/cliParser/cliParser.shortOption.js +7 -4
- package/dist/src/cliVersion/cliVersion.update.js +5 -3
- package/dist/src/commands/add.command.js +17 -2
- package/dist/src/commands/commandError.helper.d.ts +15 -0
- package/dist/src/commands/commandError.helper.js +28 -0
- package/dist/src/commands/create.command.js +284 -46
- package/dist/src/commands/doctor.command.d.ts +8 -0
- package/dist/src/commands/doctor.command.js +38 -5
- package/dist/src/commands/generate.command.js +71 -32
- package/dist/src/constants/index.d.ts +40 -68
- package/dist/src/constants/index.js +73 -23
- package/dist/src/generators/frontend/frontendPipeline.js +16 -4
- package/dist/src/generators/integration/integrationGenerator.core.js +10 -6
- package/dist/src/generators/project/project.generator.js +5 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.js +3 -3
- package/dist/src/manifest/index.d.ts +1 -0
- package/dist/src/manifest/index.js +1 -0
- package/dist/src/manifest/manifestFile.helper.d.ts +42 -0
- package/dist/src/manifest/manifestFile.helper.js +141 -0
- package/dist/src/manifest/manifestManager.core.d.ts +16 -0
- package/dist/src/manifest/manifestManager.core.js +65 -35
- package/dist/src/prompts/backend/api-style.prompt.js +2 -5
- package/dist/src/prompts/backend/backend-architecture.prompt.js +5 -22
- package/dist/src/prompts/backend/database.prompt.js +5 -23
- package/dist/src/prompts/backend/services.prompt.js +12 -10
- package/dist/src/prompts/cancel.prompt.d.ts +18 -0
- package/dist/src/prompts/cancel.prompt.js +26 -0
- package/dist/src/prompts/capabilities/capabilities.prompt.js +2 -5
- package/dist/src/prompts/frontend/framework.prompt.js +2 -5
- package/dist/src/prompts/frontend/frontend-architecture.prompt.js +2 -5
- package/dist/src/prompts/index.d.ts +1 -0
- package/dist/src/prompts/index.js +1 -0
- package/dist/src/prompts/project/confirmation.prompt.js +2 -5
- package/dist/src/prompts/project/project-name.prompt.js +6 -7
- package/dist/src/prompts/project/project-type.prompt.js +2 -5
- package/dist/src/prompts/workspace/package-manager.prompt.js +5 -12
- package/dist/src/registries/adapter/frontendAdapterRegistry.core.d.ts +6 -0
- package/dist/src/registries/adapter/frontendAdapterRegistry.core.js +12 -0
- package/dist/src/registries/adapter/packageManagerRegistry.core.d.ts +5 -0
- package/dist/src/registries/adapter/packageManagerRegistry.core.js +11 -0
- package/dist/src/registries/dependency/dependencyRegistry.core.d.ts +9 -0
- package/dist/src/registries/dependency/dependencyRegistry.core.js +16 -0
- package/dist/src/registries/generator/generatorRegistry.core.d.ts +8 -0
- package/dist/src/registries/generator/generatorRegistry.core.js +14 -0
- package/dist/src/resolvers/capability/capabilityResolver.core.d.ts +1 -1
- package/dist/src/resolvers/capability/capabilityResolver.core.js +0 -2
- package/dist/src/resolvers/layout/projectLayout.core.js +1 -6
- package/dist/src/resolvers/project.resolver.d.ts +9 -3
- package/dist/src/resolvers/project.resolver.js +11 -7
- package/dist/src/rollback/index.d.ts +1 -1
- package/dist/src/rollback/index.js +1 -1
- package/dist/src/rollback/rollbackManager.core.d.ts +19 -1
- package/dist/src/rollback/rollbackManager.core.js +21 -2
- package/dist/src/runners/package-manager/index.d.ts +1 -1
- package/dist/src/runners/package-manager/index.js +1 -1
- package/dist/src/runners/package-manager/packageManagerRunner.core.d.ts +13 -1
- package/dist/src/runners/package-manager/packageManagerRunner.core.js +19 -1
- package/dist/src/runners/process/processRunner.core.d.ts +11 -0
- package/dist/src/runners/process/processRunner.core.js +41 -6
- package/dist/src/runners/task/index.d.ts +1 -1
- package/dist/src/runners/task/taskRunner.core.d.ts +22 -1
- package/dist/src/runners/task/taskRunner.core.js +35 -6
- package/dist/src/scaffolders/framework.scaffolder.js +3 -0
- package/dist/src/scaffolders/scaffolder.helper.d.ts +10 -0
- package/dist/src/scaffolders/scaffolder.helper.js +25 -2
- package/dist/src/templates/microservice/index.d.ts +1 -1
- package/dist/src/templates/microservice/index.js +1 -1
- package/dist/src/templates/microservice/microservice.template.d.ts +8 -4
- package/dist/src/templates/microservice/microservice.template.js +30 -19
- package/dist/src/templates/modular-monolith/modularMonolith.template.js +27 -8
- package/dist/src/templates/monolith/monolith.template.js +11 -17
- package/dist/src/templates/shared/capability.template.d.ts +25 -0
- package/dist/src/templates/shared/capability.template.js +46 -0
- package/dist/src/templates/shared/index.d.ts +1 -0
- package/dist/src/templates/shared/index.js +1 -0
- package/dist/src/utils/utils.exec.d.ts +22 -0
- package/dist/src/utils/utils.exec.js +51 -4
- package/dist/src/utils/utils.fileSystem.js +46 -2
- package/dist/src/utils/utils.name.d.ts +9 -0
- package/dist/src/utils/utils.name.js +29 -3
- package/dist/src/validators/environment/environmentValidator.core.d.ts +11 -1
- package/dist/src/validators/environment/environmentValidator.core.js +40 -73
- package/dist/src/validators/project/index.d.ts +1 -1
- package/dist/src/validators/project/projectValidator.core.d.ts +11 -1
- package/dist/src/validators/project/projectValidator.core.js +20 -4
- package/package.json +1 -1
|
@@ -9,18 +9,32 @@ export function normalizeName(name) {
|
|
|
9
9
|
.replace(/^-+/, "")
|
|
10
10
|
.replace(/(?<!-)-+$/, "");
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Prefixes an underscore when the first character cannot start a TypeScript
|
|
14
|
+
* identifier.
|
|
15
|
+
*
|
|
16
|
+
* `normalizeName` keeps digits, so `2fa` came out of the converters as `2fa`
|
|
17
|
+
* and was emitted verbatim as a class name — a syntax error in the generated
|
|
18
|
+
* file, and in every barrel and `app.ts` that imports it. Generators reject
|
|
19
|
+
* such a name up front (see {@link assertGeneratableName}); this is the
|
|
20
|
+
* last-resort guarantee for the callers that do not, such as the project
|
|
21
|
+
* templates rendering `--services 2fa`.
|
|
22
|
+
*/
|
|
23
|
+
function toIdentifier(value) {
|
|
24
|
+
return /^[0-9]/.test(value) ? `_${value}` : value;
|
|
25
|
+
}
|
|
12
26
|
/** Converts an arbitrary name to PascalCase (safe as a TS identifier). */
|
|
13
27
|
export function toPascalCase(name) {
|
|
14
|
-
return normalizeName(name)
|
|
28
|
+
return toIdentifier(normalizeName(name)
|
|
15
29
|
.split("-")
|
|
16
30
|
.filter(Boolean)
|
|
17
31
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
18
|
-
.join("");
|
|
32
|
+
.join(""));
|
|
19
33
|
}
|
|
20
34
|
/** Converts an arbitrary name to camelCase (safe as a TS identifier). */
|
|
21
35
|
export function toCamelCase(name) {
|
|
22
36
|
const pascal = toPascalCase(name);
|
|
23
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
37
|
+
return toIdentifier(pascal.charAt(0).toLowerCase() + pascal.slice(1));
|
|
24
38
|
}
|
|
25
39
|
/**
|
|
26
40
|
* Pattern for names that may be used verbatim as a path segment
|
|
@@ -34,12 +48,24 @@ export const SAFE_PATH_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
|
34
48
|
* `normalizeName` strips everything outside `[a-z0-9-]`, so a name such as
|
|
35
49
|
* `"..."` or `"!!!"` collapses to the empty string and the generator writes
|
|
36
50
|
* `src//.event.ts` with an anonymous exported class. Reject it up front.
|
|
51
|
+
*
|
|
52
|
+
* A name whose normalized form starts with a digit (`2fa`, `401-handler`) is
|
|
53
|
+
* rejected for the same reason: it becomes a class name, and `2faModule` is
|
|
54
|
+
* not a TypeScript identifier. The generated file, the barrel it is appended
|
|
55
|
+
* to and the `app.ts` it is registered in would all stop compiling, and the
|
|
56
|
+
* appends mean the overwrite guard cannot undo it. The converters would
|
|
57
|
+
* rather rename it to `_2faModule`, but a class whose name no longer contains
|
|
58
|
+
* the name that was asked for — and disagrees with its own file name — is a
|
|
59
|
+
* worse surprise than a one-line failure the author can act on.
|
|
37
60
|
*/
|
|
38
61
|
export function assertGeneratableName(name, kind = "name") {
|
|
39
62
|
const normalized = normalizeName(name);
|
|
40
63
|
if (normalized === "") {
|
|
41
64
|
throw new CLIValidationError(`Invalid ${kind}: "${name}". It must contain at least one letter or digit.`);
|
|
42
65
|
}
|
|
66
|
+
if (/^[0-9]/.test(normalized)) {
|
|
67
|
+
throw new CLIValidationError(`Invalid ${kind}: "${name}". It must start with a letter: the name becomes a TypeScript class name, and "${normalized}" is not a valid identifier. Try "two-factor-auth" instead of "2fa".`);
|
|
68
|
+
}
|
|
43
69
|
return normalized;
|
|
44
70
|
}
|
|
45
71
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module validators/environment
|
|
5
5
|
*/
|
|
6
|
+
import type { PackageManager } from "../../types/index.js";
|
|
6
7
|
/**
|
|
7
8
|
* Environment check result.
|
|
8
9
|
*/
|
|
@@ -26,10 +27,19 @@ export interface EnvironmentValidationResult {
|
|
|
26
27
|
export declare class EnvironmentValidator {
|
|
27
28
|
/**
|
|
28
29
|
* Validates the environment for a given project type.
|
|
30
|
+
*
|
|
31
|
+
* `packageManager` is the one the project will actually use. Without it
|
|
32
|
+
* the check probed pnpm, yarn, bun and npm in turn and reported the first
|
|
33
|
+
* one found, so it said "valid" while the chosen manager was missing.
|
|
29
34
|
*/
|
|
30
|
-
validate(projectType: "backend" | "frontend" | "fullstack"): Promise<EnvironmentValidationResult>;
|
|
35
|
+
validate(projectType: "backend" | "frontend" | "fullstack", packageManager?: PackageManager): Promise<EnvironmentValidationResult>;
|
|
31
36
|
private checkNode;
|
|
32
37
|
private checkGit;
|
|
38
|
+
/**
|
|
39
|
+
* Checks the selected package manager, or — when none was selected — the
|
|
40
|
+
* first one that is installed.
|
|
41
|
+
*/
|
|
33
42
|
private checkPackageManager;
|
|
43
|
+
private checkBinary;
|
|
34
44
|
}
|
|
35
45
|
//# sourceMappingURL=environmentValidator.core.d.ts.map
|
|
@@ -4,20 +4,30 @@
|
|
|
4
4
|
* @module validators/environment
|
|
5
5
|
*/
|
|
6
6
|
import { execCommand } from "../../utils/utils.exec.js";
|
|
7
|
+
const PACKAGE_MANAGER_CANDIDATES = [
|
|
8
|
+
"pnpm",
|
|
9
|
+
"yarn",
|
|
10
|
+
"bun",
|
|
11
|
+
"npm",
|
|
12
|
+
];
|
|
7
13
|
/**
|
|
8
14
|
* Validates the development environment before project generation.
|
|
9
15
|
*/
|
|
10
16
|
export class EnvironmentValidator {
|
|
11
17
|
/**
|
|
12
18
|
* Validates the environment for a given project type.
|
|
19
|
+
*
|
|
20
|
+
* `packageManager` is the one the project will actually use. Without it
|
|
21
|
+
* the check probed pnpm, yarn, bun and npm in turn and reported the first
|
|
22
|
+
* one found, so it said "valid" while the chosen manager was missing.
|
|
13
23
|
*/
|
|
14
|
-
async validate(projectType) {
|
|
24
|
+
async validate(projectType, packageManager) {
|
|
15
25
|
const checks = [];
|
|
16
26
|
checks.push(await this.checkNode());
|
|
17
27
|
checks.push(await this.checkGit());
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
// A backend project installs dependencies too, so the package manager
|
|
29
|
+
// is checked for every project type, not just frontend and fullstack.
|
|
30
|
+
checks.push(await this.checkPackageManager(packageManager));
|
|
21
31
|
const missing = checks
|
|
22
32
|
.filter((c) => c.required && !c.installed)
|
|
23
33
|
.map((c) => c.name);
|
|
@@ -28,28 +38,36 @@ export class EnvironmentValidator {
|
|
|
28
38
|
};
|
|
29
39
|
}
|
|
30
40
|
async checkNode() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
return this.checkBinary("Node.js", "node");
|
|
42
|
+
}
|
|
43
|
+
async checkGit() {
|
|
44
|
+
return this.checkBinary("Git", "git");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Checks the selected package manager, or — when none was selected — the
|
|
48
|
+
* first one that is installed.
|
|
49
|
+
*/
|
|
50
|
+
async checkPackageManager(packageManager) {
|
|
51
|
+
if (packageManager !== undefined) {
|
|
52
|
+
return this.checkBinary(packageManager, packageManager);
|
|
39
53
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
54
|
+
for (const candidate of PACKAGE_MANAGER_CANDIDATES) {
|
|
55
|
+
const check = await this.checkBinary(candidate, candidate);
|
|
56
|
+
if (check.installed) {
|
|
57
|
+
return check;
|
|
58
|
+
}
|
|
46
59
|
}
|
|
60
|
+
return {
|
|
61
|
+
name: "Package Manager",
|
|
62
|
+
installed: false,
|
|
63
|
+
required: true,
|
|
64
|
+
};
|
|
47
65
|
}
|
|
48
|
-
async
|
|
66
|
+
async checkBinary(name, binary) {
|
|
49
67
|
try {
|
|
50
|
-
const result = await execCommand(
|
|
68
|
+
const result = await execCommand(binary, ["--version"], ".");
|
|
51
69
|
return {
|
|
52
|
-
name
|
|
70
|
+
name,
|
|
53
71
|
installed: true,
|
|
54
72
|
version: result.stdout.trim(),
|
|
55
73
|
required: true,
|
|
@@ -57,62 +75,11 @@ export class EnvironmentValidator {
|
|
|
57
75
|
}
|
|
58
76
|
catch {
|
|
59
77
|
return {
|
|
60
|
-
name
|
|
78
|
+
name,
|
|
61
79
|
installed: false,
|
|
62
80
|
required: true,
|
|
63
81
|
};
|
|
64
82
|
}
|
|
65
83
|
}
|
|
66
|
-
async checkPackageManager() {
|
|
67
|
-
try {
|
|
68
|
-
const result = await execCommand("pnpm", ["--version"], ".");
|
|
69
|
-
return {
|
|
70
|
-
name: "pnpm",
|
|
71
|
-
installed: true,
|
|
72
|
-
version: result.stdout.trim(),
|
|
73
|
-
required: true,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
try {
|
|
78
|
-
const result = await execCommand("yarn", ["--version"], ".");
|
|
79
|
-
return {
|
|
80
|
-
name: "yarn",
|
|
81
|
-
installed: true,
|
|
82
|
-
version: result.stdout.trim(),
|
|
83
|
-
required: true,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
try {
|
|
88
|
-
const result = await execCommand("bun", ["--version"], ".");
|
|
89
|
-
return {
|
|
90
|
-
name: "bun",
|
|
91
|
-
installed: true,
|
|
92
|
-
version: result.stdout.trim(),
|
|
93
|
-
required: true,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
try {
|
|
98
|
-
const result = await execCommand("npm", ["--version"], ".");
|
|
99
|
-
return {
|
|
100
|
-
name: "npm",
|
|
101
|
-
installed: true,
|
|
102
|
-
version: result.stdout.trim(),
|
|
103
|
-
required: true,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return {
|
|
108
|
-
name: "Package Manager",
|
|
109
|
-
installed: false,
|
|
110
|
-
required: true,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
84
|
}
|
|
118
85
|
//# sourceMappingURL=environmentValidator.core.js.map
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module validators/project
|
|
5
5
|
*/
|
|
6
|
-
export type { ProjectCheck, ProjectValidationResult, } from "./projectValidator.core.js";
|
|
6
|
+
export type { ProjectCheck, ProjectValidationResult, ProjectValidationOptions, } from "./projectValidator.core.js";
|
|
7
7
|
export { ProjectValidator } from "./projectValidator.core.js";
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -13,8 +13,18 @@ export interface ProjectCheck {
|
|
|
13
13
|
readonly passed: boolean;
|
|
14
14
|
readonly message?: string;
|
|
15
15
|
}
|
|
16
|
+
/** What a validation run should look at. */
|
|
17
|
+
export interface ProjectValidationOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Whether dependencies are expected to be installed. A project created
|
|
20
|
+
* with `--no-install` has no node_modules on purpose.
|
|
21
|
+
*/
|
|
22
|
+
readonly expectInstalled?: boolean;
|
|
23
|
+
/** Whether to run the project's own TypeScript compiler. */
|
|
24
|
+
readonly typecheck?: boolean;
|
|
25
|
+
}
|
|
16
26
|
export declare class ProjectValidator {
|
|
17
|
-
validate(projectPath: string): Promise<ProjectValidationResult>;
|
|
27
|
+
validate(projectPath: string, options?: ProjectValidationOptions): Promise<ProjectValidationResult>;
|
|
18
28
|
private checkPackageJson;
|
|
19
29
|
private checkTsConfig;
|
|
20
30
|
private checkNodeModules;
|
|
@@ -9,14 +9,19 @@ import { stat } from "node:fs/promises";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { execCommand } from "../../utils/utils.exec.js";
|
|
11
11
|
export class ProjectValidator {
|
|
12
|
-
async validate(projectPath) {
|
|
12
|
+
async validate(projectPath, options = {}) {
|
|
13
|
+
const { expectInstalled = true, typecheck = true } = options;
|
|
13
14
|
const checks = [];
|
|
14
15
|
const errors = [];
|
|
15
16
|
checks.push(await this.checkPackageJson(projectPath));
|
|
16
17
|
checks.push(await this.checkTsConfig(projectPath));
|
|
17
|
-
|
|
18
|
+
if (expectInstalled) {
|
|
19
|
+
checks.push(await this.checkNodeModules(projectPath));
|
|
20
|
+
}
|
|
18
21
|
checks.push(await this.checkSourceFiles(projectPath));
|
|
19
|
-
|
|
22
|
+
if (typecheck) {
|
|
23
|
+
checks.push(await this.checkTypeScript(projectPath));
|
|
24
|
+
}
|
|
20
25
|
for (const check of checks) {
|
|
21
26
|
if (!check.passed && check.message) {
|
|
22
27
|
errors.push(check.message);
|
|
@@ -96,8 +101,19 @@ export class ProjectValidator {
|
|
|
96
101
|
message: "Skipped (no tsconfig)",
|
|
97
102
|
};
|
|
98
103
|
}
|
|
104
|
+
// `npx tsc` downloads TypeScript from the registry when the project has
|
|
105
|
+
// no local copy — a network fetch nobody asked for. Only the project's
|
|
106
|
+
// own compiler is used, and the check is skipped when it is absent.
|
|
107
|
+
const tsc = join(projectPath, "node_modules", ".bin", process.platform === "win32" ? "tsc.cmd" : "tsc");
|
|
108
|
+
if (!existsSync(tsc)) {
|
|
109
|
+
return {
|
|
110
|
+
name: "typescript",
|
|
111
|
+
passed: true,
|
|
112
|
+
message: "Skipped (typescript is not installed in this project)",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
99
115
|
try {
|
|
100
|
-
await execCommand(
|
|
116
|
+
await execCommand(tsc, ["--noEmit"], projectPath);
|
|
101
117
|
return { name: "typescript", passed: true };
|
|
102
118
|
}
|
|
103
119
|
catch {
|