express-project-init 1.0.0 → 1.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 (29) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +57 -75
  3. package/dist/index.js +4 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/services/prompts.service.js +29 -0
  6. package/dist/services/prompts.service.js.map +1 -1
  7. package/dist/services/template.service.js +65 -17
  8. package/dist/services/template.service.js.map +1 -1
  9. package/docs/express-project-init-v1.1.0-demo.gif +0 -0
  10. package/docs/express-project-init-v1.1.0-demo.jpg +0 -0
  11. package/docs/express-project-init-v1.1.0-demo.mp4 +0 -0
  12. package/package.json +5 -2
  13. package/templates/format/biome/both/biome.json +17 -0
  14. package/templates/format/biome/both/package.json +12 -0
  15. package/templates/format/biome/format/biome.json +14 -0
  16. package/templates/format/biome/format/package.json +9 -0
  17. package/templates/format/prettier/.prettierignore +3 -0
  18. package/templates/format/prettier/.prettierrc +6 -0
  19. package/templates/format/prettier/package.json +9 -0
  20. package/templates/javascript/error-handler/src/middleware/error.middleware.js +2 -2
  21. package/templates/javascript/error-handler/src/middleware/notFound.middleware.js +1 -1
  22. package/templates/lint/biome/biome.json +15 -0
  23. package/templates/lint/biome/package.json +9 -0
  24. package/templates/lint/eslint/eslint.config.js +36 -0
  25. package/templates/lint/eslint/package.json +12 -0
  26. package/templates/lint/oxlint/.oxlintrc.json +13 -0
  27. package/templates/lint/oxlint/package.json +9 -0
  28. package/templates/typescript/base/tsconfig.json +13 -13
  29. package/templates/typescript/error-handler/src/middleware/error.middleware.ts +1 -1
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Raunak Ray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,33 +1,42 @@
1
- # ExpressKit
2
-
3
- **Scaffold a clean Express API in seconds — JavaScript or TypeScript.**
4
-
5
- [![Watch the ExpressKit demo](docs/demo.jpg)](docs/demo.mp4)
6
-
7
- ExpressKit asks four questions, then writes a ready-to-run Express 5 project. Choose JavaScript or TypeScript, optionally add centralized error handling, and start building.
1
+ # express-project-init
2
+
3
+ Set up a clean Express 5 API in seconds. Pick JavaScript or TypeScript, your linter, and your formatter. Then run it.
4
+
5
+ <p align="center">
6
+ <video
7
+ src="https://cdn.jsdelivr.net/gh/raunak-ray/ExpressKit@main/docs/express-project-init-v1.1.0-demo.mp4"
8
+ poster="https://cdn.jsdelivr.net/gh/raunak-ray/ExpressKit@main/docs/express-project-init-v1.1.0-demo.jpg"
9
+ autoplay
10
+ muted
11
+ loop
12
+ playsinline
13
+ controls
14
+ width="100%"
15
+ >
16
+ <img
17
+ src="https://cdn.jsdelivr.net/gh/raunak-ray/ExpressKit@main/docs/express-project-init-v1.1.0-demo.gif"
18
+ alt="express-project-init demo"
19
+ width="100%"
20
+ />
21
+ </video>
22
+ </p>
8
23
 
9
24
  ## Quick start
10
25
 
11
- Requires **Node.js 20+**.
26
+ Requires Node.js 20 or newer.
12
27
 
13
28
  ```bash
14
- npm create expresskit@latest
29
+ npx express-project-init@latest
15
30
  ```
16
31
 
17
- Or run it directly:
32
+ It asks six quick questions:
18
33
 
19
- ```bash
20
- npx create-expresskit@latest
21
- ```
22
-
23
- Answer the prompts:
24
-
25
- ```text
26
- ? Project name › my-api
27
- ? Language › TypeScript
28
- ? Create central error handling middleware? › Yes
29
- ? Install dependencies? › Yes
30
- ```
34
+ 1. Project name
35
+ 2. JavaScript or TypeScript
36
+ 3. Central error handling
37
+ 4. Linter
38
+ 5. Formatter
39
+ 6. Install dependencies
31
40
 
32
41
  Then:
33
42
 
@@ -38,72 +47,45 @@ npm run dev
38
47
 
39
48
  Open <http://localhost:3000/health>.
40
49
 
41
- Use `.` at the project name prompt to scaffold in the current directory. ExpressKit will not overwrite existing files.
50
+ Use `.` as the project name to set up in the current folder. Existing files are never overwritten.
42
51
 
43
52
  ## What you get
44
53
 
45
- ```text
46
- my-api/
47
- ├── package.json
48
- ├── tsconfig.json # TypeScript only
49
- └── src/
50
- ├── server.ts
51
- ├── app.ts
52
- ├── middleware/ # with the optional error handler
53
- │ ├── error.middleware.ts
54
- │ └── notFound.middleware.ts
55
- └── utils/
56
- ├── helpers.ts
57
- ├── responseHelpers.ts
58
- └── AppError.ts # with the optional error handler
59
- ```
60
-
61
- JavaScript projects use the same layout with `.js` files and no `tsconfig.json`.
62
-
63
- ### Scripts
64
-
65
- | Command | JavaScript | TypeScript |
66
- | --- | --- | --- |
67
- | `npm run dev` | `node --watch` | `tsx watch` |
68
- | `npm start` | `node` | `tsx` |
69
- | `npm run typecheck` | — | `tsc --noEmit` |
54
+ - A small Express 5 API with a `/health` route
55
+ - JavaScript or TypeScript
56
+ - Optional central error handling with one response format
57
+ - ESLint, Biome, or Oxlint
58
+ - Prettier or Biome
59
+ - Real config files, dependencies, and npm scripts
60
+ - Dependencies installed for you, if you want
70
61
 
71
- ## Error handling
62
+ TypeScript projects also get `tsconfig.json` and `npm run typecheck`.
72
63
 
73
- With the error handler enabled, throw `BadRequestError`, `UnauthorizedError`, or `NotFoundError` from any route and one middleware formats the response:
74
-
75
- ```json
76
- {
77
- "success": false,
78
- "message": "Route not found",
79
- "code": "NOT_FOUND"
80
- }
81
- ```
64
+ ## Scripts
82
65
 
83
- Successful responses use the same envelope with `success: true` and `data`.
66
+ The scripts you get depend on your choices.
84
67
 
85
- ## How it works
68
+ | Command | What it does |
69
+ | --- | --- |
70
+ | `npm run dev` | Start the API and watch for changes |
71
+ | `npm start` | Run the API |
72
+ | `npm run lint` | Check your code |
73
+ | `npm run format` | Format your code |
74
+ | `npm run typecheck` | Check TypeScript types |
86
75
 
87
- Projects are assembled from a base template plus optional feature layers. Feature files replace base files at the same path, and feature `package.json` fragments are merged into the base manifest.
88
-
89
- ## Local development
90
-
91
- ```bash
92
- npm install
93
- npm run build
94
- npm link
95
- ```
76
+ ## Publish
96
77
 
97
- Then, in a separate directory:
78
+ Commit your changes first. If this version is already on npm, bump it with `npm version patch` before publishing.
98
79
 
99
80
  ```bash
100
- mkdir -p /tmp/expresskit-test
101
- cd /tmp/expresskit-test
102
- create-expresskit
81
+ npm login
82
+ npm pack --dry-run # check what goes into the package
83
+ npm publish
84
+ npm view express-project-init version
103
85
  ```
104
86
 
105
- Rebuild with `npm run build` after changing `src/`; the linked command picks up the new `dist/` automatically. Remove the global link with `npm unlink -g create-expresskit`.
87
+ `npm publish` builds the package first.
106
88
 
107
89
  ## License
108
90
 
109
- MIT
91
+ [MIT](LICENSE.md) © 2026 Raunak Ray
package/dist/index.js CHANGED
@@ -13,11 +13,15 @@ async function main() {
13
13
  const language = await promptService.askLanguage();
14
14
  const availableFeatures = await templateService.getAvailableFeatures(language);
15
15
  const features = await promptService.askFeatureAnswers(availableFeatures);
16
+ const linter = await promptService.askLinter();
17
+ const formatter = await promptService.askFormatter();
16
18
  const installDependencies = await promptService.askShouldInstall();
17
19
  const answers = {
18
20
  projectName,
19
21
  language,
20
22
  features,
23
+ linter,
24
+ formatter,
21
25
  installDependencies,
22
26
  };
23
27
  // 2. Run the commands behind a spinner
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,KAAK,UAAU,IAAI;IACjB,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAE9C,qFAAqF;IACrF,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,cAAc,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,iBAAiB,GACrB,MAAM,eAAe,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC1E,MAAM,mBAAmB,GAAG,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAEnE,MAAM,OAAO,GAAmB;QAC9B,WAAW;QACX,QAAQ;QACR,QAAQ;QACR,mBAAmB;KACpB,CAAC;IAEF,uCAAuC;IACvC,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACnE,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QAErC,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;YAC3C,MAAM,cAAc,CAAC,iBAAiB,EAAE,CAAC;QAC3C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,WAAW,QAAQ,eAAe,WAAW,EAAE,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;IAEtE,OAAO,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,KAAK,UAAU,IAAI;IACjB,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAE9C,qFAAqF;IACrF,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,cAAc,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,iBAAiB,GACrB,MAAM,eAAe,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,CAAC;IAC/C,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,CAAC;IACrD,MAAM,mBAAmB,GAAG,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAEnE,MAAM,OAAO,GAAmB;QAC9B,WAAW;QACX,QAAQ;QACR,QAAQ;QACR,MAAM;QACN,SAAS;QACT,mBAAmB;KACpB,CAAC;IAEF,uCAAuC;IACvC,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACnE,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QAErC,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;YAC3C,MAAM,cAAc,CAAC,iBAAiB,EAAE,CAAC;QAC3C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,WAAW,QAAQ,eAAe,WAAW,EAAE,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;IAEtE,OAAO,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -5,6 +5,17 @@ export class PromptService {
5
5
  { value: "javascript", label: "JavaScript" },
6
6
  { value: "typescript", label: "TypeScript" },
7
7
  ];
8
+ LINTER_OPTIONS = [
9
+ { value: "none", label: "None" },
10
+ { value: "eslint", label: "ESLint" },
11
+ { value: "biome", label: "Biome" },
12
+ { value: "oxlint", label: "Oxlint" },
13
+ ];
14
+ FORMATTER_OPTIONS = [
15
+ { value: "none", label: "None" },
16
+ { value: "prettier", label: "Prettier" },
17
+ { value: "biome", label: "Biome" },
18
+ ];
8
19
  async askProjectName() {
9
20
  const response = await text({
10
21
  message: "What would you like to name your project?",
@@ -44,6 +55,24 @@ export class PromptService {
44
55
  }
45
56
  return answers;
46
57
  }
58
+ async askLinter() {
59
+ const response = await select({
60
+ message: "Which linter would you like to use?",
61
+ options: this.LINTER_OPTIONS,
62
+ initialValue: "oxlint",
63
+ });
64
+ this.handleCancel(response);
65
+ return response;
66
+ }
67
+ async askFormatter() {
68
+ const response = await select({
69
+ message: "Which formatter would you like to use?",
70
+ options: this.FORMATTER_OPTIONS,
71
+ initialValue: "biome",
72
+ });
73
+ this.handleCancel(response);
74
+ return response;
75
+ }
47
76
  async askShouldInstall() {
48
77
  const response = await confirm({
49
78
  message: "Install dependencies?",
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.service.js","sourceRoot":"","sources":["../../src/services/prompts.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAgB,MAAM,gBAAgB,CAAC;AAGxD,MAAM,OAAO,aAAa;IACP,gBAAgB,GAG3B;QACJ,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;QAC5C,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;KAC7C,CAAC;IAEK,KAAK,CAAC,cAAc;QACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;YAC1B,OAAO,EAAE,2CAA2C;YACpD,WAAW,EAAE,QAAQ;YACrB,YAAY,EAAE,GAAG;YACjB,QAAQ,CAAC,KAAK;gBACZ,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;oBACnB,OAAO,kEAAkE,CAAC;gBAC5E,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAS,QAAQ,CAAC,CAAC;QAEpC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,WAAW;QACtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;YAC5B,OAAO,EAAE,uCAAuC;YAChD,OAAO,EAAE,IAAI,CAAC,gBAAgB;YAC9B,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAW,QAAQ,CAAC,CAAC;QAEtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,iBAAiB,CAC5B,iBAAqC;QAErC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAChC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAC7B,CAAC;QAEpB,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;gBAC7B,OAAO,EAAE,OAAO,CAAC,MAAM;gBACvB,YAAY,EAAE,OAAO,CAAC,YAAY;aACnC,CAAC,CAAC;YAEH,IAAI,CAAC,YAAY,CAAU,QAAQ,CAAC,CAAC;YAErC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC;QACjC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,KAAK,CAAC,gBAAgB;QAC3B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;YAC7B,OAAO,EAAE,uBAAuB;YAChC,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAU,QAAQ,CAAC,CAAC;QAErC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,qEAAqE;IAC7D,YAAY,CAAI,QAAiB;QACvC,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,0BAA0B,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"prompts.service.js","sourceRoot":"","sources":["../../src/services/prompts.service.ts"],"names":[],"mappings":"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"}
@@ -27,18 +27,43 @@ export class TemplateService {
27
27
  catch (error) {
28
28
  throw new Error(`Unable to read templates for "${language}" at "${languageDirectory}".`, { cause: error });
29
29
  }
30
- const folders = new Set(entries
31
- .filter((entry) => entry.isDirectory())
32
- .map((entry) => entry.name));
30
+ const folders = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
33
31
  return FEATURES.filter((feature) => folders.has(feature.id));
34
32
  }
33
+ resolveToolLayers(linter, formatter) {
34
+ if (linter === "biome" && formatter === "biome") {
35
+ return ["format/biome/both"];
36
+ }
37
+ const layers = [];
38
+ switch (linter) {
39
+ case "oxlint":
40
+ layers.push("lint/oxlint");
41
+ break;
42
+ case "eslint":
43
+ layers.push("lint/eslint");
44
+ break;
45
+ case "biome":
46
+ layers.push("lint/biome");
47
+ break;
48
+ }
49
+ switch (formatter) {
50
+ case "prettier":
51
+ layers.push("format/prettier");
52
+ break;
53
+ case "biome":
54
+ layers.push("format/biome/format");
55
+ break;
56
+ }
57
+ return layers;
58
+ }
35
59
  /**
36
60
  * Builds the complete project in memory.
37
61
  *
38
62
  * Base files come first. Each enabled feature is then layered on top:
39
63
  * feature files replace base files with the same relative path, while new
40
- * paths are added. package.json is the exception — feature package.json
41
- * files are fragments merged into the base package.json.
64
+ * paths are added. Tool layers (linters and formatters) are applied next.
65
+ * package.json is the exception — feature and tool package.json files are
66
+ * fragments merged into the base package.json.
42
67
  */
43
68
  async buildFilePlan(answers) {
44
69
  const baseFiles = await this.readLayer(answers.language, "base");
@@ -52,29 +77,52 @@ export class TemplateService {
52
77
  if (!answers.features[feature.id]) {
53
78
  continue;
54
79
  }
55
- const layer = await this.readLayer(answers.language, feature.id);
56
- const fragmentSource = layer["package.json"];
57
- if (fragmentSource !== undefined) {
58
- const fragment = this.parsePackageFragment(fragmentSource, feature.id);
59
- packageJson = this.mergePackageJson(packageJson, fragment, feature.id);
60
- // The merged package.json is written last, not copied from the layer.
61
- delete layer["package.json"];
62
- }
63
- files = { ...files, ...layer };
80
+ const applied = await this.applyLayer(path.join(answers.language, feature.id), files, packageJson);
81
+ files = applied.files;
82
+ packageJson = applied.packageJson;
83
+ }
84
+ for (const toolLayer of this.resolveToolLayers(answers.linter, answers.formatter)) {
85
+ const applied = await this.applyLayer(toolLayer, files, packageJson);
86
+ files = applied.files;
87
+ packageJson = applied.packageJson;
88
+ }
89
+ if (answers.linter === "eslint" && answers.formatter === "prettier") {
90
+ packageJson = this.mergePackageJson(packageJson, {
91
+ devDependencies: {
92
+ "eslint-config-prettier": "^10.1.8",
93
+ },
94
+ }, "eslint-prettier-compatibility");
64
95
  }
65
96
  files["package.json"] = `${JSON.stringify(packageJson, null, 2)}\n`;
66
97
  return files;
67
98
  }
68
- async readLayer(language, layerName) {
69
- const layerDirectory = path.join(this.templateRoot, language, layerName);
99
+ async readLayer(...segments) {
100
+ const layerDirectory = path.join(this.templateRoot, ...segments);
70
101
  try {
71
102
  await access(layerDirectory);
72
103
  }
73
104
  catch (error) {
74
- throw new Error(`Template folder not found: "${language}/${layerName}".`, { cause: error });
105
+ throw new Error(`Template folder not found: "${segments.join("/")}".`, {
106
+ cause: error,
107
+ });
75
108
  }
76
109
  return this.readDirectory(layerDirectory);
77
110
  }
111
+ async applyLayer(layerPath, files, packageJson) {
112
+ const layer = await this.readLayer(layerPath);
113
+ const fragmentSource = layer["package.json"];
114
+ let updatedPackageJson = packageJson;
115
+ if (fragmentSource !== undefined) {
116
+ const fragment = this.parsePackageFragment(fragmentSource, layerPath);
117
+ updatedPackageJson = this.mergePackageJson(packageJson, fragment, layerPath);
118
+ // The merged package.json is written last, not copied from the layer.
119
+ delete layer["package.json"];
120
+ }
121
+ return {
122
+ files: { ...files, ...layer },
123
+ packageJson: updatedPackageJson,
124
+ };
125
+ }
78
126
  async readDirectory(root, relativeDirectory = "") {
79
127
  const directory = path.join(root, relativeDirectory);
80
128
  const entries = await readdir(directory, { withFileTypes: true });
@@ -1 +1 @@
1
- {"version":3,"file":"template.service.js","sourceRoot":"","sources":["../../src/services/template.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"template.service.js","sourceRoot":"","sources":["../../src/services/template.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-project-init",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Create production-ready Express.js API projects with JavaScript or TypeScript using clean, reusable starter templates.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,7 +11,10 @@
11
11
  "dist",
12
12
  "templates",
13
13
  "README.md",
14
- "LICENSE"
14
+ "LICENSE.md",
15
+ "docs/express-project-init-v1.1.0-demo.mp4",
16
+ "docs/express-project-init-v1.1.0-demo.jpg",
17
+ "docs/express-project-init-v1.1.0-demo.gif"
15
18
  ],
16
19
  "engines": {
17
20
  "node": ">=20"
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": true,
8
+ "indentStyle": "space",
9
+ "indentWidth": 2
10
+ },
11
+ "linter": {
12
+ "enabled": true,
13
+ "rules": {
14
+ "preset": "recommended"
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "biome lint",
4
+ "lint:fix": "biome lint --write",
5
+ "format": "biome format --write",
6
+ "format:check": "biome format",
7
+ "check": "biome check"
8
+ },
9
+ "devDependencies": {
10
+ "@biomejs/biome": "^2.6.4"
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": true,
8
+ "indentStyle": "space",
9
+ "indentWidth": 2
10
+ },
11
+ "linter": {
12
+ "enabled": false
13
+ }
14
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "format": "biome format --write",
4
+ "format:check": "biome format"
5
+ },
6
+ "devDependencies": {
7
+ "@biomejs/biome": "^2.6.4"
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ node_modules
2
+ dist
3
+ coverage
@@ -0,0 +1,6 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "all",
5
+ "tabWidth": 2
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "format": "prettier --write .",
4
+ "format:check": "prettier --check ."
5
+ },
6
+ "devDependencies": {
7
+ "prettier": "^3.9.10"
8
+ }
9
+ }
@@ -1,9 +1,9 @@
1
1
  import { AppError, BadRequestError } from "../utils/AppError.js";
2
- import { errorResponse } from "../utils/responseHelpers.js";
3
2
  import { getTimeStamp } from "../utils/helpers.js";
3
+ import { errorResponse } from "../utils/responseHelpers.js";
4
4
 
5
5
  // Express error handler — needs all 4 params, that's how Express recognizes it.
6
- export default function errorMiddleware(error, req, res, next) {
6
+ export default function errorMiddleware(error, req, res, _next) {
7
7
  const timeStamp = getTimeStamp();
8
8
 
9
9
  // Expected errors — log them and send their details
@@ -1,5 +1,5 @@
1
1
  import { NotFoundError } from "../utils/AppError.js";
2
2
 
3
- export default function notFoundMiddleware(req, res, next) {
3
+ export default function notFoundMiddleware(_req, _res, next) {
4
4
  next(new NotFoundError("Route not found"));
5
5
  }
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": false
8
+ },
9
+ "linter": {
10
+ "enabled": true,
11
+ "rules": {
12
+ "preset": "recommended"
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "biome lint",
4
+ "lint:fix": "biome lint --write"
5
+ },
6
+ "devDependencies": {
7
+ "@biomejs/biome": "^2.6.4"
8
+ }
9
+ }
@@ -0,0 +1,36 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import tseslint from "typescript-eslint";
4
+
5
+ let prettier = [];
6
+ try {
7
+ const prettierConfig = await import("eslint-config-prettier");
8
+ prettier = [prettierConfig.default];
9
+ } catch (error) {
10
+ // eslint-config-prettier is optional, used when Prettier is also configured
11
+ void error;
12
+ }
13
+
14
+ export default tseslint.config(
15
+ {
16
+ languageOptions: {
17
+ globals: {
18
+ ...globals.node,
19
+ },
20
+ },
21
+ },
22
+ js.configs.recommended,
23
+ ...tseslint.configs.recommended,
24
+ {
25
+ rules: {
26
+ "@typescript-eslint/no-unused-vars": [
27
+ "error",
28
+ {
29
+ argsIgnorePattern: "^_",
30
+ varsIgnorePattern: "^_",
31
+ },
32
+ ],
33
+ },
34
+ },
35
+ ...prettier,
36
+ );
@@ -0,0 +1,12 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "eslint .",
4
+ "lint:fix": "eslint . --fix"
5
+ },
6
+ "devDependencies": {
7
+ "@eslint/js": "^9.20.0",
8
+ "eslint": "^9.20.0",
9
+ "globals": "^16.0.0",
10
+ "typescript-eslint": "^8.24.0"
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["typescript", "unicorn", "oxc"],
4
+ "categories": {
5
+ "correctness": "error"
6
+ },
7
+ "rules": {},
8
+ "env": {
9
+ "builtin": true,
10
+ "node": true
11
+ },
12
+ "ignorePatterns": ["node_modules", "dist"]
13
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "oxlint",
4
+ "lint:fix": "oxlint --fix"
5
+ },
6
+ "devDependencies": {
7
+ "oxlint": "^1.90.0"
8
+ }
9
+ }
@@ -3,28 +3,28 @@
3
3
  // Imports / modules
4
4
  // "bundler" is THE setting that lets you import WITHOUT extensions:
5
5
  // import app from "./app" (not "./app.ts")
6
- "module": "esnext", // emit modern ES module syntax
6
+ "module": "esnext", // emit modern ES module syntax
7
7
  "moduleResolution": "bundler", // resolve imports without ".ts" extensions
8
- "moduleDetection": "force", // treat every file as an ES module (no CommonJS guessing)
9
- "esModuleInterop": true, // allow normal default imports from CJS packages (express)
10
- "verbatimModuleSyntax": true, // keep imports exactly as written; type-only imports must use "import type"
8
+ "moduleDetection": "force", // treat every file as an ES module (no CommonJS guessing)
9
+ "esModuleInterop": true, // allow normal default imports from CJS packages (express)
10
+ "verbatimModuleSyntax": true, // keep imports exactly as written; type-only imports must use "import type"
11
11
 
12
12
  // Language level
13
- "target": "esnext", // allow the newest JS features, no downleveling
13
+ "target": "esnext", // allow the newest JS features, no downleveling
14
14
 
15
15
  // Type checking
16
- "strict": true, // turn on all strict type checks
17
- "noUnusedLocals": true, // error on declared-but-unused variables
18
- "noUnusedParameters": true, // error on unused function parameters
19
- "skipLibCheck": true, // don't type-check ".d.ts" files inside node_modules (faster)
16
+ "strict": true, // turn on all strict type checks
17
+ "noUnusedLocals": true, // error on declared-but-unused variables
18
+ "noUnusedParameters": true, // error on unused function parameters
19
+ "skipLibCheck": true, // don't type-check ".d.ts" files inside node_modules (faster)
20
20
 
21
21
  // Runtime types
22
- "types": ["node"], // auto-include ONLY Node types (no stray umbrella types)
22
+ "types": ["node"], // auto-include ONLY Node types (no stray umbrella types)
23
23
 
24
24
  // Output
25
- "noEmit": true // tsx runs the code directly, so tsc only type-checks, never writes files
25
+ "noEmit": true // tsx runs the code directly, so tsc only type-checks, never writes files
26
26
  },
27
27
  // Files in scope
28
- "include": ["src"], // the compiler only looks at src/
29
- "exclude": ["node_modules"] // never scan dependencies
28
+ "include": ["src"], // the compiler only looks at src/
29
+ "exclude": ["node_modules"] // never scan dependencies
30
30
  }
@@ -1,7 +1,7 @@
1
1
  import type { NextFunction, Request, Response } from "express";
2
2
  import { AppError, BadRequestError } from "../utils/AppError";
3
- import { errorResponse } from "../utils/responseHelpers";
4
3
  import { getTimeStamp } from "../utils/helpers";
4
+ import { errorResponse } from "../utils/responseHelpers";
5
5
 
6
6
  // Express error handler — needs all 4 params, that's how Express recognizes it.
7
7
  export default function errorMiddleware(