eslint-plugin-greasemonkey 1.1.0 → 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
@@ -1,40 +1,703 @@
1
- # eslint-plugin-greasemonkey
1
+ <a id="top"></a>
2
2
 
3
- [![](https://img.shields.io/npm/v/eslint-plugin-greasemonkey?style=for-the-badge&label=Latest%20Build&color=32fcee)](https://www.npmjs.com/package/eslint-plugin-greasemonkey)
4
- <a href="./#license">
5
- <img src="https://img.shields.io/badge/License-MIT-f99b27.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
3
+ # <img height=24 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/e9128375d4/assets/images/icons/eslint/purple/icon32.png"> eslint-plugin-greasemonkey
4
+
5
+ [![](https://img.shields.io/npm/v/eslint-plugin-greasemonkey?logo=icinga&style=for-the-badge&label=Latest%20Build&color=32fcee)][epg-npm]
6
+ [![](https://img.shields.io/badge/License-MIT-f1f20a.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge)](#license)
6
7
  [![](https://img.shields.io/badge/Requires-ESLint_%3E%3D9.0.0-4B32C3?style=for-the-badge&logo=eslint)](https://eslint.org/)
7
8
 
8
9
  ESLint rules for Greasemonkey userscripts.
9
10
 
10
- <img src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/b7c510f949/assets/images/screenshots/meta-spacing/auto-fix.png">
11
+ <img src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/c9ac2985bb/assets/images/screenshots/vs-code/squiggles.png">
12
+
13
+ ---
11
14
 
12
15
  ## Installation
13
16
 
17
+ From your project root:
18
+
14
19
  ```bash
15
20
  npm i -D eslint-plugin-greasemonkey
16
21
  ```
17
22
 
18
- ## Usage (flat config)
23
+ ---
24
+
25
+ ## Usage
26
+
27
+ Add `greasemonkey` [rules][epg-rules] to your `eslint.config.*js`:
19
28
 
20
29
  ```js
30
+ ...
21
31
  import greasemonkey from 'eslint-plugin-greasemonkey'
32
+
22
33
  export default [
34
+ // other configs
23
35
  {
24
36
  files: ['**/*.user.js'],
25
37
  plugins: { greasemonkey },
26
- rules: {
27
- 'greasemonkey/meta-spacing': 'error',
38
+ rules: { // recommended set w/ default options
39
+ 'greasemonkey/meta-spacing': ['error', 3],
40
+ 'greasemonkey/no-duplicate-keys': 'error',
41
+ 'greasemonkey/no-missing-grants': 'error',
28
42
  'greasemonkey/no-unused-grants': 'error',
29
43
  'greasemonkey/no-unused-resources': 'error',
44
+ 'greasemonkey/prefer-match': 'error',
30
45
  'greasemonkey/require-matching-localized-fields': 'error',
46
+ 'greasemonkey/require-meta-newline': 'error',
31
47
  'greasemonkey/require-required-fields': 'error',
32
- 'greasemonkey/valid-field-values': 'error'
48
+ 'greasemonkey/require-space-before-meta-key': 'error',
49
+ 'greasemonkey/require-user-js-filename': 'error',
50
+ 'greasemonkey/valid-field-values': ['error', { versionType: 'semver' }],
51
+ 'greasemonkey/valid-grants': ['error', { allowedGrants: [] }]
52
+ }
53
+ }
54
+ ]
55
+ ```
56
+
57
+ ...or use a bundled config:
58
+
59
+ ```js
60
+ ...
61
+ import greasemonkey from 'eslint-plugin-greasemonkey'
62
+
63
+ export default [
64
+ // other configs
65
+ {
66
+ files: ['**/*.user.js'],
67
+ plugins: { greasemonkey }
68
+ rules: {
69
+ ...greasemonkey.configs.recommended.rules, // or .strict.rules
70
+ 'greasemonkey/no-unused-resources': 'off', // selectively disable rule
71
+ 'greasemonkey/meta-spacing': ['error', 2] // selectively tweak rule
33
72
  }
34
73
  }
35
74
  ]
36
75
  ```
37
76
 
77
+ **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
78
+
79
+ ---
80
+
81
+ ## Supported rules
82
+
83
+ | ID | Description | Auto-fixable | Recommended |
84
+ | --- | --- | :-: | :-: |
85
+ | [`meta-spacing`](#meta-spacing-auto-fixable) | Aligns metadata values to the column after the longest key | ✅ | ✅ |
86
+ | [`no-duplicate-keys`](#no-duplicate-keys) | Disallows duplicate metadata keys | ❌ | ✅ |
87
+ | [`no-missing-grants`](#no-missing-grants) | Flags API calls w/o a matching `@grant` | ❌ | ✅ |
88
+ | [`no-unused-grants`](#no-unused-grants) | Flags `@grant` entries whose APIs are never used | ❌ | ✅ |
89
+ | [`no-unused-resources`](#no-unused-resources) | Flags `@resource` entries that are never referenced | ❌ | ✅ |
90
+ | [`prefer-match`](#prefer-match) | Prefers `@match` over `@include` | ❌ | ✅ |
91
+ | [`require-homepage-pair`](#require-homepage-pair-auto-fixable) | Requires `@homepage` and `@homepageURL` to be used together | ✅ | ❌ |
92
+ | [`require-matching-localized-fields`](#require-matching-localized-fields) | Requires matching localized `@name:xx` / `@description:xx` pairs | ❌ | ✅ |
93
+ | [`require-meta-newline`](#require-meta-newline-auto-fixable) | Requires a newline between the metadata and code | ✅ | ✅ |
94
+ | [`require-required-fields`](#require-required-fields) | Requires essential metadata fields | ❌ | ✅ |
95
+ | [`require-space-before-meta-key`](#require-space-before-meta-key-auto-fixable) | Requires exactly one space between `//` and metadata keys | ✅ | ✅ |
96
+ | [`require-update-download-pair`](#require-update-download-pair) | Requires `@updateURL` and `@downloadURL` to be used together | ❌ | ❌ |
97
+ | [`require-user-js-filename`](#require-user-js-filename) | Requires userscript filenames end in `.user.js` | ❌ | ✅ |
98
+ | [`valid-field-values`](#valid-field-values) | Validates `@version` and URL fields | ❌ | ✅ |
99
+ | [`valid-grants`](#valid-grants) | Disallows invalid `@grant` values | ❌ | ✅ |
100
+ ---
101
+
102
+ ### `meta-spacing` (auto-fixable)
103
+
104
+ > Aligns metadata values to the column after the longest key.
105
+
106
+ #### Options
107
+
108
+ - `number` (default `3`) – minimum spaces after the longest key
109
+
110
+ #### Incorrect code
111
+
112
+ ```js
113
+ // ==UserScript==
114
+ // @name My Script
115
+ // @namespace example.com
116
+ // @version 1.0.0
117
+ // ==/UserScript==
118
+ ```
119
+
120
+ #### Correct code
121
+
122
+ ```js
123
+ // ==UserScript==
124
+ // @name My Script
125
+ // @namespace example.com
126
+ // @version 1.0.0
127
+ // ==/UserScript==
128
+ ```
129
+
130
+ #### When not to use it
131
+
132
+ If you don't care about visual alignment in metadata blocks.
133
+
134
+ <div align="center">
135
+
136
+ [Back to index ↑][epg-rules]
137
+
138
+ </div>
139
+
140
+ ---
141
+
142
+ ### `no-duplicate-keys`
143
+
144
+ > Disallows duplicate metadata keys. Multi-value keys are exempt (`@compatible`, `@connect`, `@description`, `@exclude`, `@exclude-match`, `@grant`, `@homepageURL`, `@include`, `@license`, `@match`, `@require`, `@resource`, `@supportURL`).
145
+
146
+ #### Incorrect code
147
+
148
+ ```js
149
+ // ==UserScript==
150
+ // @name Foo
151
+ // @name Bar
152
+ // @version 1.0.0
153
+ // @version 2.0.0
154
+ // ==/UserScript==
155
+ ```
156
+
157
+ #### Correct code
158
+
159
+ ```js
160
+ // ==UserScript==
161
+ // @name My Script
162
+ // @version 1.0.0
163
+ // @match https://a.example.com/*
164
+ // @match https://b.example.com/*
165
+ // ==/UserScript==
166
+ ```
167
+
168
+ #### When not to use it
169
+
170
+ If you intentionally repeat single-value keys.
171
+
172
+ <div align="center">
173
+
174
+ [Back to index ↑][epg-rules]
175
+
176
+ </div>
177
+
178
+ ---
179
+
180
+ ### `no-missing-grants`
181
+
182
+ > Flags API calls (e.g. `GM_setValue`, `GM.setValue`, `CAT.agent.dom`) used w/o a matching `@grant` declaration.
183
+
184
+ #### Incorrect code
185
+
186
+ ```js
187
+ // ==UserScript==
188
+ // @name My Script
189
+ // ==/UserScript==
190
+
191
+ GM_setValue('key', 'value')
192
+ ```
193
+
194
+ #### Correct code
195
+
196
+ ```js
197
+ // ==UserScript==
198
+ // @name My Script
199
+ // @grant GM_setValue
200
+ // ==/UserScript==
201
+
202
+ GM_setValue('key', 'value')
203
+ ```
204
+
205
+ #### When not to use it
206
+
207
+ If you use APIs through aliases or wrappers that obscure the original call site.
208
+
209
+ <div align="center">
210
+
211
+ [Back to index ↑][epg-rules]
212
+
213
+ </div>
214
+
215
+ ---
216
+
217
+ ### `no-unused-grants`
218
+
219
+ > Flags `@grant` entries whose APIs are never used in the script.
220
+
221
+ #### Incorrect code
222
+
223
+ ```js
224
+ // ==UserScript==
225
+ // @grant GM_setValue
226
+ // ==/UserScript==
227
+
228
+ console.log('no GM_setValue call')
229
+ ```
230
+
231
+ #### Correct code
232
+
233
+ ```js
234
+ // ==UserScript==
235
+ // @grant GM_setValue
236
+ // ==/UserScript==
237
+
238
+ GM_setValue('key', 'value')
239
+ ```
240
+
241
+ #### When not to use it
242
+
243
+ If you access the granted API through an alias or computed property rather than calling it directly.
244
+
245
+ <div align="center">
246
+
247
+ [Back to index ↑][epg-rules]
248
+
249
+ </div>
250
+
251
+ ---
252
+
253
+ ### `no-unused-resources`
254
+
255
+ > Flags `@resource` entries that are never referenced via `GM_getResourceText()` or `GM_getResourceURL()`.
256
+
257
+ #### Incorrect code
258
+
259
+ ```js
260
+ // ==UserScript==
261
+ // @resource myCSS https://example.com/style.css
262
+ // ==/UserScript==
263
+ ```
264
+
265
+ #### Correct code
266
+
267
+ ```js
268
+ // ==UserScript==
269
+ // @resource myCSS https://example.com/style.css
270
+ // ==/UserScript==
271
+
272
+ GM_getResourceText('myCSS')
273
+ ```
274
+
275
+ #### When not to use it
276
+
277
+ If you pass the resource name through a variable or alias rather than using it literally.
278
+
279
+ <div align="center">
280
+
281
+ [Back to index ↑][epg-rules]
282
+
283
+ </div>
284
+
285
+ ---
286
+
287
+ ### `prefer-match`
288
+
289
+ > Prefers `@match` over `@include` (deprecated in Chrome MV3).
290
+
291
+ #### Incorrect code
292
+
293
+ ```js
294
+ // ==UserScript==
295
+ // @include https://example.com/*
296
+ // ==/UserScript==
297
+ ```
298
+
299
+ #### Correct code
300
+
301
+ ```js
302
+ // ==UserScript==
303
+ // @match https://example.com/*
304
+ // ==/UserScript==
305
+ ```
306
+
307
+ #### When not to use it
308
+
309
+ If you use `@include` in non-MV3 environments, or rely on regex syntax that `@match` cannot express.
310
+
311
+ <div align="center">
312
+
313
+ [Back to index ↑][epg-rules]
314
+
315
+ </div>
316
+
317
+ ---
318
+
319
+ ### `require-homepage-pair` (auto-fixable)
320
+
321
+ > Requires `@homepage` and `@homepageURL` to be used together.
322
+
323
+ #### Incorrect code
324
+
325
+ ```js
326
+ // ==UserScript==
327
+ // @homepage https://example.com
328
+ // ==/UserScript==
329
+ ```
330
+
331
+ #### Correct code
332
+
333
+ ```js
334
+ // ==UserScript==
335
+ // @homepage https://example.com
336
+ // @homepageURL https://example.com
337
+ // ==/UserScript==
338
+ ```
339
+
340
+ #### When not to use it
341
+
342
+ If your target manager does not fall back to `@namespace` when a homepage key is missing (which usually produces a broken URL).
343
+
344
+ <div align="center">
345
+
346
+ [Back to index ↑][epg-rules]
347
+
348
+ </div>
349
+
350
+ ---
351
+
352
+ ### `require-matching-localized-fields`
353
+
354
+ > Requires that every `@name:xx` has a matching `@description:xx` (and vice versa).
355
+
356
+ #### Options
357
+
358
+ - `ignoreLanguages` (default `[]`) – language codes to skip, e.g. `['fr', 'de']`
359
+
360
+ #### Incorrect code
361
+
362
+ ```js
363
+ // ==UserScript==
364
+ // @name:en My Script
365
+ // @description:en Does something
366
+ // @name:fr Mon Script
367
+ // ==/UserScript==
368
+ ```
369
+
370
+ #### Correct code
371
+
372
+ ```js
373
+ // ==UserScript==
374
+ // @name:en My Script
375
+ // @description:en Does something
376
+ // @name:fr Mon Script
377
+ // @description:fr Fait quelque chose
378
+ // ==/UserScript==
379
+ ```
380
+
381
+ #### When not to use it
382
+
383
+ If you intentionally provide localized names without descriptions (or vice versa).
384
+
385
+ <div align="center">
386
+
387
+ [Back to index ↑][epg-rules]
388
+
389
+ </div>
390
+
391
+ ---
392
+
393
+ ### `require-meta-newline` (auto-fixable)
394
+
395
+ > Requires a newline between the closing `// ==/UserScript==` comment and the first line of code.
396
+
397
+ #### Incorrect code
398
+
399
+ ```js
400
+ // ==UserScript==
401
+ // @name My Script
402
+ // ==/UserScript==
403
+ console.log('hi')
404
+ ```
405
+
406
+ #### Correct code
407
+
408
+ ```js
409
+ // ==UserScript==
410
+ // @name My Script
411
+ // ==/UserScript==
412
+
413
+ console.log('hi')
414
+ ```
415
+
416
+ #### When not to use it
417
+
418
+ If you don't care about visual separation between metadata and code.
419
+
420
+ <div align="center">
421
+
422
+ [Back to index ↑][epg-rules]
423
+
424
+ </div>
425
+
426
+ ---
427
+
428
+ ### `require-required-fields`
429
+
430
+ > Requires essential metadata fields (`@name`, `@version` by default) and at least one `@match` or `@include`.
431
+
432
+ #### Options
433
+
434
+ - `fields` (default `['name', 'version']`) – override the required field list
435
+
436
+ #### Incorrect code
437
+
438
+ ```js
439
+ // ==UserScript==
440
+ // @name My Script
441
+ // ==/UserScript==
442
+ ```
443
+
444
+ #### Correct code
445
+
446
+ ```js
447
+ // ==UserScript==
448
+ // @name My Script
449
+ // @version 1.0.0
450
+ // @match https://example.com/*
451
+ // ==/UserScript==
452
+ ```
453
+
454
+ #### When not to use it
455
+
456
+ If you use a subset of metadata fields that doesn't match the convention.
457
+
458
+ <div align="center">
459
+
460
+ [Back to index ↑][epg-rules]
461
+
462
+ </div>
463
+
464
+ ---
465
+
466
+ ### `require-space-before-meta-key` (auto-fixable)
467
+
468
+ > Requires exactly one space between `//` and metadata keys.
469
+
470
+ #### Incorrect code
471
+
472
+ ```js
473
+ // ==UserScript==
474
+ //@name My Script
475
+ // @version 1.0.0
476
+ // ==/UserScript==
477
+ ```
478
+
479
+ #### Correct code
480
+
481
+ ```js
482
+ // ==UserScript==
483
+ // @name My Script
484
+ // @version 1.0.0
485
+ // ==/UserScript==
486
+ ```
487
+
488
+ #### When not to use it
489
+
490
+ If you intentionally use a different prefix style.
491
+
492
+ <div align="center">
493
+
494
+ [Back to index ↑][epg-rules]
495
+
496
+ </div>
497
+
498
+ ---
499
+
500
+ ### `require-update-download-pair`
501
+
502
+ > Requires `@updateURL` and `@downloadURL` to be used together.
503
+
504
+ #### Incorrect code
505
+
506
+ ```js
507
+ // ==UserScript==
508
+ // @downloadURL https://example.com/script.user.js
509
+ // ==/UserScript==
510
+ ```
511
+
512
+ #### Correct code
513
+
514
+ ```js
515
+ // ==UserScript==
516
+ // @downloadURL https://example.com/script.user.js
517
+ // @updateURL https://example.com/script.meta.js
518
+ // ==/UserScript==
519
+ ```
520
+
521
+ #### When not to use it
522
+
523
+ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the full script on every update check).
524
+
525
+ <div align="center">
526
+
527
+ [Back to index ↑][epg-rules]
528
+
529
+ </div>
530
+
531
+ ---
532
+
533
+ ### `require-user-js-filename`
534
+
535
+ > Requires that files containing a userscript metadata block end in `.user.js`.
536
+
537
+ #### When not to use it
538
+
539
+ If you intentionally name your userscripts something other than `*.user.js`.
540
+
541
+ <div align="center">
542
+
543
+ [Back to index ↑][epg-rules]
544
+
545
+ </div>
546
+
547
+ ---
548
+
549
+ ### `valid-field-values`
550
+
551
+ > Validates `@version` (semver or date format) and URL fields (`@homepage`, `@icon`, `@icon64`, `@require`, `@resource`, `@source`, `@website`, any key ending in `URL` case-insensitively).
552
+
553
+ #### Options
554
+
555
+ - `versionType` (default `'semver'`) – version format to enforce (`'semver'`, `'date'`)
556
+
557
+ #### Incorrect code
558
+
559
+ ```js
560
+ // ==UserScript==
561
+ // @version abc
562
+ // @homepage not-a-url
563
+ // ==/UserScript==
564
+ ```
565
+
566
+ #### Correct code
567
+
568
+ ```js
569
+ // ==UserScript==
570
+ // @version 1.0.0
571
+ // @homepage https://example.com
572
+ // ==/UserScript==
573
+ ```
574
+
575
+ #### When not to use it
576
+
577
+ If you use a custom versioning scheme or URLs that aren't standard.
578
+
579
+ <div align="center">
580
+
581
+ [Back to index ↑][epg-rules]
582
+
583
+ </div>
584
+
585
+ ---
586
+
587
+ ### `valid-grants`
588
+
589
+ > Disallows invalid `@grant` values.
590
+
591
+ #### Options
592
+
593
+ - `allowedGrants` (default `[]`) – additional `@grant` values to allow beyond the built-in list (covering Tampermonkey, Violentmonkey and ScriptCat)
594
+
595
+ #### Incorrect code
596
+
597
+ ```js
598
+ // ==UserScript==
599
+ // @grant GM_notificaiton
600
+ // @grant gm_setvalue
601
+ // @grant GM_xmlHttpRequest
602
+ // ==/UserScript==
603
+ ```
604
+
605
+ #### Correct code
606
+
607
+ ```js
608
+ // ==UserScript==
609
+ // @grant GM_notification
610
+ // @grant GM_setValue
611
+ // @grant GM_xmlhttpRequest
612
+ // ==/UserScript==
613
+ ```
614
+
615
+ #### When not to use it
616
+
617
+ If you don't want `@grant` validation at all. For individual uncovered grants, prefer whitelisting via `allowedGrants` over disabling the rule.
618
+
619
+ <div align="center">
620
+
621
+ [Back to index ↑][epg-rules]
622
+
623
+ </div>
624
+
625
+ ---
626
+
627
+ ## Shield
628
+
629
+ <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">
630
+ <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
631
+
632
+ #### HTML
633
+
634
+ ```html
635
+ <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">
636
+ <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
637
+ ```
638
+
639
+ #### Markdown
640
+
641
+ ```md
642
+ [![Linted by eslint-plugin-greasemonkey](https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme)
643
+ ```
644
+
645
+ ---
646
+
38
647
  ## License
39
648
 
40
- Copyright © 2026 [Adam Lui](https://codeberg.org/adamlui).
649
+ [<img height=62 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png">][epg-license]
650
+
651
+ <details>
652
+
653
+ <summary>Copyright © 2026 <a href="https://codeberg.org/adamlui">Adam Lui</a> under the <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/src/branch/main/docs/LICENSE.md">MIT license</a>.</summary><br>
654
+
655
+ 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:
656
+
657
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
658
+
659
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
660
+
661
+ </details>
662
+
663
+ ---
664
+
665
+ ## Related
666
+
667
+ <!-- eslint-plugin-constructors -->
668
+
669
+ ### [<img height=15 width=auto src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/e9128375d4/assets/images/icons/eslint/purple/icon16.png">][epc-readme] [eslint-plugin-constructors][epc-readme]
670
+
671
+ <details>
672
+
673
+ <summary>ESLint rules for JavaScript constructor usage.</summary><br>
674
+
675
+ > [<img width=555 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-constructors/6eeba7b2cb/assets/images/screenshots/vs-code/squiggles.png">][epc-readme]
676
+
677
+ > [**Install**][epc-install] / [Readme][epc-readme] / [Supported rules][epc-rules]
678
+
679
+ </details>
680
+
681
+ [epc-install]: https://codeberg.org/adamlui/eslint-plugin-constructors/#installation
682
+ [epc-readme]: https://codeberg.org/adamlui/eslint-plugin-constructors/#readme
683
+ [epc-rules]: https://codeberg.org/adamlui/eslint-plugin-constructors/#supported-rules
684
+
685
+ <!-- Footer -->
686
+
687
+ <img height=10 width="100%" src="https://cdn.staticdelivr.com/gl/adamlui/ai-web-extensions/d11d2ee/assets/images/separators/gradient-aqua.png">
688
+
689
+ <div align="center">
690
+
691
+ <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>
692
+ [**Latest releases**][epg-releases] / [Report a bug][epg-bugs] / [More packages by author][adamlui-npmx] / [Back to top ↑](#top)
693
+
694
+ </div>
695
+
696
+ <!-- Links -->
697
+
698
+ [adamlui-npmx]: https://npmx.dev/org/adamlui
699
+ [epg-bugs]: https://codeberg.org/adamlui/eslint-plugin-greasemonkey/issues/new
700
+ [epg-license]: https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md
701
+ [epg-npm]: https://www.npmjs.com/package/eslint-plugin-greasemonkey
702
+ [epg-releases]: https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases
703
+ [epg-rules]: #supported-rules