eslint-plugin-constructors 1.2.2 → 1.4.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
@@ -2,9 +2,13 @@
2
2
 
3
3
  # <img height=24 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-constructors/9b14b5d0f2/assets/images/icons/eslint/purple/icon32.png"> eslint-plugin-constructors
4
4
 
5
- [![](https://img.shields.io/npm/v/eslint-plugin-constructors?logo=icinga&style=for-the-badge&label=Latest%20Build&color=32fcee)][epc-npm]
6
- [![](https://img.shields.io/badge/License-MIT-f1f20a.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge)](#license)
7
- [![](https://img.shields.io/badge/Requires-ESLint_%3E%3D9.0.0-4B32C3?style=for-the-badge&logo=eslint)](https://eslint.org/)
5
+ <a target="_blank" href="https://www.npmjs.com/package/eslint-plugin-constructors">
6
+ <img alt="[Latest Build]" src="https://img.shields.io/npm/v/eslint-plugin-constructors?logo=icinga&style=for-the-badge&label=Latest%20Build&color=32fcee"></a>
7
+ <a href="#license">
8
+ <img alt="[License: MIT]" src="https://img.shields.io/badge/License-MIT-f1f20a.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
9
+ <a target="_blank" href="https://eslint.org/">
10
+ <img alt="[Requires ESLint >=9.0.0]" src="https://img.shields.io/badge/Requires-ESLint_%3E%3D9.0.0-4B32C3?style=for-the-badge&logo=eslint"></a>
11
+ <br><br>
8
12
 
9
13
  ESLint rules to enforce best practices for constructor usage.
10
14
 
@@ -12,7 +16,7 @@ ESLint rules to enforce best practices for constructor usage.
12
16
 
13
17
  ---
14
18
 
15
- ## Installation
19
+ ## <img height=30 width=27 align="top" src="https://api.iconify.design/ic/sharp-install-desktop.svg?color=%232b2b2a"> Installation
16
20
 
17
21
  From your project root:
18
22
 
@@ -23,59 +27,45 @@ npm i -D eslint-plugin-constructors
23
27
  ---
24
28
 
25
29
  <h2 id="usage">
30
+ <img height=30 width=28 align="top" src="https://api.iconify.design/entypo/power-plug.svg?color=%232b2b2a">
26
31
  Usage
27
- <a title="Copy section URL" target="_blank"
28
- href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23usage">
29
- <img height=17 width=22 alt="[Copy section URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="bottom"></a>
30
32
  </h2>
31
33
 
32
- Add `constructors` to your flat config:
34
+ Add a bundled config to your `eslint.config.*js`:
33
35
 
34
36
  ```js
37
+ ...
35
38
  import constructors from 'eslint-plugin-constructors'
36
39
 
37
40
  export default [
41
+ // other configs
38
42
  {
39
- files: ['**/*.js'],
40
- plugins: { constructors },
43
+ files: ['**/*.js'], plugins: { constructors },
41
44
  rules: {
42
- 'constructors/no-explicit-return': 'error',
43
- 'constructors/require-error-subclass-name': 'error',
44
- 'constructors/require-new': ['error', 'errors']
45
+ ...constructors.configs.recommended.rules,
46
+ 'constructors/no-explicit-return': 'off', // selectively disable rule
47
+ 'constructors/require-new': ['error', { mode: 'throwing' }] // selectively tewak rule
45
48
  }
46
49
  }
47
50
  ]
48
51
  ```
49
52
 
50
- **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
51
-
52
- To use the bundled recommended config (enables all 3 rules at `'error'`):
53
-
54
- ```js
55
- import constructors from 'eslint-plugin-constructors'
53
+ Available bundles: `recommended`, `problem`
56
54
 
57
- export default [
58
- {
59
- files: ['**/*.js'],
60
- ...constructors.configs.recommended
61
- }
62
- ]
63
- ```
55
+ **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
64
56
 
65
57
  ---
66
58
 
67
59
  <h2 id="supported-rules">
60
+ <img height=30 width=27 align="top" src="https://api.iconify.design/mdi/format-list-checks.svg?color=%232b2b2a">
68
61
  Supported rules
69
- <a title="Copy section URL" target="_blank"
70
- href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23supported-rules">
71
- <img height=17 width=22 alt="[Copy section URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="bottom"></a>
72
62
  </h2>
73
63
 
74
64
  | ID | Description | Auto-fixable | Recommended |
75
65
  | --- | --- | :-: | :-: |
76
- | [`no-explicit-return`](#no-explicit-return) | Disallows explicit `return` statements in class constructors | ❌ | ✅ |
77
- | [`require-error-subclass-name`](#require-error-subclass-name) | Requires classes extending `Error` to have names ending in `Error` | ❌ | ✅ |
78
- | [`require-new`](#require-new) | Requires `new` when calling error constructors | ✅ | ✅ |
66
+ | [`no-explicit-return`](#no-explicit-return) | Disallows explicit `return` statements inside class constructors | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> |
67
+ | [`require-error-subclass-name`](#require-error-subclass-name) | Requires classes extending `Error` have a name ending in `Error` | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> |
68
+ | [`require-new`](#require-new) | Requires `new` when calling error constructors (and optionally other built-ins) | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> | <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> |
79
69
 
80
70
  ---
81
71
 
@@ -88,9 +78,9 @@ export default [
88
78
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
89
79
  </h3>
90
80
 
91
- > Disallows explicit `return` statements inside class constructors.
81
+ Disallows explicit `return` statements inside class constructors.
92
82
 
93
- #### Incorrect code
83
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
94
84
 
95
85
  ```diff
96
86
  class A {
@@ -106,7 +96,7 @@ export default [
106
96
  }
107
97
  ```
108
98
 
109
- #### Correct code
99
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
110
100
 
111
101
  ```diff
112
102
  class A {
@@ -114,7 +104,7 @@ export default [
114
104
  - return
115
105
  + this.x = 1
116
106
  }
117
-
107
+
118
108
  class B {
119
109
  constructor() {
120
110
  - return this
@@ -139,26 +129,28 @@ If you need to return a different object from a constructor.
139
129
  <code>require-error-subclass-name</code>
140
130
  <a title="Included in recommended config" href="#usage">
141
131
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
132
+ <a title="Doesn't prevent bugs" href="#meta-spacing">
133
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
142
134
  <a title="Copy rule URL" target="_blank"
143
135
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23require-error-subclass-name">
144
136
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
145
137
  </h3>
146
138
 
147
- > Requires classes extending `Error` have a name ending in `Error`.
139
+ Requires classes extending `Error` have a name ending in `Error`.
148
140
 
149
- #### Incorrect code
141
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
150
142
 
151
143
  ```diff
152
144
  ! class My extends Error {}
153
145
  ! const Custom = class extends Error {}
154
146
  ```
155
147
 
156
- #### Correct code
148
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
157
149
 
158
150
  ```diff
159
151
  - class My extends Error {}
160
- - const Custom = class extends Error {}
161
152
  + class MyError extends Error {}
153
+ - const Custom = class extends Error {}
162
154
  + const CustomError = class extends Error {}
163
155
  ```
164
156
 
@@ -179,47 +171,45 @@ If you don't follow the convention of suffixing custom error classes w/ `Error`.
179
171
  <a title="Included in recommended config" href="#usage">
180
172
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
181
173
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
182
- <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
174
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
175
+ <a title="Accepts array w/ options" href="#usage">
176
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
183
177
  <a title="Copy rule URL" target="_blank"
184
178
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23require-new">
185
179
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
186
180
  </h3>
187
181
 
188
- > Requires `new` when calling error constructors (and optionally other built-ins).
182
+ Requires `new` when calling error constructors (and optionally other built-ins).
189
183
 
190
184
  #### Options
191
185
 
192
- - `'errors'` (default) — require for error constructors.
193
- - `'throwing'` — require for errors + constructors that throw a `TypeError` when called without `new`.
194
- - `'all'` — require for errors + throwing constructors + constructors where `new` is optional.
186
+ - `mode` (default `'errors'`) – constructor category to enforce `new` on (`'errors'`, `'throwing'`, `'all'`)
195
187
 
196
- Excluded: `Boolean`, `Number`, `String` (calling w/ `new` returns wrapper objects), and `Symbol`, `BigInt` (cannot be called w/ `new`).
197
-
198
- #### Incorrect code
188
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
199
189
 
200
190
  ```diff
201
- /* eslint constructors/require-new: ['error', 'errors'] */
191
+ /* eslint constructors/require-new: ['error', { mode: 'errors' }] */
202
192
  ! throw Error('boom')
203
193
 
204
- /* eslint constructors/require-new: ['error', 'throwing'] */
194
+ /* eslint constructors/require-new: ['error', { mode: 'throwing' }] */
205
195
  ! const m = Map()
206
196
 
207
- /* eslint constructors/require-new: ['error', 'all'] */
197
+ /* eslint constructors/require-new: ['error', { mode: 'all' }] */
208
198
  ! const arr = Array()
209
199
  ```
210
200
 
211
- #### Correct code
201
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
212
202
 
213
203
  ```diff
214
- /* eslint constructors/require-new: ['error', 'errors'] */
204
+ /* eslint constructors/require-new: ['error', { mode: 'errors' }] */
215
205
  - throw Error('boom')
216
206
  + throw new Error('boom')
217
207
 
218
- /* eslint constructors/require-new: ['error', 'throwing'] */
208
+ /* eslint constructors/require-new: ['error', { mode: 'throwing' }] */
219
209
  - const m = Map()
220
210
  + const m = new Map()
221
211
 
222
- /* eslint constructors/require-new: ['error', 'all'] */
212
+ /* eslint constructors/require-new: ['error', { mode: 'all' }] */
223
213
  - const arr = Array()
224
214
  + const arr = new Array()
225
215
  ```
@@ -236,33 +226,35 @@ If you prefer calling built-ins w/o `new` (which the runtime allows for some of
236
226
 
237
227
  ---
238
228
 
239
- ## Shield embed
229
+ ## <img height=30 align="top" src="https://api.iconify.design/boxicons/code-alt-filled.svg?color=%232b2b2a"> Shield embed
240
230
 
241
- <a href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
242
- <img height=32 alt="[Linted by eslint-plugin-constructors]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=4B32C3&style=for-the-badge"></a>
231
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
232
+ <img height=32 alt="[Linted by eslint-plugin-constructors]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
243
233
 
244
234
  #### HTML
245
235
 
246
236
  ```html
247
- <a href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
248
- <img height=32 alt="[Linted by eslint-plugin-constructors]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=4B32C3&style=for-the-badge"></a>
237
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
238
+ <img height=32 alt="[Linted by eslint-plugin-constructors]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
249
239
  ```
250
240
 
251
241
  #### Markdown
252
242
 
253
243
  ```md
254
- [![Linted by eslint-plugin-constructors](https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=4B32C3&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-constructors/#readme)
244
+ [![[Linted by eslint-plugin-constructors]](https://img.shields.io/badge/Linted_by-eslint--plugin--constructors-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-constructors/#readme)
255
245
  ```
256
246
 
257
247
  ---
258
248
 
259
- ## License
249
+ ## <img height=30 width=27 align="top" src="https://api.iconify.design/ic/baseline-account-balance.svg?color=%232b2b2a"> License
260
250
 
261
- [<img height=62 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-constructors/af5fe76586/assets/images/logos/mit-license/red-pixelated.png">][epc-license]
251
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md">
252
+ <img height=85 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
253
+ <br><br>
262
254
 
263
255
  <details>
264
256
 
265
- <summary>Copyright © 2026 <a href="https://codeberg.org/adamlui"><b>Adam Lui</b></a> under the <a href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md"><b>MIT license</b></a>.</summary><br>
257
+ <summary>Copyright © 2026 <a target="_blank" href="https://codeberg.org/adamlui"><b>Adam Lui</b></a> under the <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md"><b>MIT license</b></a>.</summary><br>
266
258
 
267
259
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
268
260
 
@@ -274,26 +266,22 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
274
266
 
275
267
  ---
276
268
 
277
- ## Related
269
+ ## <img height=30 width=29 align="top" src="https://api.iconify.design/bxs/package.svg?color=%232b2b2a"> Related
278
270
 
279
- <!-- eslint-plugin-greasemonkey -->
271
+ <!-- eslint-plugin-greasemonkey -->
280
272
 
281
- ### [<img height=15 width=auto src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-constructors/9b14b5d0f2/assets/images/icons/eslint/purple/icon16.png">][epg-readme] [eslint-plugin-greasemonkey][epg-readme]
273
+ ### <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme"><img height=15 width=auto src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/e9128375d4/assets/images/icons/eslint/purple/icon16.png"> eslint-plugin-greasemonkey</a>
282
274
 
283
275
  <details>
284
276
 
285
277
  <summary>ESLint rules for Greasemonkey userscripts.</summary><br>
286
278
 
287
- > [<img width=555 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/c9ac2985bb/assets/images/screenshots/vs-code/squiggles.png">][epg-readme]
279
+ > <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme"><img width=555 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-constructors/6eeba7b2cb/assets/images/screenshots/vs-code/squiggles.png"></a>
288
280
 
289
- > [**Install**][epg-install] / [Readme][epg-readme] / [Supported rules][epg-rules]
281
+ > <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#installation"><b>Install</b></a> / <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">Readme</a> / <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#supported-rules">Supported rules</a>
290
282
 
291
283
  </details>
292
284
 
293
- [epg-install]: https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#installation
294
- [epg-readme]: https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme
295
- [epg-rules]: https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#supported-rules
296
-
297
285
  <!-- Footer -->
298
286
 
299
287
  <img height=10 width="100%" src="https://cdn.staticdelivr.com/gl/adamlui/ai-web-extensions/d11d2ee/assets/images/separators/gradient-aqua.png">
@@ -301,15 +289,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
301
289
  <div align="center">
302
290
 
303
291
  <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.staticdelivr.com/gl/adamlui/js-utils/6b0d399/assets/images/icons/tag/white/icon16.svg"><img height=14 src="https://cdn.staticdelivr.com/gl/adamlui/js-utils/6b0d399/assets/images/icons/tag/dark-gray/icon16.svg"></picture>
304
- [**Latest releases**][epc-releases] / [Report a bug][epc-bugs] / [More packages by author][adamlui-npmx] / [Back to top ↑](#top)
292
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/releases"><b>Latest releases</b></a> / <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/issues/new">Report a bug</a> / <a target="_blank" href="https://www.npmjs.com/~adamlui">More packages by author</a> / [Back to top ↑](#top)
305
293
 
306
294
  </div>
307
295
 
308
296
  <!-- Links -->
309
297
 
310
- [adamlui-npmx]: https://npmx.dev/org/adamlui
311
- [epc-bugs]: https://codeberg.org/adamlui/eslint-plugin-constructors/issues/new
312
- [epc-license]: https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md
313
- [epc-npm]: https://www.npmjs.com/package/eslint-plugin-constructors
314
298
  [epc-rules]: #supported-rules
315
- [epc-releases]: https://codeberg.org/adamlui/eslint-plugin-constructors/releases
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-constructors",
3
- "version": "1.2.2",
3
+ "version": "1.4.0",
4
4
  "description": "ESLint rules for constructor usage",
5
5
  "type": "module",
6
6
  "engines": {
@@ -66,20 +66,20 @@
66
66
  "eslint": ">=9.0.0"
67
67
  },
68
68
  "devDependencies": {
69
- "@e18e/eslint-plugin": "^0.8.0",
69
+ "@e18e/eslint-plugin": "^0.8.1",
70
70
  "@eslint/js": "^10.0.1",
71
71
  "@eslint/json": "^2.1.0",
72
72
  "@eslint/markdown": "^8.0.3",
73
73
  "@stylistic/eslint-plugin": "^5.10.0",
74
- "eslint": "^10.10.0",
74
+ "eslint": "^10.11.0",
75
75
  "eslint-plugin-eslint-plugin": "^7.6.2",
76
76
  "eslint-plugin-import-x": "^4.17.1",
77
- "eslint-plugin-n": "^18.3.0",
77
+ "eslint-plugin-n": "^18.4.0",
78
78
  "eslint-plugin-no-secrets": "^2.3.3",
79
79
  "eslint-plugin-no-unsanitized": "^4.1.5",
80
80
  "eslint-plugin-promise": "^7.3.0",
81
- "eslint-plugin-regexp": "^3.3.0",
82
- "eslint-plugin-security": "^4.0.1",
81
+ "eslint-plugin-regexp": "^3.3.1",
82
+ "eslint-plugin-security": "^4.2.0",
83
83
  "husky": "^9.1.7",
84
84
  "yamllint-js": "^0.2.4"
85
85
  }
@@ -1,3 +1,10 @@
1
- export const options = { 'require-new': { 'error-only': 'errors' }} // 2026-9-13
1
+ // Delete a line to end support
2
2
 
3
- export default { options }
3
+ export const rules = { // old: new
4
+ 'require-new': {
5
+ 'require-new': { mode: 'errors', // 2026-9-24 announced certain default switch + possible unnamed syntax removal
6
+ builtins: 'all', 'error-only': 'errors' } // 2026-9-13 announced removal @ v2
7
+ }
8
+ }
9
+
10
+ export default { rules }
package/src/index.js CHANGED
@@ -1,7 +1,11 @@
1
+ import { rules as oldRules } from './data/deprecations.js'
2
+
1
3
  import noExplicitReturn from './rules/no-explicit-return.js'
2
4
  import requireErrorSubclassName from './rules/require-error-subclass-name.js'
3
5
  import requireNew from './rules/require-new.js'
4
6
 
7
+ import { initDeprecatedAlias } from './utils.js'
8
+
5
9
  const plugin = {
6
10
  rules: {
7
11
  'no-explicit-return': noExplicitReturn,
@@ -13,6 +17,9 @@ const plugin = {
13
17
  for (const [ruleId, rule] of Object.entries(plugin.rules))
14
18
  rule.meta.docs.url = `https://codeberg.org/adamlui/eslint-plugin-constructors/#${ruleId}`
15
19
 
20
+ for (const entry of Object.entries(oldRules))
21
+ initDeprecatedAlias(plugin, entry)
22
+
16
23
  plugin.configs = {
17
24
  recommended: {
18
25
  plugins: { constructors: plugin },
@@ -21,6 +28,12 @@ plugin.configs = {
21
28
  'constructors/require-error-subclass-name': 'error',
22
29
  'constructors/require-new': 'error'
23
30
  }
31
+ },
32
+ problem: {
33
+ plugins: { constructors: plugin },
34
+ rules: Object.fromEntries(Object.entries(plugin.rules)
35
+ .filter(([, rule]) => rule.meta.type == 'problem')
36
+ .map(([id]) => [`constructors/${id}`, 'error']))
24
37
  }
25
38
  }
26
39
 
@@ -1,4 +1,3 @@
1
- import deprecations from '../data/deprecations.js'
2
1
  import globals from 'globals'
3
2
 
4
3
  const errorConstructors = new Set(Object.keys(globals.builtin).filter(name => name.endsWith('Error')))
@@ -11,11 +10,6 @@ const throwingConstructors = new Set([
11
10
 
12
11
  const lenientConstructors = new Set(['Array', 'Date', 'Function', 'Object', 'RegExp'])
13
12
 
14
- const legacyBuiltins = new Set([
15
- 'Array', 'BigInt', 'Boolean', 'Date', 'Function', 'Map', 'Number', 'Object', 'RegExp', 'Set', 'String', 'Symbol',
16
- 'WeakMap', 'WeakSet'
17
- ])
18
-
19
13
  export default {
20
14
  meta: {
21
15
  type: 'problem',
@@ -26,43 +20,30 @@ export default {
26
20
  },
27
21
  fixable: 'code',
28
22
  schema: [{
29
- type: 'string',
30
- enum: ['errors', 'throwing', 'all', 'error-only', 'builtins'],
31
- description: 'Constructor categories to check'
23
+ type: 'object',
24
+ properties: {
25
+ mode: {
26
+ type: 'string',
27
+ enum: ['errors', 'throwing', 'all'],
28
+ description: 'Constructor category to check (default: errors)'
29
+ }
30
+ },
31
+ additionalProperties: false
32
32
  }],
33
- defaultOptions: ['errors'],
34
- messages: {
35
- requireNew: 'Use `new {{name}}()` instead of `{{name}}()`',
36
- deprecatedMode: `'{{old}}' is deprecated. Use '{{new}}' instead.`
37
- }
33
+ defaultOptions: [{ mode: 'throwing' }],
34
+ messages: { requireNew: 'Use `new {{name}}()` instead of `{{name}}()`' }
38
35
  },
39
36
 
40
37
  create(context) {
41
- const optionAliases = deprecations.options['require-new'] || {},
42
- rawMode = context.options[0] || 'errors'
43
- /* eslint-disable security/detect-object-injection */
44
- let mode = optionAliases[rawMode] || rawMode, deprecation
45
- if (optionAliases[rawMode])
46
- deprecation = { old: rawMode, new: optionAliases[rawMode] }
47
- /* eslint-enable security/detect-object-injection */
48
- else if (rawMode == 'builtins')
49
- mode = 'legacy-builtins'
50
-
38
+ const mode = context.options[0]?.mode ?? 'throwing'
51
39
  function shouldReportName(name) {
52
40
  return mode == 'errors' ? errorConstructors.has(name)
53
41
  : mode == 'throwing' ? errorConstructors.has(name) || throwingConstructors.has(name)
54
42
  : mode == 'all' ? errorConstructors.has(name) || throwingConstructors.has(name)
55
43
  || lenientConstructors.has(name)
56
- : mode == 'legacy-builtins' ? errorConstructors.has(name) || legacyBuiltins.has(name)
57
44
  : false
58
45
  }
59
-
60
46
  return {
61
- Program(node) {
62
- if (deprecation)
63
- context.report({
64
- node, messageId: 'deprecatedMode', data: { old: deprecation.old, new: deprecation.new }})
65
- },
66
47
  CallExpression(node) {
67
48
  if (node.new) return
68
49
  const calleeName = node.callee.name ; if (!calleeName) return
package/src/utils.js ADDED
@@ -0,0 +1,74 @@
1
+ export function initDeprecatedAlias(plugin, [oldName, alias]) { /* eslint-disable security/detect-object-injection */
2
+ const routes = typeof alias == 'string' ? { [alias]: null } // 'old-rule': 'new-rule'
3
+ : Array.isArray(alias) ? Object.fromEntries(alias.map(entry =>
4
+ typeof entry == 'string' ? [entry, null] // ['new-rule-1', 'new-rule-2']
5
+ : Object.entries(entry)[0])) // [{ 'new-rule': { 'old-opt': 'new-opt' }}]
6
+ : alias // { 'new-rule': null | { 'new-opt': default } | { 'old-val': 'new-val' } | { ..., 'new-opt': default }}
7
+ const targetNames = Object.keys(routes),
8
+ isRename = !targetNames.includes(oldName),
9
+ originals = Object.fromEntries(targetNames.map(name => [name, plugin.rules[name]])),
10
+ source = originals[oldName] ?? originals[targetNames[0]]
11
+ plugin.rules[oldName] = {
12
+ meta: {
13
+ ...source.meta,
14
+ defaultOptions: [],
15
+ schema: [{ type: ['object', 'array', 'string', 'number', 'boolean', 'null'] }],
16
+ docs: { ...source.meta.docs, recommended: isRename ? false : source.meta.docs.recommended },
17
+ messages: {
18
+ ...source.meta.messages,
19
+ deprecatedOption: `'{{old}}' is deprecated. Use '{{new}}' instead.`
20
+ },
21
+ ...(isRename ? { deprecated: {
22
+ message: `Use ${targetNames.map(name => `\`${name}\``).join(', ')} instead.`,
23
+ replacedBy: targetNames.map(name => ({ rule: { name }}))
24
+ }} : {})
25
+ },
26
+ create(context) {
27
+ const opts = context.options[0],
28
+ isObj = opts?.constructor === Object
29
+ return Object.assign({}, ...Object.entries(routes).map(([targetName, mapping]) => {
30
+ let newOpts = opts, deprecation
31
+ if (mapping) {
32
+ const entries = Object.entries(mapping),
33
+ namedRemap = entries.every(([, val]) => typeof val == 'string'),
34
+ wrapKey = namedRemap && entries.length > 1 ? entries.at(-1)[0] : null,
35
+ valMap = wrapKey ? Object.fromEntries(entries.slice(0, -1)) : mapping
36
+ if (namedRemap) {
37
+ if (typeof opts == 'string') { // bare old val → remap, optionally wrapped
38
+ if (valMap[opts]) deprecation = { old: opts, new: valMap[opts] }
39
+ const remapped = valMap[opts] ?? opts
40
+ newOpts = wrapKey ? { [wrapKey]: remapped } : remapped
41
+ } else if (wrapKey) { // object opts (or defaults) → remap inner val, warn if deprecated
42
+ const raw = isObj ? (opts[wrapKey] ?? mapping[wrapKey]) : mapping[wrapKey],
43
+ remapped = valMap[raw]
44
+ if (remapped) deprecation = { old: raw, new: remapped }
45
+ newOpts = { [wrapKey]: remapped ?? raw }
46
+ } else { // object opts → old key → new key
47
+ newOpts = { ...opts }
48
+ for (const [oldKey, newKey] of entries)
49
+ if (opts?.[oldKey] !== undefined) {
50
+ newOpts[newKey] = opts[oldKey] ; delete newOpts[oldKey] }
51
+ }
52
+ } else { // { new-opt: default } — positional wrap
53
+ const [newKey, defaultValue] = entries[0]
54
+ if (opts !== undefined && !isObj)
55
+ deprecation = { old: JSON.stringify(opts), new: `{ ${newKey}: ${JSON.stringify(opts)} }` }
56
+ newOpts = { [newKey]: isObj ? (opts[newKey] ?? defaultValue) : (opts ?? defaultValue) }
57
+ }
58
+ }
59
+ const aliasContext = Object.create(context)
60
+ Object.defineProperty(aliasContext, 'options',
61
+ { value: [newOpts], writable: true, configurable: true, enumerable: true })
62
+ const visitors = { ...originals[targetName].create(aliasContext) }
63
+ if (deprecation) {
64
+ const ruleProgram = visitors.Program
65
+ visitors.Program = function(node) {
66
+ context.report({ node, messageId: 'deprecatedOption', data: deprecation })
67
+ if (ruleProgram) ruleProgram.call(this, node)
68
+ }
69
+ }
70
+ return visitors
71
+ }))
72
+ }
73
+ }
74
+ } /* eslint-enable security/detect-object-injection */