create-sprint 0.0.7 → 0.0.32
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/dist/generators.js +119 -38
- package/dist/index.js +38 -37
- package/dist/validators.js +7 -12
- package/package.json +4 -3
- package/src/cli.ts +1 -1
- package/src/generators.ts +123 -38
- package/src/index.ts +44 -58
- package/src/validators.ts +10 -21
package/dist/generators.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
export function getTypeScriptPackageJson(name, telemetry) {
|
|
2
2
|
const deps = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
3
|
+
"sprint-es": "^0.0.29",
|
|
4
4
|
dotenv: "^17.0.0",
|
|
5
5
|
};
|
|
6
6
|
const devDeps = {
|
|
7
7
|
"@types/node": "^22.0.0",
|
|
8
8
|
"tsx": "^4.19.0",
|
|
9
9
|
typescript: "^5.6.0",
|
|
10
|
-
vite: "^6.0.0",
|
|
11
10
|
};
|
|
12
11
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
13
12
|
deps["@sentry/node"] = "^8.0.0";
|
|
@@ -21,9 +20,9 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
21
20
|
description: "Sprint API",
|
|
22
21
|
main: "dist/index.js",
|
|
23
22
|
scripts: {
|
|
24
|
-
build: "
|
|
25
|
-
start: "
|
|
26
|
-
dev: "
|
|
23
|
+
build: "sprint-es build",
|
|
24
|
+
start: "sprint-es start",
|
|
25
|
+
dev: "sprint-es dev",
|
|
27
26
|
},
|
|
28
27
|
dependencies: deps,
|
|
29
28
|
devDependencies: devDeps,
|
|
@@ -31,7 +30,7 @@ export function getTypeScriptPackageJson(name, telemetry) {
|
|
|
31
30
|
}
|
|
32
31
|
export function getJavaScriptPackageJson(name, telemetry) {
|
|
33
32
|
const deps = {
|
|
34
|
-
"sprint-es": "^0.0.
|
|
33
|
+
"sprint-es": "^0.0.29",
|
|
35
34
|
dotenv: "^17.0.0",
|
|
36
35
|
};
|
|
37
36
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -47,8 +46,9 @@ export function getJavaScriptPackageJson(name, telemetry) {
|
|
|
47
46
|
main: "src/index.js",
|
|
48
47
|
type: "module",
|
|
49
48
|
scripts: {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
build: "sprint-es build",
|
|
50
|
+
start: "sprint-es start",
|
|
51
|
+
dev: "sprint-es dev",
|
|
52
52
|
},
|
|
53
53
|
dependencies: deps,
|
|
54
54
|
};
|
|
@@ -71,6 +71,10 @@ export function getTsConfig() {
|
|
|
71
71
|
declarationMap: true,
|
|
72
72
|
sourceMap: true,
|
|
73
73
|
tabWidth: 4,
|
|
74
|
+
baseUrl: ".",
|
|
75
|
+
paths: {
|
|
76
|
+
"@/*": ["./src/*"]
|
|
77
|
+
}
|
|
74
78
|
},
|
|
75
79
|
include: ["src/**/*"],
|
|
76
80
|
exclude: ["node_modules", "dist"],
|
|
@@ -104,43 +108,35 @@ export default defineConfig({
|
|
|
104
108
|
export function getMainFile(language) {
|
|
105
109
|
if (language === "typescript") {
|
|
106
110
|
return `import Sprint from "sprint-es";
|
|
107
|
-
import { config } from "./sprint.config";
|
|
108
111
|
|
|
109
|
-
const app = new Sprint(
|
|
112
|
+
const app = new Sprint();
|
|
110
113
|
`;
|
|
111
114
|
}
|
|
112
115
|
return `import Sprint from "sprint-es";
|
|
113
|
-
import { config } from "./sprint.config.js";
|
|
114
116
|
|
|
115
|
-
const app = new Sprint(
|
|
117
|
+
const app = new Sprint();
|
|
116
118
|
`;
|
|
117
119
|
}
|
|
118
120
|
export function getHomeRoute(language) {
|
|
119
121
|
if (language === "typescript") {
|
|
120
122
|
return `import { Router } from "sprint-es";
|
|
123
|
+
import { homeSchema } from "@/schemas/home";
|
|
124
|
+
import { homeController } from "@/controllers/home";
|
|
121
125
|
|
|
122
126
|
const router = Router();
|
|
123
127
|
|
|
124
|
-
router.get("/",
|
|
125
|
-
res.json({
|
|
126
|
-
message: "Hello World",
|
|
127
|
-
status: "ok"
|
|
128
|
-
});
|
|
129
|
-
});
|
|
128
|
+
router.get("/", homeSchema, homeController);
|
|
130
129
|
|
|
131
130
|
export default router;
|
|
132
131
|
`;
|
|
133
132
|
}
|
|
134
133
|
return `import { Router } from "sprint-es";
|
|
134
|
+
import { homeSchema } from "../schemas/home.js";
|
|
135
|
+
import { homeController } from "../controllers/home.js";
|
|
135
136
|
|
|
136
137
|
const router = Router();
|
|
137
138
|
|
|
138
|
-
router.get("/",
|
|
139
|
-
res.json({
|
|
140
|
-
message: "Hello World",
|
|
141
|
-
status: "ok"
|
|
142
|
-
});
|
|
143
|
-
});
|
|
139
|
+
router.get("/", homeSchema, homeController);
|
|
144
140
|
|
|
145
141
|
export default router;
|
|
146
142
|
`;
|
|
@@ -148,49 +144,129 @@ export default router;
|
|
|
148
144
|
export function getAdminRoute(language) {
|
|
149
145
|
if (language === "typescript") {
|
|
150
146
|
return `import { Router } from "sprint-es";
|
|
147
|
+
import { adminSchema } from "@/schemas/admin";
|
|
148
|
+
import { adminController, adminUsersController } from "@/controllers/admin";
|
|
149
|
+
|
|
150
|
+
const router = Router();
|
|
151
|
+
|
|
152
|
+
router.get("/", adminSchema, adminController);
|
|
153
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
154
|
+
|
|
155
|
+
export default router;
|
|
156
|
+
`;
|
|
157
|
+
}
|
|
158
|
+
return `import { Router } from "sprint-es";
|
|
159
|
+
import { adminSchema } from "../schemas/admin.js";
|
|
160
|
+
import { adminController, adminUsersController } from "../controllers/admin.js";
|
|
151
161
|
|
|
152
162
|
const router = Router();
|
|
153
163
|
|
|
154
|
-
router.get("/",
|
|
164
|
+
router.get("/", adminSchema, adminController);
|
|
165
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
166
|
+
|
|
167
|
+
export default router;
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
export function getHomeController(language) {
|
|
171
|
+
if (language === "typescript") {
|
|
172
|
+
return `import { Handler } from "sprint-es";
|
|
173
|
+
|
|
174
|
+
export const homeController: Handler = (req, res) => {
|
|
175
|
+
res.json({
|
|
176
|
+
message: "Hello World",
|
|
177
|
+
status: "ok"
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
return `import { Handler } from "sprint-es";
|
|
183
|
+
|
|
184
|
+
export const homeController = (req, res) => {
|
|
185
|
+
res.json({
|
|
186
|
+
message: "Hello World",
|
|
187
|
+
status: "ok"
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
export function getAdminController(language) {
|
|
193
|
+
if (language === "typescript") {
|
|
194
|
+
return `import { Handler } from "sprint-es";
|
|
195
|
+
|
|
196
|
+
export const adminController: Handler = (req, res) => {
|
|
155
197
|
res.json({
|
|
156
198
|
message: "Admin Dashboard",
|
|
157
199
|
status: "ok"
|
|
158
200
|
});
|
|
159
|
-
}
|
|
201
|
+
};
|
|
160
202
|
|
|
161
|
-
|
|
203
|
+
export const adminUsersController: Handler = (req, res) => {
|
|
162
204
|
res.json({
|
|
163
205
|
users: [
|
|
164
206
|
{ id: 1, name: "John Doe", role: "admin" },
|
|
165
207
|
{ id: 2, name: "Jane Smith", role: "user" }
|
|
166
208
|
]
|
|
167
209
|
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export default router;
|
|
210
|
+
};
|
|
171
211
|
`;
|
|
172
212
|
}
|
|
173
|
-
return `import {
|
|
213
|
+
return `import { Handler } from "sprint-es";
|
|
174
214
|
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
router.get("/", (req, res) => {
|
|
215
|
+
export const adminController = (req, res) => {
|
|
178
216
|
res.json({
|
|
179
217
|
message: "Admin Dashboard",
|
|
180
218
|
status: "ok"
|
|
181
219
|
});
|
|
182
|
-
}
|
|
220
|
+
};
|
|
183
221
|
|
|
184
|
-
|
|
222
|
+
export const adminUsersController = (req, res) => {
|
|
185
223
|
res.json({
|
|
186
224
|
users: [
|
|
187
225
|
{ id: 1, name: "John Doe", role: "admin" },
|
|
188
226
|
{ id: 2, name: "Jane Smith", role: "user" }
|
|
189
227
|
]
|
|
190
228
|
});
|
|
191
|
-
}
|
|
229
|
+
};
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
export function getHomeSchema(language) {
|
|
233
|
+
if (language === "typescript") {
|
|
234
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
192
235
|
|
|
193
|
-
export
|
|
236
|
+
export const homeSchema = defineRouteSchema({});
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
240
|
+
|
|
241
|
+
export const homeSchema = defineRouteSchema({});
|
|
242
|
+
`;
|
|
243
|
+
}
|
|
244
|
+
export function getAdminSchema(language) {
|
|
245
|
+
if (language === "typescript") {
|
|
246
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
247
|
+
|
|
248
|
+
export const adminSchema = defineRouteSchema({
|
|
249
|
+
queryParams: z.object({
|
|
250
|
+
id: z.string().uuid()
|
|
251
|
+
}),
|
|
252
|
+
body: z.object({
|
|
253
|
+
name: z.string().min(1),
|
|
254
|
+
email: z.email().optional()
|
|
255
|
+
})
|
|
256
|
+
});
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
260
|
+
|
|
261
|
+
export const adminSchema = defineRouteSchema({
|
|
262
|
+
queryParams: z.object({
|
|
263
|
+
id: z.string().uuid()
|
|
264
|
+
}),
|
|
265
|
+
body: z.object({
|
|
266
|
+
name: z.string().min(1),
|
|
267
|
+
email: z.email().optional()
|
|
268
|
+
})
|
|
269
|
+
});
|
|
194
270
|
`;
|
|
195
271
|
}
|
|
196
272
|
export function getAuthMiddleware(language) {
|
|
@@ -358,6 +434,11 @@ export const config: SprintOptions = {
|
|
|
358
434
|
port: process.env.PORT ? parseInt(process.env.PORT) : 3000
|
|
359
435
|
};
|
|
360
436
|
|
|
437
|
+
// Add Vite config here if needed
|
|
438
|
+
// export const vite = {
|
|
439
|
+
// build: { ... }
|
|
440
|
+
// };
|
|
441
|
+
|
|
361
442
|
`;
|
|
362
443
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
363
444
|
config += `import { initTelemetry } from "sprint-es/telemetry";
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
7
|
-
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getAuthMiddleware, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile,
|
|
7
|
+
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction } from "./generators.js";
|
|
8
8
|
export async function runCLI(args) {
|
|
9
9
|
const options = parseArgs(args);
|
|
10
10
|
console.log("\n🚀 Welcome to Sprint - Quickly API Framework\n");
|
|
@@ -30,7 +30,7 @@ export async function runCLI(args) {
|
|
|
30
30
|
if (options.skipInstall) {
|
|
31
31
|
installDeps = false;
|
|
32
32
|
}
|
|
33
|
-
else
|
|
33
|
+
else {
|
|
34
34
|
installDeps = await confirm({
|
|
35
35
|
message: "Do you want to install dependencies now?",
|
|
36
36
|
default: true,
|
|
@@ -61,41 +61,39 @@ function parseArgs(args) {
|
|
|
61
61
|
const hasJs = args.includes("--js") || args.includes("--javascript");
|
|
62
62
|
const hasName = args.indexOf("--name");
|
|
63
63
|
const telemetryArg = args.includes("--telemetry") ? args[args.indexOf("--telemetry") + 1] : null;
|
|
64
|
-
if (args.includes("--yes") || args.includes("-y"))
|
|
64
|
+
if (args.includes("--yes") || args.includes("-y"))
|
|
65
65
|
options.skipPrompts = true;
|
|
66
|
+
if (!options.skipPrompts) {
|
|
67
|
+
if (hasTs)
|
|
68
|
+
options.language = "typescript";
|
|
69
|
+
else if (hasJs)
|
|
70
|
+
options.language = "javascript";
|
|
66
71
|
}
|
|
67
|
-
|
|
72
|
+
else
|
|
68
73
|
options.language = "typescript";
|
|
69
|
-
|
|
70
|
-
else if (hasJs) {
|
|
71
|
-
options.language = "javascript";
|
|
72
|
-
}
|
|
73
|
-
if (hasName !== -1 && args[hasName + 1]) {
|
|
74
|
+
if (hasName !== -1 && args[hasName + 1])
|
|
74
75
|
options.projectName = args[hasName + 1];
|
|
75
|
-
|
|
76
|
-
if (args.includes("--current")) {
|
|
76
|
+
if (args.includes("--current"))
|
|
77
77
|
options.projectName = ".";
|
|
78
|
-
|
|
79
|
-
if (args.includes("--docker")) {
|
|
78
|
+
if (args.includes("--docker"))
|
|
80
79
|
options.docker = true;
|
|
81
|
-
|
|
82
|
-
if (args.includes("--no-install")) {
|
|
80
|
+
if (args.includes("--no-install"))
|
|
83
81
|
options.skipInstall = true;
|
|
84
|
-
|
|
85
|
-
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) {
|
|
82
|
+
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg))
|
|
86
83
|
options.telemetry = telemetryArg;
|
|
87
|
-
}
|
|
88
84
|
return options;
|
|
89
85
|
}
|
|
86
|
+
;
|
|
90
87
|
async function getProjectName() {
|
|
91
88
|
const name = await input({
|
|
92
89
|
message: "Enter project name:",
|
|
93
90
|
validate: (value) => {
|
|
94
91
|
return validateProjectName(value) || true;
|
|
95
|
-
}
|
|
92
|
+
}
|
|
96
93
|
});
|
|
97
94
|
return name;
|
|
98
95
|
}
|
|
96
|
+
;
|
|
99
97
|
async function selectLanguage() {
|
|
100
98
|
const language = await select({
|
|
101
99
|
message: "Select your preferred language:",
|
|
@@ -109,11 +107,12 @@ async function selectLanguage() {
|
|
|
109
107
|
name: "JavaScript",
|
|
110
108
|
value: "javascript",
|
|
111
109
|
description: "Vanilla JavaScript for simpler projects",
|
|
112
|
-
}
|
|
113
|
-
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
114
112
|
});
|
|
115
113
|
return language;
|
|
116
114
|
}
|
|
115
|
+
;
|
|
117
116
|
async function selectTelemetry() {
|
|
118
117
|
const telemetry = await select({
|
|
119
118
|
message: "Select error tracking/telemetry solution:",
|
|
@@ -137,11 +136,12 @@ async function selectTelemetry() {
|
|
|
137
136
|
name: "Discord Webhook",
|
|
138
137
|
value: "discord",
|
|
139
138
|
description: "Send error notifications to Discord channel",
|
|
140
|
-
}
|
|
141
|
-
]
|
|
139
|
+
}
|
|
140
|
+
]
|
|
142
141
|
});
|
|
143
142
|
return telemetry;
|
|
144
143
|
}
|
|
144
|
+
;
|
|
145
145
|
async function createProject(projectName, language, telemetryArg, useDockerArg) {
|
|
146
146
|
const isCurrentDir = projectName === ".";
|
|
147
147
|
const targetDir = isCurrentDir ? process.cwd() : join(process.cwd(), projectName);
|
|
@@ -149,13 +149,11 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
149
149
|
console.error(`Error: Directory ${projectName} already exists`);
|
|
150
150
|
process.exit(1);
|
|
151
151
|
}
|
|
152
|
-
if (!isCurrentDir)
|
|
152
|
+
if (!isCurrentDir)
|
|
153
153
|
await mkdir(targetDir, { recursive: true });
|
|
154
|
-
}
|
|
155
154
|
let telemetry = telemetryArg || "none";
|
|
156
|
-
if (!telemetryArg)
|
|
155
|
+
if (!telemetryArg)
|
|
157
156
|
telemetry = await selectTelemetry();
|
|
158
|
-
}
|
|
159
157
|
let useDocker = useDockerArg || false;
|
|
160
158
|
if (!useDockerArg) {
|
|
161
159
|
useDocker = await confirm({
|
|
@@ -164,35 +162,37 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
164
162
|
});
|
|
165
163
|
}
|
|
166
164
|
let pkgJson;
|
|
167
|
-
if (language === "typescript")
|
|
165
|
+
if (language === "typescript")
|
|
168
166
|
pkgJson = getTypeScriptPackageJson(projectName, telemetry);
|
|
169
|
-
|
|
170
|
-
else {
|
|
167
|
+
else
|
|
171
168
|
pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
172
|
-
}
|
|
173
169
|
await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
174
170
|
if (language === "typescript") {
|
|
175
171
|
await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
|
|
176
172
|
await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
|
|
177
173
|
await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry));
|
|
178
174
|
}
|
|
179
|
-
else
|
|
175
|
+
else
|
|
180
176
|
await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry));
|
|
181
|
-
}
|
|
182
177
|
const srcDir = join(targetDir, "src");
|
|
183
178
|
await mkdir(srcDir, { recursive: true });
|
|
184
179
|
await mkdir(join(srcDir, "middlewares"), { recursive: true });
|
|
185
180
|
await mkdir(join(srcDir, "routes"), { recursive: true });
|
|
186
181
|
await mkdir(join(srcDir, "controllers"), { recursive: true });
|
|
182
|
+
await mkdir(join(srcDir, "schemas"), { recursive: true });
|
|
187
183
|
await writeFile(join(srcDir, "middlewares", ".gitkeep"), "");
|
|
188
|
-
await writeFile(join(srcDir, "controllers", ".gitkeep"), "");
|
|
189
184
|
await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
|
|
190
185
|
await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
|
|
191
186
|
await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
|
|
187
|
+
await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
|
|
188
|
+
await writeFile(join(srcDir, "controllers", "admin." + (language === "typescript" ? "ts" : "js")), getAdminController(language));
|
|
192
189
|
await writeFile(join(srcDir, "middlewares", "auth." + (language === "typescript" ? "ts" : "js")), getAuthMiddleware(language));
|
|
193
|
-
await writeFile(join(
|
|
194
|
-
await writeFile(join(
|
|
195
|
-
await writeFile(join(targetDir, ".env.
|
|
190
|
+
await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
|
|
191
|
+
await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
|
|
192
|
+
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
193
|
+
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
194
|
+
await writeFile(join(targetDir, ".env.development"), "");
|
|
195
|
+
await writeFile(join(targetDir, ".env.production"), "");
|
|
196
196
|
await writeFile(join(targetDir, ".gitignore"), getGitignore());
|
|
197
197
|
if (useDocker) {
|
|
198
198
|
await writeFile(join(targetDir, "Dockerfile"), getDockerfile(language));
|
|
@@ -200,3 +200,4 @@ async function createProject(projectName, language, telemetryArg, useDockerArg)
|
|
|
200
200
|
await writeFile(join(targetDir, ".dockerignore"), getDockerIgnore());
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
+
;
|
package/dist/validators.js
CHANGED
|
@@ -2,24 +2,19 @@ export function validateProjectName(name) {
|
|
|
2
2
|
if (!name.trim())
|
|
3
3
|
return "Please enter a project name";
|
|
4
4
|
const n = name.trim();
|
|
5
|
-
if (n !== n.toLowerCase())
|
|
5
|
+
if (n !== n.toLowerCase())
|
|
6
6
|
return "Project name must be lowercase";
|
|
7
|
-
|
|
8
|
-
if (n.length > 214) {
|
|
7
|
+
if (n.length > 214)
|
|
9
8
|
return "Project name must be less than 214 characters";
|
|
10
|
-
|
|
11
|
-
if (n.startsWith("-") || n.startsWith(".")) {
|
|
9
|
+
if (n.startsWith("-") || n.startsWith("."))
|
|
12
10
|
return "Project name cannot start with - or .";
|
|
13
|
-
}
|
|
14
|
-
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n)) {
|
|
11
|
+
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n))
|
|
15
12
|
return "Project name cannot contain special characters (only letters, numbers, - and _)";
|
|
16
|
-
|
|
17
|
-
if (n !== encodeURIComponent(n)) {
|
|
13
|
+
if (n !== encodeURIComponent(n))
|
|
18
14
|
return "Project name must be URL-safe";
|
|
19
|
-
}
|
|
20
15
|
const reserved = ["node_modules", "favicon.ico"];
|
|
21
|
-
if (reserved.includes(n.toLowerCase()))
|
|
16
|
+
if (reserved.includes(n.toLowerCase()))
|
|
22
17
|
return `Cannot use "${n}" as project name`;
|
|
23
|
-
}
|
|
24
18
|
return null;
|
|
25
19
|
}
|
|
20
|
+
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-sprint",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "Create a new Sprint API project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc && node -e \"const fs=require('fs');const p='dist/cli.js';let c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c)}\"",
|
|
16
|
-
"prepublishOnly": "npm run build",
|
|
16
|
+
"prepublishOnly": "npm version patch && npm run build",
|
|
17
17
|
"start": "node dist/cli.js"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
@@ -29,10 +29,11 @@
|
|
|
29
29
|
"@inquirer/prompts": "^7.10.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.3.3",
|
|
32
33
|
"tsx": "^4.19.0",
|
|
33
34
|
"typescript": "^5.9.3"
|
|
34
35
|
},
|
|
35
36
|
"engines": {
|
|
36
37
|
"node": ">=18.0.0"
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
}
|
package/src/cli.ts
CHANGED
package/src/generators.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
2
2
|
const deps: Record<string, string> = {
|
|
3
|
-
"sprint-es": "^0.0.
|
|
3
|
+
"sprint-es": "^0.0.29",
|
|
4
4
|
dotenv: "^17.0.0",
|
|
5
5
|
};
|
|
6
6
|
|
|
@@ -8,7 +8,6 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
8
8
|
"@types/node": "^22.0.0",
|
|
9
9
|
"tsx": "^4.19.0",
|
|
10
10
|
typescript: "^5.6.0",
|
|
11
|
-
vite: "^6.0.0",
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
|
@@ -23,9 +22,9 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
23
22
|
description: "Sprint API",
|
|
24
23
|
main: "dist/index.js",
|
|
25
24
|
scripts: {
|
|
26
|
-
build: "
|
|
27
|
-
start: "
|
|
28
|
-
dev: "
|
|
25
|
+
build: "sprint-es build",
|
|
26
|
+
start: "sprint-es start",
|
|
27
|
+
dev: "sprint-es dev",
|
|
29
28
|
},
|
|
30
29
|
dependencies: deps,
|
|
31
30
|
devDependencies: devDeps,
|
|
@@ -34,7 +33,7 @@ export function getTypeScriptPackageJson(name: string, telemetry: string) {
|
|
|
34
33
|
|
|
35
34
|
export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
36
35
|
const deps: Record<string, string> = {
|
|
37
|
-
"sprint-es": "^0.0.
|
|
36
|
+
"sprint-es": "^0.0.29",
|
|
38
37
|
dotenv: "^17.0.0",
|
|
39
38
|
};
|
|
40
39
|
|
|
@@ -51,8 +50,9 @@ export function getJavaScriptPackageJson(name: string, telemetry: string) {
|
|
|
51
50
|
main: "src/index.js",
|
|
52
51
|
type: "module",
|
|
53
52
|
scripts: {
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
build: "sprint-es build",
|
|
54
|
+
start: "sprint-es start",
|
|
55
|
+
dev: "sprint-es dev",
|
|
56
56
|
},
|
|
57
57
|
dependencies: deps,
|
|
58
58
|
};
|
|
@@ -76,6 +76,10 @@ export function getTsConfig() {
|
|
|
76
76
|
declarationMap: true,
|
|
77
77
|
sourceMap: true,
|
|
78
78
|
tabWidth: 4,
|
|
79
|
+
baseUrl: ".",
|
|
80
|
+
paths: {
|
|
81
|
+
"@/*": ["./src/*"]
|
|
82
|
+
}
|
|
79
83
|
},
|
|
80
84
|
include: ["src/**/*"],
|
|
81
85
|
exclude: ["node_modules", "dist"],
|
|
@@ -111,45 +115,37 @@ export default defineConfig({
|
|
|
111
115
|
export function getMainFile(language: string) {
|
|
112
116
|
if (language === "typescript") {
|
|
113
117
|
return `import Sprint from "sprint-es";
|
|
114
|
-
import { config } from "./sprint.config";
|
|
115
118
|
|
|
116
|
-
const app = new Sprint(
|
|
119
|
+
const app = new Sprint();
|
|
117
120
|
`;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
return `import Sprint from "sprint-es";
|
|
121
|
-
import { config } from "./sprint.config.js";
|
|
122
124
|
|
|
123
|
-
const app = new Sprint(
|
|
125
|
+
const app = new Sprint();
|
|
124
126
|
`;
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
export function getHomeRoute(language: string) {
|
|
128
130
|
if (language === "typescript") {
|
|
129
131
|
return `import { Router } from "sprint-es";
|
|
132
|
+
import { homeSchema } from "@/schemas/home";
|
|
133
|
+
import { homeController } from "@/controllers/home";
|
|
130
134
|
|
|
131
135
|
const router = Router();
|
|
132
136
|
|
|
133
|
-
router.get("/",
|
|
134
|
-
res.json({
|
|
135
|
-
message: "Hello World",
|
|
136
|
-
status: "ok"
|
|
137
|
-
});
|
|
138
|
-
});
|
|
137
|
+
router.get("/", homeSchema, homeController);
|
|
139
138
|
|
|
140
139
|
export default router;
|
|
141
140
|
`;
|
|
142
141
|
}
|
|
143
142
|
return `import { Router } from "sprint-es";
|
|
143
|
+
import { homeSchema } from "../schemas/home.js";
|
|
144
|
+
import { homeController } from "../controllers/home.js";
|
|
144
145
|
|
|
145
146
|
const router = Router();
|
|
146
147
|
|
|
147
|
-
router.get("/",
|
|
148
|
-
res.json({
|
|
149
|
-
message: "Hello World",
|
|
150
|
-
status: "ok"
|
|
151
|
-
});
|
|
152
|
-
});
|
|
148
|
+
router.get("/", homeSchema, homeController);
|
|
153
149
|
|
|
154
150
|
export default router;
|
|
155
151
|
`;
|
|
@@ -158,49 +154,133 @@ export default router;
|
|
|
158
154
|
export function getAdminRoute(language: string) {
|
|
159
155
|
if (language === "typescript") {
|
|
160
156
|
return `import { Router } from "sprint-es";
|
|
157
|
+
import { adminSchema } from "@/schemas/admin";
|
|
158
|
+
import { adminController, adminUsersController } from "@/controllers/admin";
|
|
161
159
|
|
|
162
160
|
const router = Router();
|
|
163
161
|
|
|
164
|
-
router.get("/",
|
|
162
|
+
router.get("/", adminSchema, adminController);
|
|
163
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
164
|
+
|
|
165
|
+
export default router;
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
return `import { Router } from "sprint-es";
|
|
169
|
+
import { adminSchema } from "../schemas/admin.js";
|
|
170
|
+
import { adminController, adminUsersController } from "../controllers/admin.js";
|
|
171
|
+
|
|
172
|
+
const router = Router();
|
|
173
|
+
|
|
174
|
+
router.get("/", adminSchema, adminController);
|
|
175
|
+
router.get("/users", adminSchema, adminUsersController);
|
|
176
|
+
|
|
177
|
+
export default router;
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function getHomeController(language: string) {
|
|
182
|
+
if (language === "typescript") {
|
|
183
|
+
return `import { Handler } from "sprint-es";
|
|
184
|
+
|
|
185
|
+
export const homeController: Handler = (req, res) => {
|
|
186
|
+
res.json({
|
|
187
|
+
message: "Hello World",
|
|
188
|
+
status: "ok"
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
return `import { Handler } from "sprint-es";
|
|
194
|
+
|
|
195
|
+
export const homeController = (req, res) => {
|
|
196
|
+
res.json({
|
|
197
|
+
message: "Hello World",
|
|
198
|
+
status: "ok"
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function getAdminController(language: string) {
|
|
205
|
+
if (language === "typescript") {
|
|
206
|
+
return `import { Handler } from "sprint-es";
|
|
207
|
+
|
|
208
|
+
export const adminController: Handler = (req, res) => {
|
|
165
209
|
res.json({
|
|
166
210
|
message: "Admin Dashboard",
|
|
167
211
|
status: "ok"
|
|
168
212
|
});
|
|
169
|
-
}
|
|
213
|
+
};
|
|
170
214
|
|
|
171
|
-
|
|
215
|
+
export const adminUsersController: Handler = (req, res) => {
|
|
172
216
|
res.json({
|
|
173
217
|
users: [
|
|
174
218
|
{ id: 1, name: "John Doe", role: "admin" },
|
|
175
219
|
{ id: 2, name: "Jane Smith", role: "user" }
|
|
176
220
|
]
|
|
177
221
|
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export default router;
|
|
222
|
+
};
|
|
181
223
|
`;
|
|
182
224
|
}
|
|
183
|
-
return `import {
|
|
225
|
+
return `import { Handler } from "sprint-es";
|
|
184
226
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
router.get("/", (req, res) => {
|
|
227
|
+
export const adminController = (req, res) => {
|
|
188
228
|
res.json({
|
|
189
229
|
message: "Admin Dashboard",
|
|
190
230
|
status: "ok"
|
|
191
231
|
});
|
|
192
|
-
}
|
|
232
|
+
};
|
|
193
233
|
|
|
194
|
-
|
|
234
|
+
export const adminUsersController = (req, res) => {
|
|
195
235
|
res.json({
|
|
196
236
|
users: [
|
|
197
237
|
{ id: 1, name: "John Doe", role: "admin" },
|
|
198
238
|
{ id: 2, name: "Jane Smith", role: "user" }
|
|
199
239
|
]
|
|
200
240
|
});
|
|
201
|
-
}
|
|
241
|
+
};
|
|
242
|
+
`;
|
|
243
|
+
}
|
|
202
244
|
|
|
203
|
-
export
|
|
245
|
+
export function getHomeSchema(language: string) {
|
|
246
|
+
if (language === "typescript") {
|
|
247
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
248
|
+
|
|
249
|
+
export const homeSchema = defineRouteSchema({});
|
|
250
|
+
`;
|
|
251
|
+
}
|
|
252
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
253
|
+
|
|
254
|
+
export const homeSchema = defineRouteSchema({});
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function getAdminSchema(language: string) {
|
|
259
|
+
if (language === "typescript") {
|
|
260
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
261
|
+
|
|
262
|
+
export const adminSchema = defineRouteSchema({
|
|
263
|
+
queryParams: z.object({
|
|
264
|
+
id: z.string().uuid()
|
|
265
|
+
}),
|
|
266
|
+
body: z.object({
|
|
267
|
+
name: z.string().min(1),
|
|
268
|
+
email: z.email().optional()
|
|
269
|
+
})
|
|
270
|
+
});
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
return `import { z, defineRouteSchema } from "sprint-es/schemas";
|
|
274
|
+
|
|
275
|
+
export const adminSchema = defineRouteSchema({
|
|
276
|
+
queryParams: z.object({
|
|
277
|
+
id: z.string().uuid()
|
|
278
|
+
}),
|
|
279
|
+
body: z.object({
|
|
280
|
+
name: z.string().min(1),
|
|
281
|
+
email: z.email().optional()
|
|
282
|
+
})
|
|
283
|
+
});
|
|
204
284
|
`;
|
|
205
285
|
}
|
|
206
286
|
|
|
@@ -374,6 +454,11 @@ export const config: SprintOptions = {
|
|
|
374
454
|
port: process.env.PORT ? parseInt(process.env.PORT) : 3000
|
|
375
455
|
};
|
|
376
456
|
|
|
457
|
+
// Add Vite config here if needed
|
|
458
|
+
// export const vite = {
|
|
459
|
+
// build: { ... }
|
|
460
|
+
// };
|
|
461
|
+
|
|
377
462
|
`;
|
|
378
463
|
|
|
379
464
|
if (telemetry === "sentry" || telemetry === "glitchtip") {
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
6
6
|
import { validateProjectName } from "./validators.js";
|
|
7
|
-
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getAuthMiddleware, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile,
|
|
7
|
+
import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getViteConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction } from "./generators.js";
|
|
8
8
|
|
|
9
9
|
export interface CLIOptions {
|
|
10
10
|
projectName?: string;
|
|
@@ -48,7 +48,7 @@ export async function runCLI(args: string[]) {
|
|
|
48
48
|
let installDeps = true;
|
|
49
49
|
if (options.skipInstall) {
|
|
50
50
|
installDeps = false;
|
|
51
|
-
} else
|
|
51
|
+
} else {
|
|
52
52
|
installDeps = await confirm({
|
|
53
53
|
message: "Do you want to install dependencies now?",
|
|
54
54
|
default: true,
|
|
@@ -83,49 +83,36 @@ function parseArgs(args: string[]): CLIOptions {
|
|
|
83
83
|
const hasName = args.indexOf("--name");
|
|
84
84
|
const telemetryArg = args.includes("--telemetry") ? args[args.indexOf("--telemetry") + 1] : null;
|
|
85
85
|
|
|
86
|
-
if (args.includes("--yes") || args.includes("-y"))
|
|
87
|
-
options.skipPrompts = true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (hasTs) {
|
|
91
|
-
options.language = "typescript";
|
|
92
|
-
} else if (hasJs) {
|
|
93
|
-
options.language = "javascript";
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (hasName !== -1 && args[hasName + 1]) {
|
|
97
|
-
options.projectName = args[hasName + 1];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (args.includes("--current")) {
|
|
101
|
-
options.projectName = ".";
|
|
102
|
-
}
|
|
86
|
+
if (args.includes("--yes") || args.includes("-y")) options.skipPrompts = true;
|
|
103
87
|
|
|
104
|
-
if (
|
|
105
|
-
options.
|
|
106
|
-
|
|
88
|
+
if (!options.skipPrompts) {
|
|
89
|
+
if (hasTs) options.language = "typescript";
|
|
90
|
+
else if (hasJs) options.language = "javascript";
|
|
91
|
+
} else options.language = "typescript";
|
|
92
|
+
|
|
93
|
+
if (hasName !== -1 && args[hasName + 1]) options.projectName = args[hasName + 1];
|
|
107
94
|
|
|
108
|
-
if (args.includes("--
|
|
109
|
-
options.skipInstall = true;
|
|
110
|
-
}
|
|
95
|
+
if (args.includes("--current")) options.projectName = ".";
|
|
111
96
|
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
97
|
+
if (args.includes("--docker")) options.docker = true;
|
|
98
|
+
|
|
99
|
+
if (args.includes("--no-install")) options.skipInstall = true;
|
|
115
100
|
|
|
101
|
+
if (telemetryArg && ["sentry", "glitchtip", "discord", "none"].includes(telemetryArg)) options.telemetry = telemetryArg as CLIOptions["telemetry"];
|
|
102
|
+
|
|
116
103
|
return options;
|
|
117
|
-
}
|
|
104
|
+
};
|
|
118
105
|
|
|
119
106
|
async function getProjectName(): Promise<string> {
|
|
120
107
|
const name = await input({
|
|
121
108
|
message: "Enter project name:",
|
|
122
109
|
validate: (value) => {
|
|
123
110
|
return validateProjectName(value) || true;
|
|
124
|
-
}
|
|
111
|
+
}
|
|
125
112
|
});
|
|
126
113
|
|
|
127
114
|
return name;
|
|
128
|
-
}
|
|
115
|
+
};
|
|
129
116
|
|
|
130
117
|
async function selectLanguage(): Promise<"typescript" | "javascript"> {
|
|
131
118
|
const language = await select({
|
|
@@ -140,12 +127,12 @@ async function selectLanguage(): Promise<"typescript" | "javascript"> {
|
|
|
140
127
|
name: "JavaScript",
|
|
141
128
|
value: "javascript",
|
|
142
129
|
description: "Vanilla JavaScript for simpler projects",
|
|
143
|
-
}
|
|
144
|
-
]
|
|
130
|
+
}
|
|
131
|
+
]
|
|
145
132
|
});
|
|
146
133
|
|
|
147
134
|
return language as "typescript" | "javascript";
|
|
148
|
-
}
|
|
135
|
+
};
|
|
149
136
|
|
|
150
137
|
async function selectTelemetry(): Promise<"none" | "sentry" | "glitchtip" | "discord"> {
|
|
151
138
|
const telemetry = await select({
|
|
@@ -170,12 +157,12 @@ async function selectTelemetry(): Promise<"none" | "sentry" | "glitchtip" | "dis
|
|
|
170
157
|
name: "Discord Webhook",
|
|
171
158
|
value: "discord",
|
|
172
159
|
description: "Send error notifications to Discord channel",
|
|
173
|
-
}
|
|
174
|
-
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
175
162
|
});
|
|
176
163
|
|
|
177
164
|
return telemetry as "none" | "sentry" | "glitchtip" | "discord";
|
|
178
|
-
}
|
|
165
|
+
};
|
|
179
166
|
|
|
180
167
|
async function createProject(
|
|
181
168
|
projectName: string,
|
|
@@ -191,14 +178,10 @@ async function createProject(
|
|
|
191
178
|
process.exit(1);
|
|
192
179
|
}
|
|
193
180
|
|
|
194
|
-
if (!isCurrentDir) {
|
|
195
|
-
await mkdir(targetDir, { recursive: true });
|
|
196
|
-
}
|
|
181
|
+
if (!isCurrentDir) await mkdir(targetDir, { recursive: true });
|
|
197
182
|
|
|
198
183
|
let telemetry = telemetryArg || "none";
|
|
199
|
-
if (!telemetryArg)
|
|
200
|
-
telemetry = await selectTelemetry();
|
|
201
|
-
}
|
|
184
|
+
if (!telemetryArg) telemetry = await selectTelemetry();
|
|
202
185
|
|
|
203
186
|
let useDocker = useDockerArg || false;
|
|
204
187
|
if (!useDockerArg) {
|
|
@@ -209,42 +192,45 @@ async function createProject(
|
|
|
209
192
|
}
|
|
210
193
|
|
|
211
194
|
let pkgJson;
|
|
212
|
-
if (language === "typescript")
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
216
|
-
}
|
|
217
|
-
|
|
195
|
+
if (language === "typescript") pkgJson = getTypeScriptPackageJson(projectName, telemetry);
|
|
196
|
+
else pkgJson = getJavaScriptPackageJson(projectName, telemetry);
|
|
197
|
+
|
|
218
198
|
await writeFile(join(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
219
199
|
|
|
220
200
|
if (language === "typescript") {
|
|
221
201
|
await writeFile(join(targetDir, "tsconfig.json"), getTsConfig());
|
|
222
202
|
await writeFile(join(targetDir, "vite.config.ts"), getViteConfig());
|
|
223
203
|
await writeFile(join(targetDir, "sprint.config.ts"), getSprintConfigFile(language, telemetry));
|
|
224
|
-
} else
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
204
|
+
} else await writeFile(join(targetDir, "sprint.config.js"), getSprintConfigFile(language, telemetry));
|
|
205
|
+
|
|
228
206
|
const srcDir = join(targetDir, "src");
|
|
229
207
|
await mkdir(srcDir, { recursive: true });
|
|
230
208
|
|
|
231
209
|
await mkdir(join(srcDir, "middlewares"), { recursive: true });
|
|
232
210
|
await mkdir(join(srcDir, "routes"), { recursive: true });
|
|
233
211
|
await mkdir(join(srcDir, "controllers"), { recursive: true });
|
|
212
|
+
await mkdir(join(srcDir, "schemas"), { recursive: true });
|
|
234
213
|
|
|
235
214
|
await writeFile(join(srcDir, "middlewares", ".gitkeep"), "");
|
|
236
|
-
await writeFile(join(srcDir, "controllers", ".gitkeep"), "");
|
|
237
215
|
|
|
238
216
|
await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language));
|
|
239
217
|
|
|
240
218
|
await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
|
|
241
219
|
await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
|
|
242
220
|
|
|
221
|
+
await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
|
|
222
|
+
await writeFile(join(srcDir, "controllers", "admin." + (language === "typescript" ? "ts" : "js")), getAdminController(language));
|
|
223
|
+
|
|
243
224
|
await writeFile(join(srcDir, "middlewares", "auth." + (language === "typescript" ? "ts" : "js")), getAuthMiddleware(language));
|
|
244
225
|
|
|
245
|
-
await writeFile(join(
|
|
246
|
-
await writeFile(join(
|
|
247
|
-
|
|
226
|
+
await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
|
|
227
|
+
await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
|
|
228
|
+
|
|
229
|
+
await writeFile(join(targetDir, ".env.development.example"), getEnvDevelopment(telemetry));
|
|
230
|
+
await writeFile(join(targetDir, ".env.production.example"), getEnvProduction(telemetry));
|
|
231
|
+
|
|
232
|
+
await writeFile(join(targetDir, ".env.development"), "");
|
|
233
|
+
await writeFile(join(targetDir, ".env.production"), "");
|
|
248
234
|
|
|
249
235
|
await writeFile(join(targetDir, ".gitignore"), getGitignore());
|
|
250
236
|
|
|
@@ -253,4 +239,4 @@ async function createProject(
|
|
|
253
239
|
await writeFile(join(targetDir, "docker-compose.yml"), getDockerCompose(language));
|
|
254
240
|
await writeFile(join(targetDir, ".dockerignore"), getDockerIgnore());
|
|
255
241
|
}
|
|
256
|
-
}
|
|
242
|
+
};
|
package/src/validators.ts
CHANGED
|
@@ -3,30 +3,19 @@ export function validateProjectName(name: string): string | null {
|
|
|
3
3
|
|
|
4
4
|
const n = name.trim();
|
|
5
5
|
|
|
6
|
-
if (n !== n.toLowerCase())
|
|
7
|
-
return "Project name must be lowercase";
|
|
8
|
-
}
|
|
6
|
+
if (n !== n.toLowerCase()) return "Project name must be lowercase";
|
|
9
7
|
|
|
10
|
-
if (n.length > 214)
|
|
11
|
-
return "Project name must be less than 214 characters";
|
|
12
|
-
}
|
|
8
|
+
if (n.length > 214) return "Project name must be less than 214 characters";
|
|
13
9
|
|
|
14
|
-
if (n.startsWith("-") || n.startsWith("."))
|
|
15
|
-
return "Project name cannot start with - or .";
|
|
16
|
-
}
|
|
10
|
+
if (n.startsWith("-") || n.startsWith(".")) return "Project name cannot start with - or .";
|
|
17
11
|
|
|
18
|
-
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n))
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (n !== encodeURIComponent(n)) {
|
|
23
|
-
return "Project name must be URL-safe";
|
|
24
|
-
}
|
|
12
|
+
if (/[~!@#$%^&*(){}[\]<>?:]/.test(n)) return "Project name cannot contain special characters (only letters, numbers, - and _)";
|
|
13
|
+
|
|
14
|
+
if (n !== encodeURIComponent(n)) return "Project name must be URL-safe";
|
|
15
|
+
|
|
25
16
|
|
|
26
17
|
const reserved = ["node_modules", "favicon.ico"];
|
|
27
|
-
if (reserved.includes(n.toLowerCase())) {
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
18
|
+
if (reserved.includes(n.toLowerCase())) return `Cannot use "${n}" as project name`;
|
|
19
|
+
|
|
31
20
|
return null;
|
|
32
|
-
}
|
|
21
|
+
};
|