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 +62 -79
- package/package.json +6 -6
- package/src/data/deprecations.js +9 -2
- package/src/index.js +13 -0
- 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
|
|
|
@@ -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
|
|
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
|
-
|
|
43
|
-
'constructors/
|
|
44
|
-
'constructors/require-new': ['error', '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
77
|
-
| [`require-error-subclass-name`](#require-error-subclass-name) | Requires classes extending `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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
182
|
+
Requires `new` when calling error constructors (and optionally other built-ins).
|
|
189
183
|
|
|
190
184
|
#### Options
|
|
191
185
|
|
|
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.
|
|
186
|
+
- `mode` (default `'errors'`) – constructor category to enforce `new` on (`'errors'`, `'throwing'`, `'all'`)
|
|
195
187
|
|
|
196
|
-
|
|
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=
|
|
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=
|
|
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
|
-
[](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
|
-
|
|
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
|
-
|
|
271
|
+
<!-- eslint-plugin-greasemonkey -->
|
|
280
272
|
|
|
281
|
-
###
|
|
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
|
-
>
|
|
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
|
-
>
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
"eslint-plugin-n": "^18.
|
|
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.
|
|
82
|
-
"eslint-plugin-security": "^4.0
|
|
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
|
}
|
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 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
|
|
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 */
|