zudojs-cli 1.0.0 → 1.1.1

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.
Files changed (68) hide show
  1. package/README.md +16 -6
  2. package/dist/src/adapters/frontend/frontendAdapter.type.d.ts +6 -0
  3. package/dist/src/bin/zudojs.js +8 -32
  4. package/dist/src/cliApplication/cliApplication.core.js +2 -2
  5. package/dist/src/cliApplication/cliApplication.logger.d.ts +28 -0
  6. package/dist/src/cliApplication/cliApplication.logger.js +68 -0
  7. package/dist/src/cliApplication/index.d.ts +1 -3
  8. package/dist/src/cliApplication/index.js +1 -3
  9. package/dist/src/cliVersion/cliVersion.update.d.ts +38 -0
  10. package/dist/src/cliVersion/cliVersion.update.js +63 -0
  11. package/dist/src/cliVersion/index.d.ts +2 -1
  12. package/dist/src/cliVersion/index.js +2 -1
  13. package/dist/src/commands/add.command.d.ts +29 -0
  14. package/dist/src/commands/add.command.js +94 -109
  15. package/dist/src/commands/build.command.d.ts +8 -0
  16. package/dist/src/commands/build.command.js +12 -18
  17. package/dist/src/commands/create.command.js +8 -5
  18. package/dist/src/commands/dev.command.d.ts +30 -2
  19. package/dist/src/commands/dev.command.js +104 -183
  20. package/dist/src/commands/doctor.command.d.ts +18 -0
  21. package/dist/src/commands/doctor.command.js +141 -113
  22. package/dist/src/commands/generate.command.d.ts +2 -1
  23. package/dist/src/commands/generate.command.js +23 -42
  24. package/dist/src/commands/info.command.js +61 -30
  25. package/dist/src/constants/index.d.ts +18 -2
  26. package/dist/src/constants/index.js +31 -2
  27. package/dist/src/generators/frontend/frontendGenerator.core.d.ts +2 -0
  28. package/dist/src/generators/frontend/frontendGenerator.core.js +11 -0
  29. package/dist/src/generators/frontend/frontendPipeline.js +45 -2
  30. package/dist/src/generators/fullstack/fullstackComposer.core.d.ts +2 -0
  31. package/dist/src/generators/fullstack/fullstackComposer.core.js +8 -22
  32. package/dist/src/index.d.ts +3 -2
  33. package/dist/src/index.js +3 -2
  34. package/dist/src/installers/dependency.installer.d.ts +9 -0
  35. package/dist/src/installers/dependency.installer.js +21 -0
  36. package/dist/src/installers/index.d.ts +1 -3
  37. package/dist/src/installers/index.js +1 -3
  38. package/dist/src/resolvers/architecture.resolver.d.ts +11 -1
  39. package/dist/src/resolvers/architecture.resolver.js +12 -13
  40. package/dist/src/resolvers/configuration/configurationResolver.core.d.ts +10 -1
  41. package/dist/src/resolvers/configuration/configurationResolver.core.js +68 -29
  42. package/dist/src/resolvers/index.d.ts +1 -0
  43. package/dist/src/resolvers/index.js +1 -0
  44. package/dist/src/resolvers/layout/index.d.ts +5 -0
  45. package/dist/src/resolvers/layout/index.js +5 -0
  46. package/dist/src/resolvers/layout/projectLayout.core.d.ts +60 -0
  47. package/dist/src/resolvers/layout/projectLayout.core.js +236 -0
  48. package/dist/src/resolvers/project.resolver.d.ts +5 -0
  49. package/dist/src/resolvers/project.resolver.js +10 -6
  50. package/dist/src/templates/microservice/microservice.template.d.ts +0 -1
  51. package/dist/src/templates/microservice/microservice.template.js +2 -10
  52. package/dist/src/templates/modular-monolith/modularMonolith.template.d.ts +0 -1
  53. package/dist/src/templates/modular-monolith/modularMonolith.template.js +4 -7
  54. package/dist/src/templates/monolith/monolith.template.d.ts +0 -1
  55. package/dist/src/templates/monolith/monolith.template.js +4 -7
  56. package/dist/src/templates/shared/appRuntime.template.d.ts +0 -11
  57. package/dist/src/templates/shared/appRuntime.template.js +0 -20
  58. package/dist/src/templates/shared/index.d.ts +1 -0
  59. package/dist/src/templates/shared/index.js +1 -0
  60. package/dist/src/templates/shared/pnpm.template.d.ts +27 -0
  61. package/dist/src/templates/shared/pnpm.template.js +57 -0
  62. package/dist/src/utils/utils.detect.d.ts +9 -0
  63. package/dist/src/utils/utils.detect.js +11 -11
  64. package/dist/src/utils/utils.exec.d.ts +17 -1
  65. package/dist/src/utils/utils.exec.js +65 -4
  66. package/package.json +12 -10
  67. package/dist/src/scripts/postinstall.cjs +0 -77
  68. package/src/scripts/postinstall.cjs +0 -77
@@ -1,50 +1,89 @@
1
1
  /**
2
2
  * zudojs-cli — Configuration Resolver
3
3
  *
4
- * Resolves and validates project configuration from multiple sources.
4
+ * Resolves project configuration from the sources `zudojs create` writes.
5
5
  */
6
6
  import { existsSync, readFileSync } from "node:fs";
7
7
  import { join } from "node:path";
8
+ import { resolveProjectLayout } from "../layout/projectLayout.core.js";
8
9
  export class ConfigurationResolver {
10
+ /**
11
+ * Resolves the configuration of the project at `cwd`, or `null` when the
12
+ * directory is not a Zudojs project.
13
+ *
14
+ * Only `zudojs.config.ts` used to be consulted, so every project created
15
+ * since the manifest became the source of truth resolved to `null`.
16
+ */
9
17
  resolve(cwd) {
10
- const configPath = join(cwd, "zudojs.config.ts");
11
- if (!existsSync(configPath)) {
18
+ const layout = resolveProjectLayout(cwd);
19
+ if (!layout)
20
+ return null;
21
+ const manifest = this.readJson(join(cwd, ".zudojs", "manifest.json"));
22
+ const pkg = this.readJson(join(cwd, "package.json"));
23
+ const legacy = this.readLegacyConfig(cwd);
24
+ const features = manifest?.capabilities ??
25
+ (Array.isArray(pkg?.zudojs?.features)
26
+ ? pkg.zudojs.features.filter((feature) => typeof feature === "string")
27
+ : undefined) ??
28
+ this.extractArray(legacy, "features") ??
29
+ [];
30
+ const frontendArchitecture = manifest?.frontend?.architecture ??
31
+ this.extractValue(legacy, "architecture", "frontend");
32
+ const language = this.extractValue(legacy, "language");
33
+ return {
34
+ projectName: this.extractValue(legacy, "name") ?? pkg?.name ?? "unknown",
35
+ projectType: layout.projectType,
36
+ architecture: layout.architecture,
37
+ packageManager: layout.packageManager,
38
+ database: manifest?.database?.provider ??
39
+ this.extractValue(legacy, "provider") ??
40
+ "postgresql",
41
+ api: manifest?.backend?.api ?? this.extractValue(legacy, "api") ?? "rest",
42
+ ...(layout.frontendFramework !== undefined
43
+ ? { frontend: layout.frontendFramework }
44
+ : {}),
45
+ ...(frontendArchitecture !== undefined ? { frontendArchitecture } : {}),
46
+ ...(language !== undefined ? { language } : {}),
47
+ features,
48
+ };
49
+ }
50
+ readJson(path) {
51
+ if (!existsSync(path))
12
52
  return null;
13
- }
14
53
  try {
15
- const content = readFileSync(configPath, "utf-8");
16
- return {
17
- projectName: this.extractValue(content, "name") ?? "unknown",
18
- projectType: this.extractValue(content, "type") ?? "backend",
19
- architecture: this.extractValue(content, "architecture") ?? "monolith",
20
- packageManager: this.extractValue(content, "packageManager") ?? "pnpm",
21
- database: this.extractValue(content, "provider") ?? "postgresql",
22
- api: this.extractValue(content, "api") ?? "rest",
23
- frontend: this.extractValue(content, "framework"),
24
- frontendArchitecture: this.extractValue(content, "architecture", "frontend"),
25
- language: this.extractValue(content, "language"),
26
- features: this.extractArray(content, "features") ?? [],
27
- };
54
+ return JSON.parse(readFileSync(path, "utf-8"));
28
55
  }
29
56
  catch {
30
57
  return null;
31
58
  }
32
59
  }
33
- extractValue(content, key, section) {
34
- let pattern;
35
- if (section) {
36
- pattern = new RegExp(`${section}[\\s\\S]*?${key}:\\s*["']([^"']+)["']`);
37
- }
38
- else {
39
- pattern = new RegExp(`${key}:\\s*["']([^"']+)["']`);
60
+ readLegacyConfig(cwd) {
61
+ for (const name of ["zudojs.config.ts", "zudojs.config.js"]) {
62
+ const path = join(cwd, name);
63
+ if (!existsSync(path))
64
+ continue;
65
+ try {
66
+ return readFileSync(path, "utf-8");
67
+ }
68
+ catch {
69
+ return "";
70
+ }
40
71
  }
41
- const match = content.match(pattern);
42
- return match?.[1];
72
+ return "";
73
+ }
74
+ extractValue(content, key, section) {
75
+ if (content.length === 0)
76
+ return undefined;
77
+ const pattern = section
78
+ ? new RegExp(`${section}[\\s\\S]*?${key}:\\s*["']([^"']+)["']`)
79
+ : new RegExp(`(?<![\\w])${key}:\\s*["']([^"']+)["']`);
80
+ return content.match(pattern)?.[1];
43
81
  }
44
82
  extractArray(content, key) {
45
- const pattern = new RegExp(`${key}:\\s*\\[([^\\]]+)\\]`);
46
- const match = content.match(pattern);
47
- if (!match || !match[1])
83
+ if (content.length === 0)
84
+ return undefined;
85
+ const match = content.match(new RegExp(`${key}:\\s*\\[([^\\]]+)\\]`));
86
+ if (!match?.[1])
48
87
  return undefined;
49
88
  return match[1]
50
89
  .split(",")
@@ -7,4 +7,5 @@ export { detectArchitecture } from "./architecture.resolver.js";
7
7
  export { resolveProjectPath, findProjectRoot } from "./project.resolver.js";
8
8
  export { CapabilityResolver, type CapabilityDependency, type CapabilityResolutionResult, } from "./capability/index.js";
9
9
  export { ConfigurationResolver, type ResolvedConfiguration, } from "./configuration/index.js";
10
+ export { resolveProjectLayout, detectPackageManager, type ProjectLayout, type ProjectLayoutType, type ProjectLayoutSource, } from "./layout/index.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -7,4 +7,5 @@ export { detectArchitecture } from "./architecture.resolver.js";
7
7
  export { resolveProjectPath, findProjectRoot } from "./project.resolver.js";
8
8
  export { CapabilityResolver, } from "./capability/index.js";
9
9
  export { ConfigurationResolver, } from "./configuration/index.js";
10
+ export { resolveProjectLayout, detectPackageManager, } from "./layout/index.js";
10
11
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * zudojs-cli — Project Layout Resolver
3
+ */
4
+ export { resolveProjectLayout, detectPackageManager, type ProjectLayout, type ProjectLayoutType, type ProjectLayoutSource, } from "./projectLayout.core.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * zudojs-cli — Project Layout Resolver
3
+ */
4
+ export { resolveProjectLayout, detectPackageManager, } from "./projectLayout.core.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * zudojs-cli — Project Layout Resolver
3
+ *
4
+ * One place that answers "what kind of project is this directory, and where
5
+ * do its apps live?". Every follow-up command (`dev`, `add`, `generate`,
6
+ * `doctor`, `info`, `build`) used to answer that question on its own, and
7
+ * each answer was different: `dev` read `zudojs.config.ts` first and only
8
+ * fell back to the manifest, `generate` never looked past the workspace
9
+ * root for a fullstack project, `doctor` required a `tsconfig.json` at the
10
+ * root of a workspace that has none, and `add` wrote into the workspace root
11
+ * `package.json` where no app can import from.
12
+ *
13
+ * Resolution order:
14
+ *
15
+ * 1. `.zudojs/manifest.json` — written by `zudojs create`, machine-managed.
16
+ * 2. `zudojs.config.ts` / `.js` — older projects; read with a regex, never
17
+ * executed.
18
+ * 3. the `zudojs` block in `package.json`.
19
+ *
20
+ * @module resolvers/layout
21
+ */
22
+ import type { PackageManager } from "../../types/index.js";
23
+ /** Project type recorded by `zudojs create`. */
24
+ export type ProjectLayoutType = "backend" | "frontend" | "fullstack";
25
+ /** Where the description of the project came from. */
26
+ export type ProjectLayoutSource = "manifest" | "config" | "package.json";
27
+ /** The resolved shape of a Zudojs project on disk. */
28
+ export interface ProjectLayout {
29
+ /** Absolute project root: the directory holding the manifest or config. */
30
+ readonly root: string;
31
+ readonly projectType: ProjectLayoutType;
32
+ /** Backend architecture (`monolith`, `modular-monolith`, `microservice`). */
33
+ readonly architecture: string;
34
+ readonly packageManager: PackageManager;
35
+ /** Whether the root is a workspace (pnpm-workspace.yaml or `workspaces`). */
36
+ readonly isWorkspace: boolean;
37
+ /**
38
+ * Absolute directories that hold a backend app, each with its own
39
+ * `package.json`. Empty for a frontend-only project. A monolith has one
40
+ * (the root, or `apps/api` in a fullstack workspace); a microservice
41
+ * project has the gateway plus one per service.
42
+ */
43
+ readonly backendDirs: readonly string[];
44
+ /** Absolute directory of the frontend app, when the project has one. */
45
+ readonly frontendDir?: string;
46
+ readonly frontendFramework?: string;
47
+ /** Service names of a microservice project. */
48
+ readonly services: readonly string[];
49
+ readonly source: ProjectLayoutSource;
50
+ }
51
+ /** Detects the package manager from lock files and workspace markers. */
52
+ export declare function detectPackageManager(root: string): PackageManager;
53
+ /**
54
+ * Resolves the layout of the Zudojs project rooted at `cwd`.
55
+ *
56
+ * Returns `null` when the directory is not a Zudojs project: no manifest,
57
+ * no legacy config and no `zudojs` block in `package.json`.
58
+ */
59
+ export declare function resolveProjectLayout(cwd: string): ProjectLayout | null;
60
+ //# sourceMappingURL=projectLayout.core.d.ts.map
@@ -0,0 +1,236 @@
1
+ /**
2
+ * zudojs-cli — Project Layout Resolver
3
+ *
4
+ * One place that answers "what kind of project is this directory, and where
5
+ * do its apps live?". Every follow-up command (`dev`, `add`, `generate`,
6
+ * `doctor`, `info`, `build`) used to answer that question on its own, and
7
+ * each answer was different: `dev` read `zudojs.config.ts` first and only
8
+ * fell back to the manifest, `generate` never looked past the workspace
9
+ * root for a fullstack project, `doctor` required a `tsconfig.json` at the
10
+ * root of a workspace that has none, and `add` wrote into the workspace root
11
+ * `package.json` where no app can import from.
12
+ *
13
+ * Resolution order:
14
+ *
15
+ * 1. `.zudojs/manifest.json` — written by `zudojs create`, machine-managed.
16
+ * 2. `zudojs.config.ts` / `.js` — older projects; read with a regex, never
17
+ * executed.
18
+ * 3. the `zudojs` block in `package.json`.
19
+ *
20
+ * @module resolvers/layout
21
+ */
22
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
23
+ import { join } from "node:path";
24
+ import { SAFE_PATH_SEGMENT } from "../../utils/utils.name.js";
25
+ const PROJECT_TYPES = [
26
+ "backend",
27
+ "frontend",
28
+ "fullstack",
29
+ ];
30
+ const PACKAGE_MANAGERS = [
31
+ "pnpm",
32
+ "npm",
33
+ "yarn",
34
+ "bun",
35
+ ];
36
+ function readJson(path) {
37
+ try {
38
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
39
+ return typeof parsed === "object" && parsed !== null
40
+ ? parsed
41
+ : null;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ function asString(value) {
48
+ return typeof value === "string" && value.length > 0 ? value : undefined;
49
+ }
50
+ function readManifest(root) {
51
+ const manifest = readJson(join(root, ".zudojs", "manifest.json"));
52
+ if (!manifest)
53
+ return null;
54
+ const backend = manifest.backend;
55
+ const frontend = manifest.frontend;
56
+ const workspace = manifest.workspace;
57
+ const services = Array.isArray(manifest.services)
58
+ ? manifest.services.filter((service) => typeof service === "string")
59
+ : undefined;
60
+ return {
61
+ projectType: asString(manifest.projectType),
62
+ architecture: asString(backend?.architecture) ?? asString(manifest.architecture),
63
+ packageManager: asString(workspace?.packageManager),
64
+ frontendFramework: asString(frontend?.framework),
65
+ services,
66
+ source: "manifest",
67
+ };
68
+ }
69
+ /**
70
+ * Reads the legacy `zudojs.config.ts` with a regex. The file is user-owned
71
+ * TypeScript and is never executed.
72
+ */
73
+ function readLegacyConfig(root) {
74
+ for (const name of ["zudojs.config.ts", "zudojs.config.js"]) {
75
+ const path = join(root, name);
76
+ if (!existsSync(path))
77
+ continue;
78
+ let content;
79
+ try {
80
+ content = readFileSync(path, "utf-8");
81
+ }
82
+ catch {
83
+ continue;
84
+ }
85
+ const projectType = content.match(/projectType:\s*["'](\w+)["']/)?.[1];
86
+ const architecture = content.match(/architecture:\s*["'](\w[\w-]*)["']/)?.[1];
87
+ const frontendFramework = content.match(/frontend:\s*\{[\s\S]*?framework:\s*["']([^"']+)["']/)?.[1];
88
+ return {
89
+ projectType,
90
+ architecture,
91
+ frontendFramework,
92
+ source: "config",
93
+ };
94
+ }
95
+ return null;
96
+ }
97
+ function readPackageJsonBlock(root) {
98
+ const pkg = readJson(join(root, "package.json"));
99
+ const block = pkg?.zudojs;
100
+ if (typeof block !== "object" || block === null)
101
+ return null;
102
+ const zudojs = block;
103
+ return {
104
+ projectType: asString(zudojs.projectType),
105
+ architecture: asString(zudojs.architecture),
106
+ frontendFramework: asString(zudojs.frontend),
107
+ source: "package.json",
108
+ };
109
+ }
110
+ /** Detects the package manager from lock files and workspace markers. */
111
+ export function detectPackageManager(root) {
112
+ if (existsSync(join(root, "pnpm-lock.yaml")) ||
113
+ existsSync(join(root, "pnpm-workspace.yaml"))) {
114
+ return "pnpm";
115
+ }
116
+ if (existsSync(join(root, "yarn.lock")))
117
+ return "yarn";
118
+ if (existsSync(join(root, "bun.lock")) || existsSync(join(root, "bun.lockb")))
119
+ return "bun";
120
+ return "npm";
121
+ }
122
+ /**
123
+ * Whether `root` is a multi-package workspace.
124
+ *
125
+ * A `pnpm-workspace.yaml` alone is not enough: pnpm 10+ also uses that file
126
+ * for settings (the build-script allow-list every generated project
127
+ * carries), so only one that declares `packages:` makes a workspace.
128
+ */
129
+ function isWorkspaceRoot(root) {
130
+ const workspaceFile = join(root, "pnpm-workspace.yaml");
131
+ if (existsSync(workspaceFile)) {
132
+ try {
133
+ if (/^packages:/m.test(readFileSync(workspaceFile, "utf-8")))
134
+ return true;
135
+ }
136
+ catch {
137
+ // unreadable: fall through to package.json
138
+ }
139
+ }
140
+ const pkg = readJson(join(root, "package.json"));
141
+ return pkg?.workspaces !== undefined;
142
+ }
143
+ /**
144
+ * Lists the service apps under `<backendRoot>/apps/services`, preferring the
145
+ * names recorded in the manifest and falling back to the directory listing.
146
+ */
147
+ function listServiceDirs(backendRoot, recorded) {
148
+ const servicesRoot = join(backendRoot, "apps", "services");
149
+ let names;
150
+ if (recorded && recorded.length > 0) {
151
+ // Names come from a file on disk and become path segments.
152
+ names = recorded.filter((name) => SAFE_PATH_SEGMENT.test(name));
153
+ }
154
+ else if (existsSync(servicesRoot)) {
155
+ names = readdirSync(servicesRoot, { withFileTypes: true })
156
+ .filter((entry) => entry.isDirectory())
157
+ .map((entry) => entry.name)
158
+ .filter((name) => SAFE_PATH_SEGMENT.test(name));
159
+ }
160
+ else {
161
+ names = [];
162
+ }
163
+ const dirs = names
164
+ .map((name) => join(servicesRoot, name))
165
+ .filter((dir) => existsSync(join(dir, "package.json")));
166
+ return { names, dirs };
167
+ }
168
+ /**
169
+ * Resolves the layout of the Zudojs project rooted at `cwd`.
170
+ *
171
+ * Returns `null` when the directory is not a Zudojs project: no manifest,
172
+ * no legacy config and no `zudojs` block in `package.json`.
173
+ */
174
+ export function resolveProjectLayout(cwd) {
175
+ const raw = readManifest(cwd) ?? readLegacyConfig(cwd) ?? readPackageJsonBlock(cwd);
176
+ if (!raw)
177
+ return null;
178
+ const projectType = PROJECT_TYPES.includes(raw.projectType)
179
+ ? raw.projectType
180
+ : "backend";
181
+ const architecture = raw.architecture ?? "monolith";
182
+ const packageManager = PACKAGE_MANAGERS.includes(raw.packageManager)
183
+ ? raw.packageManager
184
+ : detectPackageManager(cwd);
185
+ // In a fullstack workspace the backend is generated into apps/api; a
186
+ // backend-only project is its own backend root.
187
+ const fullstackApi = join(cwd, "apps", "api");
188
+ const backendRoot = projectType === "fullstack" &&
189
+ existsSync(join(fullstackApi, "package.json"))
190
+ ? fullstackApi
191
+ : cwd;
192
+ let backendDirs = [];
193
+ let services = [];
194
+ if (projectType !== "frontend") {
195
+ if (architecture === "microservice") {
196
+ const gateway = join(backendRoot, "apps", "gateway");
197
+ const listed = listServiceDirs(backendRoot, raw.services);
198
+ services = listed.names;
199
+ backendDirs = [
200
+ ...(existsSync(join(gateway, "package.json")) ? [gateway] : []),
201
+ ...listed.dirs,
202
+ ];
203
+ }
204
+ else {
205
+ backendDirs = [backendRoot];
206
+ }
207
+ }
208
+ let frontendDir;
209
+ let frontendFramework;
210
+ if (projectType === "frontend") {
211
+ const nested = join(cwd, "apps", "web");
212
+ frontendDir = existsSync(join(nested, "package.json")) ? nested : cwd;
213
+ frontendFramework = raw.frontendFramework ?? "react";
214
+ }
215
+ else if (projectType === "fullstack") {
216
+ frontendDir = join(cwd, "apps", "web");
217
+ frontendFramework = raw.frontendFramework ?? "react";
218
+ }
219
+ else if (raw.frontendFramework && raw.frontendFramework !== "none") {
220
+ frontendDir = join(cwd, "apps", "web");
221
+ frontendFramework = raw.frontendFramework;
222
+ }
223
+ return {
224
+ root: cwd,
225
+ projectType,
226
+ architecture,
227
+ packageManager,
228
+ isWorkspace: isWorkspaceRoot(cwd),
229
+ backendDirs,
230
+ ...(frontendDir !== undefined ? { frontendDir } : {}),
231
+ ...(frontendFramework !== undefined ? { frontendFramework } : {}),
232
+ services,
233
+ source: raw.source,
234
+ };
235
+ }
236
+ //# sourceMappingURL=projectLayout.core.js.map
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Walks upward from `startDir` to the nearest directory that looks like a
3
+ * project root: one holding a `.zudojs/manifest.json`, a legacy
4
+ * `zudojs.config.ts`, or a `package.json`.
5
+ */
1
6
  export declare function findProjectRoot(startDir?: string): string | null;
2
7
  export declare function resolveProjectPath(cwd: string, name: string): string;
3
8
  //# sourceMappingURL=project.resolver.d.ts.map
@@ -1,15 +1,19 @@
1
1
  import { existsSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ /**
4
+ * Walks upward from `startDir` to the nearest directory that looks like a
5
+ * project root: one holding a `.zudojs/manifest.json`, a legacy
6
+ * `zudojs.config.ts`, or a `package.json`.
7
+ */
3
8
  export function findProjectRoot(startDir = process.cwd()) {
4
9
  let dir = startDir;
5
10
  while (true) {
6
- if (existsSync(join(dir, "zudojs.config.ts"))) {
11
+ if (existsSync(join(dir, ".zudojs", "manifest.json")) ||
12
+ existsSync(join(dir, "zudojs.config.ts")) ||
13
+ existsSync(join(dir, "package.json"))) {
7
14
  return dir;
8
15
  }
9
- if (existsSync(join(dir, "package.json"))) {
10
- return dir;
11
- }
12
- const parent = join(dir, "..");
16
+ const parent = dirname(dir);
13
17
  if (parent === dir) {
14
18
  return null;
15
19
  }
@@ -17,7 +17,6 @@
17
17
  * ├── infrastructure/
18
18
  * ├── package.json
19
19
  * ├── pnpm-workspace.yaml
20
- * ├── zudojs.config.ts
21
20
  * ├── docker-compose.yml
22
21
  * └── README.md
23
22
  * ```
@@ -17,14 +17,13 @@
17
17
  * ├── infrastructure/
18
18
  * ├── package.json
19
19
  * ├── pnpm-workspace.yaml
20
- * ├── zudojs.config.ts
21
20
  * ├── docker-compose.yml
22
21
  * └── README.md
23
22
  * ```
24
23
  */
25
24
  import { ZUDOJS_PACKAGES_VERSION } from "../../constants/index.js";
26
25
  import { normalizeName } from "../../utils/utils.name.js";
27
- import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderZudojsConfig, } from "../shared/index.js";
26
+ import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderPnpmWorkspaceFile, } from "../shared/index.js";
28
27
  /** Default service names used when none are provided. */
29
28
  export const DEFAULT_MICROSERVICE_SERVICES = [
30
29
  "identity",
@@ -104,9 +103,7 @@ export function generateMicroserviceFiles(options) {
104
103
  },
105
104
  }, null, 2) + "\n";
106
105
  if (options.packageManager === "pnpm") {
107
- files["pnpm-workspace.yaml"] = `packages:
108
- ${workspaceGlobs.map((g) => ` - "${g}"`).join("\n")}
109
- `;
106
+ files["pnpm-workspace.yaml"] = renderPnpmWorkspaceFile(workspaceGlobs);
110
107
  }
111
108
  // Docker Compose — gateway on 3000, service i on 3001+i.
112
109
  let composeServices = "";
@@ -139,11 +136,6 @@ ${composeServices}
139
136
  volumes:
140
137
  ${services.map((s) => `${s}-data:`).join("\n ")}
141
138
  `;
142
- files["zudojs.config.ts"] = renderZudojsConfig({
143
- projectName: nameSlug,
144
- projectType: "backend",
145
- architecture: "microservice",
146
- });
147
139
  files[".env.example"] = `NODE_ENV=development
148
140
  PORT=3000
149
141
  `;
@@ -28,7 +28,6 @@
28
28
  * ├── tests/
29
29
  * ├── package.json
30
30
  * ├── tsconfig.json
31
- * ├── zudojs.config.ts
32
31
  * └── README.md
33
32
  * ```
34
33
  */
@@ -28,13 +28,12 @@
28
28
  * ├── tests/
29
29
  * ├── package.json
30
30
  * ├── tsconfig.json
31
- * ├── zudojs.config.ts
32
31
  * └── README.md
33
32
  * ```
34
33
  */
35
34
  import { ZUDOJS_PACKAGES_VERSION } from "../../constants/index.js";
36
35
  import { normalizeName } from "../../utils/utils.name.js";
37
- import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderZudojsConfig, } from "../shared/index.js";
36
+ import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderPnpmWorkspaceFile, } from "../shared/index.js";
38
37
  export function generateModularMonolithFiles(options) {
39
38
  const nameSlug = options.projectName
40
39
  .replace(/[^a-z0-9-]+/gi, "-")
@@ -103,11 +102,9 @@ export function generateModularMonolithFiles(options) {
103
102
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
104
103
  }
105
104
  `;
106
- files["zudojs.config.ts"] = renderZudojsConfig({
107
- projectName: nameSlug,
108
- projectType: "backend",
109
- architecture: "modular-monolith",
110
- });
105
+ if (options.packageManager === "pnpm") {
106
+ files["pnpm-workspace.yaml"] = renderPnpmWorkspaceFile();
107
+ }
111
108
  files[".env.example"] = `NODE_ENV=development
112
109
  PORT=3000
113
110
  DATABASE_URL=postgresql://localhost:5432/${nameSlug}
@@ -34,7 +34,6 @@
34
34
  * ├── tests/
35
35
  * ├── package.json
36
36
  * ├── tsconfig.json
37
- * ├── zudojs.config.ts
38
37
  * └── README.md
39
38
  * ```
40
39
  */
@@ -34,13 +34,12 @@
34
34
  * ├── tests/
35
35
  * ├── package.json
36
36
  * ├── tsconfig.json
37
- * ├── zudojs.config.ts
38
37
  * └── README.md
39
38
  * ```
40
39
  */
41
40
  import { ZUDOJS_PACKAGES_VERSION } from "../../constants/index.js";
42
41
  import { normalizeName, toPascalCase } from "../../utils/utils.name.js";
43
- import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderServiceFile, renderZudojsConfig, } from "../shared/index.js";
42
+ import { RUNTIME_APP_DEPENDENCIES, moduleSpec, renderAppFile, renderModuleFile, renderServerFile, renderServiceFile, renderPnpmWorkspaceFile, } from "../shared/index.js";
44
43
  export function generateMonolithFiles(options) {
45
44
  const name = options.projectName;
46
45
  const nameSlug = name.replace(/[^a-z0-9-]+/gi, "-").toLowerCase();
@@ -118,11 +117,9 @@ export function generateMonolithFiles(options) {
118
117
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
119
118
  }
120
119
  `;
121
- files["zudojs.config.ts"] = renderZudojsConfig({
122
- projectName: nameSlug,
123
- projectType: "backend",
124
- architecture: "monolith",
125
- });
120
+ if (options.packageManager === "pnpm") {
121
+ files["pnpm-workspace.yaml"] = renderPnpmWorkspaceFile();
122
+ }
126
123
  // Environment
127
124
  files[".env.example"] = `NODE_ENV=development
128
125
  PORT=3000
@@ -24,17 +24,6 @@ export interface RuntimeModuleSpec {
24
24
  }
25
25
  /** Builds a module spec from a raw name. */
26
26
  export declare function moduleSpec(name: string, importPath: string): RuntimeModuleSpec;
27
- /**
28
- * Renders `zudojs.config.ts`.
29
- *
30
- * The shape matches what the fullstack composer writes and what
31
- * `zudojs generate` parses to detect the project architecture.
32
- */
33
- export declare function renderZudojsConfig(options: {
34
- readonly projectName: string;
35
- readonly projectType: string;
36
- readonly architecture: string;
37
- }): string;
38
27
  /**
39
28
  * Renders `src/app.ts`: assembles the runtime dependencies and returns a
40
29
  * started-on-demand `Runtime`.
@@ -33,26 +33,6 @@ export function moduleSpec(name, importPath) {
33
33
  function literal(value) {
34
34
  return JSON.stringify(value);
35
35
  }
36
- /**
37
- * Renders `zudojs.config.ts`.
38
- *
39
- * The shape matches what the fullstack composer writes and what
40
- * `zudojs generate` parses to detect the project architecture.
41
- */
42
- export function renderZudojsConfig(options) {
43
- return `/**
44
- * Zudojs project configuration.
45
- *
46
- * Read by the \`zudojs\` CLI to detect this project's architecture.
47
- */
48
-
49
- export default {
50
- name: ${literal(options.projectName)},
51
- projectType: ${literal(options.projectType)},
52
- architecture: ${literal(options.architecture)},
53
- };
54
- `;
55
- }
56
36
  /**
57
37
  * Renders `src/app.ts`: assembles the runtime dependencies and returns a
58
38
  * started-on-demand `Runtime`.
@@ -2,4 +2,5 @@
2
2
  * zudojs-cli — Shared Template Fragments
3
3
  */
4
4
  export * from "./appRuntime.template.js";
5
+ export * from "./pnpm.template.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -2,4 +2,5 @@
2
2
  * zudojs-cli — Shared Template Fragments
3
3
  */
4
4
  export * from "./appRuntime.template.js";
5
+ export * from "./pnpm.template.js";
5
6
  //# sourceMappingURL=index.js.map