@hs-web-team/eslint-config-node 3.0.0-next.7 → 3.0.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/CLAUDE.md CHANGED
@@ -26,8 +26,13 @@ When testing changes to this package in downstream projects, you'll typically:
26
26
  ### Core Configuration File
27
27
  - **`index.js`**: The main ESLint configuration export using ESLint 9's flat config format
28
28
  - Uses `@eslint/js`, `typescript-eslint`, and `globals` packages
29
- - Exports two separate configurations: one for JavaScript files (`**/*.{js,mjs,cjs}`) and one for TypeScript files (`**/*.{ts,mts,cts,tsx}`)
30
- - JavaScript config uses `js/recommended`, TypeScript config uses `tseslint.configs.recommended`
29
+ - Exports an array of configuration objects (flat config format)
30
+ - Structure:
31
+ 1. Global ignores object
32
+ 2. `js.configs.recommended` for JavaScript baseline
33
+ 3. JavaScript-specific config for `**/*.{js,mjs,cjs}` files
34
+ 4. Spreads `tseslint.configs.recommended` for TypeScript baseline
35
+ 5. TypeScript-specific config for `**/*.{ts,mts,cts,tsx}` files
31
36
  - Includes Node.js, ES2022, and Jest globals
32
37
  - Common ignores: `node_modules`, `.serverless`, `.webpack`, `dist`, `eslint.config.js`
33
38
  - Key custom rules: `no-console` (allows info/warn/error), `max-len` (120 chars), camelcase disabled
package/README.md CHANGED
@@ -22,21 +22,19 @@ This is a list of ESLint rules that are recommended for use with **Hubspot Marke
22
22
  2. Add to `eslint.config.js` in project root directory
23
23
 
24
24
  ```typescript
25
- import { defineConfig } from 'eslint/config';
26
25
  import wtConfig from '@hs-web-team/eslint-config-node';
27
26
 
28
- export default defineConfig([
27
+ export default [
29
28
  ...wtConfig,
30
- ]);
29
+ ];
31
30
  ```
32
31
 
33
32
  3. Extend the eslint on a project basis by adding rules to `eslint.config.js` e.g.
34
33
 
35
34
  ```typescript
36
- import { defineConfig } from 'eslint/config';
37
35
  import wtConfig from '@hs-web-team/eslint-config-node';
38
36
 
39
- export default defineConfig([
37
+ export default [
40
38
  // Add project-specific ignores here
41
39
  {
42
40
  ignores: ['dist/**'],
@@ -48,7 +46,7 @@ This is a list of ESLint rules that are recommended for use with **Hubspot Marke
48
46
  },
49
47
  },
50
48
  ...wtConfig, // This will include the shared rules from @hs-web-team/eslint-config-node
51
- ]);
49
+ ];
52
50
  ```
53
51
 
54
52
  ## Where to use it
@@ -4,13 +4,16 @@
4
4
 
5
5
  > **Note**
6
6
  >
7
- > This migration requires a manual review of the changes and also that you run your project in Node.js v22 or higher.
7
+ > This migration requires Node.js v22 or higher and a **manual migration** from `.eslintrc` to `eslint.config.mjs`.
8
8
 
9
9
  - [ ] Upgrade to Node.js v22 or higher
10
- - [ ] Upgrade all dependencies to the latest version
11
- - [ ] Update the package `npm install @hs-web-team/eslint-config-node@latest`
12
- - [ ] Run the script `npx @eslint/migrate-config .eslintrc`
10
+ - [ ] Update the package: `npm install -D @hs-web-team/eslint-config-node@latest`
11
+ - [ ] **Remove** `@hs-web-team/eslint-config-ts` from dependencies (no longer needed - TypeScript support is now included)
12
+ - [ ] Remove the `--ext .js,.ts` flag from the ESLint command in your project's package.json
13
+ - [ ] Manually create `eslint.config.mjs` (see [Manual Migration Guide](#manual-migration-guide) below)
14
+ - [ ] Delete `.eslintrc` file
13
15
  - [ ] Run `npm run lint` to check for any errors
16
+ - [ ] Fix any linting errors
14
17
  - [ ] Commit the changes
15
18
  - [ ] Create a PR
16
19
  - [ ] Get it approved
@@ -20,5 +23,268 @@
20
23
 
21
24
  > **Important**
22
25
  >
23
- > Bear in mind that this migration will remove the `.eslintrc` file and replace it with `eslint.config.js`.
24
- > Also the automated migration might fail to migrate some of the rules, so you may need to manually adjust the `eslint.config.js` file.
26
+ > The automated migration script (`npx @eslint/migrate-config .eslintrc`) **will not work** for most projects migrating from ESLint 8 to ESLint 9. You must manually create the new `eslint.config.js` file.
27
+ >
28
+ > This is because:
29
+ > - ESLint 9 uses a completely different flat config format
30
+ > - The `@hs-web-team/eslint-config-ts` package is no longer needed (TypeScript support is built-in)
31
+ > - Many ESLint plugins have changed their configuration APIs
32
+
33
+ ## Manual Migration Guide
34
+
35
+ ### Before: Typical `.eslintrc` file
36
+
37
+ ```json
38
+ {
39
+ "extends": [
40
+ "@hs-web-team/eslint-config-node",
41
+ "@hs-web-team/eslint-config-ts"
42
+ ],
43
+ "rules": {
44
+ "no-restricted-syntax": 0,
45
+ "no-console": 0,
46
+ "no-param-reassign": 0,
47
+ "no-await-in-loop": 0,
48
+ "max-classes-per-file": 0,
49
+ "import/no-extraneous-dependencies": 0,
50
+ "@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true }],
51
+ "@typescript-eslint/no-unnecessary-condition": "error"
52
+ },
53
+ "overrides": [
54
+ {
55
+ "files": ["*.test.ts", "*.spec.ts"],
56
+ "rules": {
57
+ "no-unused-expressions": "off"
58
+ }
59
+ }
60
+ ],
61
+ "env": {
62
+ "jest": true
63
+ },
64
+ "parserOptions": {
65
+ "project": "./tsconfig.json"
66
+ },
67
+ "globals": {
68
+ "window": true
69
+ }
70
+ }
71
+ ```
72
+
73
+ ### After: New `eslint.config.mjs` file
74
+
75
+ ```javascript
76
+ import wtConfig from '@hs-web-team/eslint-config-node';
77
+ import tseslint from 'typescript-eslint';
78
+
79
+ export default [
80
+ // Spread the base config (includes both JS and TS configs)
81
+ ...wtConfig,
82
+
83
+ // Add custom rules for all files
84
+ {
85
+ rules: {
86
+ 'no-restricted-syntax': 'off',
87
+ 'no-console': 'off',
88
+ 'no-param-reassign': 'off',
89
+ 'no-await-in-loop': 'off',
90
+ 'max-classes-per-file': 'off',
91
+ 'import/no-extraneous-dependencies': 'off',
92
+ },
93
+ },
94
+
95
+ // TypeScript-specific rules (applied only to TS files)
96
+ {
97
+ files: ['**/*.{ts,mts,cts,tsx}'],
98
+ languageOptions: {
99
+ parserOptions: {
100
+ project: './tsconfig.json',
101
+ },
102
+ },
103
+ rules: {
104
+ '@typescript-eslint/no-unused-vars': [
105
+ 'error',
106
+ { vars: 'all', args: 'after-used', ignoreRestSiblings: true }
107
+ ],
108
+ '@typescript-eslint/no-unnecessary-condition': 'error',
109
+ },
110
+ },
111
+
112
+ // Test file overrides
113
+ {
114
+ files: ['**/*.test.{ts,js}', '**/*.spec.{ts,js}'],
115
+ rules: {
116
+ 'no-unused-expressions': 'off',
117
+ },
118
+ },
119
+
120
+ // Global variables (if needed)
121
+ {
122
+ languageOptions: {
123
+ globals: {
124
+ window: 'readonly',
125
+ },
126
+ },
127
+ },
128
+ ];
129
+ ```
130
+
131
+ ### Key Migration Changes
132
+
133
+ 1. **No separate TypeScript config needed**: TypeScript support is now included in `@hs-web-team/eslint-config-node`, so you can remove `@hs-web-team/eslint-config-ts` from your dependencies.
134
+
135
+ 2. **Environment variables**: The `env` property is replaced with `languageOptions.globals`. Jest globals are already included in the base config, so you don't need to specify them again.
136
+
137
+ 3. **Parser options**: Move `parserOptions` inside `languageOptions.parserOptions` and apply only to TypeScript files.
138
+
139
+ 4. **Overrides become separate objects**: Instead of `overrides` array, create separate configuration objects with `files` patterns.
140
+
141
+ 5. **Use `'off'` instead of `0`**: While numbers still work, the string values (`'off'`, `'warn'`, `'error'`) are more readable.
142
+
143
+ 6. **Import as ES module**: Use `import` instead of `require`.
144
+
145
+ ## Extending the Configuration
146
+
147
+ Once you've completed the migration, you can easily extend the configuration for specific needs:
148
+
149
+ ### Adding Rules for Specific File Patterns
150
+
151
+ ```javascript
152
+ import wtConfig from '@hs-web-team/eslint-config-node';
153
+
154
+ export default [
155
+ ...wtConfig,
156
+ {
157
+ files: ['src/**/*.js'],
158
+ rules: {
159
+ 'no-restricted-imports': ['error', 'lodash'],
160
+ },
161
+ },
162
+ ];
163
+ ```
164
+
165
+ ### Adding Custom Plugins
166
+
167
+ ```javascript
168
+ import wtConfig from '@hs-web-team/eslint-config-node';
169
+ import securityPlugin from 'eslint-plugin-security';
170
+
171
+ export default [
172
+ ...wtConfig,
173
+ {
174
+ plugins: {
175
+ security: securityPlugin,
176
+ },
177
+ rules: {
178
+ 'security/detect-object-injection': 'warn',
179
+ },
180
+ },
181
+ ];
182
+ ```
183
+
184
+ ### Adding Custom Ignores
185
+
186
+ ```javascript
187
+ import wtConfig from '@hs-web-team/eslint-config-node';
188
+
189
+ export default [
190
+ ...wtConfig,
191
+ {
192
+ ignores: [
193
+ '**/coverage/**',
194
+ '**/build/**',
195
+ '**/*.config.js',
196
+ ],
197
+ },
198
+ ];
199
+ ```
200
+
201
+ ### Complex Example with Multiple Customizations
202
+
203
+ ```javascript
204
+ import wtConfig from '@hs-web-team/eslint-config-node';
205
+ import importPlugin from 'eslint-plugin-import';
206
+
207
+ export default [
208
+ ...wtConfig,
209
+
210
+ // Global overrides
211
+ {
212
+ rules: {
213
+ 'no-console': 'off',
214
+ 'max-len': ['error', { code: 100 }],
215
+ },
216
+ },
217
+
218
+ // Import plugin configuration
219
+ {
220
+ plugins: {
221
+ import: importPlugin,
222
+ },
223
+ rules: {
224
+ 'import/order': ['error', { 'newlines-between': 'always' }],
225
+ 'import/no-duplicates': 'error',
226
+ },
227
+ },
228
+
229
+ // TypeScript-specific configuration
230
+ {
231
+ files: ['**/*.{ts,tsx}'],
232
+ languageOptions: {
233
+ parserOptions: {
234
+ project: './tsconfig.json',
235
+ },
236
+ },
237
+ rules: {
238
+ '@typescript-eslint/strict-boolean-expressions': 'error',
239
+ },
240
+ },
241
+
242
+ // Test files
243
+ {
244
+ files: ['**/*.test.{js,ts}', '**/__tests__/**'],
245
+ rules: {
246
+ 'max-len': 'off',
247
+ 'no-magic-numbers': 'off',
248
+ },
249
+ },
250
+
251
+ // Additional ignores
252
+ {
253
+ ignores: ['**/generated/**', '**/migrations/**'],
254
+ },
255
+ ];
256
+ ```
257
+
258
+ ## Common Issues
259
+
260
+ ### Module Type Warning
261
+
262
+ If you created `eslint.config.js` instead of `eslint.config.mjs`, you may see this warning when running ESLint:
263
+
264
+ ```bash
265
+ (node:40504) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///path/to/your/project/eslint.config.js?mtime=1762786140088 is not specified and it doesn't parse as CommonJS.
266
+ Reparsing as ES module because module syntax was detected. This incurs a performance overhead.
267
+ To eliminate this warning, add "type": "module" to /path/to/your/project/package.json.
268
+ ```
269
+
270
+ **Why this happens:** This ESLint config package uses ES modules (`"type": "module"`), and your `eslint.config.js` imports it using ES module syntax. If your project's `package.json` doesn't specify the module type, Node.js has to parse the file twice, causing the warning.
271
+
272
+ **Solution (choose one):**
273
+
274
+ **Option 1 (Recommended for CommonJS projects):** Rename the config file to explicitly mark it as an ES module:
275
+
276
+ ```bash
277
+ mv eslint.config.js eslint.config.mjs
278
+ ```
279
+
280
+ This is the recommended approach because it doesn't require any changes to your existing codebase.
281
+
282
+ **Option 2 (Only if already using ES modules):** Add to your project's `package.json`:
283
+
284
+ ```jsonc
285
+ {
286
+ "type": "module"
287
+ }
288
+ ```
289
+
290
+ > **Warning:** Option 2 requires migrating your entire project from CommonJS to ES modules. All `.js` files must use ES module syntax (import/export) or be renamed to `.cjs`. Only use this option if your project is already using ES modules throughout.
package/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import js from '@eslint/js';
2
2
  import globals from 'globals';
3
3
  import tseslint from 'typescript-eslint';
4
- import { defineConfig } from 'eslint/config';
5
4
 
6
5
  // Base rules for all JavaScript files
7
6
  const baseRules = {
@@ -47,26 +46,30 @@ const commonIgnores = [
47
46
  'eslint.config.js',
48
47
  ];
49
48
 
50
- export default defineConfig([
49
+ export default [
50
+ // Global ignores
51
+ {
52
+ ignores: commonIgnores,
53
+ },
51
54
  // Base config for all JavaScript files
55
+ js.configs.recommended,
52
56
  {
53
57
  files: ['**/*.{js,mjs,cjs}'],
54
- plugins: { js },
55
- extends: ['js/recommended'],
56
58
  languageOptions: {
57
59
  globals: {...globals.node, ...globals.es2022, ...globals.jest},
58
60
  },
59
- ignores: commonIgnores,
60
61
  rules: baseRules,
61
62
  },
62
- // TypeScript config that extends the base config
63
+ // TypeScript config - restrict to TypeScript files only
64
+ ...tseslint.configs.recommended.map(config => ({
65
+ ...config,
66
+ files: ['**/*.{ts,mts,cts,tsx}'],
67
+ })),
63
68
  {
64
69
  files: ['**/*.{ts,mts,cts,tsx}'],
65
- ...tseslint.configs.recommended,
66
- // You can add or override rules specific to TypeScript here
67
- rules: {
68
- ...baseRules,
69
- // Add any TypeScript-specific rules here
70
+ languageOptions: {
71
+ globals: {...globals.node, ...globals.es2022, ...globals.jest},
70
72
  },
73
+ rules: baseRules,
71
74
  },
72
- ]);
75
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hs-web-team/eslint-config-node",
3
- "version": "3.0.0-next.7",
3
+ "version": "3.0.0",
4
4
  "description": "HubSpot Marketing WebTeam ESLint rules for Node.js",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,13 +28,15 @@
28
28
  },
29
29
  "homepage": "https://github.com/HubSpotWebTeam/wt-eslint-node#readme",
30
30
  "dependencies": {
31
- "@eslint/eslintrc": "^3.3.1",
31
+ "@eslint/eslintrc": "^3.3.3",
32
32
  "@eslint/js": "^9.39.1",
33
33
  "@typescript-eslint/eslint-plugin": "^8.46.3",
34
34
  "@typescript-eslint/parser": "^8.46.3",
35
+ "eslint": "^9.39.1",
36
+ "eslint-formatter-checkstyle": "^9.0.1",
35
37
  "globals": "^16.5.0",
36
- "prettier": "^3.6.2",
37
38
  "jiti": "^2.6.1",
38
- "typescript-eslint": "^8.46.3"
39
+ "prettier": "^3.7.3",
40
+ "typescript-eslint": "^8.48.0"
39
41
  }
40
42
  }