@pauldvlp/vp-react-ts-nestjs 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +25 -58
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -42,18 +42,28 @@ function patchJson(tree, relPath, mutate) {
42
42
  node[key] = `${JSON.stringify(json, null, 2)}
43
43
  `;
44
44
  }
45
+ function validateScope(value) {
46
+ return /^@?[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(value.trim()) ? void 0 : "must be a package scope/name, e.g. @acme";
47
+ }
48
+ function validateName(value) {
49
+ return /^@?[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(value.trim()) ? void 0 : "must be a package name, e.g. my-app or @acme/app";
50
+ }
45
51
  function defineTemplate(config) {
46
52
  return config;
47
53
  }
48
- function writeTree(node, dir) {
54
+ function writeTree(node, dir, root = path.resolve(dir)) {
49
55
  for (const [name, value] of Object.entries(node)) {
50
- const p = path.join(dir, name);
56
+ const p = path.resolve(dir, name);
57
+ const rel = path.relative(root, p);
58
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
59
+ throw new Error(`Refusing to write outside the target directory: ${name}`);
60
+ }
51
61
  if (typeof value === "string") {
52
62
  fs.mkdirSync(path.dirname(p), { recursive: true });
53
63
  fs.writeFileSync(p, value);
54
64
  } else {
55
65
  fs.mkdirSync(p, { recursive: true });
56
- writeTree(value, p);
66
+ writeTree(value, p, root);
57
67
  }
58
68
  }
59
69
  }
@@ -193,8 +203,9 @@ async function runTemplateCLI(template) {
193
203
  writeTree(creation.files, directory);
194
204
  if (creation.scripts?.length) {
195
205
  for (const step of [...creation.scripts].sort((a, b) => a.phase - b.phase)) {
196
- for (const command of step.commands) {
197
- execFileSync(command, { cwd: directory, stdio: "inherit", shell: true });
206
+ for (const [program, ...commandArgs] of step.commands) {
207
+ if (!program) continue;
208
+ execFileSync(program, commandArgs, { cwd: directory, stdio: "inherit" });
198
209
  }
199
210
  }
200
211
  }
@@ -207,60 +218,16 @@ async function runTemplateCLI(template) {
207
218
  }
208
219
 
209
220
  // src/template.ts
221
+ import { readFileSync } from "node:fs";
210
222
  import path2 from "node:path";
211
223
  import { fileURLToPath } from "node:url";
212
-
213
- // package.json
214
- var package_default = {
215
- name: "@pauldvlp/vp-react-ts-nestjs",
216
- version: "0.2.0",
217
- description: "Vite+ monorepo template: a React web app + a NestJS api (conformed to the Vite+ toolchain) sharing Zod contracts.",
218
- author: "pauldvlp (https://github.com/pauldvlp/vp-templates)",
219
- license: "MIT",
220
- homepage: "https://github.com/pauldvlp/vp-templates",
221
- repository: {
222
- type: "git",
223
- url: "git+https://github.com/pauldvlp/vp-templates.git",
224
- directory: "packages/vp-react-ts-nestjs"
225
- },
226
- bugs: "https://github.com/pauldvlp/vp-templates/issues",
227
- keywords: [
228
- "vite-plus-generator",
229
- "vite-plus",
230
- "nestjs",
231
- "react",
232
- "template"
233
- ],
234
- bin: "./dist/index.js",
235
- type: "module",
236
- files: [
237
- "dist",
238
- "template"
239
- ],
240
- scripts: {
241
- build: "esbuild bin/index.ts --bundle --outfile=dist/index.js --format=esm --platform=node --target=node22 --packages=external",
242
- dev: "node bin/index.ts",
243
- prepack: "pnpm run build"
244
- },
245
- dependencies: {
246
- "@clack/prompts": "^1.6.0"
247
- },
248
- devDependencies: {
249
- "@pauldvlp/template-kit": "workspace:*",
250
- "@types/node": "^24",
251
- esbuild: "^0.25.0",
252
- typescript: "^5"
253
- },
254
- engines: {
255
- node: ">=22.18.0"
256
- }
257
- };
258
-
259
- // src/template.ts
260
224
  function validatePort(value) {
261
225
  return /^\d+$/.test(value) && Number(value) > 0 && Number(value) < 65536 ? void 0 : "must be a number between 1 and 65535";
262
226
  }
263
227
  var TEMPLATE_DIR = path2.join(path2.dirname(fileURLToPath(import.meta.url)), "..", "template");
228
+ var { name: pkgName, description: pkgDescription } = JSON.parse(
229
+ readFileSync(new URL("../package.json", import.meta.url), "utf8")
230
+ );
264
231
  var MAIN_TS = path2.join("apps", "api", "src", "main.ts");
265
232
  var SWAGGER_IMPORT = "import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'";
266
233
  var APP_MODULE = path2.join("apps", "api", "src", "app.module.ts");
@@ -277,15 +244,15 @@ function applyDocBlock(text2, tag, keep) {
277
244
  }
278
245
  var template_default = defineTemplate({
279
246
  about: {
280
- name: package_default.name,
281
- description: package_default.description
247
+ name: pkgName,
248
+ description: pkgDescription
282
249
  },
283
250
  options: [
284
251
  // Default the name to the target directory the user chose, so they don't retype it.
285
- { key: "name", type: "string", message: "Root project / package name", default: ({ directory }) => dirName(directory) },
252
+ { key: "name", type: "string", message: "Root project / package name", default: ({ directory }) => dirName(directory), validate: validateName },
286
253
  // Lazily default the package scope to `@<name>` (prefixing `@` unless the name already has one),
287
254
  // so it tracks the project name instead of a fixed value. Falls back to `@app` when no name is set.
288
- { key: "scope", type: "string", message: "npm scope for workspace packages, e.g. @acme (defaults to @<name>)", default: ({ options }) => options.name ? toScope(options.name) : "@app" },
255
+ { key: "scope", type: "string", message: "npm scope for workspace packages, e.g. @acme (defaults to @<name>)", default: ({ options }) => options.name ? toScope(options.name) : "@app", validate: validateScope },
289
256
  // Ports stay strings (validated as integers): they're only ever substituted into config files as text.
290
257
  { key: "apiPort", type: "string", message: "Port the NestJS api listens on", default: "3000", validate: validatePort },
291
258
  { key: "webPort", type: "string", message: "Port the web dev server listens on", default: "5173", validate: validatePort },
@@ -327,7 +294,7 @@ var template_default = defineTemplate({
327
294
  delete files[".dockerignore"];
328
295
  delete files.apps.api["Dockerfile"];
329
296
  }
330
- const scripts = options.install ? [{ commands: ["pnpm install --silent"], phase: 0 }] : [];
297
+ const scripts = options.install ? [{ commands: [["pnpm", "install", "--silent"]], phase: 0 }] : [];
331
298
  return {
332
299
  files,
333
300
  scripts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pauldvlp/vp-react-ts-nestjs",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Vite+ monorepo template: a React web app + a NestJS api (conformed to the Vite+ toolchain) sharing Zod contracts.",
5
5
  "author": "pauldvlp (https://github.com/pauldvlp/vp-templates)",
6
6
  "license": "MIT",