eslint-plugin-greasemonkey 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ npm i -D eslint-plugin-greasemonkey
24
24
 
25
25
  ## Usage
26
26
 
27
- Add `greasemonkey` [rules][epg-rules] to your `eslint.config.*js`:
27
+ Add a bundled config to your `eslint.config.*js`:
28
28
 
29
29
  ```js
30
30
  ...
@@ -33,40 +33,9 @@ import greasemonkey from 'eslint-plugin-greasemonkey'
33
33
  export default [
34
34
  // other configs
35
35
  {
36
- files: ['**/*.user.js'],
37
- plugins: { greasemonkey },
38
- rules: { // recommended set w/ default options
39
- 'greasemonkey/meta-spacing': ['error', 3],
40
- 'greasemonkey/no-duplicate-keys': 'error',
41
- 'greasemonkey/no-missing-grants': 'error',
42
- 'greasemonkey/no-unused-grants': 'error',
43
- 'greasemonkey/no-unused-resources': 'error',
44
- 'greasemonkey/prefer-match': 'error',
45
- 'greasemonkey/require-matching-localized-fields': 'error',
46
- 'greasemonkey/require-meta-newline': 'error',
47
- 'greasemonkey/require-required-fields': 'error',
48
- 'greasemonkey/require-space-before-meta-key': 'error',
49
- 'greasemonkey/require-user-js-filename': 'error',
50
- 'greasemonkey/valid-field-values': ['error', { versionType: 'semver' }],
51
- 'greasemonkey/valid-grants': ['error', { allowedGrants: [] }]
52
- }
53
- }
54
- ]
55
- ```
56
-
57
- ...or use a bundled config:
58
-
59
- ```js
60
- ...
61
- import greasemonkey from 'eslint-plugin-greasemonkey'
62
-
63
- export default [
64
- // other configs
65
- {
66
- files: ['**/*.user.js'],
67
- plugins: { greasemonkey }
36
+ files: ['**/*.user.js'], plugins: { greasemonkey }
68
37
  rules: {
69
- ...greasemonkey.configs.recommended.rules, // or .strict.rules
38
+ ...greasemonkey.configs.recommended.rules, // or .strict.rules to enable all
70
39
  'greasemonkey/no-unused-resources': 'off', // selectively disable rule
71
40
  'greasemonkey/meta-spacing': ['error', 2] // selectively tweak rule
72
41
  }
@@ -82,24 +51,40 @@ export default [
82
51
 
83
52
  | ID | Description | Auto-fixable | Recommended |
84
53
  | --- | --- | :-: | :-: |
85
- | [`meta-spacing`](#meta-spacing-auto-fixable) | Aligns metadata values to the column after the longest key | ✅ | ✅ |
86
- | [`no-duplicate-keys`](#no-duplicate-keys) | Disallows duplicate metadata keys | ❌ | ✅ |
87
- | [`no-missing-grants`](#no-missing-grants) | Flags API calls w/o a matching `@grant` | ❌ | ✅ |
88
- | [`no-unused-grants`](#no-unused-grants) | Flags `@grant` entries whose APIs are never used | ❌ | ✅ |
89
- | [`no-unused-resources`](#no-unused-resources) | Flags `@resource` entries that are never referenced | ❌ | ✅ |
90
- | [`prefer-match`](#prefer-match) | Prefers `@match` over `@include` | ❌ | ✅ |
91
- | [`require-homepage-pair`](#require-homepage-pair-auto-fixable) | Requires `@homepage` and `@homepageURL` to be used together | ✅ | ❌ |
92
- | [`require-matching-localized-fields`](#require-matching-localized-fields) | Requires matching localized `@name:xx` / `@description:xx` pairs | ❌ | ✅ |
93
- | [`require-meta-newline`](#require-meta-newline-auto-fixable) | Requires a newline between the metadata and code | ✅ | ✅ |
94
- | [`require-required-fields`](#require-required-fields) | Requires essential metadata fields | ❌ | ✅ |
95
- | [`require-space-before-meta-key`](#require-space-before-meta-key-auto-fixable) | Requires exactly one space between `//` and metadata keys | ✅ | ✅ |
96
- | [`require-update-download-pair`](#require-update-download-pair) | Requires `@updateURL` and `@downloadURL` to be used together | ❌ | ❌ |
97
- | [`require-user-js-filename`](#require-user-js-filename) | Requires userscript filenames end in `.user.js` | ❌ | ✅ |
98
- | [`valid-field-values`](#valid-field-values) | Validates `@version` and URL fields | ❌ | ✅ |
99
- | [`valid-grants`](#valid-grants) | Disallows invalid `@grant` values | ❌ | ✅ |
54
+ | [`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"> |
55
+ | [`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"> |
56
+ | [`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"> |
57
+ | [`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"> |
58
+ | [`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"> |
59
+ | [`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"> |
60
+ | [`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"> |
61
+ | [`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"> |
62
+ | [`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"> |
63
+ | [`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"> |
64
+ | [`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"> |
65
+ | [`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"> |
66
+ | [`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"> |
67
+ | [`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"> |
68
+ | [`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"> |
69
+ | [`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"> |
70
+ | [`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"> |
71
+
100
72
  ---
101
73
 
102
- ### `meta-spacing` (auto-fixable)
74
+ <h3 id="meta-spacing">
75
+ <code>meta-spacing</code>
76
+ <a title="Included in recommended config" href="#usage">
77
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
78
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
79
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
80
+ <a title="Doesn't catch bugs" href="#meta-spacing">
81
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
82
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
83
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
84
+ <a title="Copy rule URL" target="_blank"
85
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23meta-spacing">
86
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
87
+ </h3>
103
88
 
104
89
  > Aligns metadata values to the column after the longest key.
105
90
 
@@ -107,30 +92,41 @@ export default [
107
92
 
108
93
  - `number` (default `3`) – minimum spaces after the longest key
109
94
 
110
- #### Incorrect code
95
+ #### <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
111
96
 
112
- ```js
113
- // ==UserScript==
114
- // @name My Script
115
- // @namespace example.com
116
- // @version 1.0.0
117
- // ==/UserScript==
97
+ ```diff
98
+ /* eslint greasemonkey/meta-spacing: ['error', 1] */
99
+
100
+ // ==UserScript==
101
+ ! // @name My Script
102
+ // @namespace example.com
103
+ ! // @version 1.0.0
104
+ // ==/UserScript==
118
105
  ```
119
106
 
120
- #### Correct code
107
+ #### <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
121
108
 
122
- ```js
123
- // ==UserScript==
124
- // @name My Script
125
- // @namespace example.com
126
- // @version 1.0.0
127
- // ==/UserScript==
109
+ ```diff
110
+ /* eslint greasemonkey/meta-spacing: ['error', 1] */
111
+
112
+ // ==UserScript==
113
+ - // @name My Script
114
+ + // @name My Script
115
+ // @namespace example.com
116
+ - // @version 1.0.0
117
+ + // @version 1.0.0
118
+ // ==/UserScript==
128
119
  ```
129
120
 
130
121
  #### When not to use it
131
122
 
132
123
  If you don't care about visual alignment in metadata blocks.
133
124
 
125
+ #### See also
126
+
127
+ - [`require-blank-line-after-meta-block`](#require-blank-line-after-meta-block)
128
+ - [`require-space-before-meta-key`](#require-space-before-meta-key)
129
+
134
130
  <div align="center">
135
131
 
136
132
  [Back to index ↑][epg-rules]
@@ -139,36 +135,52 @@ If you don't care about visual alignment in metadata blocks.
139
135
 
140
136
  ---
141
137
 
142
- ### `no-duplicate-keys`
138
+ <h3 id="no-duplicate-keys">
139
+ <code>no-duplicate-keys</code>
140
+ <a title="Included in recommended config" href="#usage">
141
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
142
+ <a title="Copy rule URL" target="_blank"
143
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-duplicate-keys">
144
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
145
+ </h3>
143
146
 
144
147
  > Disallows duplicate metadata keys. Multi-value keys are exempt (`@compatible`, `@connect`, `@description`, `@exclude`, `@exclude-match`, `@grant`, `@homepageURL`, `@include`, `@license`, `@match`, `@require`, `@resource`, `@supportURL`).
145
148
 
146
- #### Incorrect code
149
+ #### <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
147
150
 
148
- ```js
149
- // ==UserScript==
150
- // @name Foo
151
- // @name Bar
152
- // @version 1.0.0
153
- // @version 2.0.0
154
- // ==/UserScript==
151
+ ```diff
152
+ // ==UserScript==
153
+ ! // @name Foo
154
+ ! // @name Bar
155
+ ! // @version 1.0.0
156
+ ! // @version 2.0.0
157
+ // ==/UserScript==
155
158
  ```
156
159
 
157
- #### Correct code
160
+ #### <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
158
161
 
159
- ```js
160
- // ==UserScript==
161
- // @name My Script
162
- // @version 1.0.0
163
- // @match https://a.example.com/*
164
- // @match https://b.example.com/*
165
- // ==/UserScript==
162
+ ```diff
163
+ // ==UserScript==
164
+ - // @name Foo
165
+ - // @name Bar
166
+ - // @version 1.0.0
167
+ - // @version 2.0.0
168
+ + // @name My Script
169
+ + // @version 1.0.0
170
+ + // @match https://a.example.com/*
171
+ + // @match https://b.example.com/*
172
+ // ==/UserScript==
166
173
  ```
167
174
 
168
175
  #### When not to use it
169
176
 
170
177
  If you intentionally repeat single-value keys.
171
178
 
179
+ #### See also
180
+
181
+ - [`require-matching-localized-fields`](#require-matching-localized-fields)
182
+ - [`require-required-fields`](#require-required-fields)
183
+
172
184
  <div align="center">
173
185
 
174
186
  [Back to index ↑][epg-rules]
@@ -177,35 +189,109 @@ If you intentionally repeat single-value keys.
177
189
 
178
190
  ---
179
191
 
180
- ### `no-missing-grants`
192
+ <h3 id="no-invalid-headers">
193
+ <code>no-invalid-headers</code>
194
+ <a title="Included in recommended config" href="#usage">
195
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
196
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
197
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
198
+ <a title="Copy rule URL" target="_blank"
199
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-invalid-headers">
200
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
201
+ </h3>
181
202
 
182
- > Flags API calls (e.g. `GM_setValue`, `GM.setValue`, `CAT.agent.dom`) used w/o a matching `@grant` declaration.
203
+ > Disallows invalid or unsupported metadata headers.
204
+
205
+ #### Options
183
206
 
184
- #### Incorrect code
207
+ - `target` (default `'all'`) – manager(s) whose headers to validate against (`'all'`, `'tampermonkey'`, `'violentmonkey'`, `'greasemonkey'`, `'scriptish'`) as a single string or array
208
+ - `allowedHeaders` (default `[]`) – additional headers to allow (strings or regexes) as a single value or array
185
209
 
186
- ```js
187
- // ==UserScript==
188
- // @name My Script
189
- // ==/UserScript==
210
+ #### <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
190
211
 
191
- GM_setValue('key', 'value')
212
+ ```diff
213
+ /* eslint greasemonkey/no-invalid-headers: ['error', { target: 'tampermonkey', allowedHeaders: /^\w*url$/i }] */
214
+
215
+ // ==UserScript==
216
+ // @name My Script
217
+ ! // @runin normal-tabs
218
+ ! // @inject-into page
219
+ // @customURL https://example.com
220
+ // ==/UserScript==
192
221
  ```
193
222
 
194
- #### Correct code
223
+ #### <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
195
224
 
196
- ```js
197
- // ==UserScript==
198
- // @name My Script
199
- // @grant GM_setValue
200
- // ==/UserScript==
225
+ ```diff
226
+ /* eslint greasemonkey/no-invalid-headers: ['error', { target: 'tampermonkey', allowedHeaders: /^\w*url$/i }] */
227
+
228
+ // ==UserScript==
229
+ // @name My Script
230
+ - // @runin normal-tabs
231
+ + // @run-in normal-tabs
232
+ - // @inject-into page
233
+ // @customURL https://example.com
234
+ // ==/UserScript==
235
+ ```
236
+
237
+ #### When not to use it
201
238
 
202
- GM_setValue('key', 'value')
239
+ If your script relies entirely on custom headers that aren't in the built-in list and you'd rather not maintain an `allowedHeaders` list.
240
+
241
+ #### See also
242
+
243
+ - [`valid-field-values`](#valid-field-values)
244
+ - [`valid-grants`](#valid-grants)
245
+
246
+ <div align="center">
247
+
248
+ [Back to index ↑][epg-rules]
249
+
250
+ </div>
251
+
252
+ ---
253
+
254
+ <h3 id="no-missing-grants">
255
+ <code>no-missing-grants</code>
256
+ <a title="Included in recommended config" href="#usage">
257
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
258
+ <a title="Copy rule URL" target="_blank"
259
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-missing-grants">
260
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
261
+ </h3>
262
+
263
+ > Flags API calls (e.g. `GM_setValue`, `GM.setValue`, `CAT.agent.dom`) used w/o a matching `@grant` declaration.
264
+
265
+ #### <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
266
+
267
+ ```diff
268
+ // ==UserScript==
269
+ // @name My Script
270
+ // ==/UserScript==
271
+
272
+ ! GM_setValue('key', 'value')
273
+ ```
274
+
275
+ #### <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
276
+
277
+ ```diff
278
+ // ==UserScript==
279
+ // @name My Script
280
+ + // @grant GM_setValue
281
+ // ==/UserScript==
282
+
283
+ GM_setValue('key', 'value')
203
284
  ```
204
285
 
205
286
  #### When not to use it
206
287
 
207
288
  If you use APIs through aliases or wrappers that obscure the original call site.
208
289
 
290
+ #### See also
291
+
292
+ - [`no-unused-grants`](#no-unused-grants)
293
+ - [`valid-grants`](#valid-grants)
294
+
209
295
  <div align="center">
210
296
 
211
297
  [Back to index ↑][epg-rules]
@@ -214,34 +300,92 @@ If you use APIs through aliases or wrappers that obscure the original call site.
214
300
 
215
301
  ---
216
302
 
217
- ### `no-unused-grants`
303
+ <h3 id="no-missing-resources">
304
+ <code>no-missing-resources</code>
305
+ <a title="Included in recommended config" href="#usage">
306
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
307
+ <a title="Copy rule URL" target="_blank"
308
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-missing-resources">
309
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
310
+ </h3>
218
311
 
219
- > Flags `@grant` entries whose APIs are never used in the script.
312
+ > Flags `@resource` references via `GM_getResourceText()` or `GM_getResourceURL()` where no matching `@resource` is declared.
220
313
 
221
- #### Incorrect code
314
+ #### <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
222
315
 
223
- ```js
224
- // ==UserScript==
225
- // @grant GM_setValue
226
- // ==/UserScript==
316
+ ```diff
317
+ // ==UserScript==
318
+ // @name My Script
319
+ // ==/UserScript==
320
+
321
+ ! const css = GM_getResourceText('myCSS')
322
+ ```
227
323
 
228
- console.log('no GM_setValue call')
324
+ #### <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
325
+
326
+ ```diff
327
+ // ==UserScript==
328
+ // @name My Script
329
+ + // @resource myCSS https://example.com/style.css
330
+ // ==/UserScript==
331
+
332
+ const css = GM_getResourceText('myCSS')
229
333
  ```
230
334
 
231
- #### Correct code
335
+ #### When not to use it
336
+
337
+ If you reference resources through an alias or computed pattern that obscures the call site.
232
338
 
233
- ```js
234
- // ==UserScript==
235
- // @grant GM_setValue
236
- // ==/UserScript==
339
+ #### See also
340
+
341
+ - [`no-unused-resources`](#no-unused-resources)
342
+
343
+ <div align="center">
344
+
345
+ [Back to index ↑][epg-rules]
346
+
347
+ </div>
348
+
349
+ ---
350
+
351
+ <h3 id="no-unused-grants">
352
+ <code>no-unused-grants</code>
353
+ <a title="Included in recommended config" href="#usage">
354
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
355
+ <a title="Copy rule URL" target="_blank"
356
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-unused-grants">
357
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
358
+ </h3>
237
359
 
238
- GM_setValue('key', 'value')
360
+ > Flags `@grant` entries whose APIs are never used in the script.
361
+
362
+ #### <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
363
+
364
+ ```diff
365
+ // ==UserScript==
366
+ ! // @grant GM_setValue
367
+ // ==/UserScript==
368
+ ```
369
+
370
+ #### <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
371
+
372
+ ```diff
373
+ // ==UserScript==
374
+ // @grant GM_setValue
375
+ // ==/UserScript==
376
+
377
+ + GM_setValue('key', 'value')
239
378
  ```
240
379
 
241
380
  #### When not to use it
242
381
 
243
382
  If you access the granted API through an alias or computed property rather than calling it directly.
244
383
 
384
+ #### See also
385
+
386
+ - [`no-missing-grants`](#no-missing-grants)
387
+ - [`valid-grants`](#valid-grants)
388
+
245
389
  <div align="center">
246
390
 
247
391
  [Back to index ↑][epg-rules]
@@ -250,32 +394,43 @@ If you access the granted API through an alias or computed property rather than
250
394
 
251
395
  ---
252
396
 
253
- ### `no-unused-resources`
397
+ <h3 id="no-unused-resources">
398
+ <code>no-unused-resources</code>
399
+ <a title="Included in recommended config" href="#usage">
400
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
401
+ <a title="Copy rule URL" target="_blank"
402
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23no-unused-resources">
403
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
404
+ </h3>
254
405
 
255
406
  > Flags `@resource` entries that are never referenced via `GM_getResourceText()` or `GM_getResourceURL()`.
256
407
 
257
- #### Incorrect code
408
+ #### <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
258
409
 
259
- ```js
260
- // ==UserScript==
261
- // @resource myCSS https://example.com/style.css
262
- // ==/UserScript==
410
+ ```diff
411
+ // ==UserScript==
412
+ ! // @resource myCSS https://example.com/style.css
413
+ // ==/UserScript==
263
414
  ```
264
415
 
265
- #### Correct code
416
+ #### <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
266
417
 
267
- ```js
268
- // ==UserScript==
269
- // @resource myCSS https://example.com/style.css
270
- // ==/UserScript==
271
-
272
- GM_getResourceText('myCSS')
418
+ ```diff
419
+ // ==UserScript==
420
+ // @resource myCSS https://example.com/style.css
421
+ // ==/UserScript==
422
+
423
+ + const css = GM_getResourceText('myCSS')
273
424
  ```
274
425
 
275
426
  #### When not to use it
276
427
 
277
428
  If you pass the resource name through a variable or alias rather than using it literally.
278
429
 
430
+ #### See also
431
+
432
+ - [`no-missing-resources`](#no-missing-resources)
433
+
279
434
  <div align="center">
280
435
 
281
436
  [Back to index ↑][epg-rules]
@@ -284,24 +439,32 @@ If you pass the resource name through a variable or alias rather than using it l
284
439
 
285
440
  ---
286
441
 
287
- ### `prefer-match`
442
+ <h3 id="prefer-match">
443
+ <code>prefer-match</code>
444
+ <a title="Included in recommended config" href="#usage">
445
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
446
+ <a title="Copy rule URL" target="_blank"
447
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23prefer-match">
448
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
449
+ </h3>
288
450
 
289
451
  > Prefers `@match` over `@include` (deprecated in Chrome MV3).
290
452
 
291
- #### Incorrect code
453
+ #### <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
292
454
 
293
- ```js
294
- // ==UserScript==
295
- // @include https://example.com/*
296
- // ==/UserScript==
455
+ ```diff
456
+ // ==UserScript==
457
+ ! // @include https://example.com/*
458
+ // ==/UserScript==
297
459
  ```
298
460
 
299
- #### Correct code
461
+ #### <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
300
462
 
301
- ```js
302
- // ==UserScript==
303
- // @match https://example.com/*
304
- // ==/UserScript==
463
+ ```diff
464
+ // ==UserScript==
465
+ - // @include https://example.com/*
466
+ + // @match https://example.com/*
467
+ // ==/UserScript==
305
468
  ```
306
469
 
307
470
  #### When not to use it
@@ -316,30 +479,47 @@ If you use `@include` in non-MV3 environments, or rely on regex syntax that `@ma
316
479
 
317
480
  ---
318
481
 
319
- ### `require-homepage-pair` (auto-fixable)
482
+ <h3 id="require-blank-line-after-meta-block">
483
+ <code>require-blank-line-after-meta-block</code>
484
+ <a title="Included in recommended config" href="#usage">
485
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
486
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
487
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
488
+ <a title="Doesn't catch bugs" href="#require-blank-line-after-meta-block">
489
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
490
+ <a title="Copy rule URL" target="_blank"
491
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-blank-line-after-meta-block">
492
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
493
+ </h3>
320
494
 
321
- > Requires `@homepage` and `@homepageURL` to be used together.
495
+ > Requires a blank line between the closing `// ==/UserScript==` and the first line of code.
322
496
 
323
- #### Incorrect code
497
+ #### <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
324
498
 
325
- ```js
326
- // ==UserScript==
327
- // @homepage https://example.com
328
- // ==/UserScript==
499
+ ```diff
500
+ // ==UserScript==
501
+ // @name My Script
502
+ // ==/UserScript==
503
+ ! console.log('hi')
329
504
  ```
330
505
 
331
- #### Correct code
506
+ #### <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
332
507
 
333
- ```js
334
- // ==UserScript==
335
- // @homepage https://example.com
336
- // @homepageURL https://example.com
337
- // ==/UserScript==
508
+ ```diff
509
+ // ==UserScript==
510
+ // @name My Script
511
+ // ==/UserScript==
512
+ +
513
+ console.log('hi')
338
514
  ```
339
515
 
340
516
  #### When not to use it
341
517
 
342
- If your target manager does not fall back to `@namespace` when a homepage key is missing (which usually produces a broken URL).
518
+ If you don't care about visual separation between metadata and code.
519
+
520
+ #### See also
521
+
522
+ - [`meta-spacing`](#meta-spacing)
343
523
 
344
524
  <div align="center">
345
525
 
@@ -349,38 +529,43 @@ If your target manager does not fall back to `@namespace` when a homepage key is
349
529
 
350
530
  ---
351
531
 
352
- ### `require-matching-localized-fields`
353
-
354
- > Requires that every `@name:xx` has a matching `@description:xx` (and vice versa).
355
-
356
- #### Options
532
+ <h3 id="require-homepage-pair">
533
+ <code>require-homepage-pair</code>
534
+ <a title="Only included in strict config" href="#usage">
535
+ <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
536
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
537
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
538
+ <a title="Copy rule URL" target="_blank"
539
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-homepage-pair">
540
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
541
+ </h3>
357
542
 
358
- - `ignoreLanguages` (default `[]`) – language codes to skip, e.g. `['fr', 'de']`
543
+ > Requires `@homepage` and `@homepageURL` to be used together.
359
544
 
360
- #### Incorrect code
545
+ #### <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
361
546
 
362
- ```js
363
- // ==UserScript==
364
- // @name:en My Script
365
- // @description:en Does something
366
- // @name:fr Mon Script
367
- // ==/UserScript==
547
+ ```diff
548
+ // ==UserScript==
549
+ ! // @homepage https://example.com
550
+ // ==/UserScript==
368
551
  ```
369
552
 
370
- #### Correct code
553
+ #### <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
371
554
 
372
- ```js
373
- // ==UserScript==
374
- // @name:en My Script
375
- // @description:en Does something
376
- // @name:fr Mon Script
377
- // @description:fr Fait quelque chose
378
- // ==/UserScript==
555
+ ```diff
556
+ // ==UserScript==
557
+ // @homepage https://example.com
558
+ + // @homepageURL https://example.com
559
+ // ==/UserScript==
379
560
  ```
380
561
 
381
562
  #### When not to use it
382
563
 
383
- If you intentionally provide localized names without descriptions (or vice versa).
564
+ If your target manager does not fall back to `@namespace` when a homepage key is missing (which usually produces a broken URL).
565
+
566
+ #### See also
567
+
568
+ - [`require-update-download-pair`](#require-update-download-pair)
384
569
 
385
570
  <div align="center">
386
571
 
@@ -390,32 +575,58 @@ If you intentionally provide localized names without descriptions (or vice versa
390
575
 
391
576
  ---
392
577
 
393
- ### `require-meta-newline` (auto-fixable)
578
+ <h3 id="require-matching-localized-fields">
579
+ <code>require-matching-localized-fields</code>
580
+ <a title="Included in recommended config" href="#usage">
581
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
582
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
583
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
584
+ <a title="Copy rule URL" target="_blank"
585
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-matching-localized-fields">
586
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
587
+ </h3>
394
588
 
395
- > Requires a newline between the closing `// ==/UserScript==` comment and the first line of code.
589
+ > Requires that every `@name:xx` has a matching `@description:xx` (and vice versa).
396
590
 
397
- #### Incorrect code
591
+ #### Options
398
592
 
399
- ```js
400
- // ==UserScript==
401
- // @name My Script
402
- // ==/UserScript==
403
- console.log('hi')
404
- ```
593
+ - `ignoreLanguages` (default `[]`) – language codes to skip, e.g. `['fr', 'de']`
405
594
 
406
- #### Correct code
595
+ #### <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
407
596
 
408
- ```js
409
- // ==UserScript==
410
- // @name My Script
411
- // ==/UserScript==
597
+ ```diff
598
+ /* eslint greasemonkey/require-matching-localized-fields: ['error', { ignoreLanguages: ['fr'] }] */
599
+
600
+ // ==UserScript==
601
+ // @name:en My Script
602
+ ! // @name:de Mein Skript
603
+ // @name:fr Mon Script
604
+ // @description:en Does something
605
+ // ==/UserScript==
606
+ ```
607
+
608
+ #### <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
412
609
 
413
- console.log('hi')
610
+ ```diff
611
+ /* eslint greasemonkey/require-matching-localized-fields: ['error', { ignoreLanguages: ['fr'] }] */
612
+
613
+ // ==UserScript==
614
+ // @name:en My Script
615
+ // @name:de Mein Skript
616
+ // @name:fr Mon Script
617
+ // @description:en Does something
618
+ + // @description:de Tut etwas
619
+ // ==/UserScript==
414
620
  ```
415
621
 
416
622
  #### When not to use it
417
623
 
418
- If you don't care about visual separation between metadata and code.
624
+ If you intentionally provide localized names without descriptions (or vice versa).
625
+
626
+ #### See also
627
+
628
+ - [`no-duplicate-keys`](#no-duplicate-keys)
629
+ - [`require-required-fields`](#require-required-fields)
419
630
 
420
631
  <div align="center">
421
632
 
@@ -425,7 +636,16 @@ If you don't care about visual separation between metadata and code.
425
636
 
426
637
  ---
427
638
 
428
- ### `require-required-fields`
639
+ <h3 id="require-required-fields">
640
+ <code>require-required-fields</code>
641
+ <a title="Included in recommended config" href="#usage">
642
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
643
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
644
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
645
+ <a title="Copy rule URL" target="_blank"
646
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-required-fields">
647
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
648
+ </h3>
429
649
 
430
650
  > Requires essential metadata fields (`@name`, `@version` by default) and at least one `@match` or `@include`.
431
651
 
@@ -433,28 +653,37 @@ If you don't care about visual separation between metadata and code.
433
653
 
434
654
  - `fields` (default `['name', 'version']`) – override the required field list
435
655
 
436
- #### Incorrect code
656
+ #### <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
437
657
 
438
- ```js
439
- // ==UserScript==
440
- // @name My Script
441
- // ==/UserScript==
658
+ ```diff
659
+ /* eslint greasemonkey/require-required-fields: ['error', { fields: ['name', 'version', 'match'] }] */
660
+
661
+ // ==UserScript==
662
+ // @name My Script
663
+ // ==/UserScript==
442
664
  ```
443
665
 
444
- #### Correct code
666
+ #### <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
445
667
 
446
- ```js
447
- // ==UserScript==
448
- // @name My Script
449
- // @version 1.0.0
450
- // @match https://example.com/*
451
- // ==/UserScript==
668
+ ```diff
669
+ /* eslint greasemonkey/require-required-fields: ['error', { fields: ['name', 'version', 'match'] }] */
670
+
671
+ // ==UserScript==
672
+ // @name My Script
673
+ + // @version 1.0.0
674
+ + // @match https://example.com/*
675
+ // ==/UserScript==
452
676
  ```
453
677
 
454
678
  #### When not to use it
455
679
 
456
680
  If you use a subset of metadata fields that doesn't match the convention.
457
681
 
682
+ #### See also
683
+
684
+ - [`no-duplicate-keys`](#no-duplicate-keys)
685
+ - [`require-matching-localized-fields`](#require-matching-localized-fields)
686
+
458
687
  <div align="center">
459
688
 
460
689
  [Back to index ↑][epg-rules]
@@ -463,32 +692,49 @@ If you use a subset of metadata fields that doesn't match the convention.
463
692
 
464
693
  ---
465
694
 
466
- ### `require-space-before-meta-key` (auto-fixable)
695
+ <h3 id="require-space-before-meta-key">
696
+ <code>require-space-before-meta-key</code>
697
+ <a title="Included in recommended config" href="#usage">
698
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
699
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
700
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-e8357a?style=flat-square" align="middle"></a>
701
+ <a title="Doesn't catch bugs" href="#require-space-before-meta-key">
702
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
703
+ <a title="Copy rule URL" target="_blank"
704
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-space-before-meta-key">
705
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
706
+ </h3>
467
707
 
468
708
  > Requires exactly one space between `//` and metadata keys.
469
709
 
470
- #### Incorrect code
710
+ #### <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
471
711
 
472
- ```js
473
- // ==UserScript==
474
- //@name My Script
475
- // @version 1.0.0
476
- // ==/UserScript==
712
+ ```diff
713
+ // ==UserScript==
714
+ ! //@name My Script
715
+ // @version 1.0.0
716
+ // ==/UserScript==
477
717
  ```
478
718
 
479
- #### Correct code
719
+ #### <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
480
720
 
481
- ```js
482
- // ==UserScript==
483
- // @name My Script
484
- // @version 1.0.0
485
- // ==/UserScript==
721
+ ```diff
722
+ // ==UserScript==
723
+ - //@name My Script
724
+ + // @name My Script
725
+ // @version 1.0.0
726
+ // ==/UserScript==
486
727
  ```
487
728
 
488
729
  #### When not to use it
489
730
 
490
731
  If you intentionally use a different prefix style.
491
732
 
733
+ #### See also
734
+
735
+ - [`meta-spacing`](#meta-spacing)
736
+ - [`require-blank-line-after-meta-block`](#require-blank-line-after-meta-block)
737
+
492
738
  <div align="center">
493
739
 
494
740
  [Back to index ↑][epg-rules]
@@ -497,31 +743,43 @@ If you intentionally use a different prefix style.
497
743
 
498
744
  ---
499
745
 
500
- ### `require-update-download-pair`
746
+ <h3 id="require-update-download-pair">
747
+ <code>require-update-download-pair</code>
748
+ <a title="Only included in strict config" href="#usage">
749
+ <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
750
+ <a title="Copy rule URL" target="_blank"
751
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-update-download-pair">
752
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
753
+ </h3>
501
754
 
502
755
  > Requires `@updateURL` and `@downloadURL` to be used together.
503
756
 
504
- #### Incorrect code
757
+ #### <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
758
 
506
- ```js
507
- // ==UserScript==
508
- // @downloadURL https://example.com/script.user.js
509
- // ==/UserScript==
759
+ ```diff
760
+ // ==UserScript==
761
+ ! // @downloadURL https://example.com/script.user.js
762
+ // ==/UserScript==
510
763
  ```
511
764
 
512
- #### Correct code
765
+ #### <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
513
766
 
514
- ```js
515
- // ==UserScript==
516
- // @downloadURL https://example.com/script.user.js
517
- // @updateURL https://example.com/script.meta.js
518
- // ==/UserScript==
767
+ ```diff
768
+ // ==UserScript==
769
+ // @downloadURL https://example.com/script.user.js
770
+ + // @updateURL https://example.com/script.meta.js
771
+ // ==/UserScript==
519
772
  ```
520
773
 
521
774
  #### When not to use it
522
775
 
523
776
  If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the full script on every update check).
524
777
 
778
+ #### See also
779
+
780
+ - [`@updateURL`](https://www.tampermonkey.net/documentation.php?q=update_url#meta:updateURL)
781
+ - [`require-homepage-pair`](#require-homepage-pair)
782
+
525
783
  <div align="center">
526
784
 
527
785
  [Back to index ↑][epg-rules]
@@ -530,7 +788,14 @@ If you don't target Tampermonkey (where `@updateURL` avoids re-downloading the f
530
788
 
531
789
  ---
532
790
 
533
- ### `require-user-js-filename`
791
+ <h3 id="require-user-js-filename">
792
+ <code>require-user-js-filename</code>
793
+ <a title="Included in recommended config" href="#usage">
794
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
795
+ <a title="Copy rule URL" target="_blank"
796
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23require-user-js-filename">
797
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
798
+ </h3>
534
799
 
535
800
  > Requires that files containing a userscript metadata block end in `.user.js`.
536
801
 
@@ -546,7 +811,16 @@ If you intentionally name your userscripts something other than `*.user.js`.
546
811
 
547
812
  ---
548
813
 
549
- ### `valid-field-values`
814
+ <h3 id="valid-field-values">
815
+ <code>valid-field-values</code>
816
+ <a title="Included in recommended config" href="#usage">
817
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
818
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
819
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
820
+ <a title="Copy rule URL" target="_blank"
821
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23valid-field-values">
822
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
823
+ </h3>
550
824
 
551
825
  > Validates `@version` (semver or date format) and URL fields (`@homepage`, `@icon`, `@icon64`, `@require`, `@resource`, `@source`, `@website`, any key ending in `URL` case-insensitively).
552
826
 
@@ -554,28 +828,39 @@ If you intentionally name your userscripts something other than `*.user.js`.
554
828
 
555
829
  - `versionType` (default `'semver'`) – version format to enforce (`'semver'`, `'date'`)
556
830
 
557
- #### Incorrect code
831
+ #### <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
558
832
 
559
- ```js
560
- // ==UserScript==
561
- // @version abc
562
- // @homepage not-a-url
563
- // ==/UserScript==
833
+ ```diff
834
+ /* eslint greasemonkey/valid-field-values: ['error', { versionType: 'semver' }] */
835
+
836
+ // ==UserScript==
837
+ ! // @version abc
838
+ ! // @homepage not-a-url
839
+ // ==/UserScript==
564
840
  ```
565
841
 
566
- #### Correct code
842
+ #### <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
567
843
 
568
- ```js
569
- // ==UserScript==
570
- // @version 1.0.0
571
- // @homepage https://example.com
572
- // ==/UserScript==
844
+ ```diff
845
+ /* eslint greasemonkey/valid-field-values: ['error', { versionType: 'semver' }] */
846
+
847
+ // ==UserScript==
848
+ - // @version abc
849
+ + // @version 1.0.0
850
+ - // @homepage not-a-url
851
+ + // @homepage https://example.com
852
+ // ==/UserScript==
573
853
  ```
574
854
 
575
855
  #### When not to use it
576
856
 
577
857
  If you use a custom versioning scheme or URLs that aren't standard.
578
858
 
859
+ #### See also
860
+
861
+ - [`no-missing-resources`](#no-missing-resources)
862
+ - [`valid-grants`](#valid-grants)
863
+
579
864
  <div align="center">
580
865
 
581
866
  [Back to index ↑][epg-rules]
@@ -584,38 +869,57 @@ If you use a custom versioning scheme or URLs that aren't standard.
584
869
 
585
870
  ---
586
871
 
587
- ### `valid-grants`
872
+ <h3 id="valid-grants">
873
+ <code>valid-grants</code>
874
+ <a title="Included in recommended config" href="#usage">
875
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
876
+ <a title="Accepts array w/ options" target="_blank" href="https://eslint.org/docs/latest/extend/custom-rules#option-defaults">
877
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
878
+ <a title="Copy rule URL" target="_blank"
879
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-greasemonkey%2F%23valid-grants">
880
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
881
+ </h3>
588
882
 
589
- > Disallows invalid `@grant` values.
883
+ > Disallows invalid or unsupported `@grant` values.
590
884
 
591
885
  #### Options
592
886
 
887
+ - `target` (default `'all'`) – manager(s) whose grants to validate against (`'all'`, `'tampermonkey'`, `'violentmonkey'`, `'greasemonkey'`, `'scriptcat'`) as a single string or array
593
888
  - `allowedGrants` (default `[]`) – additional `@grant` values to allow beyond the built-in list (covering Tampermonkey, Violentmonkey and ScriptCat)
594
889
 
595
- #### Incorrect code
890
+ #### <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
891
 
597
- ```js
598
- // ==UserScript==
599
- // @grant GM_notificaiton
600
- // @grant gm_setvalue
601
- // @grant GM_xmlHttpRequest
602
- // ==/UserScript==
892
+ ```diff
893
+ /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
894
+
895
+ // ==UserScript==
896
+ ! // @grant GM_notificaiton
897
+ ! // @grant CAT.agent.dom
898
+ // ==/UserScript==
603
899
  ```
604
900
 
605
- #### Correct code
901
+ #### <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
606
902
 
607
- ```js
608
- // ==UserScript==
609
- // @grant GM_notification
610
- // @grant GM_setValue
611
- // @grant GM_xmlhttpRequest
612
- // ==/UserScript==
903
+ ```diff
904
+ /* eslint greasemonkey/valid-grants: ['error', { target: 'tampermonkey' }] */
905
+
906
+ // ==UserScript==
907
+ - // @grant GM_notificaiton
908
+ + // @grant GM_notification
909
+ - // @grant CAT.agent.dom
910
+ + // @grant GM_getTab
911
+ // ==/UserScript==
613
912
  ```
614
913
 
615
914
  #### When not to use it
616
915
 
617
916
  If you don't want `@grant` validation at all. For individual uncovered grants, prefer whitelisting via `allowedGrants` over disabling the rule.
618
917
 
918
+ #### See also
919
+
920
+ - [`no-missing-grants`](#no-missing-grants)
921
+ - [`no-unused-grants`](#no-unused-grants)
922
+
619
923
  <div align="center">
620
924
 
621
925
  [Back to index ↑][epg-rules]
@@ -624,22 +928,22 @@ If you don't want `@grant` validation at all. For individual uncovered grants, p
624
928
 
625
929
  ---
626
930
 
627
- ## Shield
931
+ ## Shield embed
628
932
 
629
933
  <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">
630
- <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
934
+ <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
631
935
 
632
936
  #### HTML
633
937
 
634
938
  ```html
635
939
  <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">
636
- <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
940
+ <img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>
637
941
  ```
638
942
 
639
943
  #### Markdown
640
944
 
641
945
  ```md
642
- [![Linted by eslint-plugin-greasemonkey](https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-4b32c3?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme)
946
+ [![Linted by eslint-plugin-greasemonkey](https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme)
643
947
  ```
644
948
 
645
949
  ---
@@ -650,7 +954,7 @@ If you don't want `@grant` validation at all. For individual uncovered grants, p
650
954
 
651
955
  <details>
652
956
 
653
- <summary>Copyright © 2026 <a href="https://codeberg.org/adamlui">Adam Lui</a> under the <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/src/branch/main/docs/LICENSE.md">MIT license</a>.</summary><br>
957
+ <summary>Copyright © 2026 <a href="https://codeberg.org/adamlui"><b>Adam Lui</b></a> under the <a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/src/branch/main/docs/LICENSE.md"><b>MIT license</b></a>.</summary><br>
654
958
 
655
959
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
656
960