eslint-plugin-greasemonkey 1.5.0 → 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
 
@@ -38,7 +44,7 @@ export default [
38
44
  {
39
45
  files: ['**/*.user.js'], plugins: { greasemonkey }
40
46
  rules: {
41
- ...greasemonkey.configs.recommended.rules, // or .strict.rules to enable all
47
+ ...greasemonkey.configs.recommended.rules,
42
48
  'greasemonkey/no-unused-resources': 'off', // selectively disable rule
43
49
  'greasemonkey/meta-spacing': ['error', 2] // selectively tweak rule
44
50
  }
@@ -46,35 +52,18 @@ export default [
46
52
  ]
47
53
  ```
48
54
 
55
+ Avaialble bundles: `recommended`, `strict`, `tampermonkey`, `violentmonkey`, `greasemonkey`, `scriptcat`
56
+
49
57
  **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
50
58
 
51
59
  ---
52
60
 
53
- ## Supported rules
54
-
55
- | ID | Description | Auto-fixable | Recommended |
56
- | --- | --- | :-: | :-: |
57
- | [`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"> |
58
- | [`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"> |
59
- | [`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"> |
60
- | [`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"> |
61
- | [`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"> |
62
- | [`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"> |
63
- | [`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"> |
64
- | [`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"> |
65
- | [`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"> |
66
- | [`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"> |
67
- | [`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"> |
68
- | [`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"> |
69
- | [`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"> |
70
- | [`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"> |
71
- | [`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"> |
72
- | [`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"> |
73
- | [`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"> |
74
- | [`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"> |
75
- | [`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"> |
76
-
77
- ---
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>
78
67
 
79
68
  <h3 id="meta-order">
80
69
  <code>meta-order</code>
@@ -82,7 +71,7 @@ export default [
82
71
  <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
83
72
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
84
73
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
85
- <a title="Doesn't catch bugs" href="#meta-order">
74
+ <a title="Doesn't prevent bugs" href="#meta-order">
86
75
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
87
76
  <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
88
77
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -91,18 +80,14 @@ export default [
91
80
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
92
81
  </h3>
93
82
 
94
- > Enforces a preferred order for metadata keys.
83
+ <details>
84
+
85
+ <summary>Enforces a preferred order for metadata keys.</summary>
95
86
 
96
87
  #### Options
97
88
 
98
89
  - `string[]` (default `[]`) – metadata keys in custom order
99
90
 
100
- For example:
101
-
102
- ```js
103
- /* eslint greasemonkey/meta-order: ['error', ['run-in', 'inject-into']] */
104
- ```
105
-
106
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
107
92
 
108
93
  ```diff
@@ -113,12 +98,6 @@ For example:
113
98
  ! // @namespace example.com
114
99
  // @author John Doe
115
100
  ! // @license MIT
116
- // @icon https://example.com/icon.png
117
- ! // @match https://example.com/*
118
- // @grant GM_setValue
119
- // @require https://example.com/lib.js
120
- // @resource logo https://example.com/logo.png
121
- ! // @connect example.com
122
101
  // ==/UserScript==
123
102
  ```
124
103
 
@@ -135,16 +114,6 @@ For example:
135
114
  + // @namespace example.com
136
115
  + // @version 1.0.0
137
116
  + // @license MIT
138
- // @icon https://example.com/icon.png
139
- - // @match https://example.com/*
140
- + // @connect example.com
141
- // @grant GM_setValue
142
- - // @require https://example.com/lib.js
143
- - // @resource logo https://example.com/logo.png
144
- - // @connect example.com
145
- + // @match https://example.com/*
146
- + // @require https://example.com/lib.js
147
- + // @resource logo https://example.com/logo.png
148
117
  // ==/UserScript==
149
118
  ```
150
119
 
@@ -152,6 +121,10 @@ For example:
152
121
 
153
122
  If you don't care about the order of metadata fields.
154
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
+
155
128
  #### See also
156
129
 
157
130
  - [`meta-spacing`](#meta-spacing)
@@ -165,13 +138,15 @@ If you don't care about the order of metadata fields.
165
138
 
166
139
  ---
167
140
 
141
+ </details>
142
+
168
143
  <h3 id="meta-spacing">
169
144
  <code>meta-spacing</code>
170
145
  <a title="Included in recommended config" href="#usage">
171
146
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
172
147
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
173
148
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
174
- <a title="Doesn't catch bugs" href="#meta-spacing">
149
+ <a title="Doesn't prevent bugs" href="#meta-spacing">
175
150
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
176
151
  <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
177
152
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -180,7 +155,9 @@ If you don't care about the order of metadata fields.
180
155
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
181
156
  </h3>
182
157
 
183
- > 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>
184
161
 
185
162
  #### Options
186
163
 
@@ -216,6 +193,10 @@ If you don't care about the order of metadata fields.
216
193
 
217
194
  If you don't care about visual alignment in metadata blocks.
218
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
+
219
200
  #### See also
220
201
 
221
202
  - [`require-blank-line-after-meta-block`](#require-blank-line-after-meta-block)
@@ -229,6 +210,8 @@ If you don't care about visual alignment in metadata blocks.
229
210
 
230
211
  ---
231
212
 
213
+ </details>
214
+
232
215
  <h3 id="no-duplicate-keys">
233
216
  <code>no-duplicate-keys</code>
234
217
  <a title="Included in recommended config" href="#usage">
@@ -238,7 +221,9 @@ If you don't care about visual alignment in metadata blocks.
238
221
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
239
222
  </h3>
240
223
 
241
- > 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>
242
227
 
243
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
244
229
 
@@ -248,6 +233,8 @@ If you don't care about visual alignment in metadata blocks.
248
233
  ! // @name Bar
249
234
  ! // @version 1.0.0
250
235
  ! // @version 2.0.0
236
+ // @match https://a.example.com/*
237
+ // @match https://b.example.com/*
251
238
  // ==/UserScript==
252
239
  ```
253
240
 
@@ -257,12 +244,12 @@ If you don't care about visual alignment in metadata blocks.
257
244
  // ==UserScript==
258
245
  - // @name Foo
259
246
  - // @name Bar
247
+ + // @name My Script
260
248
  - // @version 1.0.0
261
249
  - // @version 2.0.0
262
- + // @name My Script
263
250
  + // @version 1.0.0
264
- + // @match https://a.example.com/*
265
- + // @match https://b.example.com/*
251
+ // @match https://a.example.com/*
252
+ // @match https://b.example.com/*
266
253
  // ==/UserScript==
267
254
  ```
268
255
 
@@ -270,6 +257,10 @@ If you don't care about visual alignment in metadata blocks.
270
257
 
271
258
  If you intentionally repeat single-value keys.
272
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
+
273
264
  #### See also
274
265
 
275
266
  - [`require-matching-localized-fields`](#require-matching-localized-fields)
@@ -283,6 +274,91 @@ If you intentionally repeat single-value keys.
283
274
 
284
275
  ---
285
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
+
286
362
  <h3 id="no-invalid-headers">
287
363
  <code>no-invalid-headers</code>
288
364
  <a title="Included in recommended config" href="#usage">
@@ -294,7 +370,9 @@ If you intentionally repeat single-value keys.
294
370
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
295
371
  </h3>
296
372
 
297
- > Disallows invalid or unsupported metadata headers.
373
+ <details>
374
+
375
+ <summary>Disallows invalid or unsupported metadata headers.</summary>
298
376
 
299
377
  #### Options
300
378
 
@@ -332,10 +410,14 @@ If you intentionally repeat single-value keys.
332
410
 
333
411
  If your script relies heavily on custom headers and you'd rather not maintain `allowedHeaders`.
334
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
+
335
417
  #### See also
336
418
 
419
+ - [`no-invalid-grants`](#no-invalid-grants)
337
420
  - [`valid-field-values`](#valid-field-values)
338
- - [`valid-grants`](#valid-grants)
339
421
 
340
422
  <div align="center">
341
423
 
@@ -345,6 +427,8 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
345
427
 
346
428
  ---
347
429
 
430
+ </details>
431
+
348
432
  <h3 id="no-missing-grants">
349
433
  <code>no-missing-grants</code>
350
434
  <a title="Included in recommended config" href="#usage">
@@ -354,7 +438,9 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
354
438
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
355
439
  </h3>
356
440
 
357
- > 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>
358
444
 
359
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
360
446
 
@@ -381,10 +467,14 @@ If your script relies heavily on custom headers and you'd rather not maintain `a
381
467
 
382
468
  If you use APIs through aliases or wrappers that obscure the original call site.
383
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
+
384
474
  #### See also
385
475
 
476
+ - [`no-invalid-grants`](#no-invalid-grants)
386
477
  - [`no-unused-grants`](#no-unused-grants)
387
- - [`valid-grants`](#valid-grants)
388
478
 
389
479
  <div align="center">
390
480
 
@@ -394,6 +484,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
394
484
 
395
485
  ---
396
486
 
487
+ </details>
488
+
397
489
  <h3 id="no-missing-resources">
398
490
  <code>no-missing-resources</code>
399
491
  <a title="Included in recommended config" href="#usage">
@@ -403,7 +495,9 @@ If you use APIs through aliases or wrappers that obscure the original call site.
403
495
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
404
496
  </h3>
405
497
 
406
- > 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>
407
501
 
408
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
409
503
 
@@ -430,6 +524,10 @@ If you use APIs through aliases or wrappers that obscure the original call site.
430
524
 
431
525
  If you reference resources through an alias or computed pattern that obscures the call site.
432
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
+
433
531
  #### See also
434
532
 
435
533
  - [`no-unused-resources`](#no-unused-resources)
@@ -442,6 +540,8 @@ If you reference resources through an alias or computed pattern that obscures th
442
540
 
443
541
  ---
444
542
 
543
+ </details>
544
+
445
545
  <h3 id="no-unused-grants">
446
546
  <code>no-unused-grants</code>
447
547
  <a title="Included in recommended config" href="#usage">
@@ -451,7 +551,9 @@ If you reference resources through an alias or computed pattern that obscures th
451
551
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
452
552
  </h3>
453
553
 
454
- > 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>
455
557
 
456
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
457
559
 
@@ -475,10 +577,14 @@ If you reference resources through an alias or computed pattern that obscures th
475
577
 
476
578
  If you access the granted API through an alias or computed property rather than calling it directly.
477
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
+
478
584
  #### See also
479
585
 
586
+ - [`no-invalid-grants`](#no-invalid-grants)
480
587
  - [`no-missing-grants`](#no-missing-grants)
481
- - [`valid-grants`](#valid-grants)
482
588
 
483
589
  <div align="center">
484
590
 
@@ -488,6 +594,8 @@ If you access the granted API through an alias or computed property rather than
488
594
 
489
595
  ---
490
596
 
597
+ </details>
598
+
491
599
  <h3 id="no-unused-resources">
492
600
  <code>no-unused-resources</code>
493
601
  <a title="Included in recommended config" href="#usage">
@@ -497,7 +605,9 @@ If you access the granted API through an alias or computed property rather than
497
605
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
498
606
  </h3>
499
607
 
500
- > 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>
501
611
 
502
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
503
613
 
@@ -521,6 +631,10 @@ If you access the granted API through an alias or computed property rather than
521
631
 
522
632
  If you pass resource names through variables or aliases rather than use them literally.
523
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
+
524
638
  #### See also
525
639
 
526
640
  - [`no-missing-resources`](#no-missing-resources)
@@ -533,6 +647,8 @@ If you pass resource names through variables or aliases rather than use them lit
533
647
 
534
648
  ---
535
649
 
650
+ </details>
651
+
536
652
  <h3 id="prefer-match">
537
653
  <code>prefer-match</code>
538
654
  <a title="Included in recommended config" href="#usage">
@@ -542,7 +658,9 @@ If you pass resource names through variables or aliases rather than use them lit
542
658
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
543
659
  </h3>
544
660
 
545
- > 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>
546
664
 
547
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
548
666
 
@@ -565,6 +683,10 @@ If you pass resource names through variables or aliases rather than use them lit
565
683
 
566
684
  If you rely on `@include` patterns that cannot be expressed using `@match`.
567
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
+
568
690
  #### See also
569
691
 
570
692
  - <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">Chrome match patterns</a>
@@ -577,20 +699,24 @@ If you rely on `@include` patterns that cannot be expressed using `@match`.
577
699
 
578
700
  ---
579
701
 
702
+ </details>
703
+
580
704
  <h3 id="require-blank-line-after-meta-block">
581
705
  <code>require-blank-line-after-meta-block</code>
582
706
  <a title="Included in recommended config" href="#usage">
583
707
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
584
708
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
585
709
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
586
- <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">
587
711
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
588
712
  <a title="Copy rule URL" target="_blank"
589
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">
590
714
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
591
715
  </h3>
592
716
 
593
- > 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>
594
720
 
595
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
596
722
 
@@ -615,8 +741,17 @@ If you rely on `@include` patterns that cannot be expressed using `@match`.
615
741
 
616
742
  If you don't care about visual separation between metadata and code.
617
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
+
618
752
  #### See also
619
753
 
754
+ - [`meta-order`](#meta-order)
620
755
  - [`meta-spacing`](#meta-spacing)
621
756
 
622
757
  <div align="center">
@@ -627,6 +762,8 @@ If you don't care about visual separation between metadata and code.
627
762
 
628
763
  ---
629
764
 
765
+ </details>
766
+
630
767
  <h3 id="require-homepage-pair">
631
768
  <code>require-homepage-pair</code>
632
769
  <a title="Only included in strict config" href="#usage">
@@ -638,7 +775,9 @@ If you don't care about visual separation between metadata and code.
638
775
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
639
776
  </h3>
640
777
 
641
- > 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>
642
781
 
643
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
644
783
 
@@ -661,6 +800,10 @@ If you don't care about visual separation between metadata and code.
661
800
 
662
801
  If your target manager does not fall back to `@namespace` when a homepage key is missing (which usually produces a broken URL).
663
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
+
664
807
  #### See also
665
808
 
666
809
  - [`require-update-download-pair`](#require-update-download-pair)
@@ -673,6 +816,8 @@ If your target manager does not fall back to `@namespace` when a homepage key is
673
816
 
674
817
  ---
675
818
 
819
+ </details>
820
+
676
821
  <h3 id="require-matching-localized-fields">
677
822
  <code>require-matching-localized-fields</code>
678
823
  <a title="Included in recommended config" href="#usage">
@@ -684,7 +829,9 @@ If your target manager does not fall back to `@namespace` when a homepage key is
684
829
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
685
830
  </h3>
686
831
 
687
- > 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>
688
835
 
689
836
  #### Options
690
837
 
@@ -721,6 +868,10 @@ If your target manager does not fall back to `@namespace` when a homepage key is
721
868
 
722
869
  If you intentionally provide localized names without descriptions (or vice versa).
723
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
+
724
875
  #### See also
725
876
 
726
877
  - [`no-duplicate-keys`](#no-duplicate-keys)
@@ -734,6 +885,8 @@ If you intentionally provide localized names without descriptions (or vice versa
734
885
 
735
886
  ---
736
887
 
888
+ </details>
889
+
737
890
  <h3 id="require-required-fields">
738
891
  <code>require-required-fields</code>
739
892
  <a title="Included in recommended config" href="#usage">
@@ -745,7 +898,9 @@ If you intentionally provide localized names without descriptions (or vice versa
745
898
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
746
899
  </h3>
747
900
 
748
- > 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>
749
904
 
750
905
  #### Options
751
906
 
@@ -777,6 +932,10 @@ If you intentionally provide localized names without descriptions (or vice versa
777
932
 
778
933
  If you use a subset of metadata fields that doesn't match the convention.
779
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
+
780
939
  #### See also
781
940
 
782
941
  - [`no-duplicate-keys`](#no-duplicate-keys)
@@ -790,20 +949,24 @@ If you use a subset of metadata fields that doesn't match the convention.
790
949
 
791
950
  ---
792
951
 
952
+ </details>
953
+
793
954
  <h3 id="require-space-before-meta-key">
794
955
  <code>require-space-before-meta-key</code>
795
956
  <a title="Included in recommended config" href="#usage">
796
957
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
797
958
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
798
959
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
799
- <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">
800
961
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
801
962
  <a title="Copy rule URL" target="_blank"
802
963
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-space-before-meta-key">
803
964
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
804
965
  </h3>
805
966
 
806
- > Requires exactly one space between `//` and metadata keys.
967
+ <details>
968
+
969
+ <summary>Requires exactly one space between <code>//</code> and metadata keys.</summary>
807
970
 
808
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
809
972
 
@@ -828,6 +991,10 @@ If you use a subset of metadata fields that doesn't match the convention.
828
991
 
829
992
  If you intentionally use a different prefix style.
830
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
+
831
998
  #### See also
832
999
 
833
1000
  - [`meta-spacing`](#meta-spacing)
@@ -841,20 +1008,22 @@ If you intentionally use a different prefix style.
841
1008
 
842
1009
  ---
843
1010
 
1011
+ </details>
1012
+
844
1013
  <h3 id="require-sri-hashing">
845
1014
  <code>require-sri-hashing</code>
846
1015
  <a title="Only included in strict config" href="#usage">
847
1016
  <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
848
- <a title="Doesn't catch bugs" href="#require-sri-hashing">
849
- <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
850
- <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">
851
1018
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
852
1019
  <a title="Copy rule URL" target="_blank"
853
1020
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-sri-hashing">
854
1021
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
855
1022
  </h3>
856
1023
 
857
- > 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>
858
1027
 
859
1028
  #### Options
860
1029
 
@@ -866,8 +1035,9 @@ If you intentionally use a different prefix style.
866
1035
  /* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
867
1036
 
868
1037
  // ==UserScript==
869
- ! // @require https://example.com/library.js#sha256-BASE64HASH
870
- ! // @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...
871
1041
  // ==/UserScript==
872
1042
  ```
873
1043
 
@@ -877,16 +1047,21 @@ If you intentionally use a different prefix style.
877
1047
  /* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
878
1048
 
879
1049
  // ==UserScript==
880
- - // @require https://example.com/library.js#sha256-BASE64HASH
881
- - // @resource logo https://example.com/logo.png#sha256-BASE64HASH
882
- + // @require https://example.com/library.js#sha384-BASE64HASH
883
- + // @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...
884
1055
  // ==/UserScript==
885
1056
  ```
886
1057
 
887
1058
  #### When not to use it
888
1059
 
889
- 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)
890
1065
 
891
1066
  #### See also
892
1067
 
@@ -900,7 +1075,9 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
900
1075
 
901
1076
  </div>
902
1077
 
903
- ----
1078
+ ---
1079
+
1080
+ </details>
904
1081
 
905
1082
  <h3 id="require-update-download-pair">
906
1083
  <code>require-update-download-pair</code>
@@ -911,7 +1088,9 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
911
1088
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
912
1089
  </h3>
913
1090
 
914
- > 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>
915
1094
 
916
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
917
1096
 
@@ -934,6 +1113,10 @@ If you prefer shorter URLs, or don't support users who enforce subresource integ
934
1113
 
935
1114
  If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the full script on every update check).
936
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
+
937
1120
  #### See also
938
1121
 
939
1122
  - <a target="_blank" href="https://www.tampermonkey.net/documentation.php?q=update_url#meta:updateURL"><code>@updateURL</code></a>
@@ -947,6 +1130,8 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
947
1130
 
948
1131
  ---
949
1132
 
1133
+ </details>
1134
+
950
1135
  <h3 id="require-user-js-filename">
951
1136
  <code>require-user-js-filename</code>
952
1137
  <a title="Included in recommended config" href="#usage">
@@ -956,7 +1141,9 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
956
1141
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
957
1142
  </h3>
958
1143
 
959
- > 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>
960
1147
 
961
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
962
1149
 
@@ -975,6 +1162,10 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
975
1162
 
976
1163
  If you intentionally name your userscripts something other than `*.user.js`.
977
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
+
978
1169
  <div align="center">
979
1170
 
980
1171
  [Back to index ↑][epg-rules]
@@ -983,6 +1174,8 @@ If you intentionally name your userscripts something other than `*.user.js`.
983
1174
 
984
1175
  ---
985
1176
 
1177
+ </details>
1178
+
986
1179
  <h3 id="valid-field-values">
987
1180
  <code>valid-field-values</code>
988
1181
  <a title="Included in recommended config" href="#usage">
@@ -994,7 +1187,9 @@ If you intentionally name your userscripts something other than `*.user.js`.
994
1187
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
995
1188
  </h3>
996
1189
 
997
- > 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>
998
1193
 
999
1194
  #### Options
1000
1195
 
@@ -1028,69 +1223,14 @@ If you intentionally name your userscripts something other than `*.user.js`.
1028
1223
 
1029
1224
  If you use a custom versioning scheme or URLs that aren't standard.
1030
1225
 
1031
- #### See also
1032
-
1033
- - [`no-missing-resources`](#no-missing-resources)
1034
- - [`valid-grants`](#valid-grants)
1035
-
1036
- <div align="center">
1037
-
1038
- [Back to index ↑][epg-rules]
1039
-
1040
- </div>
1041
-
1042
- ---
1043
-
1044
- <h3 id="valid-grants">
1045
- <code>valid-grants</code>
1046
- <a title="Included in recommended config" href="#usage">
1047
- <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1048
- <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
1049
- <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1050
- <a title="Copy rule URL" target="_blank"
1051
- href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23valid-grants">
1052
- <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1053
- </h3>
1054
-
1055
- > Disallows invalid or unsupported `@grant` values.
1226
+ #### Introduced in
1056
1227
 
1057
- #### Options
1058
-
1059
- - `target` (default `'all'`) – manager(s) whose grants to validate against (`'all'`, `'tampermonkey'`, `'violentmonkey'`, `'greasemonkey'`, `'scriptcat'`), as a single string or array
1060
- - `allowedGrants` (default `[]`) – additional `@grant` values to allow beyond the built-in list (covering Tampermonkey, Violentmonkey and ScriptCat), as a single string or array
1061
-
1062
- #### <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
1063
-
1064
- ```diff
1065
- /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
1066
-
1067
- // ==UserScript==
1068
- ! // @grant GM_notificaiton
1069
- ! // @grant CAT.agent.dom
1070
- // ==/UserScript==
1071
- ```
1072
-
1073
- #### <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
1074
-
1075
- ```diff
1076
- /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
1077
-
1078
- // ==UserScript==
1079
- - // @grant GM_notificaiton
1080
- + // @grant GM_notification
1081
- - // @grant CAT.agent.dom
1082
- + // @grant GM_getTab
1083
- // ==/UserScript==
1084
- ```
1085
-
1086
- #### When not to use it
1087
-
1088
- 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)
1089
1229
 
1090
1230
  #### See also
1091
1231
 
1092
- - [`no-missing-grants`](#no-missing-grants)
1093
- - [`no-unused-grants`](#no-unused-grants)
1232
+ - [`no-invalid-grants`](#no-invalid-grants)
1233
+ - [`no-missing-resources`](#no-missing-resources)
1094
1234
 
1095
1235
  <div align="center">
1096
1236
 
@@ -1124,6 +1264,7 @@ If you don't want `@grant` validation at all. For individual uncovered grants, p
1124
1264
 
1125
1265
  <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-constructors/src/branch/main/docs/LICENSE.md">
1126
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>
1127
1268
 
1128
1269
  <details>
1129
1270
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-greasemonkey",
3
- "version": "1.5.0",
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
  })