eslint-plugin-greasemonkey 1.5.1 → 1.5.2

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
@@ -7,7 +7,8 @@
7
7
  <a href="#license">
8
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
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>
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>
11
12
 
12
13
  ESLint rules for Greasemonkey userscripts.
13
14
 
@@ -25,7 +26,12 @@ npm i -D eslint-plugin-greasemonkey
25
26
 
26
27
  ---
27
28
 
28
- ## Usage
29
+ <h2 id="usage">
30
+ Usage
31
+ <a title="Copy section URL" target="_blank"
32
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23usage">
33
+ <img height=17 width=22 alt="[Copy section URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="bottom"></a>
34
+ </h2>
29
35
 
30
36
  Add a bundled config to your `eslint.config.*js`:
31
37
 
@@ -52,31 +58,12 @@ Avaialble bundles: `recommended`, `strict`, `tampermonkey`, `violentmonkey`, `gr
52
58
 
53
59
  ---
54
60
 
55
- ## Supported rules
56
-
57
- | ID | Description | Auto-fixable | Recommended |
58
- | --- | --- | :-: | :-: |
59
- | [`meta-order`](#meta-order) | Enforces a preferred order for metadata keys | <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/gray.svg" align="bottom"> |
60
- | [`meta-spacing`](#meta-spacing) | Aligns metadata values to the column after the longest key | <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"> |
61
- | [`no-duplicate-keys`](#no-duplicate-keys) | Disallows duplicate metadata keys | <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"> |
62
- | [`no-invalid-headers`](#no-invalid-headers) | Disallows invalid or unsupported metadata headers | <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"> |
63
- | [`no-missing-grants`](#no-missing-grants) | Flags API calls w/o a matching `@grant` | <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"> |
64
- | [`no-missing-resources`](#no-missing-resources) | Flags `@resource` references w/o a matching declaration | <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"> |
65
- | [`no-unused-grants`](#no-unused-grants) | Flags `@grant` entries whose APIs are never used | <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"> |
66
- | [`no-unused-resources`](#no-unused-resources) | Flags `@resource` entries that are never referenced | <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
- | [`prefer-match`](#prefer-match) | Prefers `@match` over `@include` | <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-blank-line-after-meta-block`](#require-blank-line-after-meta-block) | Requires a blank line between the metadata and code | <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"> |
69
- | [`require-homepage-pair`](#require-homepage-pair) | Requires `@homepage` and `@homepageURL` to be used together | <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/gray.svg" align="bottom"> |
70
- | [`require-matching-localized-fields`](#require-matching-localized-fields) | Requires matching localized `@name:xx` / `@description:xx` pairs | <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"> |
71
- | [`require-required-fields`](#require-required-fields) | Requires essential metadata fields | <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"> |
72
- | [`require-space-before-meta-key`](#require-space-before-meta-key) | Requires exactly one space between `//` and metadata keys | <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"> |
73
- | [`require-sri-hashing`](#require-sri-hashing) | Requires SRI hashes for external `@require` URLs | <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"> |
74
- | [`require-update-download-pair`](#require-update-download-pair) | Requires `@updateURL` and `@downloadURL` to be used together | <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/gray.svg" align="bottom"> |
75
- | [`require-user-js-filename`](#require-user-js-filename) | Requires userscript filenames end in `.user.js` | <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"> |
76
- | [`valid-field-values`](#valid-field-values) | Validates `@version` and URL fields | <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"> |
77
- | [`valid-grants`](#valid-grants) | Disallows invalid or unsupported `@grant` values | <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"> |
78
-
79
- ---
61
+ <h2 id="supported-rules">
62
+ Supported rules
63
+ <a title="Copy section URL" target="_blank"
64
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23supported-rules">
65
+ <img height=17 width=22 alt="[Copy section URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="bottom"></a>
66
+ </h2>
80
67
 
81
68
  <h3 id="meta-order">
82
69
  <code>meta-order</code>
@@ -84,7 +71,7 @@ Avaialble bundles: `recommended`, `strict`, `tampermonkey`, `violentmonkey`, `gr
84
71
  <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
85
72
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
86
73
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
87
- <a title="Doesn't catch bugs" href="#meta-order">
74
+ <a title="Doesn't prevent bugs" href="#meta-order">
88
75
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
89
76
  <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
90
77
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -93,18 +80,14 @@ Avaialble bundles: `recommended`, `strict`, `tampermonkey`, `violentmonkey`, `gr
93
80
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
94
81
  </h3>
95
82
 
96
- > Enforces a preferred order for metadata keys.
83
+ <details>
84
+
85
+ <summary>Enforces a preferred order for metadata keys.</summary>
97
86
 
98
87
  #### Options
99
88
 
100
89
  - `string[]` (default `[]`) – metadata keys in custom order
101
90
 
102
- For example:
103
-
104
- ```js
105
- /* eslint greasemonkey/meta-order: ['error', ['run-in', 'inject-into']] */
106
- ```
107
-
108
91
  #### <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
109
92
 
110
93
  ```diff
@@ -115,12 +98,6 @@ For example:
115
98
  ! // @namespace example.com
116
99
  // @author John Doe
117
100
  ! // @license MIT
118
- // @icon https://example.com/icon.png
119
- ! // @match https://example.com/*
120
- // @grant GM_setValue
121
- // @require https://example.com/lib.js
122
- // @resource logo https://example.com/logo.png
123
- ! // @connect example.com
124
101
  // ==/UserScript==
125
102
  ```
126
103
 
@@ -137,16 +114,6 @@ For example:
137
114
  + // @namespace example.com
138
115
  + // @version 1.0.0
139
116
  + // @license MIT
140
- // @icon https://example.com/icon.png
141
- - // @match https://example.com/*
142
- + // @connect example.com
143
- // @grant GM_setValue
144
- - // @require https://example.com/lib.js
145
- - // @resource logo https://example.com/logo.png
146
- - // @connect example.com
147
- + // @match https://example.com/*
148
- + // @require https://example.com/lib.js
149
- + // @resource logo https://example.com/logo.png
150
117
  // ==/UserScript==
151
118
  ```
152
119
 
@@ -154,6 +121,10 @@ For example:
154
121
 
155
122
  If you don't care about the order of metadata fields.
156
123
 
124
+ #### Introduced in
125
+
126
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.5.0">v1.5.0</a> (September 15, 2026)
127
+
157
128
  #### See also
158
129
 
159
130
  - [`meta-spacing`](#meta-spacing)
@@ -167,13 +138,15 @@ If you don't care about the order of metadata fields.
167
138
 
168
139
  ---
169
140
 
141
+ </details>
142
+
170
143
  <h3 id="meta-spacing">
171
144
  <code>meta-spacing</code>
172
145
  <a title="Included in recommended config" href="#usage">
173
146
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
174
147
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
175
148
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
176
- <a title="Doesn't catch bugs" href="#meta-spacing">
149
+ <a title="Doesn't prevent bugs" href="#meta-spacing">
177
150
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
178
151
  <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
179
152
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -182,7 +155,9 @@ If you don't care about the order of metadata fields.
182
155
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
183
156
  </h3>
184
157
 
185
- > Aligns metadata values to the column after the longest key.
158
+ <details>
159
+
160
+ <summary>Aligns metadata values to the column after the longest key.</summary>
186
161
 
187
162
  #### Options
188
163
 
@@ -218,6 +193,10 @@ If you don't care about the order of metadata fields.
218
193
 
219
194
  If you don't care about visual alignment in metadata blocks.
220
195
 
196
+ #### Introduced in
197
+
198
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
199
+
221
200
  #### See also
222
201
 
223
202
  - [`require-blank-line-after-meta-block`](#require-blank-line-after-meta-block)
@@ -231,6 +210,8 @@ If you don't care about visual alignment in metadata blocks.
231
210
 
232
211
  ---
233
212
 
213
+ </details>
214
+
234
215
  <h3 id="no-duplicate-keys">
235
216
  <code>no-duplicate-keys</code>
236
217
  <a title="Included in recommended config" href="#usage">
@@ -240,7 +221,9 @@ If you don't care about visual alignment in metadata blocks.
240
221
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
241
222
  </h3>
242
223
 
243
- > Disallows duplicate metadata keys. Multi-value keys are exempt (`@compatible`, `@connect`, `@description`, `@exclude`, `@exclude-match`, `@grant`, `@homepageURL`, `@include`, `@license`, `@match`, `@require`, `@resource`, `@supportURL`).
224
+ <details>
225
+
226
+ <summary>Disallows duplicate single-value metadata keys.</summary>
244
227
 
245
228
  #### <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
246
229
 
@@ -250,6 +233,8 @@ If you don't care about visual alignment in metadata blocks.
250
233
  ! // @name Bar
251
234
  ! // @version 1.0.0
252
235
  ! // @version 2.0.0
236
+ // @match https://a.example.com/*
237
+ // @match https://b.example.com/*
253
238
  // ==/UserScript==
254
239
  ```
255
240
 
@@ -259,12 +244,12 @@ If you don't care about visual alignment in metadata blocks.
259
244
  // ==UserScript==
260
245
  - // @name Foo
261
246
  - // @name Bar
247
+ + // @name My Script
262
248
  - // @version 1.0.0
263
249
  - // @version 2.0.0
264
- + // @name My Script
265
250
  + // @version 1.0.0
266
- + // @match https://a.example.com/*
267
- + // @match https://b.example.com/*
251
+ // @match https://a.example.com/*
252
+ // @match https://b.example.com/*
268
253
  // ==/UserScript==
269
254
  ```
270
255
 
@@ -272,6 +257,10 @@ If you don't care about visual alignment in metadata blocks.
272
257
 
273
258
  If you intentionally repeat single-value keys.
274
259
 
260
+ #### Introduced in
261
+
262
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.2.0">v1.2.0</a> (September 11, 2026)
263
+
275
264
  #### See also
276
265
 
277
266
  - [`require-matching-localized-fields`](#require-matching-localized-fields)
@@ -285,6 +274,91 @@ If you intentionally repeat single-value keys.
285
274
 
286
275
  ---
287
276
 
277
+ </details>
278
+
279
+ <h3 id="no-invalid-grants">
280
+ <code>no-invalid-grants</code>
281
+ <a title="Included in recommended config" href="#usage">
282
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
283
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
284
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
285
+ <a title="Copy rule URL" target="_blank"
286
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-invalid-grants">
287
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
288
+ </h3>
289
+
290
+ <details>
291
+
292
+ <summary>Disallows invalid or unsupported <code>@grant</code> values.</summary>
293
+
294
+ #### Options
295
+
296
+ - `target` (default `'all'`) – manager(s) whose grants to validate against (`'all'`, `'tampermonkey'`, `'violentmonkey'`, `'greasemonkey'`, `'scriptcat'`), as a single string or array
297
+ - `allowedGrants` (default `[]`) – additional `@grant` values to allow beyond the built-in list (covering Tampermonkey, Violentmonkey and ScriptCat), as a single string or array
298
+
299
+ #### <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
300
+
301
+ ```diff
302
+ /* eslint greasemonkey/no-invalid-grants: ['error', { target: 'tampermonkey' }] */
303
+
304
+ // ==UserScript==
305
+ // @grant GM_getTab
306
+ ! // @grant CAT.agent.dom
307
+ // ==/UserScript==
308
+
309
+ /* eslint greasemonkey/no-invalid-grants: ['error', { target: 'scriptcat' }] */
310
+
311
+ // ==UserScript==
312
+ ! // @grant GM_getTab
313
+ // @grant CAT.agent.dom
314
+ // ==/UserScript==
315
+ ```
316
+
317
+ #### <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
318
+
319
+ ```diff
320
+ /* eslint greasemonkey/no-invalid-grants: ['error', { target: 'tampermonkey' }] */
321
+
322
+ // ==UserScript==
323
+ // @grant GM_getTab
324
+ - // @grant CAT.agent.dom
325
+ // ==/UserScript==
326
+
327
+ /* eslint greasemonkey/no-invalid-grants: ['error', { target: 'scriptcat' }] */
328
+
329
+ // ==UserScript==
330
+ - // @grant GM_getTab
331
+ // @grant CAT.agent.dom
332
+ // ==/UserScript==
333
+ ```
334
+
335
+ #### When not to use it
336
+
337
+ If you don't want `@grant` validation at all. For individual uncovered grants, prefer whitelisting via `allowedGrants` over disabling the rule.
338
+
339
+ #### Introduced in
340
+
341
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.2.0">v1.2.0</a> (September 11, 2026) as `valid-grants`
342
+
343
+ #### Renamed in
344
+
345
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.5.2">v1.5.2</a> (September 16, 2026) to `no-invalid-grants`
346
+
347
+ #### See also
348
+
349
+ - [`no-missing-grants`](#no-missing-grants)
350
+ - [`no-unused-grants`](#no-unused-grants)
351
+
352
+ <div align="center">
353
+
354
+ [Back to index ↑][epg-rules]
355
+
356
+ </div>
357
+
358
+ ---
359
+
360
+ </details>
361
+
288
362
  <h3 id="no-invalid-headers">
289
363
  <code>no-invalid-headers</code>
290
364
  <a title="Included in recommended config" href="#usage">
@@ -296,7 +370,9 @@ If you intentionally repeat single-value keys.
296
370
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
297
371
  </h3>
298
372
 
299
- > Disallows invalid or unsupported metadata headers.
373
+ <details>
374
+
375
+ <summary>Disallows invalid or unsupported metadata headers.</summary>
300
376
 
301
377
  #### Options
302
378
 
@@ -334,10 +410,14 @@ If you intentionally repeat single-value keys.
334
410
 
335
411
  If your script relies heavily on custom headers and you'd rather not maintain `allowedHeaders`.
336
412
 
413
+ #### Introduced in
414
+
415
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
416
+
337
417
  #### See also
338
418
 
419
+ - [`no-invalid-grants`](#no-invalid-grants)
339
420
  - [`valid-field-values`](#valid-field-values)
340
- - [`valid-grants`](#valid-grants)
341
421
 
342
422
  <div align="center">
343
423
 
@@ -347,6 +427,8 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
347
427
 
348
428
  ---
349
429
 
430
+ </details>
431
+
350
432
  <h3 id="no-missing-grants">
351
433
  <code>no-missing-grants</code>
352
434
  <a title="Included in recommended config" href="#usage">
@@ -356,7 +438,9 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
356
438
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
357
439
  </h3>
358
440
 
359
- > Flags API calls (e.g. `GM_setValue`, `GM.setValue`, `CAT.agent.dom`) used w/o a matching `@grant` declaration.
441
+ <details>
442
+
443
+ <summary>Flags API calls (e.g. <code>GM_setValue</code>, <code>GM.setValue</code>, <code>CAT.agent.dom</code>) used w/o a matching <code>@grant</code> declaration.</summary>
360
444
 
361
445
  #### <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
362
446
 
@@ -383,10 +467,14 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
383
467
 
384
468
  If you use APIs through aliases or wrappers that obscure the original call site.
385
469
 
470
+ #### Introduced in
471
+
472
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0">v1.3.0</a> (September 12, 2026)
473
+
386
474
  #### See also
387
475
 
476
+ - [`no-invalid-grants`](#no-invalid-grants)
388
477
  - [`no-unused-grants`](#no-unused-grants)
389
- - [`valid-grants`](#valid-grants)
390
478
 
391
479
  <div align="center">
392
480
 
@@ -396,6 +484,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
396
484
 
397
485
  ---
398
486
 
487
+ </details>
488
+
399
489
  <h3 id="no-missing-resources">
400
490
  <code>no-missing-resources</code>
401
491
  <a title="Included in recommended config" href="#usage">
@@ -405,7 +495,9 @@ If you use APIs through aliases or wrappers that obscure the original call site.
405
495
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
406
496
  </h3>
407
497
 
408
- > Flags `@resource` references via `GM_getResourceText()` or `GM_getResourceURL()` where no matching `@resource` is declared.
498
+ <details>
499
+
500
+ <summary>Flags <code>@resource</code> references via <code>GM_getResourceText()</code> or <code>GM_getResourceURL()</code> where no matching <code>@resource</code> is declared.</summary>
409
501
 
410
502
  #### <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
411
503
 
@@ -432,6 +524,10 @@ If you use APIs through aliases or wrappers that obscure the original call site.
432
524
 
433
525
  If you reference resources through an alias or computed pattern that obscures the call site.
434
526
 
527
+ #### Introduced in
528
+
529
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.4.0">v1.4.0</a> (September 13, 2026)
530
+
435
531
  #### See also
436
532
 
437
533
  - [`no-unused-resources`](#no-unused-resources)
@@ -444,6 +540,8 @@ If you reference resources through an alias or computed pattern that obscures th
444
540
 
445
541
  ---
446
542
 
543
+ </details>
544
+
447
545
  <h3 id="no-unused-grants">
448
546
  <code>no-unused-grants</code>
449
547
  <a title="Included in recommended config" href="#usage">
@@ -453,7 +551,9 @@ If you reference resources through an alias or computed pattern that obscures th
453
551
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
454
552
  </h3>
455
553
 
456
- > Flags `@grant` entries whose APIs are never used in the script.
554
+ <details>
555
+
556
+ <summary>Flags <code>@grant</code> entries whose APIs are never used in the script.</summary>
457
557
 
458
558
  #### <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
459
559
 
@@ -477,10 +577,14 @@ If you reference resources through an alias or computed pattern that obscures th
477
577
 
478
578
  If you access the granted API through an alias or computed property rather than calling it directly.
479
579
 
580
+ #### Introduced in
581
+
582
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
583
+
480
584
  #### See also
481
585
 
586
+ - [`no-invalid-grants`](#no-invalid-grants)
482
587
  - [`no-missing-grants`](#no-missing-grants)
483
- - [`valid-grants`](#valid-grants)
484
588
 
485
589
  <div align="center">
486
590
 
@@ -490,6 +594,8 @@ If you access the granted API through an alias or computed property rather than
490
594
 
491
595
  ---
492
596
 
597
+ </details>
598
+
493
599
  <h3 id="no-unused-resources">
494
600
  <code>no-unused-resources</code>
495
601
  <a title="Included in recommended config" href="#usage">
@@ -499,7 +605,9 @@ If you access the granted API through an alias or computed property rather than
499
605
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
500
606
  </h3>
501
607
 
502
- > Flags `@resource` entries that are never referenced via `GM_getResourceText()` or `GM_getResourceURL()`.
608
+ <details>
609
+
610
+ <summary>Flags <code>@resource</code> entries that are never referenced via <code>GM_getResourceText()</code>or <code>GM_getResourceURL()</code></summary>
503
611
 
504
612
  #### <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
505
613
 
@@ -523,6 +631,10 @@ If you access the granted API through an alias or computed property rather than
523
631
 
524
632
  If you pass resource names through variables or aliases rather than use them literally.
525
633
 
634
+ #### Introduced in
635
+
636
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
637
+
526
638
  #### See also
527
639
 
528
640
  - [`no-missing-resources`](#no-missing-resources)
@@ -535,6 +647,8 @@ If you pass resource names through variables or aliases rather than use them lit
535
647
 
536
648
  ---
537
649
 
650
+ </details>
651
+
538
652
  <h3 id="prefer-match">
539
653
  <code>prefer-match</code>
540
654
  <a title="Included in recommended config" href="#usage">
@@ -544,7 +658,9 @@ If you pass resource names through variables or aliases rather than use them lit
544
658
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
545
659
  </h3>
546
660
 
547
- > Prefers `@match` over `@include` to align w/ <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/userScripts/">`chrome.userScripts`</a> syntax.
661
+ <details>
662
+
663
+ <summary>Prefers <code>@match</code> over <code>@include</code> to align w/ <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/userScripts/"><code>chrome.userScripts</code></a> syntax.</summary>
548
664
 
549
665
  #### <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
550
666
 
@@ -567,6 +683,10 @@ If you pass resource names through variables or aliases rather than use them lit
567
683
 
568
684
  If you rely on `@include` patterns that cannot be expressed using `@match`.
569
685
 
686
+ #### Introduced in
687
+
688
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0">v1.3.0</a> (September 12, 2026)
689
+
570
690
  #### See also
571
691
 
572
692
  - <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">Chrome match patterns</a>
@@ -579,20 +699,24 @@ If you rely on `@include` patterns that cannot be expressed using `@match`.
579
699
 
580
700
  ---
581
701
 
702
+ </details>
703
+
582
704
  <h3 id="require-blank-line-after-meta-block">
583
705
  <code>require-blank-line-after-meta-block</code>
584
706
  <a title="Included in recommended config" href="#usage">
585
707
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
586
708
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
587
709
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
588
- <a title="Doesn't catch bugs" href="#require-blank-line-after-meta-block">
710
+ <a title="Doesn't prevent bugs" href="#require-blank-line-after-meta-block">
589
711
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
590
712
  <a title="Copy rule URL" target="_blank"
591
713
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-blank-line-after-meta-block">
592
714
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
593
715
  </h3>
594
716
 
595
- > Requires a blank line between the closing `// ==/UserScript==` and the first line of code.
717
+ <details>
718
+
719
+ <summary>Requires a blank line between the closing <code>// ==/UserScript==</code> and the first line of code.</summary>
596
720
 
597
721
  #### <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
598
722
 
@@ -617,8 +741,17 @@ If you rely on `@include` patterns that cannot be expressed using `@match`.
617
741
 
618
742
  If you don't care about visual separation between metadata and code.
619
743
 
744
+ #### Introduced in
745
+
746
+ [v1.3.0](https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0) (September 12, 2026) as `require-meta-newline`
747
+
748
+ #### Renamed in
749
+
750
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.4.0">v1.4.0</a> (September 13, 2026) to `require-blank-line-after-meta-block`
751
+
620
752
  #### See also
621
753
 
754
+ - [`meta-order`](#meta-order)
622
755
  - [`meta-spacing`](#meta-spacing)
623
756
 
624
757
  <div align="center">
@@ -629,6 +762,8 @@ If you don't care about visual separation between metadata and code.
629
762
 
630
763
  ---
631
764
 
765
+ </details>
766
+
632
767
  <h3 id="require-homepage-pair">
633
768
  <code>require-homepage-pair</code>
634
769
  <a title="Only included in strict config" href="#usage">
@@ -640,7 +775,9 @@ If you don't care about visual separation between metadata and code.
640
775
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
641
776
  </h3>
642
777
 
643
- > Requires `@homepage` and `@homepageURL` to be used together.
778
+ <details>
779
+
780
+ <summary>Requires <code>@homepage</code> and <code>@homepageURL</code> to be used together.</summary>
644
781
 
645
782
  #### <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
646
783
 
@@ -663,6 +800,10 @@ If you don't care about visual separation between metadata and code.
663
800
 
664
801
  If your target manager does not fall back to `@namespace` when a homepage key is missing (which usually produces a broken URL).
665
802
 
803
+ #### Introduced in
804
+
805
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0">v1.3.0</a> (September 12, 2026)
806
+
666
807
  #### See also
667
808
 
668
809
  - [`require-update-download-pair`](#require-update-download-pair)
@@ -675,6 +816,8 @@ If your target manager does not fall back to `@namespace` when a homepage key is
675
816
 
676
817
  ---
677
818
 
819
+ </details>
820
+
678
821
  <h3 id="require-matching-localized-fields">
679
822
  <code>require-matching-localized-fields</code>
680
823
  <a title="Included in recommended config" href="#usage">
@@ -686,7 +829,9 @@ If your target manager does not fall back to `@namespace` when a homepage key is
686
829
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
687
830
  </h3>
688
831
 
689
- > Requires that every `@name:xx` has a matching `@description:xx` (and vice versa).
832
+ <details>
833
+
834
+ <summary>Requires that every <code>@name:xx</code> has a matching <code>@description:xx</code> (and vice versa).</summary>
690
835
 
691
836
  #### Options
692
837
 
@@ -723,6 +868,10 @@ If your target manager does not fall back to `@namespace` when a homepage key is
723
868
 
724
869
  If you intentionally provide localized names without descriptions (or vice versa).
725
870
 
871
+ #### Introduced in
872
+
873
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
874
+
726
875
  #### See also
727
876
 
728
877
  - [`no-duplicate-keys`](#no-duplicate-keys)
@@ -736,6 +885,8 @@ If you intentionally provide localized names without descriptions (or vice versa
736
885
 
737
886
  ---
738
887
 
888
+ </details>
889
+
739
890
  <h3 id="require-required-fields">
740
891
  <code>require-required-fields</code>
741
892
  <a title="Included in recommended config" href="#usage">
@@ -747,7 +898,9 @@ If you intentionally provide localized names without descriptions (or vice versa
747
898
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
748
899
  </h3>
749
900
 
750
- > Requires essential metadata fields (`@name`, `@version` by default) and at least one `@match` or `@include`.
901
+ <details>
902
+
903
+ <summary>Requires essential metadata fields (<code>@name</code>, <code>@version</code> by default) and at least one <code>@match</code> or <code>@include</code></summary>
751
904
 
752
905
  #### Options
753
906
 
@@ -779,6 +932,10 @@ If you intentionally provide localized names without descriptions (or vice versa
779
932
 
780
933
  If you use a subset of metadata fields that doesn't match the convention.
781
934
 
935
+ #### Introduced in
936
+
937
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
938
+
782
939
  #### See also
783
940
 
784
941
  - [`no-duplicate-keys`](#no-duplicate-keys)
@@ -792,20 +949,24 @@ If you use a subset of metadata fields that doesn't match the convention.
792
949
 
793
950
  ---
794
951
 
952
+ </details>
953
+
795
954
  <h3 id="require-space-before-meta-key">
796
955
  <code>require-space-before-meta-key</code>
797
956
  <a title="Included in recommended config" href="#usage">
798
957
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
799
958
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
800
959
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
801
- <a title="Doesn't catch bugs" href="#require-space-before-meta-key">
960
+ <a title="Doesn't prevent bugs" href="#require-space-before-meta-key">
802
961
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
803
962
  <a title="Copy rule URL" target="_blank"
804
963
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-space-before-meta-key">
805
964
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
806
965
  </h3>
807
966
 
808
- > Requires exactly one space between `//` and metadata keys.
967
+ <details>
968
+
969
+ <summary>Requires exactly one space between <code>//</code> and metadata keys.</summary>
809
970
 
810
971
  #### <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
811
972
 
@@ -830,6 +991,10 @@ If you use a subset of metadata fields that doesn't match the convention.
830
991
 
831
992
  If you intentionally use a different prefix style.
832
993
 
994
+ #### Introduced in
995
+
996
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0">v1.3.0</a> (September 12, 2026)
997
+
833
998
  #### See also
834
999
 
835
1000
  - [`meta-spacing`](#meta-spacing)
@@ -843,20 +1008,22 @@ If you intentionally use a different prefix style.
843
1008
 
844
1009
  ---
845
1010
 
1011
+ </details>
1012
+
846
1013
  <h3 id="require-sri-hashing">
847
1014
  <code>require-sri-hashing</code>
848
1015
  <a title="Only included in strict config" href="#usage">
849
1016
  <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
850
- <a title="Doesn't catch bugs" href="#require-sri-hashing">
851
- <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
852
- <a title="Accepts object w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
1017
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
853
1018
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
854
1019
  <a title="Copy rule URL" target="_blank"
855
1020
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-sri-hashing">
856
1021
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
857
1022
  </h3>
858
1023
 
859
- > Requires SRI hashes on `@require` and `@resource` URLs.
1024
+ <details>
1025
+
1026
+ <summary>Requires SRI hashes on <code>@require</code> and <code>@resource</code> URLs.</summary>
860
1027
 
861
1028
  #### Options
862
1029
 
@@ -868,8 +1035,9 @@ If you intentionally use a different prefix style.
868
1035
  /* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
869
1036
 
870
1037
  // ==UserScript==
871
- ! // @require https://example.com/library.js#sha256-BASE64HASH
872
- ! // @resource logo https://example.com/logo.png#sha256-BASE64HASH
1038
+ ! // @require https://example.com/library.js
1039
+ // @resource css https://example.com/styles.css#sha384-h/TTEs...
1040
+ ! // @resource logo https://example.com/logo.png#sha256-xUj+3O...
873
1041
  // ==/UserScript==
874
1042
  ```
875
1043
 
@@ -879,16 +1047,21 @@ If you intentionally use a different prefix style.
879
1047
  /* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
880
1048
 
881
1049
  // ==UserScript==
882
- - // @require https://example.com/library.js#sha256-BASE64HASH
883
- - // @resource logo https://example.com/logo.png#sha256-BASE64HASH
884
- + // @require https://example.com/library.js#sha384-BASE64HASH
885
- + // @resource logo https://example.com/logo.png#sha384-BASE64HASH
1050
+ - // @require https://example.com/library.js
1051
+ + // @require https://example.com/library.js#sha384-fTbBOw...
1052
+ // @resource css https://example.com/styles.css#sha384-h/TTEs...
1053
+ - // @resource logo https://example.com/logo.png#sha256-xUj+3O...
1054
+ + // @resource logo https://example.com/logo.png#sha384-mQ3Slt...
886
1055
  // ==/UserScript==
887
1056
  ```
888
1057
 
889
1058
  #### When not to use it
890
1059
 
891
- If you prefer shorter URLs, or don't support users who enforce subresource integrity validation via manager settings.
1060
+ If you prefer shorter URLs, or don't support users who strictly enforce subresource integrity via manager settings.
1061
+
1062
+ #### Introduced in
1063
+
1064
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.5.0">v1.5.0</a> (September 15, 2026)
892
1065
 
893
1066
  #### See also
894
1067
 
@@ -902,7 +1075,9 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
902
1075
 
903
1076
  </div>
904
1077
 
905
- ----
1078
+ ---
1079
+
1080
+ </details>
906
1081
 
907
1082
  <h3 id="require-update-download-pair">
908
1083
  <code>require-update-download-pair</code>
@@ -913,7 +1088,9 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
913
1088
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
914
1089
  </h3>
915
1090
 
916
- > Requires `@updateURL` and `@downloadURL` to be used together.
1091
+ <details>
1092
+
1093
+ <summary>Requires <code>@updateURL</code> and <code>@downloadURL</code> to be used together.</summary>
917
1094
 
918
1095
  #### <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
919
1096
 
@@ -936,6 +1113,10 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
936
1113
 
937
1114
  If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the full script on every update check).
938
1115
 
1116
+ #### Introduced in
1117
+
1118
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.3.0">v1.3.0</a> (September 12, 2026)
1119
+
939
1120
  #### See also
940
1121
 
941
1122
  - <a target="_blank" href="https://www.tampermonkey.net/documentation.php?q=update_url#meta:updateURL"><code>@updateURL</code></a>
@@ -949,6 +1130,8 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
949
1130
 
950
1131
  ---
951
1132
 
1133
+ </details>
1134
+
952
1135
  <h3 id="require-user-js-filename">
953
1136
  <code>require-user-js-filename</code>
954
1137
  <a title="Included in recommended config" href="#usage">
@@ -958,7 +1141,9 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
958
1141
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
959
1142
  </h3>
960
1143
 
961
- > Requires that files containing a userscript metadata block end in `.user.js`.
1144
+ <details>
1145
+
1146
+ <summary>Requires files containing <code>// ==UserScript==</code> have names ending in <code>.user.js</code></summary>
962
1147
 
963
1148
  #### <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 filename
964
1149
 
@@ -977,6 +1162,10 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
977
1162
 
978
1163
  If you intentionally name your userscripts something other than `*.user.js`.
979
1164
 
1165
+ #### Introduced in
1166
+
1167
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.2.0">v1.2.0</a> (September 11, 2026)
1168
+
980
1169
  <div align="center">
981
1170
 
982
1171
  [Back to index ↑][epg-rules]
@@ -985,6 +1174,8 @@ If you intentionally name your userscripts something other than `*.user.js`.
985
1174
 
986
1175
  ---
987
1176
 
1177
+ </details>
1178
+
988
1179
  <h3 id="valid-field-values">
989
1180
  <code>valid-field-values</code>
990
1181
  <a title="Included in recommended config" href="#usage">
@@ -996,7 +1187,9 @@ If you intentionally name your userscripts something other than `*.user.js`.
996
1187
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
997
1188
  </h3>
998
1189
 
999
- > Validates `@version` (semver or date format) and URL fields (`@homepage`, `@icon`, `@icon64`, `@require`, `@resource`, `@source`, `@website`, any key ending in `URL` case-insensitively).
1190
+ <details>
1191
+
1192
+ <summary>Validates <code>@version</code> (semver or date format) and URL fields.</summary>
1000
1193
 
1001
1194
  #### Options
1002
1195
 
@@ -1030,69 +1223,14 @@ If you intentionally name your userscripts something other than `*.user.js`.
1030
1223
 
1031
1224
  If you use a custom versioning scheme or URLs that aren't standard.
1032
1225
 
1033
- #### See also
1034
-
1035
- - [`no-missing-resources`](#no-missing-resources)
1036
- - [`valid-grants`](#valid-grants)
1037
-
1038
- <div align="center">
1039
-
1040
- [Back to index ↑][epg-rules]
1226
+ #### Introduced in
1041
1227
 
1042
- </div>
1043
-
1044
- ---
1045
-
1046
- <h3 id="valid-grants">
1047
- <code>valid-grants</code>
1048
- <a title="Included in recommended config" href="#usage">
1049
- <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1050
- <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
1051
- <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1052
- <a title="Copy rule URL" target="_blank"
1053
- href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23valid-grants">
1054
- <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1055
- </h3>
1056
-
1057
- > Disallows invalid or unsupported `@grant` values.
1058
-
1059
- #### Options
1060
-
1061
- - `target` (default `'all'`) – manager(s) whose grants to validate against (`'all'`, `'tampermonkey'`, `'violentmonkey'`, `'greasemonkey'`, `'scriptcat'`), as a single string or array
1062
- - `allowedGrants` (default `[]`) – additional `@grant` values to allow beyond the built-in list (covering Tampermonkey, Violentmonkey and ScriptCat), as a single string or array
1063
-
1064
- #### <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
1065
-
1066
- ```diff
1067
- /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
1068
-
1069
- // ==UserScript==
1070
- ! // @grant GM_notificaiton
1071
- ! // @grant CAT.agent.dom
1072
- // ==/UserScript==
1073
- ```
1074
-
1075
- #### <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
1076
-
1077
- ```diff
1078
- /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
1079
-
1080
- // ==UserScript==
1081
- - // @grant GM_notificaiton
1082
- + // @grant GM_notification
1083
- - // @grant CAT.agent.dom
1084
- + // @grant GM_getTab
1085
- // ==/UserScript==
1086
- ```
1087
-
1088
- #### When not to use it
1089
-
1090
- If you don't want `@grant` validation at all. For individual uncovered grants, prefer whitelisting via `allowedGrants` over disabling the rule.
1228
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/releases/tag/v1.0.0">v1.0.0</a> (September 9, 2026)
1091
1229
 
1092
1230
  #### See also
1093
1231
 
1094
- - [`no-missing-grants`](#no-missing-grants)
1095
- - [`no-unused-grants`](#no-unused-grants)
1232
+ - [`no-invalid-grants`](#no-invalid-grants)
1233
+ - [`no-missing-resources`](#no-missing-resources)
1096
1234
 
1097
1235
  <div align="center">
1098
1236
 
@@ -1126,6 +1264,7 @@ If you don't want `@grant` validation at all. For individual uncovered grants, p
1126
1264
 
1127
1265
  <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md">
1128
1266
  <img height=62 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
1267
+ <br><br>
1129
1268
 
1130
1269
  <details>
1131
1270
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-greasemonkey",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "ESLint rules for Greasemonkey/Tampermonkey userscripts",
5
5
  "type": "module",
6
6
  "engines": {
@@ -69,7 +69,7 @@
69
69
  "@eslint/markdown": "^8.0.3",
70
70
  "@stylistic/eslint-plugin": "^5.10.0",
71
71
  "eslint": "^10.10.0",
72
- "eslint-plugin-constructors": "^1.2.0",
72
+ "eslint-plugin-constructors": "^1.2.2",
73
73
  "eslint-plugin-eslint-plugin": "^7.6.2",
74
74
  "eslint-plugin-import-x": "^4.17.1",
75
75
  "eslint-plugin-n": "^18.3.0",
package/src/data/apis.js CHANGED
@@ -32,5 +32,4 @@ export function supportsAPI({ manager, api }) {
32
32
  : api.startsWith('CAT') ? manager == 'scriptcat'
33
33
  : tmAPIs.has(api) ? manager == 'tampermonkey'
34
34
  : true
35
-
36
35
  }
@@ -1,3 +1,6 @@
1
- export default { // val = replacement
2
- rules: { 'require-meta-newline': 'require-blank-line-after-meta-block' } // 2026-9-13
1
+ export const rules = { // old: new
2
+ 'require-meta-newline': 'require-blank-line-after-meta-block', // 2026-9-13
3
+ 'valid-grants': 'no-invalid-grants'
3
4
  }
5
+
6
+ export default { rules }
package/src/index.js CHANGED
@@ -1,8 +1,11 @@
1
- import aliases from './data/deprecations.js'
1
+ /* eslint-disable security/detect-object-injection -- false positives */
2
+
3
+ import { rules as oldRules } from './data/deprecations.js'
2
4
 
3
5
  import metaOrder from './rules/meta-order.js'
4
6
  import metaSpacing from './rules/meta-spacing.js'
5
7
  import noDuplicateKeys from './rules/no-duplicate-keys.js'
8
+ import noInvalidGrants from './rules/no-invalid-grants.js'
6
9
  import noInvalidHeaders from './rules/no-invalid-headers.js'
7
10
  import noMissingGrants from './rules/no-missing-grants.js'
8
11
  import noMissingResources from './rules/no-missing-resources.js'
@@ -18,13 +21,13 @@ import requireSRIhashing from './rules/require-sri-hashing.js'
18
21
  import requireUpdateDownloadPair from './rules/require-update-download-pair.js'
19
22
  import requireUserJsFilename from './rules/require-user-js-filename.js'
20
23
  import validFieldValues from './rules/valid-field-values.js'
21
- import validGrants from './rules/valid-grants.js'
22
24
 
23
25
  const plugin = {
24
26
  rules: {
25
27
  'meta-order': metaOrder,
26
28
  'meta-spacing': metaSpacing,
27
29
  'no-duplicate-keys': noDuplicateKeys,
30
+ 'no-invalid-grants': noInvalidGrants,
28
31
  'no-invalid-headers': noInvalidHeaders,
29
32
  'no-missing-grants': noMissingGrants,
30
33
  'no-unused-grants': noUnusedGrants,
@@ -39,27 +42,23 @@ const plugin = {
39
42
  'require-sri-hashing': requireSRIhashing,
40
43
  'require-update-download-pair': requireUpdateDownloadPair,
41
44
  'require-user-js-filename': requireUserJsFilename,
42
- 'valid-field-values': validFieldValues,
43
- 'valid-grants': validGrants
45
+ 'valid-field-values': validFieldValues
44
46
  }
45
47
  }
46
48
 
47
- const docsURL = 'https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#'
48
49
  for (const [ruleId, rule] of Object.entries(plugin.rules))
49
- rule.meta.docs.url = docsURL + ruleId
50
+ rule.meta.docs.url = `https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#${ruleId}`
50
51
 
51
- // Generate deprecated aliases
52
- for (const [oldName, newName] of Object.entries(aliases.rules)) { /* eslint-disable security/detect-object-injection */
52
+ for (const [oldName, newName] of Object.entries(oldRules)) {
53
53
  const newRule = plugin.rules[newName]
54
54
  plugin.rules[oldName] = {
55
55
  ...newRule,
56
56
  meta: {
57
- ...newRule.meta,
58
- docs: { ...newRule.meta.docs, recommended: false },
57
+ ...newRule.meta, docs: { ...newRule.meta.docs, recommended: false },
59
58
  deprecated: { message: `Use \`${newName}\` instead.`, replacedBy: [{ rule: { name: newName }}] }
60
59
  }
61
60
  }
62
- } /* eslint-enable security/detect-object-injection */
61
+ }
63
62
 
64
63
  plugin.configs = {
65
64
  recommended: {
@@ -67,6 +66,7 @@ plugin.configs = {
67
66
  rules: {
68
67
  'greasemonkey/meta-spacing': 'error',
69
68
  'greasemonkey/no-duplicate-keys': 'error',
69
+ 'greasemonkey/no-invalid-grants': 'error',
70
70
  'greasemonkey/no-invalid-headers': 'error',
71
71
  'greasemonkey/no-missing-grants': 'error',
72
72
  'greasemonkey/no-unused-grants': 'error',
@@ -78,24 +78,22 @@ plugin.configs = {
78
78
  'greasemonkey/require-required-fields': 'error',
79
79
  'greasemonkey/require-space-before-meta-key': 'error',
80
80
  'greasemonkey/require-user-js-filename': 'error',
81
- 'greasemonkey/valid-field-values': 'error',
82
- 'greasemonkey/valid-grants': 'error'
81
+ 'greasemonkey/valid-field-values': 'error'
83
82
  }
83
+ },
84
+ strict: {
85
+ plugins: { greasemonkey: plugin },
86
+ rules: Object.fromEntries(Object.keys(plugin.rules).map(ruleId => [`greasemonkey/${ruleId}`, 'error']))
84
87
  }
85
88
  }
86
89
 
87
- plugin.configs.strict = {
88
- plugins: { greasemonkey: plugin },
89
- rules: Object.fromEntries(Object.keys(plugin.rules).map(ruleId => [`greasemonkey/${ruleId}`, 'error']))
90
- }
91
-
92
90
  for (const manager of ['tampermonkey', 'violentmonkey', 'greasemonkey', 'scriptcat'])
93
- plugin.configs[manager] = { // eslint-disable-line security/detect-object-injection
91
+ plugin.configs[manager] = {
94
92
  plugins: { greasemonkey: plugin },
95
93
  rules: {
96
94
  ...plugin.configs.recommended.rules,
97
- 'greasemonkey/no-invalid-headers': ['error', { target: manager }],
98
- 'greasemonkey/valid-grants': ['error', { target: manager }]
95
+ 'greasemonkey/no-invalid-grants': ['error', { target: manager }],
96
+ 'greasemonkey/no-invalid-headers': ['error', { target: manager }]
99
97
  }
100
98
  }
101
99
 
@@ -12,8 +12,8 @@ function findViolation(entries, keys) {
12
12
  const key = entry.key.split(':', 1)[0]
13
13
  return { entry, key, rank: ranks.get(key) }
14
14
  }).filter(item => item.rank !== undefined)
15
- for (let i = 1; i < known.length; i++) // eslint-disable-next-line security/detect-object-injection
16
- if (known[i - 1].rank > known[i].rank) return [known[i - 1], known[i]]
15
+ for (let i = 1 ; i < known.length ; i++) // eslint-disable-next-line security/detect-object-injection
16
+ if (known[i -1].rank > known[i].rank) return [known[i -1], known[i]]
17
17
  }
18
18
 
19
19
  function sortEntries(entries, keys) {
@@ -21,7 +21,7 @@ function sortEntries(entries, keys) {
21
21
  return entries.toSorted((a, b) => {
22
22
  const aRank = ranks.get(a.key.split(':', 1)[0]),
23
23
  bRank = ranks.get(b.key.split(':', 1)[0])
24
- return (aRank ?? Infinity) - (bRank ?? Infinity)
24
+ return ( aRank ?? Infinity ) -( bRank ?? Infinity )
25
25
  })
26
26
  }
27
27
 
@@ -46,7 +46,7 @@ export default {
46
46
  node: entry.comment, messageId: 'invalidHash',
47
47
  data: {
48
48
  key: entry.key,
49
- detected: match ? ` Detected ${match[1].toLowerCase()};` : '',
49
+ detected: match ? ` Detected ${match[1].toLowerCase()}.` : '',
50
50
  expected: algorithm
51
51
  }
52
52
  })