create-nattyjs 0.0.1-beta.68 → 0.0.1-beta.70

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 (28) hide show
  1. package/index.js +93 -349
  2. package/package.json +3 -2
  3. package/src/const/template-definitions.js +76 -0
  4. package/src/const/version-registry.js +74 -0
  5. package/src/const/workspace-definitions.js +27 -0
  6. package/src/functions/cli-theme.js +65 -0
  7. package/src/functions/file-system.js +96 -0
  8. package/src/functions/package-manager.js +9 -0
  9. package/src/functions/package-name.js +12 -0
  10. package/src/functions/prompt-project-options.js +114 -0
  11. package/src/functions/render-package-jsons.js +83 -0
  12. package/src/functions/render-workspace.js +114 -0
  13. package/src/functions/scaffold-project.js +65 -0
  14. package/template-fullstack-angular/apps/api/package.json +8 -8
  15. package/template-fullstack-angular/apps/web/package.json +1 -1
  16. package/template-fullstack-astro/apps/api/package.json +8 -8
  17. package/template-fullstack-astro/apps/web/package.json +1 -1
  18. package/template-fullstack-next/apps/api/package.json +8 -8
  19. package/template-fullstack-next/apps/web/package.json +1 -1
  20. package/template-fullstack-nuxt/apps/api/package.json +8 -8
  21. package/template-fullstack-nuxt/apps/web/package.json +1 -1
  22. package/template-fullstack-react/apps/api/package.json +8 -8
  23. package/template-fullstack-react/apps/web/package.json +1 -1
  24. package/template-fullstack-sveltekit/apps/api/package.json +8 -8
  25. package/template-fullstack-sveltekit/apps/web/package.json +1 -1
  26. package/template-fullstack-vue/apps/api/package.json +8 -8
  27. package/template-fullstack-vue/apps/web/package.json +1 -1
  28. package/template-nattyjs-blank/package.json +8 -8
package/index.js CHANGED
@@ -1,349 +1,93 @@
1
- #!/usr/bin/env node
2
- import fs from "fs";
3
- import path from "path";
4
- import minimist from "minimist";
5
- import prompts from "prompts";
6
- import { fileURLToPath } from "url";
7
- import { red, reset } from "kolorist";
8
-
9
- const argv = minimist(process.argv.slice(2), {
10
- string: ["template"],
11
- boolean: ["examples"],
12
- alias: {
13
- t: "template",
14
- e: "examples",
15
- },
16
- });
17
-
18
- const cwd = process.cwd();
19
-
20
- const renameFiles = {
21
- _gitignore: ".gitignore",
22
- };
23
-
24
- const TEMPLATE_DEFINITIONS = [
25
- {
26
- id: "api-only",
27
- aliases: ["nattyjs-blank"],
28
- title: "API Only",
29
- description: "Backend API (current blank template)",
30
- templateDir: "template-nattyjs-blank",
31
- exampleExcludedPaths: ["controllers"],
32
- },
33
- {
34
- id: "fullstack-vue",
35
- aliases: ["vue", "nattyjs-vue"],
36
- title: "Fullstack + Vue",
37
- description: "NattyJS API + Vue (Vite)",
38
- templateDir: "template-fullstack-vue",
39
- exampleOverlayDir: "__examples",
40
- },
41
- {
42
- id: "fullstack-react",
43
- aliases: ["react", "nattyjs-react"],
44
- title: "Fullstack + React",
45
- description: "NattyJS API + React (Vite)",
46
- templateDir: "template-fullstack-react",
47
- exampleOverlayDir: "__examples",
48
- },
49
- {
50
- id: "fullstack-next",
51
- aliases: ["next", "nextjs", "nattyjs-next"],
52
- title: "Fullstack + Next.js",
53
- description: "NattyJS API + Next.js",
54
- templateDir: "template-fullstack-next",
55
- exampleOverlayDir: "__examples",
56
- },
57
- {
58
- id: "fullstack-nuxt",
59
- aliases: ["nuxt", "nuxtjs", "nattyjs-nuxt"],
60
- title: "Fullstack + Nuxt",
61
- description: "NattyJS API + Nuxt",
62
- templateDir: "template-fullstack-nuxt",
63
- exampleOverlayDir: "__examples",
64
- },
65
- {
66
- id: "fullstack-angular",
67
- aliases: ["angular", "ng", "nattyjs-angular"],
68
- title: "Fullstack + Angular",
69
- description: "NattyJS API + Angular",
70
- templateDir: "template-fullstack-angular",
71
- exampleOverlayDir: "__examples",
72
- },
73
- {
74
- id: "fullstack-astro",
75
- aliases: ["astro", "nattyjs-astro"],
76
- title: "Fullstack + Astro",
77
- description: "NattyJS API + Astro",
78
- templateDir: "template-fullstack-astro",
79
- exampleOverlayDir: "__examples",
80
- },
81
- {
82
- id: "fullstack-sveltekit",
83
- aliases: ["sveltekit", "svelte-kit", "svelte", "nattyjs-sveltekit"],
84
- title: "Fullstack + SvelteKit",
85
- description: "NattyJS API + SvelteKit",
86
- templateDir: "template-fullstack-sveltekit",
87
- exampleOverlayDir: "__examples",
88
- },
89
- ];
90
-
91
- if (process.env.NATTYJS_PROMPT_INJECT) {
92
- prompts.inject(JSON.parse(process.env.NATTYJS_PROMPT_INJECT));
93
- }
94
-
95
- function readJson(filePath) {
96
- if (!fs.existsSync(filePath)) {
97
- return undefined;
98
- }
99
-
100
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
101
- }
102
-
103
- function getTemplateById(value) {
104
- if (!value) {
105
- return undefined;
106
- }
107
-
108
- return TEMPLATE_DEFINITIONS.find((template) => {
109
- return template.id === value || template.aliases.includes(value);
110
- });
111
- }
112
-
113
- function isValidPackageName(projectName) {
114
- return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName);
115
- }
116
-
117
- function toValidPackageName(projectName) {
118
- return projectName
119
- .trim()
120
- .toLowerCase()
121
- .replace(/\s+/g, "-")
122
- .replace(/^[._]/, "")
123
- .replace(/[^a-z0-9-~]+/g, "-");
124
- }
125
-
126
- function isEmpty(dirPath) {
127
- const files = fs.readdirSync(dirPath);
128
- return files.length === 0 || (files.length === 1 && files[0] === ".git");
129
- }
130
-
131
- function emptyDir(dir) {
132
- if (!fs.existsSync(dir)) {
133
- return;
134
- }
135
-
136
- for (const file of fs.readdirSync(dir)) {
137
- const absolutePath = path.resolve(dir, file);
138
- if (fs.lstatSync(absolutePath).isDirectory()) {
139
- emptyDir(absolutePath);
140
- fs.rmdirSync(absolutePath);
141
- } else {
142
- fs.unlinkSync(absolutePath);
143
- }
144
- }
145
- }
146
-
147
- function copy(src, dest) {
148
- const stat = fs.statSync(src);
149
- if (stat.isDirectory()) {
150
- copyDir(src, dest);
151
- return;
152
- }
153
-
154
- fs.copyFileSync(src, dest);
155
- }
156
-
157
- function copyDir(srcDir, destDir) {
158
- fs.mkdirSync(destDir, { recursive: true });
159
- for (const file of fs.readdirSync(srcDir)) {
160
- const srcFile = path.resolve(srcDir, file);
161
- const destFile = path.resolve(destDir, file);
162
- copy(srcFile, destFile);
163
- }
164
- }
165
-
166
- function pkgFromUserAgent(userAgent) {
167
- if (!userAgent) {
168
- return undefined;
169
- }
170
-
171
- const pkgSpec = userAgent.split(" ")[0];
172
- const [name, version] = pkgSpec.split("/");
173
- return { name, version };
174
- }
175
-
176
- function shouldSkipTemplateFile(relativePath, template, includeExamples) {
177
- if (includeExamples) {
178
- return false;
179
- }
180
-
181
- const excludedPaths = template.exampleExcludedPaths || [];
182
- return excludedPaths.some((excludedPath) => {
183
- return relativePath === excludedPath || relativePath.startsWith(`${excludedPath}${path.sep}`);
184
- });
185
- }
186
-
187
- function copyTemplateContents(templateDir, root, template, includeExamples) {
188
- const entries = fs.readdirSync(templateDir);
189
- for (const entry of entries) {
190
- if (entry === "package.json") {
191
- continue;
192
- }
193
-
194
- if (entry === template.exampleOverlayDir) {
195
- continue;
196
- }
197
-
198
- if (shouldSkipTemplateFile(entry, template, includeExamples)) {
199
- continue;
200
- }
201
-
202
- const sourcePath = path.join(templateDir, entry);
203
- const targetPath = renameFiles[entry]
204
- ? path.join(root, renameFiles[entry])
205
- : path.join(root, entry);
206
-
207
- copy(sourcePath, targetPath);
208
- }
209
-
210
- if (includeExamples && template.exampleOverlayDir) {
211
- const overlayDir = path.join(templateDir, template.exampleOverlayDir);
212
- if (fs.existsSync(overlayDir)) {
213
- copyDir(overlayDir, root);
214
- }
215
- }
216
- }
217
-
218
- async function resolveProjectOptions() {
219
- let targetDir = typeof argv._[0] === "string" ? argv._[0].trim() : "";
220
- let selectedTemplate = getTemplateById(argv.template);
221
- const defaultProjectName = targetDir || "nattyjs-project";
222
-
223
- try {
224
- return await prompts(
225
- [
226
- {
227
- type: targetDir ? null : "text",
228
- name: "projectName",
229
- message: reset("Project name:"),
230
- initial: defaultProjectName,
231
- validate: (value) => {
232
- const trimmed = value.trim();
233
- return trimmed.length > 0 || "Project name is required";
234
- },
235
- onState: (state) => {
236
- targetDir = state.value.trim() || defaultProjectName;
237
- },
238
- },
239
- {
240
- type: () => {
241
- return !targetDir || !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : "confirm";
242
- },
243
- name: "overwrite",
244
- message: () => {
245
- const label = targetDir === "." ? "Current directory" : `Target directory "${targetDir}"`;
246
- return `${label} is not empty. Remove existing files and continue?`;
247
- },
248
- initial: false,
249
- },
250
- {
251
- type: (_, { overwrite } = {}) => {
252
- if (overwrite === false) {
253
- throw new Error(`${red("x")} Operation cancelled`);
254
- }
255
- return null;
256
- },
257
- name: "overwriteChecker",
258
- },
259
- {
260
- type: () => (isValidPackageName(path.basename(targetDir || defaultProjectName)) ? null : "text"),
261
- name: "packageName",
262
- message: reset("Package name:"),
263
- initial: () => toValidPackageName(path.basename(targetDir || defaultProjectName)),
264
- validate: (value) => isValidPackageName(value) || "Invalid package.json name",
265
- },
266
- {
267
- type: selectedTemplate ? null : "select",
268
- name: "templateId",
269
- message: reset("Select a template:"),
270
- choices: TEMPLATE_DEFINITIONS.map((template) => ({
271
- title: template.title,
272
- description: template.description,
273
- value: template.id,
274
- })),
275
- },
276
- {
277
- type: typeof argv.examples === "boolean" ? null : "toggle",
278
- name: "includeExamples",
279
- message: reset("Include examples?"),
280
- initial: true,
281
- active: "Yes",
282
- inactive: "No",
283
- },
284
- ],
285
- {
286
- onCancel: () => {
287
- throw new Error(`${red("x")} Operation cancelled`);
288
- },
289
- }
290
- );
291
- } catch (error) {
292
- console.log(error.message);
293
- return undefined;
294
- }
295
- }
296
-
297
- async function initNatty() {
298
- const promptResult = await resolveProjectOptions();
299
- if (!promptResult) {
300
- return;
301
- }
302
-
303
- const targetDir = (promptResult.projectName || argv._[0] || "").trim() || "nattyjs-project";
304
- const template = getTemplateById(promptResult.templateId || argv.template) || TEMPLATE_DEFINITIONS[0];
305
- const includeExamples = typeof argv.examples === "boolean" ? argv.examples : promptResult.includeExamples !== false;
306
- const root = path.join(cwd, targetDir);
307
-
308
- if (promptResult.overwrite) {
309
- emptyDir(root);
310
- } else if (!fs.existsSync(root)) {
311
- fs.mkdirSync(root, { recursive: true });
312
- }
313
-
314
- const __filename = fileURLToPath(import.meta.url);
315
- const __dirname = path.dirname(__filename);
316
- const templateDir = path.join(__dirname, template.templateDir);
317
-
318
- console.log(`\nScaffolding project in ${root}...`);
319
-
320
- copyTemplateContents(templateDir, root, template, includeExamples);
321
-
322
- const packageJsonPath = path.join(templateDir, "package.json");
323
- const pkg = readJson(packageJsonPath);
324
- const packageName = promptResult.packageName || toValidPackageName(path.basename(targetDir));
325
- pkg.name = packageName;
326
- fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkg, null, 2));
327
-
328
- const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);
329
- const pkgManager = pkgInfo ? pkgInfo.name : "npm";
330
-
331
- console.log("\nDone. Now run:\n");
332
- if (root !== cwd) {
333
- console.log(` cd ${path.relative(cwd, root)}`);
334
- }
335
-
336
- if (pkgManager === "yarn") {
337
- console.log(" yarn");
338
- console.log(" yarn dev");
339
- } else {
340
- console.log(` ${pkgManager} install`);
341
- console.log(` ${pkgManager} run dev`);
342
- }
343
-
344
- console.log();
345
- }
346
-
347
- initNatty().catch((error) => {
348
- console.error(error);
349
- });
1
+ #!/usr/bin/env node
2
+ import path from "path";
3
+ import minimist from "minimist";
4
+ import prompts from "prompts";
5
+ import { fileURLToPath } from "url";
6
+ import { getTemplateById, TEMPLATE_DEFINITIONS } from "./src/const/template-definitions.js";
7
+ import { printIntro, formatSuccessSummary } from "./src/functions/cli-theme.js";
8
+ import { pkgFromUserAgent } from "./src/functions/package-manager.js";
9
+ import { toValidPackageName } from "./src/functions/package-name.js";
10
+ import { resolveProjectOptions } from "./src/functions/prompt-project-options.js";
11
+ import { prepareTargetDirectory, scaffoldProject } from "./src/functions/scaffold-project.js";
12
+ import { getWorkspaceById, isFullstackTemplate } from "./src/const/workspace-definitions.js";
13
+
14
+ const argv = minimist(process.argv.slice(2), {
15
+ string: ["template", "workspace"],
16
+ boolean: ["examples"],
17
+ alias: {
18
+ t: "template",
19
+ e: "examples",
20
+ w: "workspace",
21
+ },
22
+ });
23
+ const rawArguments = process.argv.slice(2);
24
+ const examplesFlagProvided = rawArguments.some((argument) => {
25
+ return argument === "--examples" || argument === "--no-examples" || argument === "-e";
26
+ });
27
+
28
+ const cwd = process.cwd();
29
+
30
+ if (process.env.NATTYJS_PROMPT_INJECT) {
31
+ prompts.inject(JSON.parse(process.env.NATTYJS_PROMPT_INJECT));
32
+ }
33
+
34
+ async function initNatty() {
35
+ printIntro();
36
+ const selectedTemplate = getTemplateById(argv.template);
37
+ const defaultProjectName =
38
+ (typeof argv._[0] === "string" ? argv._[0].trim() : "") || "nattyjs-project";
39
+ const promptResult = await resolveProjectOptions({
40
+ argv,
41
+ defaultProjectName,
42
+ selectedTemplate,
43
+ templateDefinitions: TEMPLATE_DEFINITIONS,
44
+ examplesFlagProvided,
45
+ });
46
+ if (!promptResult) {
47
+ return;
48
+ }
49
+
50
+ const targetDir = (promptResult.projectName || argv._[0] || "").trim() || "nattyjs-project";
51
+ const template = getTemplateById(promptResult.templateId || argv.template) || TEMPLATE_DEFINITIONS[0];
52
+ const isFullstack = isFullstackTemplate(template);
53
+ const workspaceSetup = (promptResult.workspaceSetup || argv.workspace || "pnpm-only").trim();
54
+ const selectedWorkspace = isFullstack ? getWorkspaceById(workspaceSetup) || getWorkspaceById("pnpm-only") : undefined;
55
+ const includeExamples = examplesFlagProvided ? argv.examples : promptResult.includeExamples !== false;
56
+ const root = path.join(cwd, targetDir);
57
+
58
+ prepareTargetDirectory(root, promptResult.overwrite);
59
+
60
+ const __filename = fileURLToPath(import.meta.url);
61
+ const __dirname = path.dirname(__filename);
62
+
63
+ console.log(`\nScaffolding project in ${root}...`);
64
+
65
+ const packageName = promptResult.packageName || toValidPackageName(path.basename(targetDir));
66
+ scaffoldProject({
67
+ cwd,
68
+ root,
69
+ targetDir,
70
+ template,
71
+ includeExamples,
72
+ packageName,
73
+ packageBaseDir: __dirname,
74
+ workspaceSetup: selectedWorkspace?.id,
75
+ isFullstack,
76
+ });
77
+
78
+ const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);
79
+ const pkgManager = pkgInfo ? pkgInfo.name : "npm";
80
+ formatSuccessSummary({
81
+ cwd,
82
+ root,
83
+ packageManager: pkgManager,
84
+ isFullstack,
85
+ template,
86
+ workspace: selectedWorkspace,
87
+ includeExamples,
88
+ });
89
+ }
90
+
91
+ initNatty().catch((error) => {
92
+ console.error(error);
93
+ });
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "create-nattyjs",
3
- "version": "0.0.1-beta.68",
3
+ "version": "0.0.1-beta.70",
4
4
  "description": "Create NattyJS API Project",
5
5
  "main": "./index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "type": "module",
8
8
  "files": [
9
+ "src",
9
10
  "template-nattyjs-blank",
10
11
  "template-fullstack-vue",
11
12
  "template-fullstack-react",
@@ -16,7 +17,7 @@
16
17
  "template-fullstack-sveltekit"
17
18
  ],
18
19
  "scripts": {
19
- "test": "echo \"No tests defined\""
20
+ "test": "node --test test"
20
21
  },
21
22
  "author": "ajayojha",
22
23
  "license": "MIT",
@@ -0,0 +1,76 @@
1
+ export const TEMPLATE_DEFINITIONS = [
2
+ {
3
+ id: "api-only",
4
+ aliases: ["nattyjs-blank"],
5
+ title: "API Only",
6
+ description: "Backend API starter with NattyJS conventions",
7
+ templateDir: "template-nattyjs-blank",
8
+ exampleExcludedPaths: ["controllers"],
9
+ },
10
+ {
11
+ id: "fullstack-vue",
12
+ aliases: ["vue", "nattyjs-vue"],
13
+ title: "Fullstack + Vue",
14
+ description: "NattyJS API + Vue (Vite) + typed client",
15
+ templateDir: "template-fullstack-vue",
16
+ exampleOverlayDir: "__examples",
17
+ },
18
+ {
19
+ id: "fullstack-react",
20
+ aliases: ["react", "nattyjs-react"],
21
+ title: "Fullstack + React",
22
+ description: "NattyJS API + React (Vite) + typed client",
23
+ templateDir: "template-fullstack-react",
24
+ exampleOverlayDir: "__examples",
25
+ },
26
+ {
27
+ id: "fullstack-next",
28
+ aliases: ["next", "nextjs", "nattyjs-next"],
29
+ title: "Fullstack + Next.js",
30
+ description: "NattyJS API + Next.js + typed client",
31
+ templateDir: "template-fullstack-next",
32
+ exampleOverlayDir: "__examples",
33
+ },
34
+ {
35
+ id: "fullstack-nuxt",
36
+ aliases: ["nuxt", "nuxtjs", "nattyjs-nuxt"],
37
+ title: "Fullstack + Nuxt",
38
+ description: "NattyJS API + Nuxt + typed client",
39
+ templateDir: "template-fullstack-nuxt",
40
+ exampleOverlayDir: "__examples",
41
+ },
42
+ {
43
+ id: "fullstack-angular",
44
+ aliases: ["angular", "ng", "nattyjs-angular"],
45
+ title: "Fullstack + Angular",
46
+ description: "NattyJS API + Angular + typed client",
47
+ templateDir: "template-fullstack-angular",
48
+ exampleOverlayDir: "__examples",
49
+ },
50
+ {
51
+ id: "fullstack-astro",
52
+ aliases: ["astro", "nattyjs-astro"],
53
+ title: "Fullstack + Astro",
54
+ description: "NattyJS API + Astro + typed client",
55
+ templateDir: "template-fullstack-astro",
56
+ exampleOverlayDir: "__examples",
57
+ },
58
+ {
59
+ id: "fullstack-sveltekit",
60
+ aliases: ["sveltekit", "svelte-kit", "svelte", "nattyjs-sveltekit"],
61
+ title: "Fullstack + SvelteKit",
62
+ description: "NattyJS API + SvelteKit + typed client",
63
+ templateDir: "template-fullstack-sveltekit",
64
+ exampleOverlayDir: "__examples",
65
+ },
66
+ ];
67
+
68
+ export function getTemplateById(value) {
69
+ if (!value) {
70
+ return undefined;
71
+ }
72
+
73
+ return TEMPLATE_DEFINITIONS.find((template) => {
74
+ return template.id === value || template.aliases.includes(value);
75
+ });
76
+ }
@@ -0,0 +1,74 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ const FRONTEND_PACKAGE_VERSIONS = {
5
+ concurrently: "^9.0.1",
6
+ turbo: "^2.1.3",
7
+ pnpm: "9.15.0",
8
+ "@vitejs/plugin-vue": "^5.1.4",
9
+ "@vitejs/plugin-react": "^4.3.2",
10
+ vue: "^3.5.13",
11
+ "vue-tsc": "^2.1.6",
12
+ vite: "^5.4.8",
13
+ react: "^18.3.1",
14
+ "react-dom": "^18.3.1",
15
+ "@types/react": "^18.3.3",
16
+ "@types/react-dom": "^18.3.0",
17
+ next: "^14.2.15",
18
+ nuxt: "^3.13.2",
19
+ "@angular/animations": "^18.2.8",
20
+ "@angular/common": "^18.2.8",
21
+ "@angular/compiler": "^18.2.8",
22
+ "@angular/core": "^18.2.8",
23
+ "@angular/forms": "^18.2.8",
24
+ "@angular/platform-browser": "^18.2.8",
25
+ "@angular/platform-browser-dynamic": "^18.2.8",
26
+ "@angular/router": "^18.2.8",
27
+ "@angular-devkit/build-angular": "^18.2.8",
28
+ "@angular/cli": "^18.2.8",
29
+ "@angular/compiler-cli": "^18.2.8",
30
+ rxjs: "^7.8.1",
31
+ tslib: "^2.7.0",
32
+ "zone.js": "^0.14.10",
33
+ astro: "^4.16.12",
34
+ "@sveltejs/adapter-auto": "^3.2.5",
35
+ "@sveltejs/kit": "^2.7.1",
36
+ "@sveltejs/vite-plugin-svelte": "^3.1.2",
37
+ svelte: "^4.2.19",
38
+ "svelte-check": "^4.0.4",
39
+ typescript: "^5.6.3",
40
+ "@types/node": "^22.7.4",
41
+ "reflect-metadata": "^0.2.2",
42
+ mri: "^1.2.0",
43
+ prompts: "^2.4.2",
44
+ };
45
+
46
+ const NATTY_PACKAGE_NAMES = [
47
+ "@nattyjs/cli",
48
+ "@nattyjs/client",
49
+ "@nattyjs/common",
50
+ "@nattyjs/core",
51
+ "@nattyjs/entity",
52
+ "@nattyjs/express",
53
+ "@nattyjs/orm",
54
+ "@nattyjs/types",
55
+ "@nattyjs/validation-decorators",
56
+ ];
57
+
58
+ export function getVersionRegistry(packageBaseDir) {
59
+ const createPackageJsonPath = path.join(packageBaseDir, "package.json");
60
+ const createPackageJson = JSON.parse(fs.readFileSync(createPackageJsonPath, "utf8"));
61
+ const nattyVersion = createPackageJson.version;
62
+ const versions = {
63
+ ...FRONTEND_PACKAGE_VERSIONS,
64
+ };
65
+
66
+ for (const packageName of NATTY_PACKAGE_NAMES) {
67
+ versions[packageName] = nattyVersion;
68
+ }
69
+
70
+ return {
71
+ packageManager: `pnpm@${FRONTEND_PACKAGE_VERSIONS.pnpm}`,
72
+ versions,
73
+ };
74
+ }
@@ -0,0 +1,27 @@
1
+ export const WORKSPACE_DEFINITIONS = [
2
+ {
3
+ id: "turborepo",
4
+ title: "Turborepo",
5
+ description: "Fast caching, simple fullstack DX",
6
+ recommended: true,
7
+ },
8
+ {
9
+ id: "pnpm-only",
10
+ title: "pnpm workspaces only",
11
+ description: "Minimal workspace setup",
12
+ },
13
+ ];
14
+
15
+ const FULLSTACK_TEMPLATE_PREFIX = "fullstack-";
16
+
17
+ export function isFullstackTemplate(template) {
18
+ return Boolean(template?.id?.startsWith(FULLSTACK_TEMPLATE_PREFIX));
19
+ }
20
+
21
+ export function getWorkspaceById(value) {
22
+ if (!value) {
23
+ return undefined;
24
+ }
25
+
26
+ return WORKSPACE_DEFINITIONS.find((workspace) => workspace.id === value);
27
+ }