create-template-project 0.1.0 → 0.2.0

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 (70) hide show
  1. package/README.md +8 -8
  2. package/dist/cli.mjs +54 -18
  3. package/dist/config/dependencies.json +59 -39
  4. package/dist/generators/info.mjs +58 -0
  5. package/dist/generators/project.mjs +60 -27
  6. package/dist/index.mjs +4 -1
  7. package/dist/templates/base/files/.github/workflows/node.js.yml +5 -3
  8. package/dist/templates/base/files/.prettierignore +50 -0
  9. package/dist/templates/base/files/.prettierrc.json +4 -2
  10. package/dist/templates/base/files/AGENTS.md +5 -2
  11. package/dist/templates/base/files/README.md +36 -13
  12. package/dist/templates/base/files/_oxlint.config.ts +17 -33
  13. package/dist/templates/base/files/tsconfig.json +32 -32
  14. package/dist/templates/base/files/vitest.config.ts +2 -2
  15. package/dist/templates/base/index.mjs +40 -1
  16. package/dist/templates/cli/index.mjs +14 -1
  17. package/dist/templates/web-app/files/index.html +11 -0
  18. package/dist/templates/web-app/files/playwright.config.ts +26 -0
  19. package/dist/templates/web-app/files/src/index.tsx +21 -0
  20. package/dist/templates/web-app/files/tests/e2e/basic.e2e-test.ts +13 -0
  21. package/dist/templates/web-app/files/vite.config.ts +30 -0
  22. package/dist/templates/web-app/index.mjs +69 -0
  23. package/dist/templates/web-fullstack/files/client/index.html +10 -0
  24. package/dist/templates/{fullstack → web-fullstack}/files/client/package.json +2 -2
  25. package/dist/templates/{fullstack → web-fullstack}/files/client/src/contexts/AuthContext.tsx +1 -5
  26. package/dist/templates/{fullstack → web-fullstack}/files/client/src/pages/Login.tsx +4 -33
  27. package/dist/templates/web-fullstack/files/client/vite.config.ts +26 -0
  28. package/dist/templates/web-fullstack/files/playwright.config.ts +33 -0
  29. package/dist/templates/{fullstack → web-fullstack}/files/server/package.json +2 -2
  30. package/dist/templates/web-fullstack/files/server/vite.config.ts +21 -0
  31. package/dist/templates/web-fullstack/files/tests/e2e/basic.e2e-test.ts +14 -0
  32. package/dist/templates/web-fullstack/index.mjs +78 -0
  33. package/dist/templates/web-vanilla/files/index.html +11 -0
  34. package/dist/templates/web-vanilla/files/package.json +17 -0
  35. package/dist/templates/web-vanilla/files/playwright.config.ts +26 -0
  36. package/dist/templates/web-vanilla/files/tests/e2e/basic.e2e-test.ts +11 -0
  37. package/dist/templates/web-vanilla/files/vite.config.ts +24 -0
  38. package/dist/templates/web-vanilla/index.mjs +45 -0
  39. package/dist/types.mjs +4 -4
  40. package/dist/utils/file.mjs +31 -13
  41. package/package.json +24 -21
  42. package/dist/templates/fullstack/files/client/index.html +0 -8
  43. package/dist/templates/fullstack/files/client/tsdown.config.ts +0 -3
  44. package/dist/templates/fullstack/files/server/tsdown.config.ts +0 -3
  45. package/dist/templates/fullstack/index.mjs +0 -42
  46. package/dist/templates/webapp/files/backend/src/index.ts +0 -17
  47. package/dist/templates/webapp/files/frontend/index.html +0 -9
  48. package/dist/templates/webapp/files/frontend/src/index.ts +0 -4
  49. package/dist/templates/webapp/files/package.json +0 -13
  50. package/dist/templates/webapp/files/tsdown.config.ts +0 -10
  51. package/dist/templates/webapp/index.mjs +0 -16
  52. package/dist/templates/webpage/files/index.html +0 -8
  53. package/dist/templates/webpage/files/package.json +0 -8
  54. package/dist/templates/webpage/index.mjs +0 -16
  55. /package/dist/templates/{webapp → web-app}/files/src/index.test.ts +0 -0
  56. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/App.test.tsx +0 -0
  57. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/App.tsx +0 -0
  58. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/components/ProtectedRoute.tsx +0 -0
  59. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/main.tsx +0 -0
  60. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/pages/Dashboard.tsx +0 -0
  61. /package/dist/templates/{fullstack → web-fullstack}/files/client/src/trpc.ts +0 -0
  62. /package/dist/templates/{fullstack → web-fullstack}/files/package.json +0 -0
  63. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/context.ts +0 -0
  64. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/index.test.ts +0 -0
  65. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/index.ts +0 -0
  66. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/routers/_app.ts +0 -0
  67. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/routers/auth.ts +0 -0
  68. /package/dist/templates/{fullstack → web-fullstack}/files/server/src/trpc.ts +0 -0
  69. /package/dist/templates/{webpage → web-vanilla}/files/src/index.test.ts +0 -0
  70. /package/dist/templates/{webpage → web-vanilla}/files/src/index.ts +0 -0
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Node.js CI](https://github.com/doberkofler/create-template-project/actions/workflows/node.js.yml/badge.svg)](https://github.com/doberkofler/create-template-project/actions/workflows/node.js.yml)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/doberkofler/create-template-project/badge.svg?branch=master)](https://coveralls.io/github/doberkofler/create-template-project?branch=master)
7
7
 
8
- An ultra-modular, type-safe Node.js CLI tool used to scaffold new project templates (CLI, Webpage, Webapp, Fullstack) with best-practice configurations pre-installed.
8
+ An ultra-modular, type-safe Node.js CLI tool used to scaffold new project templates (CLI, Web-Vanilla, Web-App, Web-Fullstack) with best-practice configurations pre-installed.
9
9
 
10
10
  ## Features
11
11
 
@@ -63,12 +63,12 @@ create-template-project update --template cli --name existing-project
63
63
 
64
64
  #### Command Options (create/update):
65
65
 
66
- - `-t, --template <type>`: Template type (`cli`, `webpage`, `webapp`, `fullstack`)
66
+ - `-t, --template <type>`: Template type (`cli`, `web-vanilla`, `web-app`, `web-fullstack`)
67
67
  - `-n, --name <name>`: Project name
68
68
  - `--github`: Create GitHub project (requires `gh` CLI authenticated)
69
69
  - `-d, --directory <path>`: Output directory (defaults to `.`)
70
70
  - `--overwrite`: Overwrite existing directory by removing it first (create & update)
71
- - `--no-build`: Create a project without a build step (not allowed for `webapp`)
71
+ - `--no-build`: Create a project without a build step (not allowed for `web-app`)
72
72
  - `--silent`: Reduce console output (useful for CI and scripts)
73
73
 
74
74
  ## Project Templates
@@ -76,16 +76,16 @@ create-template-project update --template cli --name existing-project
76
76
  ### 🟢 CLI
77
77
  A clean Node.js CLI environment featuring `commander` and `cli-progress`. Supports optional `tsdown` bundling.
78
78
 
79
- ### 🔵 Webpage
79
+ ### 🔵 Web-Vanilla
80
80
  Standalone web page setup for modern browsers. Can be used with or without a build step.
81
81
 
82
- ### 🟡 Webapp
83
- Classic web application structure with a `frontend/` and a `backend/` Express server. Built with TypeScript.
82
+ ### 🟡 Web-App
83
+ Modern React application featuring MUI components and TanStack Query for state management.
84
84
 
85
- ### ⚛️ Fullstack
85
+ ### ⚛️ Web-Fullstack
86
86
  A full-stack monorepo featuring:
87
87
  - **Client**: React with MUI (including Icons) and TypeScript.
88
- - **Server**: Express.js backend.
88
+ - **Server**: Express.js backend with tRPC for end-to-end type safety.
89
89
  - **E2E**: Playwright for end-to-end testing.
90
90
 
91
91
  ## Contributing
package/dist/cli.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import { ProjectOptionsSchema } from "./types.mjs";
1
+ import { ProjectOptionsSchema, TemplateTypeSchema } from "./types.mjs";
2
+ import { getAllTemplatesInfo, getTemplateInfo } from "./generators/info.mjs";
2
3
  import { Command } from "commander";
3
4
  import * as p from "@clack/prompts";
4
5
  import path from "node:path";
@@ -15,19 +16,54 @@ const parseArgs = async () => {
15
16
  writeErr: () => {}
16
17
  });
17
18
  program.name("create-template-project").exitOverride().description("Scaffold a new project template").version("0.1.0").option("--debug", "Enable debug output").on("option:debug", () => {
19
+ process.env["DEBUG"] = "create-template-project:*";
18
20
  debugLib.enable("create-template-project:*");
19
21
  }).addHelpText("after", `
22
+ Commands:
23
+ create - Create a new project from a template.
24
+ update - Update an existing project from its template.
25
+ interactive - Start interactive project configuration.
26
+ info - Show detailed information about available templates and components.
27
+
20
28
  Templates:
21
- cli - Node.js CLI application with commander and cli-progress.
22
- webpage - Standalone web page (modern HTML/JS).
23
- webapp - Web application with TypeScript and an Express backend.
24
- fullstack - Full-stack monorepo with Express server and React/MUI client.
29
+ cli - Node.js CLI application with commander and cli-progress.
30
+ web-vanilla - Standalone web page (modern HTML/JS).
31
+ web-app - React application with MUI and TanStack Query.
32
+ web-fullstack - Full-stack monorepo with Express server and React/MUI client.
25
33
  `);
26
34
  let commandResult;
27
- program.command("create").description("Create a new project from a template").option("-t, --template <type>", "Template type (cli, webpage, webapp, fullstack)").option("-n, --name <name>", "Project name").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "npm").option("--create-github-repository", "Create GitHub project").option("-d, --directory <path>", "Output directory", ".").option("--overwrite", "Overwrite existing directory by removing it first", false).option("--skip-build", "Skip build tooling (disables bundling and uses raw source files)", false).option("--install-dependencies", "Install dependencies after scaffolding", false).option("--build", "Run the CI script (lint, build, test) after scaffolding", false).option("--dev", "Run the dev server after scaffolding", false).option("--open", "Open the browser after scaffolding", false).option("--silent", "Reduce console output", false).action((opts) => {
35
+ program.command("info").description("Show detailed information about available templates and their components").option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").action((opts) => {
36
+ debug("Executing \"info\" command with options: %O", opts);
37
+ p.intro("Template Information");
38
+ if (opts.template) {
39
+ const typeResult = TemplateTypeSchema.safeParse(opts.template);
40
+ if (!typeResult.success) {
41
+ p.log.error(`Invalid template type: ${opts.template}. Must be one of: cli, web-vanilla, web-app, web-fullstack`);
42
+ process.exit(1);
43
+ }
44
+ const info = getTemplateInfo(typeResult.data);
45
+ p.note([
46
+ `Description: ${info.description}`,
47
+ "",
48
+ "Components:",
49
+ ...info.components.map((c) => ` ● ${c.name}: ${c.description}`)
50
+ ].join("\n"), `Template: ${info.name}`);
51
+ } else {
52
+ const allInfo = getAllTemplatesInfo();
53
+ for (const info of allInfo) p.note([
54
+ `Description: ${info.description}`,
55
+ "",
56
+ "Components:",
57
+ ...info.components.map((c) => ` ● ${c.name}: ${c.description}`)
58
+ ].join("\n"), `Template: ${info.name}`);
59
+ }
60
+ p.outro("Use \"create\" to scaffold a new project.");
61
+ process.exit(0);
62
+ });
63
+ program.command("create").description("Create a new project from a template").option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("-n, --name <name>", "Project name").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "npm").option("--create-github-repository", "Create GitHub project").option("-d, --directory <path>", "Output directory", ".").option("--overwrite", "Overwrite existing directory by removing it first", false).option("--skip-build", "Skip build tooling (disables bundling and uses raw source files)", false).option("--install-dependencies", "Install dependencies after scaffolding", false).option("--build", "Run the CI script (lint, build, test) after scaffolding", false).option("--dev", "Run the dev server after scaffolding", false).option("--open", "Open the browser after scaffolding", false).option("--silent", "Reduce console output", false).action((opts) => {
28
64
  debug("Executing \"create\" command with options: %O", opts);
29
- if (opts.template === "webapp" && opts.skipBuild) {
30
- p.log.error("The --skip-build option is not allowed for the \"webapp\" template.");
65
+ if (opts.template === "web-app" && opts.skipBuild) {
66
+ p.log.error("The --skip-build option is not allowed for the \"web-app\" template.");
31
67
  process.exit(1);
32
68
  }
33
69
  commandResult = {
@@ -43,10 +79,10 @@ Templates:
43
79
  };
44
80
  debug("Processed \"create\" options: %O", commandResult);
45
81
  });
46
- program.command("update").description("Update an existing project from its template").option("-t, --template <type>", "Template type (cli, webpage, webapp, fullstack)").option("-n, --name <name>", "Project name").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "npm").option("--create-github-repository", "Create GitHub project").option("-d, --directory <path>", "Output directory", ".").option("--overwrite", "Overwrite existing directory by removing it first", false).option("--skip-build", "Skip build tooling (disables bundling and uses raw source files)", false).option("--install-dependencies", "Install dependencies after scaffolding", false).option("--build", "Run the CI script (lint, build, test) after updating", false).option("--dev", "Run the dev server after scaffolding", false).option("--open", "Open the browser after scaffolding", false).option("--silent", "Reduce console output", false).action((opts) => {
82
+ program.command("update").description("Update an existing project from its template").option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("-n, --name <name>", "Project name").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "npm").option("--create-github-repository", "Create GitHub project").option("-d, --directory <path>", "Output directory", ".").option("--overwrite", "Overwrite existing directory by removing it first", false).option("--skip-build", "Skip build tooling (disables bundling and uses raw source files)", false).option("--install-dependencies", "Install dependencies after scaffolding", false).option("--build", "Run the CI script (lint, build, test) after updating", false).option("--dev", "Run the dev server after scaffolding", false).option("--open", "Open the browser after scaffolding", false).option("--silent", "Reduce console output", false).action((opts) => {
47
83
  debug("Executing \"update\" command with options: %O", opts);
48
- if (opts.template === "webapp" && opts.skipBuild) {
49
- p.log.error("The --skip-build option is not allowed for the \"webapp\" template.");
84
+ if (opts.template === "web-app" && opts.skipBuild) {
85
+ p.log.error("The --skip-build option is not allowed for the \"web-app\" template.");
50
86
  process.exit(1);
51
87
  }
52
88
  commandResult = {
@@ -131,16 +167,16 @@ Templates:
131
167
  value: "cli"
132
168
  },
133
169
  {
134
- label: "Webpage (Standalone)",
135
- value: "webpage"
170
+ label: "Web-Vanilla (Standalone)",
171
+ value: "web-vanilla"
136
172
  },
137
173
  {
138
- label: "Webapp (Express Backend)",
139
- value: "webapp"
174
+ label: "Web-App (React + MUI)",
175
+ value: "web-app"
140
176
  },
141
177
  {
142
- label: "Full-stack (Express + React/MUI Monorepo)",
143
- value: "fullstack"
178
+ label: "Web-Fullstack (Express + React Monorepo)",
179
+ value: "web-fullstack"
144
180
  }
145
181
  ]
146
182
  });
@@ -175,7 +211,7 @@ Templates:
175
211
  }
176
212
  }
177
213
  let skipBuild = false;
178
- if (template !== "webapp") {
214
+ if (template !== "web-app") {
179
215
  const res = await p.confirm({
180
216
  message: "Should we use build tooling? (Enables bundling using tsdown, and uses raw dist/ instead of src/)",
181
217
  initialValue: true
@@ -1,155 +1,175 @@
1
1
  {
2
2
  "dependencies": {
3
+ "vite": {
4
+ "version": "8.0.1",
5
+ "description": "Native-ESM powered web dev build tool"
6
+ },
7
+ "@vitejs/plugin-react": {
8
+ "version": "6.0.1",
9
+ "description": "The default Vite plugin for React projects."
10
+ },
11
+ "@vitest/browser": {
12
+ "version": "4.1.0",
13
+ "description": "Run Vitest in the browser."
14
+ },
15
+ "@vitest/browser-playwright": {
16
+ "version": "4.1.0",
17
+ "description": "Playwright provider for Vitest browser mode."
18
+ },
19
+ "playwright": {
20
+ "version": "1.58.2",
21
+ "description": "Framework for Web-browser automation."
22
+ },
3
23
  "debug": {
4
- "version": "^4.4.3",
24
+ "version": "4.4.3",
5
25
  "description": "A tiny JavaScript debugging utility modelled after Node.js core debugging technique."
6
26
  },
7
27
  "@commitlint/cli": {
8
- "version": "^20.4.4",
28
+ "version": "20.5.0",
9
29
  "description": "Lint commit messages to ensure they follow conventional commits."
10
30
  },
11
31
  "@commitlint/config-conventional": {
12
- "version": "^20.4.4",
32
+ "version": "20.5.0",
13
33
  "description": "Shareable commitlint config enforcing conventional commits."
14
34
  },
15
35
  "@types/debug": {
16
- "version": "^4.1.12",
36
+ "version": "^4.1.13",
17
37
  "description": "TypeScript definitions for debug."
18
38
  },
19
39
  "@types/node": {
20
- "version": "^25.5.0",
40
+ "version": "25.5.0",
21
41
  "description": "TypeScript definitions for Node.js."
22
42
  },
23
43
  "@vitest/coverage-v8": {
24
- "version": "^4.1.0",
44
+ "version": "4.1.0",
25
45
  "description": "V8 coverage provider for Vitest."
26
46
  },
27
47
  "conventional-changelog": {
28
- "version": "^7.2.0",
48
+ "version": "7.2.0",
29
49
  "description": "Generate a changelog from git metadata."
30
50
  },
31
51
  "husky": {
32
- "version": "^9.1.7",
52
+ "version": "9.1.7",
33
53
  "description": "Modern native git hooks made easy."
34
54
  },
35
55
  "oxlint": {
36
- "version": "^1.55.0",
56
+ "version": "1.56.0",
37
57
  "description": "A JavaScript linter written in Rust."
38
58
  },
39
59
  "oxlint-tsgolint": {
40
- "version": "^0.16.0",
60
+ "version": "0.17.0",
41
61
  "description": "TypeScript-specific rules for oxlint."
42
62
  },
43
63
  "prettier": {
44
- "version": "^3.8.1",
64
+ "version": "3.8.1",
45
65
  "description": "An opinionated code formatter."
46
66
  },
47
67
  "typescript": {
48
- "version": "^5.9.3",
68
+ "version": "5.9.3",
49
69
  "description": "A superset of JavaScript that compiles to clean JavaScript output."
50
70
  },
51
71
  "vitest": {
52
- "version": "^4.1.0",
72
+ "version": "4.1.0",
53
73
  "description": "A Vite-native unit test framework."
54
74
  },
55
75
  "commander": {
56
- "version": "^14.0.3",
76
+ "version": "14.0.3",
57
77
  "description": "The complete solution for node.js command-line interfaces."
58
78
  },
59
79
  "cli-progress": {
60
- "version": "^3.12.0",
80
+ "version": "3.12.0",
61
81
  "description": "Easy to use progress-bar for command-line/terminal applications."
62
82
  },
63
83
  "@types/cli-progress": {
64
- "version": "^3.11.6",
84
+ "version": "3.11.6",
65
85
  "description": "TypeScript definitions for cli-progress."
66
86
  },
67
87
  "tsdown": {
68
- "version": "^0.21.2",
88
+ "version": "0.21.4",
69
89
  "description": "A zero-config bundler for TypeScript."
70
90
  },
71
91
  "express": {
72
- "version": "^5.2.1",
92
+ "version": "5.2.1",
73
93
  "description": "Fast, unopinionated, minimalist web framework for Node.js."
74
94
  },
75
95
  "@types/express": {
76
- "version": "^5.0.6",
96
+ "version": "5.0.6",
77
97
  "description": "TypeScript definitions for Express."
78
98
  },
79
99
  "react": {
80
- "version": "^19.2.4",
100
+ "version": "19.2.4",
81
101
  "description": "A JavaScript library for building user interfaces."
82
102
  },
83
103
  "react-dom": {
84
- "version": "^19.2.4",
104
+ "version": "19.2.4",
85
105
  "description": "React package for working with the DOM."
86
106
  },
87
107
  "@mui/material": {
88
- "version": "^7.3.9",
108
+ "version": "7.3.9",
89
109
  "description": "Material UI components."
90
110
  },
91
111
  "@mui/icons-material": {
92
- "version": "^7.3.9",
112
+ "version": "7.3.9",
93
113
  "description": "Material Design icons distributed as SVG React components."
94
114
  },
95
115
  "@emotion/react": {
96
- "version": "^11.14.0",
116
+ "version": "11.14.0",
97
117
  "description": "CSS-in-JS library designed for high performance."
98
118
  },
99
119
  "@emotion/styled": {
100
- "version": "^11.14.1",
120
+ "version": "11.14.1",
101
121
  "description": "Styled components for Emotion."
102
122
  },
103
123
  "@types/react": {
104
- "version": "^19.2.14",
124
+ "version": "19.2.14",
105
125
  "description": "TypeScript definitions for React."
106
126
  },
107
127
  "@types/react-dom": {
108
- "version": "^19.2.3",
128
+ "version": "19.2.3",
109
129
  "description": "TypeScript definitions for React DOM."
110
130
  },
111
131
  "@playwright/test": {
112
- "version": "^1.58.2",
132
+ "version": "1.58.2",
113
133
  "description": "End-to-end testing framework."
114
134
  },
115
135
  "@trpc/server": {
116
- "version": "^11.12.0",
136
+ "version": "11.13.4",
117
137
  "description": "tRPC server library."
118
138
  },
119
139
  "@trpc/client": {
120
- "version": "^11.12.0",
140
+ "version": "11.13.4",
121
141
  "description": "tRPC client library."
122
142
  },
123
143
  "@trpc/react-query": {
124
- "version": "^11.12.0",
144
+ "version": "11.13.4",
125
145
  "description": "tRPC integration for React Query."
126
146
  },
127
147
  "@tanstack/react-query": {
128
- "version": "^5.90.21",
148
+ "version": "^5.91.2",
129
149
  "description": "Powerful asynchronous state management for TS/JS."
130
150
  },
131
151
  "zod": {
132
- "version": "^4.3.6",
152
+ "version": "4.3.6",
133
153
  "description": "TypeScript-first schema validation with static type inference."
134
154
  },
135
155
  "tinyexec": {
136
- "version": "^1.0.4",
137
- "description": "A minimal library for executing processes in Node (pinned to 1.0.2 due to broken 1.0.3 release)."
156
+ "version": "1.0.4",
157
+ "description": "A minimal library for executing processes in Node."
138
158
  },
139
159
  "react-router-dom": {
140
- "version": "^7.13.1",
160
+ "version": "7.13.1",
141
161
  "description": "Declarative routing for React web applications."
142
162
  },
143
163
  "cors": {
144
- "version": "^2.8.6",
164
+ "version": "2.8.6",
145
165
  "description": "Node.js CORS middleware."
146
166
  },
147
167
  "@types/cors": {
148
- "version": "^2.8.19",
168
+ "version": "2.8.19",
149
169
  "description": "TypeScript definitions for cors."
150
170
  },
151
171
  "eslint-plugin-regexp": {
152
- "version": "^3.1.0",
172
+ "version": "3.1.0",
153
173
  "description": "ESLint plugin for finding regexp mistakes and style guide violations."
154
174
  }
155
175
  }
@@ -0,0 +1,58 @@
1
+ import { getBaseTemplate } from "../templates/base/index.mjs";
2
+ import { getCliTemplate } from "../templates/cli/index.mjs";
3
+ import { getWebVanillaTemplate } from "../templates/web-vanilla/index.mjs";
4
+ import { getWebAppTemplate } from "../templates/web-app/index.mjs";
5
+ import { getWebFullstackTemplate } from "../templates/web-fullstack/index.mjs";
6
+ //#region src/generators/info.ts
7
+ const MOCK_OPTS = {
8
+ template: "cli",
9
+ projectName: "mock",
10
+ directory: ".",
11
+ packageManager: "npm",
12
+ overwrite: false,
13
+ update: false,
14
+ skipBuild: false,
15
+ installDependencies: false,
16
+ build: false,
17
+ dev: false,
18
+ open: false,
19
+ silent: true,
20
+ createGithubRepository: false
21
+ };
22
+ const getTemplateInfo = (type) => {
23
+ const opts = {
24
+ ...MOCK_OPTS,
25
+ template: type
26
+ };
27
+ const base = getBaseTemplate(opts);
28
+ let template;
29
+ switch (type) {
30
+ case "cli":
31
+ template = getCliTemplate(opts);
32
+ break;
33
+ case "web-vanilla":
34
+ template = getWebVanillaTemplate(opts);
35
+ break;
36
+ case "web-app":
37
+ template = getWebAppTemplate(opts);
38
+ break;
39
+ case "web-fullstack":
40
+ template = getWebFullstackTemplate(opts);
41
+ break;
42
+ }
43
+ return {
44
+ name: template.name,
45
+ description: template.description,
46
+ components: [...base.components, ...template.components]
47
+ };
48
+ };
49
+ const getAllTemplatesInfo = () => {
50
+ return [
51
+ "cli",
52
+ "web-vanilla",
53
+ "web-app",
54
+ "web-fullstack"
55
+ ].map((type) => getTemplateInfo(type));
56
+ };
57
+ //#endregion
58
+ export { getAllTemplatesInfo, getTemplateInfo };
@@ -1,8 +1,8 @@
1
1
  import { getBaseTemplate } from "../templates/base/index.mjs";
2
2
  import { getCliTemplate } from "../templates/cli/index.mjs";
3
- import { getWebpageTemplate } from "../templates/webpage/index.mjs";
4
- import { getWebappTemplate } from "../templates/webapp/index.mjs";
5
- import { getFullstackTemplate } from "../templates/fullstack/index.mjs";
3
+ import { getWebVanillaTemplate } from "../templates/web-vanilla/index.mjs";
4
+ import { getWebAppTemplate } from "../templates/web-app/index.mjs";
5
+ import { getWebFullstackTemplate } from "../templates/web-fullstack/index.mjs";
6
6
  import { getAllFiles, isSeedFile, mergeFile, mergePackageJson, processContent } from "../utils/file.mjs";
7
7
  import * as p from "@clack/prompts";
8
8
  import path from "node:path";
@@ -29,7 +29,11 @@ const getSpinner = (silent) => {
29
29
  message: (msg) => !silent ? s.message(msg) : void 0
30
30
  };
31
31
  };
32
- const showNote = (msg, title, silent) => !silent ? p.note(msg, title) : void 0;
32
+ const showNote = (msg, title, silent) => {
33
+ if (silent) return;
34
+ if (title) p.log.success(title);
35
+ p.note(msg);
36
+ };
33
37
  const generateProject = async (opts) => {
34
38
  const { template: type, projectName, directory, update, overwrite, skipBuild, silent } = opts;
35
39
  const isSilent = !!silent;
@@ -56,17 +60,17 @@ const generateProject = async (opts) => {
56
60
  debug("Applying template: cli");
57
61
  templates.push(getCliTemplate(opts));
58
62
  break;
59
- case "webpage":
60
- debug("Applying template: webpage");
61
- templates.push(getWebpageTemplate(opts));
63
+ case "web-vanilla":
64
+ debug("Applying template: web-vanilla");
65
+ templates.push(getWebVanillaTemplate(opts));
62
66
  break;
63
- case "webapp":
64
- debug("Applying template: webapp");
65
- templates.push(getWebappTemplate(opts));
67
+ case "web-app":
68
+ debug("Applying template: web-app");
69
+ templates.push(getWebAppTemplate(opts));
66
70
  break;
67
- case "fullstack":
68
- debug("Applying template: fullstack");
69
- templates.push(getFullstackTemplate(opts));
71
+ case "web-fullstack":
72
+ debug("Applying template: web-fullstack");
73
+ templates.push(getWebFullstackTemplate(opts));
70
74
  break;
71
75
  }
72
76
  debug("Ensuring directory exists: %s", projectDir);
@@ -124,6 +128,7 @@ const generateProject = async (opts) => {
124
128
  Object.assign(finalPkg.scripts, t.scripts);
125
129
  Object.assign(finalPkg.dependencies, templateDeps);
126
130
  Object.assign(finalPkg.devDependencies, templateDevDeps);
131
+ if (t.workspaces) finalPkg.workspaces = t.workspaces;
127
132
  if (t.templateDir) {
128
133
  const templatePkgPath = path.join(t.templateDir, "package.json");
129
134
  if (await pathExists(templatePkgPath)) {
@@ -156,8 +161,8 @@ const generateProject = async (opts) => {
156
161
  let content = await fs.readFile(file, "utf8");
157
162
  content = processContent(relativePath, content, opts, addedDeps);
158
163
  let finalTargetPath = targetPath;
159
- if (type === "webpage" && skipBuild && relativePath === "src/index.ts") {
160
- debug("Changing target path for webpage index.ts to .js due to skipBuild");
164
+ if (type === "web-vanilla" && skipBuild && relativePath === "src/index.ts") {
165
+ debug("Changing target path for web-vanilla index.ts to .js due to skipBuild");
161
166
  finalTargetPath = path.join(projectDir, "src/index.js");
162
167
  }
163
168
  if (isUpdate && await pathExists(finalTargetPath)) {
@@ -209,37 +214,51 @@ const generateProject = async (opts) => {
209
214
  const workspaceYaml = `packages:\n${finalPkg.workspaces.map((w) => ` - '${w}'`).join("\n")}\n`;
210
215
  await fs.writeFile(path.join(projectDir, "pnpm-workspace.yaml"), workspaceYaml);
211
216
  delete finalPkg.workspaces;
212
- for (const [key, value] of Object.entries(finalPkg.scripts)) if (typeof value === "string" && value.includes("--workspaces")) finalPkg.scripts[key] = value.replace("run ", "-r run ").replace(" --workspaces", "");
217
+ for (const key of Object.keys(finalPkg.scripts)) {
218
+ const value = finalPkg.scripts[key];
219
+ if (typeof value === "string" && value.includes("--workspaces")) finalPkg.scripts[key] = value.replace(" run ", " -r run ").replace(" --workspaces", "");
220
+ }
213
221
  }
214
222
  if (skipBuild) {
215
223
  debug("Applying skipBuild overrides");
216
224
  delete finalPkg.scripts.build;
217
225
  delete finalPkg.scripts.dev;
218
- if (finalPkg.devDependencies) delete finalPkg.devDependencies.tsdown;
226
+ if (finalPkg.devDependencies) {
227
+ delete finalPkg.devDependencies.tsdown;
228
+ delete finalPkg.devDependencies.vite;
229
+ delete finalPkg.devDependencies["@vitejs/plugin-react"];
230
+ }
219
231
  if (finalPkg.scripts.ci) finalPkg.scripts.ci = finalPkg.scripts.ci.replace(" && npm run build", "").replace(` && ${pm} run build`, "");
220
- debug("Removing tsdown configs due to skipBuild");
232
+ debug("Removing build tool configs due to skipBuild");
221
233
  await fs.rm(path.join(projectDir, "tsdown.config.ts"), { force: true });
222
- await fs.rm(path.join(projectDir, "client/tsdown.config.ts"), { force: true });
223
- await fs.rm(path.join(projectDir, "server/tsdown.config.ts"), { force: true });
234
+ await fs.rm(path.join(projectDir, "vite.config.ts"), { force: true });
235
+ await fs.rm(path.join(projectDir, "vite.config.server.ts"), { force: true });
236
+ await fs.rm(path.join(projectDir, "client/vite.config.ts"), { force: true });
237
+ await fs.rm(path.join(projectDir, "server/vite.config.ts"), { force: true });
224
238
  }
225
239
  debug("Writing final consolidated package.json to: %s", pkgPath);
226
240
  await fs.writeFile(pkgPath, JSON.stringify(finalPkg, null, " "));
241
+ const stdio = debug.enabled ? "inherit" : "pipe";
227
242
  if (!await pathExists(path.join(projectDir, ".git"))) {
228
243
  debug("Initializing Git repository");
229
244
  try {
245
+ debug("Executing: git init");
230
246
  await execa("git", ["init"], {
231
247
  cwd: projectDir,
248
+ stdio,
232
249
  preferLocal: true
233
250
  });
234
251
  log.success("Initialized Git repository (git init).");
235
252
  } catch (e) {
236
253
  debug("Failed to initialize Git: %O", e);
237
- log.error("Failed to initialize Git: " + e);
254
+ const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
255
+ log.error(`Failed to initialize Git: ${e.message}${detail}`);
238
256
  }
239
257
  }
240
258
  if (opts.createGithubRepository && !isUpdate) {
241
259
  debug("Creating GitHub repository");
242
260
  try {
261
+ debug("Executing: gh repo create %s --public --source=. --remote=origin", projectName);
243
262
  await execa("gh", [
244
263
  "repo",
245
264
  "create",
@@ -249,12 +268,14 @@ const generateProject = async (opts) => {
249
268
  "--remote=origin"
250
269
  ], {
251
270
  cwd: projectDir,
271
+ stdio,
252
272
  preferLocal: true
253
273
  });
254
274
  log.success("Created GitHub repository (gh repo create).");
255
275
  } catch (e) {
256
276
  debug("Failed to create GitHub repository: %O", e);
257
- log.warn("Failed to create GitHub repository. Ensure \"gh\" CLI is installed and authenticated.");
277
+ const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
278
+ log.warn(`Failed to create GitHub repository: ${e.message}${detail}\nEnsure "gh" CLI is installed and authenticated.`);
258
279
  }
259
280
  }
260
281
  if (opts.installDependencies) {
@@ -262,16 +283,19 @@ const generateProject = async (opts) => {
262
283
  const s = spinner();
263
284
  s.start(`Installing dependencies using ${pm}...`);
264
285
  try {
286
+ debug("Executing: %s install", pm);
265
287
  await execa(pm, ["install"], {
266
288
  cwd: projectDir,
289
+ stdio,
267
290
  preferLocal: true
268
291
  });
269
292
  s.stop(`\x1b[1G\x1b[2K\x1b[32m◆\x1b[39m Dependencies installed (${pm} install).`);
270
293
  } catch (e) {
271
294
  debug("Failed to install dependencies: %O", e);
272
295
  s.stop("Failed to install dependencies.");
273
- log.error(String(e));
274
- throw new Error("Failed to install dependencies.");
296
+ const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
297
+ log.error(`${e.message}${detail}`);
298
+ throw new Error(`Failed to install dependencies: ${e.message}${detail}`);
275
299
  }
276
300
  }
277
301
  if (opts.build && finalPkg.scripts.ci) {
@@ -280,35 +304,43 @@ const generateProject = async (opts) => {
280
304
  if (finalPkg.scripts["prettier-write"]) {
281
305
  s.start(`Formatting files with Prettier (${pm} run prettier-write)...`);
282
306
  try {
307
+ debug("Executing: %s run prettier-write", pm);
283
308
  await execa(pm, ["run", "prettier-write"], {
284
309
  cwd: projectDir,
310
+ stdio,
285
311
  preferLocal: true
286
312
  });
287
313
  s.stop(`\x1b[1G\x1b[2K\x1b[32m◆\x1b[39m Files formatted (${pm} run prettier-write).`);
288
314
  } catch (e) {
289
315
  debug("Failed to format files: %O", e);
290
316
  s.stop("Failed to format files.");
317
+ const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
318
+ log.error(`${e.message}${detail}`);
291
319
  }
292
320
  }
293
321
  s.start(`Running CI script (lint, build, test) (${pm} run ci)...`);
294
322
  try {
323
+ debug("Executing: %s run ci", pm);
295
324
  await execa(pm, ["run", "ci"], {
296
325
  cwd: projectDir,
326
+ stdio,
297
327
  preferLocal: true
298
328
  });
299
329
  s.stop(`\x1b[1G\x1b[2K\x1b[32m◆\x1b[39m CI script completed (${pm} run ci).`);
300
330
  } catch (e) {
301
331
  debug("Failed to run CI script: %O", e);
302
332
  s.stop("Failed to run CI script.");
303
- log.error(String(e));
304
- throw new Error("Failed to run CI script.");
333
+ const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
334
+ log.error(`${e.message}${detail}`);
335
+ throw new Error(`Failed to run CI script: ${e.message}${detail}`);
305
336
  }
306
337
  }
307
- log.info(`Project "${projectName}" ${isUpdate ? "updated" : "scaffolded"} successfully in ${projectDir}`);
338
+ log.success(`Project "${projectName}" ${isUpdate ? "updated" : "scaffolded"} successfully in ${projectDir}`);
308
339
  showSummary(opts, pm, isSilent);
309
340
  if (opts.dev && finalPkg.scripts.dev) {
310
341
  log.info("Starting dev server...");
311
342
  if (opts.open) try {
343
+ debug("Executing: %s run dev -- --open", pm);
312
344
  await execa(pm, [
313
345
  "run",
314
346
  "dev",
@@ -323,6 +355,7 @@ const generateProject = async (opts) => {
323
355
  log.error("Dev server failed: " + e);
324
356
  }
325
357
  else try {
358
+ debug("Executing: %s run dev", pm);
326
359
  await execa(pm, ["run", "dev"], {
327
360
  cwd: projectDir,
328
361
  stdio: "inherit",