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

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/index.js CHANGED
@@ -8,7 +8,8 @@ import * as prompts from "@clack/prompts";
8
8
  var RENAME = {
9
9
  _gitignore: ".gitignore",
10
10
  _dockerignore: ".dockerignore",
11
- "_env.example": ".env.example"
11
+ "_env.example": ".env.example",
12
+ "_package.json": "package.json"
12
13
  };
13
14
  function toScope(name) {
14
15
  const n = name.trim();
@@ -42,18 +43,28 @@ function patchJson(tree, relPath, mutate) {
42
43
  node[key] = `${JSON.stringify(json, null, 2)}
43
44
  `;
44
45
  }
46
+ function validateScope(value) {
47
+ return /^@?[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(value.trim()) ? void 0 : "must be a package scope/name, e.g. @acme";
48
+ }
49
+ function validateName(value) {
50
+ 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";
51
+ }
45
52
  function defineTemplate(config) {
46
53
  return config;
47
54
  }
48
- function writeTree(node, dir) {
55
+ function writeTree(node, dir, root = path.resolve(dir)) {
49
56
  for (const [name, value] of Object.entries(node)) {
50
- const p = path.join(dir, name);
57
+ const p = path.resolve(dir, name);
58
+ const rel = path.relative(root, p);
59
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
60
+ throw new Error(`Refusing to write outside the target directory: ${name}`);
61
+ }
51
62
  if (typeof value === "string") {
52
63
  fs.mkdirSync(path.dirname(p), { recursive: true });
53
64
  fs.writeFileSync(p, value);
54
65
  } else {
55
66
  fs.mkdirSync(p, { recursive: true });
56
- writeTree(value, p);
67
+ writeTree(value, p, root);
57
68
  }
58
69
  }
59
70
  }
@@ -193,8 +204,9 @@ async function runTemplateCLI(template) {
193
204
  writeTree(creation.files, directory);
194
205
  if (creation.scripts?.length) {
195
206
  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 });
207
+ for (const [program, ...commandArgs] of step.commands) {
208
+ if (!program) continue;
209
+ execFileSync(program, commandArgs, { cwd: directory, stdio: "inherit" });
198
210
  }
199
211
  }
200
212
  }
@@ -207,60 +219,16 @@ async function runTemplateCLI(template) {
207
219
  }
208
220
 
209
221
  // src/template.ts
222
+ import { readFileSync } from "node:fs";
210
223
  import path2 from "node:path";
211
224
  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
225
  function validatePort(value) {
261
226
  return /^\d+$/.test(value) && Number(value) > 0 && Number(value) < 65536 ? void 0 : "must be a number between 1 and 65535";
262
227
  }
263
228
  var TEMPLATE_DIR = path2.join(path2.dirname(fileURLToPath(import.meta.url)), "..", "template");
229
+ var { name: pkgName, description: pkgDescription } = JSON.parse(
230
+ readFileSync(new URL("../package.json", import.meta.url), "utf8")
231
+ );
264
232
  var MAIN_TS = path2.join("apps", "api", "src", "main.ts");
265
233
  var SWAGGER_IMPORT = "import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'";
266
234
  var APP_MODULE = path2.join("apps", "api", "src", "app.module.ts");
@@ -277,15 +245,15 @@ function applyDocBlock(text2, tag, keep) {
277
245
  }
278
246
  var template_default = defineTemplate({
279
247
  about: {
280
- name: package_default.name,
281
- description: package_default.description
248
+ name: pkgName,
249
+ description: pkgDescription
282
250
  },
283
251
  options: [
284
252
  // 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) },
253
+ { key: "name", type: "string", message: "Root project / package name", default: ({ directory }) => dirName(directory), validate: validateName },
286
254
  // Lazily default the package scope to `@<name>` (prefixing `@` unless the name already has one),
287
255
  // 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" },
256
+ { 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
257
  // Ports stay strings (validated as integers): they're only ever substituted into config files as text.
290
258
  { key: "apiPort", type: "string", message: "Port the NestJS api listens on", default: "3000", validate: validatePort },
291
259
  { key: "webPort", type: "string", message: "Port the web dev server listens on", default: "5173", validate: validatePort },
@@ -327,7 +295,7 @@ var template_default = defineTemplate({
327
295
  delete files[".dockerignore"];
328
296
  delete files.apps.api["Dockerfile"];
329
297
  }
330
- const scripts = options.install ? [{ commands: ["pnpm install --silent"], phase: 0 }] : [];
298
+ const scripts = options.install ? [{ commands: [["pnpm", "install", "--silent"]], phase: 0 }] : [];
331
299
  return {
332
300
  files,
333
301
  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.2",
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",
File without changes