eslint-plugin-constructors 1.2.1 → 1.3.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 +54 -69
- package/package.json +4 -4
- package/src/data/deprecations.js +9 -2
- package/src/index.js +8 -2
- package/src/rules/require-new.js +12 -31
- package/src/utils.js +74 -0
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
|
-
|
|
6
|
-
[
|
|
7
|
-
|
|
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
|
|
|
@@ -29,19 +33,20 @@ npm i -D eslint-plugin-constructors
|
|
|
29
33
|
<img height=17 width=22 alt="[Copy section URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="bottom"></a>
|
|
30
34
|
</h2>
|
|
31
35
|
|
|
32
|
-
Add
|
|
36
|
+
Add recommended config to your `eslint.config.*js`:
|
|
33
37
|
|
|
34
38
|
```js
|
|
39
|
+
...
|
|
35
40
|
import constructors from 'eslint-plugin-constructors'
|
|
36
41
|
|
|
37
42
|
export default [
|
|
43
|
+
// other configs
|
|
38
44
|
{
|
|
39
|
-
files: ['**/*.js'],
|
|
40
|
-
plugins: { constructors },
|
|
45
|
+
files: ['**/*.js'], plugins: { constructors },
|
|
41
46
|
rules: {
|
|
42
|
-
|
|
43
|
-
'constructors/
|
|
44
|
-
'constructors/require-new': ['error', '
|
|
47
|
+
...constructors.configs.recommended.rules,
|
|
48
|
+
'constructors/no-explicit-return': 'off', // selectively disable rule
|
|
49
|
+
'constructors/require-new': ['error', { mode: 'throwing' }] // selectively tewak rule
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
]
|
|
@@ -49,19 +54,6 @@ export default [
|
|
|
49
54
|
|
|
50
55
|
**Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
|
|
51
56
|
|
|
52
|
-
To use the bundled recommended config (enables all 3 rules at `'error'`):
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
import constructors from 'eslint-plugin-constructors'
|
|
56
|
-
|
|
57
|
-
export default [
|
|
58
|
-
{
|
|
59
|
-
files: ['**/*.js'],
|
|
60
|
-
...constructors.configs.recommended
|
|
61
|
-
}
|
|
62
|
-
]
|
|
63
|
-
```
|
|
64
|
-
|
|
65
57
|
---
|
|
66
58
|
|
|
67
59
|
<h2 id="supported-rules">
|
|
@@ -73,9 +65,9 @@ export default [
|
|
|
73
65
|
|
|
74
66
|
| ID | Description | Auto-fixable | Recommended |
|
|
75
67
|
| --- | --- | :-: | :-: |
|
|
76
|
-
| [`no-explicit-return`](#no-explicit-return) | Disallows explicit `return` statements
|
|
77
|
-
| [`require-error-subclass-name`](#require-error-subclass-name) | Requires classes extending `Error`
|
|
78
|
-
| [`require-new`](#require-new) | Requires `new` when calling error constructors |
|
|
68
|
+
| [`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"> |
|
|
69
|
+
| [`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"> |
|
|
70
|
+
| [`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
71
|
|
|
80
72
|
---
|
|
81
73
|
|
|
@@ -88,9 +80,9 @@ export default [
|
|
|
88
80
|
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
89
81
|
</h3>
|
|
90
82
|
|
|
91
|
-
|
|
83
|
+
Disallows explicit `return` statements inside class constructors.
|
|
92
84
|
|
|
93
|
-
#### Incorrect code
|
|
85
|
+
#### <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
86
|
|
|
95
87
|
```diff
|
|
96
88
|
class A {
|
|
@@ -106,7 +98,7 @@ export default [
|
|
|
106
98
|
}
|
|
107
99
|
```
|
|
108
100
|
|
|
109
|
-
#### Correct code
|
|
101
|
+
#### <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
102
|
|
|
111
103
|
```diff
|
|
112
104
|
class A {
|
|
@@ -114,7 +106,7 @@ export default [
|
|
|
114
106
|
- return
|
|
115
107
|
+ this.x = 1
|
|
116
108
|
}
|
|
117
|
-
|
|
109
|
+
|
|
118
110
|
class B {
|
|
119
111
|
constructor() {
|
|
120
112
|
- return this
|
|
@@ -139,26 +131,28 @@ If you need to return a different object from a constructor.
|
|
|
139
131
|
<code>require-error-subclass-name</code>
|
|
140
132
|
<a title="Included in recommended config" href="#usage">
|
|
141
133
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
134
|
+
<a title="Doesn't prevent bugs" href="#meta-spacing">
|
|
135
|
+
<img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
|
|
142
136
|
<a title="Copy rule URL" target="_blank"
|
|
143
137
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23require-error-subclass-name">
|
|
144
138
|
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
145
139
|
</h3>
|
|
146
140
|
|
|
147
|
-
|
|
141
|
+
Requires classes extending `Error` have a name ending in `Error`.
|
|
148
142
|
|
|
149
|
-
#### Incorrect code
|
|
143
|
+
#### <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
144
|
|
|
151
145
|
```diff
|
|
152
146
|
! class My extends Error {}
|
|
153
147
|
! const Custom = class extends Error {}
|
|
154
148
|
```
|
|
155
149
|
|
|
156
|
-
#### Correct code
|
|
150
|
+
#### <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
151
|
|
|
158
152
|
```diff
|
|
159
153
|
- class My extends Error {}
|
|
160
|
-
- const Custom = class extends Error {}
|
|
161
154
|
+ class MyError extends Error {}
|
|
155
|
+
- const Custom = class extends Error {}
|
|
162
156
|
+ const CustomError = class extends Error {}
|
|
163
157
|
```
|
|
164
158
|
|
|
@@ -179,47 +173,45 @@ If you don't follow the convention of suffixing custom error classes w/ `Error`.
|
|
|
179
173
|
<a title="Included in recommended config" href="#usage">
|
|
180
174
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
181
175
|
<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-
|
|
176
|
+
<img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-39b23f?style=flat-square" align="middle"></a>
|
|
177
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
178
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
183
179
|
<a title="Copy rule URL" target="_blank"
|
|
184
180
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-constructors%2F%23require-new">
|
|
185
181
|
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
186
182
|
</h3>
|
|
187
183
|
|
|
188
|
-
|
|
184
|
+
Requires `new` when calling error constructors (and optionally other built-ins).
|
|
189
185
|
|
|
190
186
|
#### Options
|
|
191
187
|
|
|
192
|
-
- `'errors'`
|
|
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.
|
|
195
|
-
|
|
196
|
-
Excluded: `Boolean`, `Number`, `String` (calling w/ `new` returns wrapper objects), and `Symbol`, `BigInt` (cannot be called w/ `new`).
|
|
188
|
+
- `mode` (default `'errors'`) – constructor category to enforce `new` on (`'errors'`, `'throwing'`, `'all'`)
|
|
197
189
|
|
|
198
|
-
#### Incorrect code
|
|
190
|
+
#### <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
191
|
|
|
200
192
|
```diff
|
|
201
|
-
/* eslint constructors/require-new: ['error', 'errors'] */
|
|
193
|
+
/* eslint constructors/require-new: ['error', { mode: 'errors' }] */
|
|
202
194
|
! throw Error('boom')
|
|
203
195
|
|
|
204
|
-
/* eslint constructors/require-new: ['error', 'throwing'] */
|
|
196
|
+
/* eslint constructors/require-new: ['error', { mode: 'throwing' }] */
|
|
205
197
|
! const m = Map()
|
|
206
198
|
|
|
207
|
-
/* eslint constructors/require-new: ['error', 'all'] */
|
|
199
|
+
/* eslint constructors/require-new: ['error', { mode: 'all' }] */
|
|
208
200
|
! const arr = Array()
|
|
209
201
|
```
|
|
210
202
|
|
|
211
|
-
#### Correct code
|
|
203
|
+
#### <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
204
|
|
|
213
205
|
```diff
|
|
214
|
-
/* eslint constructors/require-new: ['error', 'errors'] */
|
|
206
|
+
/* eslint constructors/require-new: ['error', { mode: 'errors' }] */
|
|
215
207
|
- throw Error('boom')
|
|
216
208
|
+ throw new Error('boom')
|
|
217
209
|
|
|
218
|
-
/* eslint constructors/require-new: ['error', 'throwing'] */
|
|
210
|
+
/* eslint constructors/require-new: ['error', { mode: 'throwing' }] */
|
|
219
211
|
- const m = Map()
|
|
220
212
|
+ const m = new Map()
|
|
221
213
|
|
|
222
|
-
/* eslint constructors/require-new: ['error', 'all'] */
|
|
214
|
+
/* eslint constructors/require-new: ['error', { mode: 'all' }] */
|
|
223
215
|
- const arr = Array()
|
|
224
216
|
+ const arr = new Array()
|
|
225
217
|
```
|
|
@@ -238,31 +230,33 @@ If you prefer calling built-ins w/o `new` (which the runtime allows for some of
|
|
|
238
230
|
|
|
239
231
|
## Shield embed
|
|
240
232
|
|
|
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=
|
|
233
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
|
|
234
|
+
<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
235
|
|
|
244
236
|
#### HTML
|
|
245
237
|
|
|
246
238
|
```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=
|
|
239
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/#readme">
|
|
240
|
+
<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
241
|
```
|
|
250
242
|
|
|
251
243
|
#### Markdown
|
|
252
244
|
|
|
253
245
|
```md
|
|
254
|
-
[](https://codeberg.org/adamlui/eslint-plugin-constructors/#readme)
|
|
255
247
|
```
|
|
256
248
|
|
|
257
249
|
---
|
|
258
250
|
|
|
259
251
|
## License
|
|
260
252
|
|
|
261
|
-
|
|
253
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md">
|
|
254
|
+
<img height=62 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
|
|
255
|
+
<br><br>
|
|
262
256
|
|
|
263
257
|
<details>
|
|
264
258
|
|
|
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>
|
|
259
|
+
<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
260
|
|
|
267
261
|
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
262
|
|
|
@@ -276,24 +270,20 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
276
270
|
|
|
277
271
|
## Related
|
|
278
272
|
|
|
279
|
-
|
|
273
|
+
<!-- eslint-plugin-greasemonkey -->
|
|
280
274
|
|
|
281
|
-
###
|
|
275
|
+
### <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
276
|
|
|
283
277
|
<details>
|
|
284
278
|
|
|
285
279
|
<summary>ESLint rules for Greasemonkey userscripts.</summary><br>
|
|
286
280
|
|
|
287
|
-
>
|
|
281
|
+
> <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
282
|
|
|
289
|
-
>
|
|
283
|
+
> <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
284
|
|
|
291
285
|
</details>
|
|
292
286
|
|
|
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
287
|
<!-- Footer -->
|
|
298
288
|
|
|
299
289
|
<img height=10 width="100%" src="https://cdn.staticdelivr.com/gl/adamlui/ai-web-extensions/d11d2ee/assets/images/separators/gradient-aqua.png">
|
|
@@ -301,15 +291,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
301
291
|
<div align="center">
|
|
302
292
|
|
|
303
293
|
<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
|
-
|
|
294
|
+
<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
295
|
|
|
306
296
|
</div>
|
|
307
297
|
|
|
308
298
|
<!-- Links -->
|
|
309
299
|
|
|
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
300
|
[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.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "ESLint rules for constructor usage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -66,19 +66,19 @@
|
|
|
66
66
|
"eslint": ">=9.0.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@e18e/eslint-plugin": "^0.8.
|
|
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.
|
|
74
|
+
"eslint": "^10.11.0",
|
|
75
75
|
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
76
76
|
"eslint-plugin-import-x": "^4.17.1",
|
|
77
77
|
"eslint-plugin-n": "^18.3.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.
|
|
81
|
+
"eslint-plugin-regexp": "^3.3.1",
|
|
82
82
|
"eslint-plugin-security": "^4.0.1",
|
|
83
83
|
"husky": "^9.1.7",
|
|
84
84
|
"yamllint-js": "^0.2.4"
|
package/src/data/deprecations.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
// Delete a line to end support
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export const rules = { // old: new
|
|
4
|
+
'require-new': {
|
|
5
|
+
'require-new': { mode: 'errors', // 2026-9-24
|
|
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,
|
|
@@ -10,9 +14,11 @@ const plugin = {
|
|
|
10
14
|
}
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
const docsURL = 'https://codeberg.org/adamlui/eslint-plugin-constructors/#'
|
|
14
17
|
for (const [ruleId, rule] of Object.entries(plugin.rules))
|
|
15
|
-
rule.meta.docs.url =
|
|
18
|
+
rule.meta.docs.url = `https://codeberg.org/adamlui/eslint-plugin-constructors/#${ruleId}`
|
|
19
|
+
|
|
20
|
+
for (const entry of Object.entries(oldRules))
|
|
21
|
+
initDeprecatedAlias(plugin, entry)
|
|
16
22
|
|
|
17
23
|
plugin.configs = {
|
|
18
24
|
recommended: {
|
package/src/rules/require-new.js
CHANGED
|
@@ -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: '
|
|
30
|
-
|
|
31
|
-
|
|
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: ['
|
|
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
|
|
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 */
|