create-nattyjs 0.0.1-beta.69 → 0.0.1-beta.71
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/index.js +92 -349
- package/package.json +4 -3
- package/src/const/template-definitions.js +76 -0
- package/src/const/version-registry.js +73 -0
- package/src/const/workspace-definitions.js +55 -0
- package/src/functions/cli-theme.js +81 -0
- package/src/functions/file-system.js +96 -0
- package/src/functions/package-manager.js +9 -0
- package/src/functions/package-name.js +12 -0
- package/src/functions/prompt-project-options.js +156 -0
- package/src/functions/render-package-jsons.js +98 -0
- package/src/functions/render-workspace.js +254 -0
- package/src/functions/scaffold-project.js +65 -0
- package/template-fullstack-angular/apps/api/package.json +8 -8
- package/template-fullstack-angular/apps/web/package.json +1 -1
- package/template-fullstack-astro/apps/api/package.json +8 -8
- package/template-fullstack-astro/apps/web/package.json +1 -1
- package/template-fullstack-next/apps/api/package.json +8 -8
- package/template-fullstack-next/apps/web/package.json +1 -1
- package/template-fullstack-nuxt/apps/api/package.json +8 -8
- package/template-fullstack-nuxt/apps/web/package.json +1 -1
- package/template-fullstack-react/apps/api/package.json +8 -8
- package/template-fullstack-react/apps/web/package.json +1 -1
- package/template-fullstack-sveltekit/apps/api/package.json +8 -8
- package/template-fullstack-sveltekit/apps/web/package.json +1 -1
- package/template-fullstack-vue/apps/api/package.json +8 -8
- package/template-fullstack-vue/apps/web/package.json +1 -1
- package/template-nattyjs-blank/package.json +8 -8
package/index.js
CHANGED
|
@@ -1,349 +1,92 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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 || "standalone").trim();
|
|
54
|
+
const selectedWorkspace = isFullstack ? getWorkspaceById(workspaceSetup) || getWorkspaceById("standalone") : 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
|
+
template,
|
|
85
|
+
workspace: selectedWorkspace,
|
|
86
|
+
includeExamples,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
initNatty().catch((error) => {
|
|
91
|
+
console.error(error);
|
|
92
|
+
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nattyjs",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.71",
|
|
4
4
|
"description": "Create NattyJS API Project",
|
|
5
5
|
"main": "./index.js",
|
|
6
|
-
"types": "./dist/index.d.ts",
|
|
7
6
|
"type": "module",
|
|
8
7
|
"files": [
|
|
8
|
+
"index.js",
|
|
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": "
|
|
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,73 @@
|
|
|
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
|
+
nx: "^20.0.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
|
+
versions,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const PROJECT_LAYOUT_DEFINITIONS = [
|
|
2
|
+
{
|
|
3
|
+
id: "standalone",
|
|
4
|
+
title: "Single Repo",
|
|
5
|
+
description: "api/ + web/ folders with the simplest dev flow",
|
|
6
|
+
recommended: true,
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: "monorepo",
|
|
10
|
+
title: "Monorepo",
|
|
11
|
+
description: "apps/api + apps/web with a dedicated workspace tool",
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const WORKSPACE_DEFINITIONS = [
|
|
16
|
+
{
|
|
17
|
+
id: "standalone",
|
|
18
|
+
title: "Single Repo",
|
|
19
|
+
description: "api/ + web/ folders with no workspace tool",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "npm-workspaces",
|
|
23
|
+
title: "npm workspaces",
|
|
24
|
+
description: "Simple npm-native monorepo",
|
|
25
|
+
recommended: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "turborepo",
|
|
29
|
+
title: "Turborepo",
|
|
30
|
+
description: "Fast task orchestration and caching",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "nx",
|
|
34
|
+
title: "Nx",
|
|
35
|
+
description: "Structured workspace tooling and task graph",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export const MONOREPO_WORKSPACE_DEFINITIONS = WORKSPACE_DEFINITIONS.filter((workspace) => {
|
|
40
|
+
return workspace.id !== "standalone";
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const FULLSTACK_TEMPLATE_PREFIX = "fullstack-";
|
|
44
|
+
|
|
45
|
+
export function isFullstackTemplate(template) {
|
|
46
|
+
return Boolean(template?.id?.startsWith(FULLSTACK_TEMPLATE_PREFIX));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getWorkspaceById(value) {
|
|
50
|
+
if (!value) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return WORKSPACE_DEFINITIONS.find((workspace) => workspace.id === value);
|
|
55
|
+
}
|