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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Watch the ExpressKit demo](docs/demo.jpg)](docs/demo.mp4)
6
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.
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 | JavaScript | TypeScript |
72
+ | Command | Provider | Description |
66
73
  | --- | --- | --- |
67
- | `npm run dev` | `node --watch` | `tsx watch` |
68
- | `npm start` | `node` | `tsx` |
69
- | `npm run typecheck` | — | `tsc --noEmit` |
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 feature `package.json` fragments are merged into the base manifest.
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. 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.1.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",
@@ -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(