create-rigg 0.0.3 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -6
- package/dist/index.mjs +138 -67
- package/package.json +5 -4
- package/template/test/index.test.ts +5 -0
- package/template/vitest.config.ts +7 -0
package/README.md
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# rigg
|
|
2
2
|
|
|
3
|
+
<p>
|
|
4
|
+
<a href="https://npmx.dev/package/create-rigg"><img src="https://npmx.dev/api/registry/badge/version/create-rigg" alt="Version"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/create-rigg"><img src="https://img.shields.io/npm/v/create-rigg.svg" alt="Version"></a>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
3
8
|
**The Unified Toolchain Starter for Node.js**
|
|
4
9
|
|
|
5
|
-
Creates a new Node.js TypeScript project using the same
|
|
10
|
+
Creates a new Node.js TypeScript project using mostly the same toolchain as [Vite+](https://github.com/voidzero-dev/vite-plus), but for backend and non-web projects.
|
|
6
11
|
|
|
7
12
|
## Create a new project with rigg
|
|
8
13
|
|
|
@@ -20,17 +25,17 @@ The project follows most of the same toolchain as Vite+.
|
|
|
20
25
|
| [Vitest](https://vitest.dev) | Testing |
|
|
21
26
|
| [Oxlint](https://oxc.rs/docs/guide/usage/linter) | Linting |
|
|
22
27
|
| [Oxfmt](https://oxc.rs/docs/guide/usage/formatter) | Formatting |
|
|
23
|
-
| [tsdown](https://tsdown.dev) | Build & bundle |
|
|
24
28
|
| [tsx](https://tsx.is) | Dev-mode execution |
|
|
29
|
+
| [tsdown](https://tsdown.dev) | Build |
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
### Backend framework
|
|
27
32
|
|
|
28
33
|
You can also choose one of the following backend frameworks:
|
|
29
34
|
|
|
30
|
-
- **None** — where you don't need a API framework, or you want to pick your own.
|
|
31
35
|
- **Hono** — lightweight, modern API framework
|
|
32
36
|
- **Fastify** — fast and low overhead
|
|
33
37
|
- **Express** — familiar and widely supported
|
|
38
|
+
- **None** — where you don't need a API framework, or you want to pick your own.
|
|
34
39
|
|
|
35
40
|
## Scripts
|
|
36
41
|
|
|
@@ -38,7 +43,7 @@ Every generated project includes:
|
|
|
38
43
|
|
|
39
44
|
```bash
|
|
40
45
|
pnpm dev # Run with tsx (no build step)
|
|
41
|
-
pnpm build #
|
|
46
|
+
pnpm build # Build with tsdown
|
|
42
47
|
pnpm test # Run Vitest
|
|
43
48
|
pnpm check # Lint + format check + type check
|
|
44
49
|
pnpm fmt # Format
|
|
@@ -47,7 +52,7 @@ pnpm lint # Lint
|
|
|
47
52
|
pnpm lint:fix # Lint with auto-fix
|
|
48
53
|
```
|
|
49
54
|
|
|
50
|
-
|
|
55
|
+
You can also use `npm` or `yarn` or `bun`, depending on your package manager.
|
|
51
56
|
|
|
52
57
|
## License
|
|
53
58
|
|
package/dist/index.mjs
CHANGED
|
@@ -26,6 +26,12 @@ const FRAMEWORKS = [
|
|
|
26
26
|
label: "Express"
|
|
27
27
|
}
|
|
28
28
|
];
|
|
29
|
+
const FRAMEWORK_LABELS = {
|
|
30
|
+
none: "None",
|
|
31
|
+
hono: "Hono",
|
|
32
|
+
fastify: "Fastify",
|
|
33
|
+
express: "Express"
|
|
34
|
+
};
|
|
29
35
|
const FRAMEWORK_DEPS = {
|
|
30
36
|
none: {
|
|
31
37
|
deps: [],
|
|
@@ -79,8 +85,15 @@ app.listen(3000, () => {
|
|
|
79
85
|
`
|
|
80
86
|
};
|
|
81
87
|
//#endregion
|
|
88
|
+
//#region src/pkg-managers.ts
|
|
89
|
+
const PKG_MANAGERS = [
|
|
90
|
+
"npm",
|
|
91
|
+
"pnpm",
|
|
92
|
+
"yarn",
|
|
93
|
+
"bun"
|
|
94
|
+
];
|
|
95
|
+
//#endregion
|
|
82
96
|
//#region src/index.ts
|
|
83
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
84
97
|
/** Creates a colored gradient text effect */
|
|
85
98
|
function gradient(text, stops, whiteRange) {
|
|
86
99
|
const chars = [...text];
|
|
@@ -97,9 +110,7 @@ function gradient(text, stops, whiteRange) {
|
|
|
97
110
|
/** Detects the package manager used to invoke the CLI via npm_config_user_agent. */
|
|
98
111
|
function detectPkgManager() {
|
|
99
112
|
const ua = process.env.npm_config_user_agent ?? "";
|
|
100
|
-
if (ua.startsWith(
|
|
101
|
-
if (ua.startsWith("bun")) return "bun";
|
|
102
|
-
if (ua.startsWith("yarn")) return "yarn";
|
|
113
|
+
for (const pm of PKG_MANAGERS) if (ua.startsWith(pm)) return pm;
|
|
103
114
|
return "npm";
|
|
104
115
|
}
|
|
105
116
|
/** Builds the install/add command args for the given package manager. */
|
|
@@ -119,11 +130,14 @@ function addArgs(pkgManager, packages, dev) {
|
|
|
119
130
|
/** Runs a command synchronously, exiting the process if it fails. */
|
|
120
131
|
function run(cmd, args, opts) {
|
|
121
132
|
const result = spawn.sync(cmd, args, {
|
|
122
|
-
stdio: "
|
|
133
|
+
stdio: "ignore",
|
|
123
134
|
...opts
|
|
124
135
|
});
|
|
125
|
-
if (result.status != null && result.status !== 0) process.exit(result.status);
|
|
126
136
|
if (result.error) throw result.error;
|
|
137
|
+
if (result.status != null && result.status !== 0) {
|
|
138
|
+
p.cancel(`${cmd} ${args.join(" ")} failed with exit code ${result.status}`);
|
|
139
|
+
process.exit(result.status);
|
|
140
|
+
}
|
|
127
141
|
}
|
|
128
142
|
/** Recursively copies a directory, renaming _gitignore to .gitignore. */
|
|
129
143
|
function copyDir(src, dest) {
|
|
@@ -141,9 +155,8 @@ function isEmpty(dir) {
|
|
|
141
155
|
const files = fs.readdirSync(dir);
|
|
142
156
|
return files.length === 0 || files.length === 1 && files[0] === ".git";
|
|
143
157
|
}
|
|
144
|
-
/**
|
|
145
|
-
async function
|
|
146
|
-
const fromArg = argv._[0] ?? "";
|
|
158
|
+
/** Resolves the project name from the CLI arg or prompts the user. */
|
|
159
|
+
async function resolveProjectName(fromArg) {
|
|
147
160
|
if (fromArg) return fromArg;
|
|
148
161
|
const answer = await p.text({
|
|
149
162
|
message: "Project name:",
|
|
@@ -156,10 +169,9 @@ async function promptProjectName(argv) {
|
|
|
156
169
|
}
|
|
157
170
|
return answer || "rigg-project";
|
|
158
171
|
}
|
|
159
|
-
/**
|
|
160
|
-
async function
|
|
161
|
-
|
|
162
|
-
if (templateArg && FRAMEWORK_DEPS[templateArg]) return templateArg;
|
|
172
|
+
/** Resolves the framework from the --framework flag or prompts the user. */
|
|
173
|
+
async function resolveFramework(fromArg) {
|
|
174
|
+
if (fromArg && FRAMEWORK_DEPS[fromArg]) return fromArg;
|
|
163
175
|
const answer = await p.select({
|
|
164
176
|
message: "Backend framework:",
|
|
165
177
|
options: FRAMEWORKS,
|
|
@@ -174,7 +186,10 @@ async function promptFramework(argv) {
|
|
|
174
186
|
/** Asks the user to confirm before wiping a non-empty target directory. */
|
|
175
187
|
async function confirmOverwrite(projectName, targetDir) {
|
|
176
188
|
if (isEmpty(targetDir)) return;
|
|
177
|
-
const overwrite = await p.confirm({
|
|
189
|
+
const overwrite = await p.confirm({
|
|
190
|
+
message: `${pc.white(projectName)} is not empty. Remove existing files and continue?`,
|
|
191
|
+
initialValue: false
|
|
192
|
+
});
|
|
178
193
|
if (p.isCancel(overwrite) || !overwrite) {
|
|
179
194
|
p.cancel("Cancelled");
|
|
180
195
|
process.exit(0);
|
|
@@ -185,18 +200,29 @@ async function confirmOverwrite(projectName, targetDir) {
|
|
|
185
200
|
});
|
|
186
201
|
}
|
|
187
202
|
/** Copies the base template, sets the package name, and writes the framework starter code. */
|
|
188
|
-
function scaffoldFiles(
|
|
189
|
-
|
|
203
|
+
function scaffoldFiles(options, targetDir) {
|
|
204
|
+
const directory = path.dirname(fileURLToPath(import.meta.url));
|
|
205
|
+
copyDir(path.join(directory, "..", "template"), targetDir);
|
|
190
206
|
const pkgJsonPath = path.join(targetDir, "package.json");
|
|
191
207
|
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
192
|
-
pkg.name = projectName;
|
|
208
|
+
pkg.name = options.projectName;
|
|
193
209
|
fs.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
194
210
|
fs.mkdirSync(path.join(targetDir, "src"), { recursive: true });
|
|
195
|
-
fs.writeFileSync(path.join(targetDir, "src", "index.ts"), FRAMEWORK_INDEX[framework]);
|
|
211
|
+
fs.writeFileSync(path.join(targetDir, "src", "index.ts"), FRAMEWORK_INDEX[options.framework]);
|
|
196
212
|
}
|
|
197
213
|
/** Installs shared dev dependencies and any framework-specific packages. */
|
|
198
|
-
function installDependencies(
|
|
199
|
-
|
|
214
|
+
function installDependencies(options, targetDir) {
|
|
215
|
+
const { pkgManager, framework, verbose } = options;
|
|
216
|
+
const stdio = verbose ? "inherit" : "ignore";
|
|
217
|
+
p.log.step(`Installing dependencies with ${gradient(pkgManager, [[
|
|
218
|
+
168,
|
|
219
|
+
85,
|
|
220
|
+
247
|
|
221
|
+
], [
|
|
222
|
+
99,
|
|
223
|
+
102,
|
|
224
|
+
241
|
|
225
|
+
]])}...`);
|
|
200
226
|
run(pkgManager, addArgs(pkgManager, [
|
|
201
227
|
"@types/node",
|
|
202
228
|
"oxfmt",
|
|
@@ -205,38 +231,33 @@ function installDependencies(pkgManager, framework, targetDir) {
|
|
|
205
231
|
"tsx",
|
|
206
232
|
"typescript",
|
|
207
233
|
"vitest"
|
|
208
|
-
], true), {
|
|
209
|
-
|
|
234
|
+
], true), {
|
|
235
|
+
cwd: targetDir,
|
|
236
|
+
stdio
|
|
237
|
+
});
|
|
210
238
|
if (framework !== "none") {
|
|
211
|
-
p.log.step(`Installing ${framework
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
239
|
+
p.log.step(`Installing ${gradient(FRAMEWORK_LABELS[framework], [[
|
|
240
|
+
168,
|
|
241
|
+
85,
|
|
242
|
+
247
|
|
243
|
+
], [
|
|
244
|
+
99,
|
|
245
|
+
102,
|
|
246
|
+
241
|
|
247
|
+
]])}...`);
|
|
248
|
+
const { deps, devDeps } = FRAMEWORK_DEPS[framework];
|
|
249
|
+
if (deps.length > 0) run(pkgManager, addArgs(pkgManager, deps, false), {
|
|
250
|
+
cwd: targetDir,
|
|
251
|
+
stdio
|
|
252
|
+
});
|
|
253
|
+
if (devDeps.length > 0) run(pkgManager, addArgs(pkgManager, devDeps, true), {
|
|
254
|
+
cwd: targetDir,
|
|
255
|
+
stdio
|
|
256
|
+
});
|
|
215
257
|
}
|
|
216
258
|
}
|
|
217
|
-
/** Prints the gradient
|
|
218
|
-
function
|
|
219
|
-
const frameworkLabel = FRAMEWORKS.find((f) => f.value === framework)?.label ?? framework;
|
|
220
|
-
const outroStops = [[
|
|
221
|
-
168,
|
|
222
|
-
85,
|
|
223
|
-
247
|
|
224
|
-
], [
|
|
225
|
-
99,
|
|
226
|
-
102,
|
|
227
|
-
241
|
|
228
|
-
]];
|
|
229
|
-
const outroText = frameworkLabel !== "None" ? `Created ${projectName} with ${frameworkLabel}` : `Created ${projectName}`;
|
|
230
|
-
const nameStart = 8;
|
|
231
|
-
const outro = gradient(outroText, outroStops, [nameStart, nameStart + projectName.length]);
|
|
232
|
-
const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
|
|
233
|
-
p.outro(`${outro}\n\n ${pc.dim("Now run:")}\n cd ${projectName}\n ${devCmd}`);
|
|
234
|
-
}
|
|
235
|
-
async function main() {
|
|
236
|
-
const argv = mri(process.argv.slice(2), {
|
|
237
|
-
string: ["template"],
|
|
238
|
-
alias: { t: "template" }
|
|
239
|
-
});
|
|
259
|
+
/** Prints the gradient intro. */
|
|
260
|
+
function showIntro() {
|
|
240
261
|
p.intro(pc.bold(gradient("rigg - The Unified Toolchain Starter for Node.js", [
|
|
241
262
|
[
|
|
242
263
|
255,
|
|
@@ -254,46 +275,96 @@ async function main() {
|
|
|
254
275
|
241
|
|
255
276
|
]
|
|
256
277
|
], [0, 6])));
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const pkgManager =
|
|
261
|
-
|
|
262
|
-
|
|
278
|
+
}
|
|
279
|
+
/** Prints the gradient outro with next steps. */
|
|
280
|
+
function showOutro(options) {
|
|
281
|
+
const { projectName, framework, pkgManager } = options;
|
|
282
|
+
const frameworkLabel = FRAMEWORK_LABELS[framework];
|
|
283
|
+
const title = gradient(frameworkLabel !== "None" ? `Created ${projectName} with ${frameworkLabel}` : `Created ${projectName}`, [[
|
|
284
|
+
168,
|
|
285
|
+
85,
|
|
286
|
+
247
|
|
287
|
+
], [
|
|
288
|
+
99,
|
|
289
|
+
102,
|
|
290
|
+
241
|
|
291
|
+
]], [8, 8 + projectName.length]);
|
|
292
|
+
const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
|
|
293
|
+
p.outro(`${title}\n\n ${pc.dim("Now run:")}\n cd ${projectName}\n ${devCmd}`);
|
|
294
|
+
}
|
|
295
|
+
/** Takes the CLI args and resolves all inputs into a single options object. */
|
|
296
|
+
async function resolveOptions(argv) {
|
|
297
|
+
const projectName = await resolveProjectName(argv._[0]);
|
|
298
|
+
await confirmOverwrite(projectName, path.resolve(process.cwd(), projectName));
|
|
299
|
+
return {
|
|
300
|
+
projectName,
|
|
301
|
+
framework: await resolveFramework(argv.framework),
|
|
302
|
+
pkgManager: argv.pm || detectPkgManager(),
|
|
303
|
+
verbose: argv.verbose ?? false
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function initializeGit(options, targetDir) {
|
|
307
|
+
p.log.step("Initializing git repository");
|
|
263
308
|
run("git", [
|
|
264
309
|
"init",
|
|
265
310
|
"-b",
|
|
266
311
|
"main"
|
|
267
312
|
], {
|
|
268
313
|
cwd: targetDir,
|
|
269
|
-
stdio: "ignore"
|
|
314
|
+
stdio: options.verbose ? "inherit" : "ignore"
|
|
270
315
|
});
|
|
271
|
-
|
|
272
|
-
|
|
316
|
+
}
|
|
317
|
+
function formatCode(options, targetDir) {
|
|
273
318
|
p.log.step("Formatting code");
|
|
319
|
+
const { pkgManager, verbose } = options;
|
|
320
|
+
const stdio = verbose ? "inherit" : "ignore";
|
|
321
|
+
const execCmd = pkgManager === "bun" ? "x" : "exec";
|
|
322
|
+
const sep = pkgManager === "npm" || pkgManager === "yarn" ? ["--"] : [];
|
|
274
323
|
run(pkgManager, [
|
|
275
|
-
|
|
324
|
+
execCmd,
|
|
276
325
|
"oxlint",
|
|
277
|
-
|
|
326
|
+
...sep,
|
|
278
327
|
"--init"
|
|
279
328
|
], {
|
|
280
329
|
cwd: targetDir,
|
|
281
|
-
stdio
|
|
330
|
+
stdio
|
|
282
331
|
});
|
|
283
332
|
run(pkgManager, [
|
|
284
|
-
|
|
333
|
+
execCmd,
|
|
285
334
|
"oxfmt",
|
|
286
|
-
|
|
335
|
+
...sep,
|
|
287
336
|
"--init"
|
|
288
337
|
], {
|
|
289
338
|
cwd: targetDir,
|
|
290
|
-
stdio
|
|
339
|
+
stdio
|
|
291
340
|
});
|
|
292
|
-
run(pkgManager, [
|
|
341
|
+
run(pkgManager, [
|
|
342
|
+
execCmd,
|
|
343
|
+
"oxfmt",
|
|
344
|
+
...sep,
|
|
345
|
+
"."
|
|
346
|
+
], {
|
|
293
347
|
cwd: targetDir,
|
|
294
|
-
stdio
|
|
348
|
+
stdio
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
async function main() {
|
|
352
|
+
const argv = mri(process.argv.slice(2), {
|
|
353
|
+
string: ["framework", "pm"],
|
|
354
|
+
boolean: ["verbose"],
|
|
355
|
+
alias: {
|
|
356
|
+
f: "framework",
|
|
357
|
+
v: "verbose"
|
|
358
|
+
}
|
|
295
359
|
});
|
|
296
|
-
|
|
360
|
+
showIntro();
|
|
361
|
+
const options = await resolveOptions(argv);
|
|
362
|
+
const targetDir = path.resolve(process.cwd(), options.projectName);
|
|
363
|
+
scaffoldFiles(options, targetDir);
|
|
364
|
+
initializeGit(options, targetDir);
|
|
365
|
+
installDependencies(options, targetDir);
|
|
366
|
+
formatCode(options, targetDir);
|
|
367
|
+
showOutro(options);
|
|
297
368
|
}
|
|
298
369
|
main().catch((err) => {
|
|
299
370
|
console.error(err);
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-rigg",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "The Unified Toolchain Starter for Node.js backend and non-web projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backend",
|
|
7
|
-
"node",
|
|
8
|
-
"nodejs",
|
|
9
7
|
"create-rigg",
|
|
10
8
|
"express",
|
|
11
9
|
"fastify",
|
|
12
10
|
"framework",
|
|
13
11
|
"hono",
|
|
12
|
+
"node",
|
|
13
|
+
"nodejs",
|
|
14
14
|
"oxfmt",
|
|
15
15
|
"oxlint",
|
|
16
16
|
"rigg",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"fmt:check": "oxfmt --check",
|
|
43
43
|
"check": "oxlint && oxfmt --check && tsc --noEmit",
|
|
44
44
|
"dev": "tsx src/index.ts",
|
|
45
|
-
"build": "tsdown src/index.ts"
|
|
45
|
+
"build": "tsdown src/index.ts",
|
|
46
|
+
"prepublishOnly": "git diff --exit-code && git diff --cached --exit-code && oxlint && oxfmt && tsc --noEmit && vitest run && pnpm build"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"@clack/prompts": "^1.1.0",
|