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 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
 
@@ -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 `constructors` to your flat config:
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
- 'constructors/no-explicit-return': 'error',
43
- 'constructors/require-error-subclass-name': 'error',
44
- 'constructors/require-new': ['error', 'errors']
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 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 | ✅ | ✅ |
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
- > Disallows explicit `return` statements inside class constructors.
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
- > Requires classes extending `Error` have a name ending in `Error`.
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-e8357a?style=flat-square" align="middle"></a>
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
- > Requires `new` when calling error constructors (and optionally other built-ins).
184
+ Requires `new` when calling error constructors (and optionally other built-ins).
189
185
 
190
186
  #### Options
191
187
 
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.
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=4B32C3&style=for-the-badge"></a>
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=4B32C3&style=for-the-badge"></a>
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
- [![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)
246
+ [![[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
247
  ```
256
248
 
257
249
  ---
258
250
 
259
251
  ## License
260
252
 
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]
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
- <!-- eslint-plugin-greasemonkey -->
273
+ <!-- eslint-plugin-greasemonkey -->
280
274
 
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]
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
- > [<img width=555 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/c9ac2985bb/assets/images/screenshots/vs-code/squiggles.png">][epg-readme]
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
- > [**Install**][epg-install] / [Readme][epg-readme] / [Supported rules][epg-rules]
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
- [**Latest releases**][epc-releases] / [Report a bug][epc-bugs] / [More packages by author][adamlui-npmx] / [Back to top ↑](#top)
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.2.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.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
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.0",
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"
@@ -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
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 = `${docsURL}${ruleId}${ rule.meta.fixable ? '-auto-fixable' : '' }`
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: {
@@ -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 */