express-project-init 1.0.0 → 1.1.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.
- package/README.md +38 -6
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/services/prompts.service.js +29 -0
- package/dist/services/prompts.service.js.map +1 -1
- package/dist/services/template.service.js +65 -17
- package/dist/services/template.service.js.map +1 -1
- package/package.json +1 -1
- package/templates/format/biome/both/biome.json +17 -0
- package/templates/format/biome/both/package.json +12 -0
- package/templates/format/biome/format/biome.json +14 -0
- package/templates/format/biome/format/package.json +9 -0
- package/templates/format/prettier/.prettierignore +3 -0
- package/templates/format/prettier/.prettierrc +6 -0
- package/templates/format/prettier/package.json +9 -0
- package/templates/javascript/error-handler/src/middleware/error.middleware.js +2 -2
- package/templates/javascript/error-handler/src/middleware/notFound.middleware.js +1 -1
- package/templates/lint/biome/biome.json +15 -0
- package/templates/lint/biome/package.json +9 -0
- package/templates/lint/eslint/eslint.config.js +36 -0
- package/templates/lint/eslint/package.json +12 -0
- package/templates/lint/oxlint/.oxlintrc.json +13 -0
- package/templates/lint/oxlint/package.json +9 -0
- package/templates/typescript/base/tsconfig.json +13 -13
- package/templates/typescript/error-handler/src/middleware/error.middleware.ts +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](docs/demo.mp4)
|
|
6
6
|
|
|
7
|
-
ExpressKit asks
|
|
7
|
+
ExpressKit asks a few quick questions, then writes a ready-to-run Express 5 project. Choose JavaScript or TypeScript, optionally add centralized error handling, pick your linter and formatter, and start building.
|
|
8
8
|
|
|
9
9
|
## Quick start
|
|
10
10
|
|
|
@@ -26,6 +26,8 @@ Answer the prompts:
|
|
|
26
26
|
? Project name › my-api
|
|
27
27
|
? Language › TypeScript
|
|
28
28
|
? Create central error handling middleware? › Yes
|
|
29
|
+
? Which linter would you like to use? › ESLint
|
|
30
|
+
? Which formatter would you like to use? › Prettier
|
|
29
31
|
? Install dependencies? › Yes
|
|
30
32
|
```
|
|
31
33
|
|
|
@@ -46,6 +48,11 @@ Use `.` at the project name prompt to scaffold in the current directory. Express
|
|
|
46
48
|
my-api/
|
|
47
49
|
├── package.json
|
|
48
50
|
├── tsconfig.json # TypeScript only
|
|
51
|
+
├── eslint.config.js # with ESLint
|
|
52
|
+
├── .oxlintrc.json # with Oxlint
|
|
53
|
+
├── biome.json # with Biome (linter, formatter, or both)
|
|
54
|
+
├── .prettierrc # with Prettier
|
|
55
|
+
├── .prettierignore # with Prettier
|
|
49
56
|
└── src/
|
|
50
57
|
├── server.ts
|
|
51
58
|
├── app.ts
|
|
@@ -62,11 +69,36 @@ JavaScript projects use the same layout with `.js` files and no `tsconfig.json`.
|
|
|
62
69
|
|
|
63
70
|
### Scripts
|
|
64
71
|
|
|
65
|
-
| Command |
|
|
72
|
+
| Command | Provider | Description |
|
|
66
73
|
| --- | --- | --- |
|
|
67
|
-
| `npm run dev` |
|
|
68
|
-
| `npm start` |
|
|
69
|
-
| `npm run typecheck` |
|
|
74
|
+
| `npm run dev` | Core | Start development server with file watching |
|
|
75
|
+
| `npm start` | Core | Run the application |
|
|
76
|
+
| `npm run typecheck` | Core (TS) | Run TypeScript compiler checks (`tsc --noEmit`) |
|
|
77
|
+
| `npm run lint` | ESLint / Biome / Oxlint | Lint source files |
|
|
78
|
+
| `npm run lint:fix` | ESLint / Biome / Oxlint | Auto-fix linting issues |
|
|
79
|
+
| `npm run format` | Prettier / Biome | Format source files |
|
|
80
|
+
| `npm run format:check` | Prettier / Biome | Check source files for formatting issues |
|
|
81
|
+
| `npm run check` | Biome (both) | Run formatting check, import sorting, and linting |
|
|
82
|
+
|
|
83
|
+
## Linters and formatters
|
|
84
|
+
|
|
85
|
+
ExpressKit supports modern, lightning-fast linting and formatting tools:
|
|
86
|
+
|
|
87
|
+
- **Linters**:
|
|
88
|
+
- **ESLint**: Industry-standard linter configured with ESLint 9+ flat config (`eslint.config.js`), Node globals, and TypeScript support via `typescript-eslint`.
|
|
89
|
+
- **Biome**: Rust-powered linter with instant feedback and safe fixes.
|
|
90
|
+
- **Oxlint**: High-speed Rust-based linter from the OXC project with `.oxlintrc.json`.
|
|
91
|
+
- **None**: Skip linter setup.
|
|
92
|
+
|
|
93
|
+
- **Formatters**:
|
|
94
|
+
- **Prettier**: Opinionated code formatter with `.prettierrc` and `.prettierignore`.
|
|
95
|
+
- **Biome**: High-performance code formatter configured with 2-space indentation.
|
|
96
|
+
- **None**: Skip formatter setup.
|
|
97
|
+
|
|
98
|
+
### Tool combinations
|
|
99
|
+
|
|
100
|
+
- **Biome for both linting & formatting**: Generates a unified `biome.json` with both features enabled, plus `lint`, `lint:fix`, `format`, `format:check`, and `check` scripts.
|
|
101
|
+
- **ESLint + Prettier**: Automatically installs and configures `eslint-config-prettier` to disable ESLint rules that might conflict with Prettier.
|
|
70
102
|
|
|
71
103
|
## Error handling
|
|
72
104
|
|
|
@@ -84,7 +116,7 @@ Successful responses use the same envelope with `success: true` and `data`.
|
|
|
84
116
|
|
|
85
117
|
## How it works
|
|
86
118
|
|
|
87
|
-
Projects are assembled from a base template plus optional feature layers. Feature files replace base files at the same path, and
|
|
119
|
+
Projects are assembled from a base template plus optional feature and tool layers. Feature and tool files replace base files at the same path, and `package.json` fragments are merged into the base manifest.
|
|
88
120
|
|
|
89
121
|
## Local development
|
|
90
122
|
|
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.
|
|
41
|
-
*
|
|
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
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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(
|
|
69
|
-
const layerDirectory = path.join(this.templateRoot,
|
|
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: "${
|
|
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":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAgB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"template.service.js","sourceRoot":"","sources":["../../src/services/template.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -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
|
+
}
|
|
@@ -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,
|
|
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
|
|
@@ -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,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
|
+
}
|
|
@@ -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",
|
|
6
|
+
"module": "esnext", // emit modern ES module syntax
|
|
7
7
|
"moduleResolution": "bundler", // resolve imports without ".ts" extensions
|
|
8
|
-
"moduleDetection": "force",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
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",
|
|
13
|
+
"target": "esnext", // allow the newest JS features, no downleveling
|
|
14
14
|
|
|
15
15
|
// Type checking
|
|
16
|
-
"strict": true,
|
|
17
|
-
"noUnusedLocals": true,
|
|
18
|
-
"noUnusedParameters": true,
|
|
19
|
-
"skipLibCheck": true,
|
|
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"],
|
|
22
|
+
"types": ["node"], // auto-include ONLY Node types (no stray umbrella types)
|
|
23
23
|
|
|
24
24
|
// Output
|
|
25
|
-
"noEmit": true
|
|
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"],
|
|
29
|
-
"exclude": ["node_modules"]
|
|
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(
|