eslint-plugin-chrome-extensions 2.5.0 → 2.7.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.
Files changed (36) hide show
  1. package/README.md +592 -124
  2. package/package.json +5 -7
  3. package/src/data/i18n.js +8 -0
  4. package/src/data/permissions.js +1 -8
  5. package/src/data/regex.js +2 -1
  6. package/src/index.js +0 -4
  7. package/src/rules/css-spacing.js +367 -0
  8. package/src/rules/manifest-key-order.js +0 -1
  9. package/src/rules/manifest-spacing.js +0 -1
  10. package/src/rules/no-duplicate-manifest-keys.js +0 -1
  11. package/src/rules/no-global-keyframes.js +84 -0
  12. package/src/rules/no-host-page-selectors.js +106 -0
  13. package/src/rules/no-invalid-locales.js +89 -0
  14. package/src/rules/no-invalid-permissions.js +3 -5
  15. package/src/rules/no-missing-default-locale.js +39 -14
  16. package/src/rules/no-missing-i18n-keys.js +3 -5
  17. package/src/rules/no-remote-urls.js +102 -0
  18. package/src/rules/no-scrollbar-styling.js +73 -0
  19. package/src/rules/no-sensitive-permissions.js +1 -1
  20. package/src/rules/no-unrestricted-host-permissions.js +31 -16
  21. package/src/rules/no-unused-i18n-keys.js +0 -1
  22. package/src/rules/no-unused-permissions.js +13 -4
  23. package/src/rules/require-license-file.js +0 -1
  24. package/src/rules/require-mv3.js +1 -1
  25. package/src/rules/require-short-name-when-useful.js +0 -1
  26. package/src/rules/valid-license-file.js +2 -4
  27. package/src/rules/valid-manifest-icons.js +31 -3
  28. package/src/rules/valid-mv3-schema.js +1 -1
  29. package/src/rules/valid-url-fields.js +42 -37
  30. package/src/rules/valid-version-field.js +1 -1
  31. package/src/utils/array.js +1 -0
  32. package/src/utils/extension.js +13 -0
  33. package/src/utils/i18n.js +3 -0
  34. package/src/utils/init.js +13 -7
  35. package/src/utils/license.js +3 -2
  36. package/src/data/deprecations.js +0 -10
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
  <img alt="[Latest Build]" src="https://img.shields.io/npm/v/eslint-plugin-chrome-extensions?logo=icinga&style=for-the-badge&label=Latest%20Build&color=32fcee"></a>
7
7
  <a href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
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
+ <a target="_blank" href="https://getnpmstats.com/?package=eslint-plugin-chrome-extensions&range=last-year&interval=monthly">
10
+ <img src="https://img.shields.io/npm/dm/eslint-plugin-chrome-extensions?style=for-the-badge&logo=npm&color=black"></a>
9
11
  <a target="_blank" href="https://eslint.org/">
10
12
  <img alt="[Requires ESLint >=9.6.0]" src="https://img.shields.io/badge/Requires-ESLint_%3E%3D9.6.0-4B32C3?style=for-the-badge&logo=eslint"></a>
11
13
  <br><br>
@@ -74,6 +76,84 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
74
76
  Supported rules
75
77
  </h2>
76
78
 
79
+ <h3 id="css-spacing">
80
+ <code>css-spacing</code>
81
+ <a title="Introduced in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">
82
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
83
+ <a title="Only works in 'css/css' config block" href="#usage">
84
+ <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
85
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
86
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
87
+ <a title="Doesn't prevent bugs" href="#css-spacing">
88
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
89
+ <a title="Accepts array w/ options" href="#usage">
90
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
91
+ <a title="Copy rule URL" target="_blank"
92
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23css-spacing">
93
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
94
+ </h3>
95
+
96
+ <details>
97
+
98
+ <summary>Enforces consistent indentation and spacing in CSS.</summary>
99
+
100
+ <h4 id="css-spacing-options">Options</h4>
101
+
102
+ - `spaces` (default `2`) – number of spaces per indent level <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
103
+ - `checkBraces` (default `true`) – enforce 1 space after `{` and before `}` in single-line rules <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
104
+ - `checkBrackets` (default `true`) – enforce 0 spaces after `[` and before `]` in attribute selectors <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
105
+ - `checkColons` (default `true`) – enforce 0 spaces before and 1 space after `:` in declarations, and 1 space between value tokens <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
106
+ - `checkCombinators` (default `true`) – enforce 1 space on each side of `>`, `+`, `~` in selectors <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
107
+ - `checkCommas` (default `true`) – enforce 0 spaces before and 1 space after `,` in selector lists <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
108
+ - `checkParentheses` (default `true`) – enforce 0 spaces after `(` and before `)` in functions and pseudo-classes <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
109
+ - `checkSemicolons` (default `true`) – enforce 1 space after `;` in single-line declaration blocks <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
110
+
111
+ #### <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
112
+
113
+ ```diff
114
+ ! .panel { background : blue }
115
+ ! .panel+em { font-style: italic }
116
+ ! :not( .bar ) { color: red }
117
+ ```
118
+
119
+ #### <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
120
+
121
+ ```diff
122
+ - .panel { background : blue }
123
+ + .panel { background: blue }
124
+ - .panel+em { font-style: italic }
125
+ + .panel + em { font-style: italic }
126
+ - :not( .bar ) { color: red }
127
+ + :not(.bar) { color: red }
128
+ ```
129
+
130
+ #### When not to use it
131
+
132
+ If you don't care about visual consistency in your CSS, or you already use Stylelint to format CSS.
133
+
134
+ #### Introduced in
135
+
136
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">v2.7.0</a> (October 17, 2026)
137
+
138
+ #### See also
139
+
140
+ - [`manifest-spacing`](#manifest-spacing)
141
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
142
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix"><img height=14 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
143
+ <a title="Doesn't prevent bugs" href="#manifest-spacing"><img height=14 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
144
+ <a title="Accepts array w/ options" href="#manifest-spacing-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
145
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.mozilla.org&sz=64">&ensp;<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax">MDN — CSS syntax</a>
146
+
147
+ <div align="center">
148
+
149
+ [Back to index ↑][epce-rules]
150
+
151
+ </div>
152
+
153
+ ---
154
+
155
+ </details>
156
+
77
157
  <h3 id="manifest-key-order">
78
158
  <code>manifest-key-order</code>
79
159
  <a title="Only works in 'json/json' config block" href="#usage">
@@ -84,7 +164,7 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
84
164
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
85
165
  <a title="Accepts array w/ options" href="#usage">
86
166
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
87
- <a title="Copy rule URL" target="_blank"
167
+ <a title="Copy rule URL" target="_blank"
88
168
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23manifest-key-order">
89
169
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
90
170
  </h3>
@@ -95,13 +175,13 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
95
175
 
96
176
  <h4 id="manifest-key-order-options">Options</h4>
97
177
 
98
- - `order` (default `[]`) – manifest keys in custom order (e.g. `['name', 'manifest_version']`) to selectively override built-in order with
178
+ - `order` (default `[]`) – manifest keys in custom order (e.g. `['name', 'manifest_version']`) to selectively override built-in order with <a title="Introduced in v2.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.0.0"><img height=14 alt="[Since v2.0.0]" src="https://img.shields.io/badge/since-v2.0.0-8a9199?style=flat-square" align="middle"></a>
99
179
 
100
180
  #### <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
101
181
 
102
182
  ```diff
103
183
  /* eslint chrome-extensions/manifest-key-order: ['error', { order: ['name', 'manifest_version'] }] */
104
-
184
+
105
185
  {
106
186
  ! "manifest_version": 3,
107
187
  "name": "My Extension",
@@ -113,7 +193,7 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
113
193
 
114
194
  ```diff
115
195
  /* eslint chrome-extensions/manifest-key-order: ['error', { order: ['name', 'manifest_version'] }] */
116
-
196
+
117
197
  {
118
198
  - "manifest_version": 3,
119
199
  "name": "My Extension",
@@ -159,7 +239,7 @@ If you don't care about the order of manifest keys.
159
239
  <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
160
240
  <a title="Accepts array w/ options" href="#usage">
161
241
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
162
- <a title="Copy rule URL" target="_blank"
242
+ <a title="Copy rule URL" target="_blank"
163
243
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23manifest-spacing">
164
244
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
165
245
  </h3>
@@ -170,17 +250,17 @@ If you don't care about the order of manifest keys.
170
250
 
171
251
  <h4 id="manifest-spacing-options">Options</h4>
172
252
 
173
- - `spaces` (default `2`) – number of spaces per indent level
174
- - `checkColons` (default `true`) – enforce 0 spaces before and 1 space after `:` in key/value pairs
175
- - `checkCommas` (default `true`) – enforce 0 spaces before and 1 space after `,` in inline objects
176
- - `checkBraces` (default `true`) – enforce 1 space after `{` and before `}` in inline objects
177
- - `checkBrackets` (default `true`) – enforce 0 spaces after `[` and before `]` in inline arrays
253
+ - `spaces` (default `2`) – number of spaces per indent level <a title="Introduced in v2.2.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0"><img height=14 alt="[Since v2.2.0]" src="https://img.shields.io/badge/since-v2.2.0-8a9199?style=flat-square" align="middle"></a>
254
+ - `checkColons` (default `true`) – enforce 0 spaces before and 1 space after `:` in key/value pairs <a title="Introduced in v2.2.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0"><img height=14 alt="[Since v2.2.0]" src="https://img.shields.io/badge/since-v2.2.0-8a9199?style=flat-square" align="middle"></a>
255
+ - `checkCommas` (default `true`) – enforce 0 spaces before and 1 space after `,` in inline objects <a title="Introduced in v2.2.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0"><img height=14 alt="[Since v2.2.0]" src="https://img.shields.io/badge/since-v2.2.0-8a9199?style=flat-square" align="middle"></a>
256
+ - `checkBraces` (default `true`) – enforce 1 space after `{` and before `}` in inline objects <a title="Introduced in v2.2.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0"><img height=14 alt="[Since v2.2.0]" src="https://img.shields.io/badge/since-v2.2.0-8a9199?style=flat-square" align="middle"></a>
257
+ - `checkBrackets` (default `true`) – enforce 0 spaces after `[` and before `]` in inline arrays <a title="Introduced in v2.2.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0"><img height=14 alt="[Since v2.2.0]" src="https://img.shields.io/badge/since-v2.2.0-8a9199?style=flat-square" align="middle"></a>
178
258
 
179
259
  #### <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
180
260
 
181
261
  ```diff
182
262
  /* eslint chrome-extensions/manifest-spacing: ['error', { spaces: 2 }] */
183
-
263
+
184
264
  {
185
265
  ! "manifest_version": 3,
186
266
  ! "version" : "1.0.0",
@@ -194,7 +274,7 @@ If you don't care about the order of manifest keys.
194
274
 
195
275
  ```diff
196
276
  /* eslint chrome-extensions/manifest-spacing: ['error', { spaces: 2 }] */
197
-
277
+
198
278
  {
199
279
  - "manifest_version": 3,
200
280
  + "manifest_version": 3,
@@ -238,9 +318,11 @@ If you don't care about visual consistency in your manifest.
238
318
 
239
319
  <h3 id="no-content-style-leak">
240
320
  <code>no-content-style-leak</code>
321
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
322
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
241
323
  <a title="Only included in strict config" href="#usage">
242
324
  <img height=18 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
243
- <a title="Copy rule URL" target="_blank"
325
+ <a title="Copy rule URL" target="_blank"
244
326
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-content-style-leak">
245
327
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
246
328
  </h3>
@@ -290,11 +372,13 @@ If you intentionally interact w/ host page styles.
290
372
 
291
373
  <h3 id="no-deprecated-apis">
292
374
  <code>no-deprecated-apis</code>
375
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
376
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
293
377
  <a title="Included in recommended config" href="#usage">
294
378
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
295
379
  <a title="Accepts array w/ options" href="#usage">
296
380
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
297
- <a title="Copy rule URL" target="_blank"
381
+ <a title="Copy rule URL" target="_blank"
298
382
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-deprecated-apis">
299
383
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
300
384
  </h3>
@@ -305,14 +389,14 @@ If you intentionally interact w/ host page styles.
305
389
 
306
390
  <h4 id="no-deprecated-apis-options">Options</h4>
307
391
 
308
- - `target` (default `'mv3'`) – Chrome extension manifest version whose deprecations to validate against (`'mv3'`, `'mv2'`)
309
- - `allowedAPIs` (default `[]`) – additional deprecated API namespaces to allow, as a single string or array
392
+ - `target` (default `'mv3'`) – Chrome extension manifest version whose deprecations to validate against (`'mv3'`, `'mv2'`) <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
393
+ - `allowedAPIs` (default `[]`) – additional deprecated API namespaces to allow, as a single string or array <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
310
394
 
311
395
  #### <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
312
396
 
313
397
  ```diff
314
398
  /* eslint chrome-extensions/no-deprecated-apis: ['error', { target: 'mv3' }] */
315
-
399
+
316
400
  ! chrome.pageAction.show(tabId)
317
401
  ! chrome.extension.getBackgroundPage().doThing()
318
402
  ! chrome.tabs.executeScript(tabId, { code: 'doThing()' })
@@ -357,7 +441,7 @@ If you don't want deprecation validation at all. For individual deprecated APIs
357
441
  <code>no-duplicate-manifest-keys</code>
358
442
  <a title="Only works in 'json/json' config block" href="#usage">
359
443
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
360
- <a title="Copy rule URL" target="_blank"
444
+ <a title="Copy rule URL" target="_blank"
361
445
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-duplicate-manifest-keys">
362
446
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
363
447
  </h3>
@@ -407,7 +491,144 @@ If you rely on a Chromium fork resolving duplicate keys in a specific order.
407
491
  <a title="Doesn't prevent bugs" href="#manifest-key-order"><img height=14 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
408
492
  <a title="Accepts array w/ options" href="#manifest-key-order-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
409
493
  - [`no-unused-permissions`](#no-unused-permissions)
410
- <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
494
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
495
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
496
+
497
+ <div align="center">
498
+
499
+ [Back to index ↑][epce-rules]
500
+
501
+ </div>
502
+
503
+ ---
504
+
505
+ </details>
506
+
507
+ <h3 id="no-global-keyframes">
508
+ <code>no-global-keyframes</code>
509
+ <a title="Introduced in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">
510
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
511
+ <a title="Only works in 'css/css' config block" href="#usage">
512
+ <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
513
+ <a title="Accepts array w/ options" href="#usage">
514
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
515
+ <a title="Copy rule URL" target="_blank"
516
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-global-keyframes">
517
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
518
+ </h3>
519
+
520
+ <details>
521
+
522
+ <summary>Disallows <code>@keyframes</code> in content-script CSS to prevent collisions w/ host animations.</summary>
523
+
524
+ <h4 id="no-global-keyframes-options">Options</h4>
525
+
526
+ - `flagCommonNames` (default `true`) – flag well-known animation names (`spin`, `fade-in`, `slide-in-right`, etc.) that are most likely to collide w/ host pages <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
527
+ - `requiredPrefix` (default `undefined`) – flag names not starting w/ this prefix <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
528
+
529
+ #### <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
530
+
531
+ ```diff
532
+ ! @keyframes spin { from { transform: rotate(0) } to { transform: rotate(360deg) } }
533
+ ! @keyframes fade-in { from { opacity: 0 } to { opacity: 1 } }
534
+ ```
535
+
536
+ #### <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
537
+
538
+ ```diff
539
+ - @keyframes spin { from { transform: rotate(0) } to { transform: rotate(360deg) } }
540
+ + @keyframes myext-spin { from { transform: rotate(0) } to { transform: rotate(360deg) } }
541
+ - @keyframes fade-in { from { opacity: 0 } to { opacity: 1 } }
542
+ + @keyframes myext-fade-in { from { opacity: 0 } to { opacity: 1 } }
543
+ ```
544
+
545
+ #### When not to use it
546
+
547
+ If your CSS is scoped inside a Shadow DOM root.
548
+
549
+ #### Introduced in
550
+
551
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">v2.7.0</a> (October 17, 2026)
552
+
553
+ #### See also
554
+
555
+ - [`no-host-page-selectors`](#no-host-page-selectors)
556
+ <a title="Only works in 'css/css' config block" href="#usage"><img height=14 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
557
+ <a title="Accepts array w/ options" href="#no-host-page-selectors-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
558
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.mozilla.org&sz=64">&ensp;<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes">MDN — `@keyframes`</a>
559
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.mozilla.org&sz=64">&ensp;<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM">MDN — Using shadow DOM</a>
560
+
561
+ <div align="center">
562
+
563
+ [Back to index ↑][epce-rules]
564
+
565
+ </div>
566
+
567
+ ---
568
+
569
+ </details>
570
+
571
+ <h3 id="no-host-page-selectors">
572
+ <code>no-host-page-selectors</code>
573
+ <a title="Introduced in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">
574
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
575
+ <a title="Only works in 'css/css' config block" href="#usage">
576
+ <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
577
+ <a title="Accepts array w/ options" href="#usage">
578
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
579
+ <a title="Copy rule URL" target="_blank"
580
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-host-page-selectors">
581
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
582
+ </h3>
583
+
584
+ <details>
585
+
586
+ <summary>Disallows host-page selectors (<code>html</code>, <code>body</code>, <code>:root</code>, <code>*</code>, bare elem types) in content-script CSS.</summary>
587
+
588
+ <h4 id="no-host-page-selectors-options">Options</h4>
589
+
590
+ - `allowedSelectors` (default `[]`) – selectors to explicitly allow (e.g. `['body.dark']`), as a single string or array <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
591
+ - `disallowUniversal` (default `true`) – flag `*` <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
592
+ - `disallowStructural` (default `true`) – flag `html`, `body`, `:root` <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
593
+ - `disallowBareElements` (default `true`) – flag elem types (e.g. `div`, `a`) that lack `class`/`id`/`attribute` <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
594
+
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
596
+
597
+ ```diff
598
+ ! * { box-sizing: border-box }
599
+
600
+ ! body { margin: 0 }
601
+ ! html { font-family: sans-serif }
602
+ ! button:hover { opacity: 0.8 }
603
+ ```
604
+
605
+ #### <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
+
607
+ ```diff
608
+ - * { box-sizing: border-box }
609
+ + :host { box-sizing: border-box }
610
+
611
+ - body { margin: 0 }
612
+ + :host { margin: 0 }
613
+ - html { font-family: sans-serif }
614
+ + :host { font-family: sans-serif }
615
+ - button:hover { opacity: 0.8 }
616
+ + .myext-button:hover { opacity: 0.8 }
617
+ ```
618
+
619
+ #### When not to use it
620
+
621
+ If you intentionally style the host page. For individual selectors you still need, prefer `allowedSelectors` over disabling the rule.
622
+
623
+ #### Introduced in
624
+
625
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">v2.7.0</a> (October 17, 2026)
626
+
627
+ #### See also
628
+
629
+ - [`no-content-style-leak`](#no-content-style-leak)
630
+ <a title="Only included in strict config" href="#usage"><img height=14 alt="[Strict only]" src="https://img.shields.io/badge/Strict_only-ff8c42?style=flat-square" align="middle"></a>
631
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.mozilla.org&sz=64">&ensp;<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:host">MDN — `:host`</a>
411
632
 
412
633
  <div align="center">
413
634
 
@@ -425,7 +646,7 @@ If you rely on a Chromium fork resolving duplicate keys in a specific order.
425
646
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
426
647
  <a title="Included in security config" href="#usage">
427
648
  <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
428
- <a title="Copy rule URL" target="_blank"
649
+ <a title="Copy rule URL" target="_blank"
429
650
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-fetch">
430
651
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
431
652
  </h3>
@@ -474,13 +695,15 @@ If you intentionally target HTTP endpoints.
474
695
 
475
696
  <h3 id="no-insecure-messaging">
476
697
  <code>no-insecure-messaging</code>
698
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
699
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
477
700
  <a title="Included in recommended config" href="#usage">
478
701
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
479
702
  <a title="Included in security config" href="#usage">
480
703
  <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
481
704
  <a title="Accepts array w/ options" href="#usage">
482
705
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
483
- <a title="Copy rule URL" target="_blank"
706
+ <a title="Copy rule URL" target="_blank"
484
707
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-messaging">
485
708
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
486
709
  </h3>
@@ -491,7 +714,7 @@ If you intentionally target HTTP endpoints.
491
714
 
492
715
  <h4 id="no-insecure-messaging-options">Options</h4>
493
716
 
494
- - `disallowWildcardTarget` (default `true`) – flag <code>postMessage()</code> calls that use <code>'*'</code> as <code>targetOrigin</code>
717
+ - `disallowWildcardTarget` (default `true`) – flag <code>postMessage()</code> calls that use <code>'*'</code> as <code>targetOrigin</code> <a title="Introduced in v2.1.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0"><img height=14 alt="[Since v2.1.0]" src="https://img.shields.io/badge/since-v2.1.0-8a9199?style=flat-square" align="middle"></a>
495
718
 
496
719
  #### <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
497
720
 
@@ -557,15 +780,90 @@ If you trust every external caller and open tab, or you intentionally broadcast
557
780
 
558
781
  </details>
559
782
 
783
+ <h3 id="no-invalid-locales">
784
+ <code>no-invalid-locales</code>
785
+ <a title="Included in recommended config" href="#usage">
786
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
787
+ <a title="Works in 'json/json' config block" href="#usage">
788
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
789
+ <a title="Accepts array w/ options" href="#usage">
790
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
791
+ <a title="Copy rule URL" target="_blank"
792
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-invalid-locales">
793
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
794
+ </h3>
795
+
796
+ <details>
797
+
798
+ <summary>Disallows invalid Chrome locale codes in <code>_locales/</code> folders and <code>default_locale</code>.</summary>
799
+
800
+ <h4 id="no-invalid-locales-options">Options</h4>
801
+
802
+ - `allowedLocales` (default `[]`) – additional locale codes to allow, as a single string or array <a title="Introduced in v2.6.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0"><img height=14 alt="[Since v2.6.0]" src="https://img.shields.io/badge/since-v2.6.0-8a9199?style=flat-square" align="middle"></a>
803
+
804
+ #### <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
805
+
806
+ ```diff
807
+ // manifest.json
808
+ {
809
+ "manifest_version": 3,
810
+ ! "default_locale": "pt-BR"
811
+ }
812
+
813
+ ! // _locales/pt-BR/messages.json
814
+ ```
815
+
816
+ #### <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
817
+
818
+ ```diff
819
+ // manifest.json
820
+ {
821
+ "manifest_version": 3,
822
+ - "default_locale": "pt-BR"
823
+ + "default_locale": "pt_BR"
824
+ }
825
+
826
+ - // _locales/pt-BR/messages.json
827
+ + // _locales/pt_BR/messages.json
828
+ ```
829
+
830
+ #### When not to use it
831
+
832
+ If your `_locales/` is externally populated at build time. If you target a Chromium fork w/ additional supported locales, prefer `allowedLocales` over disabling the rule.
833
+
834
+ #### Introduced in
835
+
836
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">v2.6.0</a> (October 16, 2026)
837
+
838
+ #### See also
839
+
840
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/i18n">Chrome for Developers — `i18n`</a>
841
+ - [`no-missing-default-locale`](#no-missing-default-locale)
842
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
843
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
844
+ <a title="Accepts array w/ options" href="#no-missing-default-locale-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
845
+
846
+ <div align="center">
847
+
848
+ [Back to index ↑][epce-rules]
849
+
850
+ </div>
851
+
852
+ ---
853
+
854
+ </details>
855
+
560
856
  <h3 id="no-invalid-permissions">
561
857
  <code>no-invalid-permissions</code>
858
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
859
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
562
860
  <a title="Included in recommended config" href="#usage">
563
861
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
564
862
  <a title="Works in 'json/json' config block" href="#usage">
565
863
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
566
864
  <a title="Accepts array w/ options" href="#usage">
567
865
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
568
- <a title="Copy rule URL" target="_blank"
866
+ <a title="Copy rule URL" target="_blank"
569
867
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-invalid-permissions">
570
868
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
571
869
  </h3>
@@ -576,14 +874,14 @@ If you trust every external caller and open tab, or you intentionally broadcast
576
874
 
577
875
  <h4 id="no-invalid-permissions-options">Options</h4>
578
876
 
579
- - `target` (default `'mv3'`) – Chrome manifest version whose permissions to validate against (`'mv3'`, `'mv2'`)
580
- - `allowedPermissions` (default `[]`) – additional permission names to allow beyond the built-in list, as a single string or array
877
+ - `target` (default `'mv3'`) – Chrome manifest version whose permissions to validate against (`'mv3'`, `'mv2'`) <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
878
+ - `allowedPermissions` (default `[]`) – additional permission names to allow beyond the built-in list, as a single string or array <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
581
879
 
582
880
  #### <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
583
881
 
584
882
  ```diff
585
883
  /* eslint chrome-extensions/no-invalid-permissions: ['error', { target: 'mv3' }] */
586
-
884
+
587
885
  {
588
886
  ! "permissions": ["browserAction", "tabs"],
589
887
  ! "optional_permissions": ["history", "pageAction"]
@@ -594,7 +892,7 @@ If you trust every external caller and open tab, or you intentionally broadcast
594
892
 
595
893
  ```diff
596
894
  /* eslint chrome-extensions/no-invalid-permissions: ['error', { target: 'mv3' }] */
597
-
895
+
598
896
  {
599
897
  - "permissions": ["browserAction", "tabs"],
600
898
  + "permissions": ["tabs"],
@@ -616,7 +914,8 @@ If you don't want permission validation at all. For custom permissions from a Ch
616
914
  - [`no-missing-permissions`](#no-missing-permissions)
617
915
  <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
618
916
  - [`no-unused-permissions`](#no-unused-permissions)
619
- <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
917
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
918
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
620
919
 
621
920
  <div align="center">
622
921
 
@@ -630,11 +929,15 @@ If you don't want permission validation at all. For custom permissions from a Ch
630
929
 
631
930
  <h3 id="no-missing-default-locale">
632
931
  <code>no-missing-default-locale</code>
633
- <a title="Only works in 'json/json' config block" href="#usage">
634
- <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
932
+ <a title="JS support + new option added in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">
933
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
934
+ <a title="Included in recommended config" href="#usage">
935
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
936
+ <a title="Works in 'json/json' config block" href="#usage">
937
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
635
938
  <a title="Accepts array w/ options" href="#usage">
636
939
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
637
- <a title="Copy rule URL" target="_blank"
940
+ <a title="Copy rule URL" target="_blank"
638
941
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-default-locale">
639
942
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
640
943
  </h3>
@@ -645,7 +948,8 @@ If you don't want permission validation at all. For custom permissions from a Ch
645
948
 
646
949
  <h4 id="no-missing-default-locale-options">Options</h4>
647
950
 
648
- - `ignoreKeys` (default `[]`) – keys to skip when checking the default locale
951
+ - `ignoreKeys` (default `[]`) – keys to skip when checking locales <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
952
+ - `checkAllLocales` (default `false`) – also flag keys missing from any locale <a title="Introduced in v2.6.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0"><img height=14 alt="[Since v2.6.0]" src="https://img.shields.io/badge/since-v2.6.0-8a9199?style=flat-square" align="middle"></a>
649
953
 
650
954
  #### <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
651
955
 
@@ -723,17 +1027,9 @@ If your `_locales/` is externally populated at build time.
723
1027
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
724
1028
  <a title="Works in 'css/css' config block" href="#usage">
725
1029
  <img height=18 alt="[CSS]" src="https://img.shields.io/badge/CSS-dcd6f7?style=flat-square" align="middle"></a>
726
- <a title="Works in 'html/html' config block" href="#usage">
727
- <img height=18 alt="[HTML]" src="https://img.shields.io/badge/HTML-a8d8ea?style=flat-square" align="middle"></a>
728
- <a title="Works in 'json/json' config block" href="#usage">
729
- <img height=18 alt="[JSON]" src="https://img.shields.io/badge/JSON-a8e6cf?style=flat-square" align="middle"></a>
730
- <a title="Works in 'json/json5' config block" href="#usage">
731
- <img height=18 alt="[JSON5]" src="https://img.shields.io/badge/JSON5-c7e6b8?style=flat-square" align="middle"></a>
732
- <a title="Works in 'json/jsonc' config block" href="#usage">
733
- <img height=18 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
734
1030
  <a title="Accepts array w/ options" href="#usage">
735
1031
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
736
- <a title="Copy rule URL" target="_blank"
1032
+ <a title="Copy rule URL" target="_blank"
737
1033
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-i18n-keys">
738
1034
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
739
1035
  </h3>
@@ -744,7 +1040,7 @@ If your `_locales/` is externally populated at build time.
744
1040
 
745
1041
  <h4 id="no-missing-i18n-keys-options">Options</h4>
746
1042
 
747
- - `ignoreKeys` (default `[]`) – keys to skip (e.g. `['customKey']`)
1043
+ - `ignoreKeys` (default `[]`) – keys to skip (e.g. `['customKey']`) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
748
1044
 
749
1045
  #### <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
750
1046
 
@@ -809,9 +1105,11 @@ If your `_locales/` is externally populated at build time.
809
1105
 
810
1106
  <h3 id="no-missing-permissions">
811
1107
  <code>no-missing-permissions</code>
1108
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
1109
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
812
1110
  <a title="Included in recommended config" href="#usage">
813
1111
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
814
- <a title="Copy rule URL" target="_blank"
1112
+ <a title="Copy rule URL" target="_blank"
815
1113
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-permissions">
816
1114
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
817
1115
  </h3>
@@ -862,7 +1160,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
862
1160
  <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
863
1161
  <a title="Accepts array w/ options" href="#no-invalid-permissions-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
864
1162
  - [`no-unused-permissions`](#no-unused-permissions)
865
- <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1163
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1164
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
866
1165
 
867
1166
  <div align="center">
868
1167
 
@@ -878,7 +1177,7 @@ If you use APIs through aliases or wrappers that obscure the original call site.
878
1177
  <code>no-missing-web-accessible-resources</code>
879
1178
  <a title="Included in recommended config" href="#usage">
880
1179
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
881
- <a title="Copy rule URL" target="_blank"
1180
+ <a title="Copy rule URL" target="_blank"
882
1181
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-web-accessible-resources">
883
1182
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
884
1183
  </h3>
@@ -939,13 +1238,15 @@ If your paths are built at runtime.
939
1238
 
940
1239
  <h3 id="no-remote-code">
941
1240
  <code>no-remote-code</code>
1241
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
1242
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
942
1243
  <a title="Included in recommended config" href="#usage">
943
1244
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
944
1245
  <a title="Included in security config" href="#usage">
945
1246
  <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
946
1247
  <a title="Accepts array w/ options" href="#usage">
947
1248
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
948
- <a title="Copy rule URL" target="_blank"
1249
+ <a title="Copy rule URL" target="_blank"
949
1250
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-remote-code">
950
1251
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
951
1252
  </h3>
@@ -956,8 +1257,8 @@ If your paths are built at runtime.
956
1257
 
957
1258
  <h4 id="no-remote-code-options">Options</h4>
958
1259
 
959
- - `patterns` (default `['eval', 'new-function', 'string-timer', 'dynamic-import', 'remote-script-src', 'execute-script-url']`) – detection paths to enable, as a single string or array
960
- - `checkExecuteScriptClosures` (default `true`) – additionally flag <code>chrome.scripting.executeScript({ func })</code> bodies that capture outer-scope variables
1260
+ - `patterns` (default `['eval', 'new-function', 'string-timer', 'dynamic-import', 'remote-script-src', 'execute-script-url']`) – detection paths to enable, as a single string or array <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
1261
+ - `checkExecuteScriptClosures` (default `true`) – additionally flag <code>chrome.scripting.executeScript({ func })</code> bodies that capture outer-scope variables <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0"><img height=14 alt="[Since v1.0.0]" src="https://img.shields.io/badge/since-v1.0.0-8a9199?style=flat-square&labelColor=464646" align="middle"></a>
961
1262
 
962
1263
  #### <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
963
1264
 
@@ -991,12 +1292,160 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
991
1292
 
992
1293
  #### See also
993
1294
 
994
- - [`require-mv3`](#require-mv3)
995
- <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
996
- <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
997
- - [`valid-mv3-schema`](#valid-mv3-schema)
1295
+ - [`no-remote-urls`](#no-remote-urls)
1296
+ <a title="Only works in 'css/css' config block" href="#usage"><img height=14 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1297
+ <a title="Accepts array w/ options" href="#no-remote-urls-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1298
+
1299
+ <div align="center">
1300
+
1301
+ [Back to index ↑][epce-rules]
1302
+
1303
+ </div>
1304
+
1305
+ ---
1306
+
1307
+ </details>
1308
+
1309
+ <h3 id="no-remote-urls">
1310
+ <code>no-remote-urls</code>
1311
+ <a title="Introduced in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">
1312
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
1313
+ <a title="Only works in 'css/css' config block" href="#usage">
1314
+ <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1315
+ <a title="Accepts array w/ options" href="#usage">
1316
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1317
+ <a title="Copy rule URL" target="_blank"
1318
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-remote-urls">
1319
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1320
+ </h3>
1321
+
1322
+ <details>
1323
+
1324
+ <summary>Disallows remote resources (<code>@import</code>, <code>@namespace</code>, <code>url()</code>) in extension CSS.</summary>
1325
+
1326
+ <h4 id="no-remote-urls-options">Options</h4>
1327
+
1328
+ - `allowedSchemes` (default `['blob', 'chrome-extension', 'data']`) – URL schemes to allow (beyond relative paths, which are always permitted), as a single string or array <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
1329
+ - `patterns` (default `['at-import', 'url']`) – detection paths to enable, as a single string or array (`'at-import'`, `'url'`, `'namespace'`) <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
1330
+
1331
+ #### <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
1332
+
1333
+ ```diff
1334
+ ! @import url("https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css");
1335
+ ! @import "https://cdn.example.com/style.css";
1336
+
1337
+ ! .panel { background: url("https://cdn.example.com/bg.png") }
1338
+ ! .cursor-area { cursor: url("//cdn.example.com/c.cur"), auto }
1339
+
1340
+ ! @font-face { font-family: Lato; src: url("https://fonts.gstatic.com/s/lato/v24/S6uyw4BMUTPHjx4wXiWtFCc.woff2") }
1341
+ ```
1342
+
1343
+ #### <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
1344
+
1345
+ ```diff
1346
+ - @import url("https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css");
1347
+ + @import url("./normalize.css");
1348
+ - @import "https://cdn.example.com/style.css";
1349
+ + @import "./reset.css";
1350
+
1351
+ - .panel { background: url("https://cdn.example.com/bg.png") }
1352
+ + .panel { background: url("/bg.png") }
1353
+ - .cursor-area { cursor: url("//cdn.example.com/c.cur"), auto }
1354
+ + .cursor-area { cursor: url("cursors/pointer.cur"), auto }
1355
+
1356
+ - @font-face { font-family: Lato; src: url("https://fonts.gstatic.com/s/lato/v24/S6uyw4BMUTPHjx4wXiWtFCc.woff2") }
1357
+ + @font-face { font-family: Lato; src: url("fonts/lato-v24.woff2") }
1358
+ ```
1359
+
1360
+ #### When not to use it
1361
+
1362
+ If you intentionally reference remote stylesheets, fonts, or images (e.g. Google Fonts, CDN assets). For individual schemes you still need, prefer `allowedSchemes` over disabling the rule.
1363
+
1364
+ #### Introduced in
1365
+
1366
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">v2.7.0</a> (October 17, 2026)
1367
+
1368
+ #### See also
1369
+
1370
+ - [`no-remote-code`](#no-remote-code)
998
1371
  <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
999
- <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1372
+ <a title="Included in security config" href="#usage"><img height=14 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
1373
+ <a title="Accepts array w/ options" href="#no-remote-code-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1374
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/content-security-policy">Chrome for Developers — `content_security_policy`</a>
1375
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources">Chrome for Developers — `web_accessible_resources`</a>
1376
+
1377
+ <div align="center">
1378
+
1379
+ [Back to index ↑][epce-rules]
1380
+
1381
+ </div>
1382
+
1383
+ ---
1384
+
1385
+ </details>
1386
+
1387
+ <h3 id="no-scrollbar-styling">
1388
+ <code>no-scrollbar-styling</code>
1389
+ <a title="Introduced in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">
1390
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
1391
+ <a title="Only works in 'css/css' config block" href="#usage">
1392
+ <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1393
+ <a title="Accepts array w/ options" href="#usage">
1394
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1395
+ <a title="Copy rule URL" target="_blank"
1396
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-scrollbar-styling">
1397
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1398
+ </h3>
1399
+
1400
+ <details>
1401
+
1402
+ <summary>Disallows scrollbar pseudo-elements (e.g. <code>::-webkit-scrollbar</code>) on unscoped selectors in content-script CSS.</summary>
1403
+
1404
+ <h4 id="no-scrollbar-styling-options">Options</h4>
1405
+
1406
+ - `allowedSelectors` (default `[]`) – selectors to explicitly allow (e.g. `['body::-webkit-scrollbar']`), as a single string or array <a title="Introduced in v2.7.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0"><img height=14 alt="[Since v2.7.0]" src="https://img.shields.io/badge/since-v2.7.0-8a9199?style=flat-square" align="middle"></a>
1407
+
1408
+ #### <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
1409
+
1410
+ ```diff
1411
+ ! ::-webkit-scrollbar { width: 8px }
1412
+ ! ::-webkit-scrollbar-thumb { background: #888 }
1413
+
1414
+ ! *::-webkit-scrollbar { width: 8px }
1415
+ ! body::-webkit-scrollbar { width: 8px }
1416
+ ! html::-webkit-scrollbar { width: 8px }
1417
+ ```
1418
+
1419
+ #### <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
1420
+
1421
+ ```diff
1422
+ - ::-webkit-scrollbar { width: 8px }
1423
+ + .myext-panel::-webkit-scrollbar { width: 8px }
1424
+ - ::-webkit-scrollbar-thumb { background: #888 }
1425
+ + .myext-panel::-webkit-scrollbar-thumb { background: #888 }
1426
+
1427
+ - *::-webkit-scrollbar { width: 8px }
1428
+ + .myext-root::-webkit-scrollbar { width: 8px }
1429
+ - body::-webkit-scrollbar { width: 8px }
1430
+ + .myext-panel::-webkit-scrollbar { width: 8px }
1431
+ - html::-webkit-scrollbar { width: 8px }
1432
+ + .myext-panel::-webkit-scrollbar { width: 8px }
1433
+ ```
1434
+
1435
+ #### When not to use it
1436
+
1437
+ If you intentionally theme the host page's scrollbar. For individual selectors you still need, prefer `allowedSelectors` over disabling the rule.
1438
+
1439
+ #### Introduced in
1440
+
1441
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.7.0">v2.7.0</a> (October 17, 2026)
1442
+
1443
+ #### See also
1444
+
1445
+ - [`no-host-page-selectors`](#no-host-page-selectors)
1446
+ <a title="Only works in 'css/css' config block" href="#usage"><img height=14 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1447
+ <a title="Accepts array w/ options" href="#no-host-page-selectors-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1448
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.mozilla.org&sz=64">&ensp;<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar">MDN — `::-webkit-scrollbar`</a>
1000
1449
 
1001
1450
  <div align="center">
1002
1451
 
@@ -1018,18 +1467,18 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
1018
1467
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1019
1468
  <a title="Accepts array w/ options" href="#usage">
1020
1469
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1021
- <a title="Copy rule URL" target="_blank"
1470
+ <a title="Copy rule URL" target="_blank"
1022
1471
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-sensitive-permissions">
1023
1472
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1024
1473
  </h3>
1025
1474
 
1026
1475
  <details>
1027
1476
 
1028
- <summary>Flags sensitive manifest permissions that warrant security review.</summary>
1477
+ <summary>Flags sensitive manifest permissions.</summary>
1029
1478
 
1030
1479
  <h4 id="no-sensitive-permissions-options">Options</h4>
1031
1480
 
1032
- - `allowedPermissions` (default `[]`) – sensitive permission names to explicitly allow, as a single string or array
1481
+ - `allowedPermissions` (default `[]`) – sensitive permission names to explicitly allow, as a single string or array <a title="Introduced in v2.5.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.5.0"><img height=14 alt="[Since v2.5.0]" src="https://img.shields.io/badge/since-v2.5.0-8a9199?style=flat-square" align="middle"></a>
1033
1482
 
1034
1483
  #### <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
1035
1484
 
@@ -1056,7 +1505,7 @@ If you legitimately require sensitive permissions, or prefer manual security rev
1056
1505
 
1057
1506
  #### Introduced in
1058
1507
 
1059
- v2.5.0 (Unreleased)
1508
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.5.0">v2.5.0</a> (October 15, 2026)
1060
1509
 
1061
1510
  #### See also
1062
1511
 
@@ -1065,7 +1514,8 @@ v2.5.0 (Unreleased)
1065
1514
  <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1066
1515
  <a title="Accepts array w/ options" href="#no-invalid-permissions-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1067
1516
  - [`no-unused-permissions`](#no-unused-permissions)
1068
- <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1517
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1518
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1069
1519
  - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">Chrome for Developers — Declare permissions</a>
1070
1520
 
1071
1521
  <div align="center">
@@ -1080,11 +1530,17 @@ v2.5.0 (Unreleased)
1080
1530
 
1081
1531
  <h3 id="no-unrestricted-host-permissions">
1082
1532
  <code>no-unrestricted-host-permissions</code>
1083
- <a title="Only works in 'json/json' config block" href="#usage">
1084
- <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1533
+ <a title="JS support added in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">
1534
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
1535
+ <a title="Included in recommended config" href="#usage">
1536
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1537
+ <a title="Included in security config" href="#usage">
1538
+ <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
1539
+ <a title="Works in 'json/json' config block" href="#usage">
1540
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1085
1541
  <a title="Accepts array w/ options" href="#usage">
1086
1542
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1087
- <a title="Copy rule URL" target="_blank"
1543
+ <a title="Copy rule URL" target="_blank"
1088
1544
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unrestricted-host-permissions">
1089
1545
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1090
1546
  </h3>
@@ -1095,7 +1551,7 @@ v2.5.0 (Unreleased)
1095
1551
 
1096
1552
  <h4 id="no-unrestricted-host-permissions-options">Options</h4>
1097
1553
 
1098
- - `allowedPatterns` (default `[]`) – host patterns to explicitly allow (e.g. `['<all_urls>']`)
1554
+ - `allowedPatterns` (default `[]`) – host patterns to explicitly allow (e.g. `['<all_urls>']`) <a title="Introduced in v2.1.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0"><img height=14 alt="[Since v2.1.0]" src="https://img.shields.io/badge/since-v2.1.0-8a9199?style=flat-square" align="middle"></a>
1099
1555
 
1100
1556
  #### <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
1101
1557
 
@@ -1148,7 +1604,7 @@ If you legitimately need broad access (e.g. ad blockers or dev tools).
1148
1604
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1149
1605
  <a title="Accepts array w/ options" href="#usage">
1150
1606
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1151
- <a title="Copy rule URL" target="_blank"
1607
+ <a title="Copy rule URL" target="_blank"
1152
1608
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-i18n-keys">
1153
1609
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1154
1610
  </h3>
@@ -1159,8 +1615,8 @@ If you legitimately need broad access (e.g. ad blockers or dev tools).
1159
1615
 
1160
1616
  <h4 id="no-unused-i18n-keys-options">Options</h4>
1161
1617
 
1162
- - `ignoreKeys` (default `[]`) – keys to always treat as used (e.g. `['customKey']`)
1163
- - `scanExtensions` (default `['cjs', 'css', 'htm', 'html', 'js', 'json', 'jsx', 'md', 'mjs', 'svg', 'ts', 'tsx', 'txt']`) – file extensions to scan for references
1618
+ - `ignoreKeys` (default `[]`) – keys to always treat as used (e.g. `['customKey']`) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1619
+ - `scanExtensions` (default `['cjs', 'css', 'htm', 'html', 'js', 'json', 'jsx', 'md', 'mjs', 'svg', 'ts', 'tsx', 'txt']`) – file extensions to scan for references <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1164
1620
 
1165
1621
  #### <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
1166
1622
 
@@ -1202,10 +1658,6 @@ If your i18n keys are referenced dynamically.
1202
1658
  <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1203
1659
  <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1204
1660
  <a title="Works in 'css/css' config block" href="#usage"><img height=14 alt="[CSS]" src="https://img.shields.io/badge/CSS-dcd6f7?style=flat-square" align="middle"></a>
1205
- <a title="Works in 'html/html' config block" href="#usage"><img height=14 alt="[HTML]" src="https://img.shields.io/badge/HTML-a8d8ea?style=flat-square" align="middle"></a>
1206
- <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[JSON]" src="https://img.shields.io/badge/JSON-a8e6cf?style=flat-square" align="middle"></a>
1207
- <a title="Works in 'json/json5' config block" href="#usage"><img height=14 alt="[JSON5]" src="https://img.shields.io/badge/JSON5-c7e6b8?style=flat-square" align="middle"></a>
1208
- <a title="Works in 'json/jsonc' config block" href="#usage"><img height=14 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
1209
1661
  <a title="Accepts array w/ options" href="#no-missing-i18n-keys-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1210
1662
  - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/i18n">Chrome for Developers — `i18n`</a>
1211
1663
 
@@ -1221,9 +1673,15 @@ If your i18n keys are referenced dynamically.
1221
1673
 
1222
1674
  <h3 id="no-unused-permissions">
1223
1675
  <code>no-unused-permissions</code>
1224
- <a title="Only works in 'json/json' config block" href="#usage">
1225
- <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1226
- <a title="Copy rule URL" target="_blank"
1676
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
1677
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
1678
+ <a title="JS support added in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">
1679
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
1680
+ <a title="Included in recommended config" href="#usage">
1681
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1682
+ <a title="Works in 'json/json' config block" href="#usage">
1683
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1684
+ <a title="Copy rule URL" target="_blank"
1227
1685
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-permissions">
1228
1686
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1229
1687
  </h3>
@@ -1288,14 +1746,14 @@ If you access the granted API through an alias or computed property rather than
1288
1746
  <code>require-license-file</code>
1289
1747
  <a title="Only works in 'json/json' config block" href="#usage">
1290
1748
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1291
- <a title="Copy rule URL" target="_blank"
1749
+ <a title="Copy rule URL" target="_blank"
1292
1750
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-license-file">
1293
1751
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1294
1752
  </h3>
1295
1753
 
1296
1754
  <details>
1297
1755
 
1298
- <summary>Requires a license file in the extension.</summary>
1756
+ <summary>Requires a license file.</summary>
1299
1757
 
1300
1758
  #### <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 directory structure
1301
1759
 
@@ -1308,7 +1766,7 @@ If you access the granted API through an alias or computed property rather than
1308
1766
 
1309
1767
  ```diff
1310
1768
  /extension/manifest.json
1311
- + /extension/LICENSE.md
1769
+ + /LICENSE.md
1312
1770
  ```
1313
1771
 
1314
1772
  #### When not to use it
@@ -1338,11 +1796,13 @@ If you intentionally omit a license, or it's injected at build time.
1338
1796
 
1339
1797
  <h3 id="require-mv3">
1340
1798
  <code>require-mv3</code>
1799
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
1800
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
1341
1801
  <a title="Included in recommended config" href="#usage">
1342
1802
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1343
1803
  <a title="Works in 'json/json' config block" href="#usage">
1344
1804
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1345
- <a title="Copy rule URL" target="_blank"
1805
+ <a title="Copy rule URL" target="_blank"
1346
1806
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-mv3">
1347
1807
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1348
1808
  </h3>
@@ -1402,7 +1862,7 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1402
1862
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1403
1863
  <a title="Accepts array w/ options" href="#usage">
1404
1864
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1405
- <a title="Copy rule URL" target="_blank"
1865
+ <a title="Copy rule URL" target="_blank"
1406
1866
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-short-name-when-useful">
1407
1867
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1408
1868
  </h3>
@@ -1413,9 +1873,9 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1413
1873
 
1414
1874
  <h4 id="require-short-name-when-useful-options">Options</h4>
1415
1875
 
1416
- - `maxNameLength` (default `12`) – length of `name` above which `short_name` is required
1417
- - `always` (default `false`) – require `short_name` regardless of `name` length
1418
- - `checkRedundant` (default `false`) – also flag `short_name` that duplicates `name`
1876
+ - `maxNameLength` (default `12`) – length of `name` above which `short_name` is required <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1877
+ - `always` (default `false`) – require `short_name` regardless of `name` length <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1878
+ - `checkRedundant` (default `false`) – also flag `short_name` that duplicates `name` <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1419
1879
 
1420
1880
  #### <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
1421
1881
 
@@ -1428,7 +1888,7 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1428
1888
 
1429
1889
  #### <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
1430
1890
 
1431
- ```diff
1891
+ ```diff
1432
1892
  {
1433
1893
  "manifest_version": 3,
1434
1894
  "name": "Extension Infinity",
@@ -1477,7 +1937,7 @@ If you primarily target a browser that doesn't support `short_name`.
1477
1937
  <img height=18 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
1478
1938
  <a title="Accepts array w/ options" href="#usage">
1479
1939
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1480
- <a title="Copy rule URL" target="_blank"
1940
+ <a title="Copy rule URL" target="_blank"
1481
1941
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-filenames">
1482
1942
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1483
1943
  </h3>
@@ -1488,16 +1948,15 @@ If you primarily target a browser that doesn't support `short_name`.
1488
1948
 
1489
1949
  <h4 id="valid-filenames-options">Options</h4>
1490
1950
 
1491
- - `noReservedPrefix` (default `true`) – disallow filenames/dirs starting w/ `_` (except `_locales`)
1492
- - `noSpecialChars` (default `true`) – warn on chars outside `a-z`, `0-9`, `-`, `_`, `.`
1493
- - `checkFileExists` (default `true`) – verify files referenced in `manifest.json` actually exist
1494
- - `enforceCaseSensitivity` (default `true`) – verify manifest references match actual file case
1495
- - `maxFullPathLength` (default `260`) – max full path char length
1951
+ - `noReservedPrefix` (default `true`) – disallow filenames/dirs starting w/ `_` (except `_locales`) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1952
+ - `noSpecialChars` (default `true`) – warn on chars outside `a-z`, `0-9`, `-`, `_`, `.` <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1953
+ - `checkFileExists` (default `true`) – verify files referenced in `manifest.json` actually exist <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1954
+ - `enforceCaseSensitivity` (default `true`) – verify manifest references match actual file case <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1955
+ - `maxFullPathLength` (default `260`) – max full path char length <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1496
1956
 
1497
- #### <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
1957
+ #### <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 names/paths
1498
1958
 
1499
1959
  ```diff
1500
- // files
1501
1960
  ! /extension/_metadata/extension.json
1502
1961
  ! /extension/content script.js
1503
1962
 
@@ -1508,7 +1967,7 @@ If you primarily target a browser that doesn't support `short_name`.
1508
1967
  }
1509
1968
  ```
1510
1969
 
1511
- #### <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
1970
+ #### <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 names/paths
1512
1971
 
1513
1972
  ```diff
1514
1973
  - /extension/_metadata/extension.json
@@ -1538,7 +1997,8 @@ If you don't use conventional filenames or paths, or they're generated at build
1538
1997
  - [`no-missing-web-accessible-resources`](#no-missing-web-accessible-resources)
1539
1998
  <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1540
1999
  - [`valid-manifest-icons`](#valid-manifest-icons)
1541
- <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
2000
+ <a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
2001
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1542
2002
  <a title="Accepts array w/ options" href="#valid-manifest-icons-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1543
2003
 
1544
2004
  <div align="center">
@@ -1559,19 +2019,19 @@ If you don't use conventional filenames or paths, or they're generated at build
1559
2019
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
1560
2020
  <a title="Accepts array w/ options" href="#usage">
1561
2021
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1562
- <a title="Copy rule URL" target="_blank"
2022
+ <a title="Copy rule URL" target="_blank"
1563
2023
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-license-file">
1564
2024
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1565
2025
  </h3>
1566
2026
 
1567
2027
  <details>
1568
2028
 
1569
- <summary>Validates SPDX identifiers in license files.</summary>
2029
+ <summary>Validates SPDX identifiers in license files (for compliance scanners + SBOM generators + CI gates).</summary>
1570
2030
 
1571
2031
  <h4 id="valid-license-file-options">Options</h4>
1572
2032
 
1573
- - `requireSPDX` (default `false`) – require <a target="_blank" href="https://spdx.dev/learn/handling-license-info/">`SPDX-License-Identifier`</a> in the license
1574
- - `allowedLicenses` (default `[]`) – <a target="_blank" href="https://spdx.org/licenses/">SPDX license IDs</a> to restrict to (e.g. `['Apache-2.0', 'MIT']`), as a single string or array
2033
+ - `requireSPDX` (default `false`) – require <a target="_blank" href="https://spdx.dev/learn/handling-license-info/">`SPDX-License-Identifier`</a> in the license <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
2034
+ - `allowedLicenses` (default `[]`) – <a target="_blank" href="https://spdx.org/licenses/">SPDX license IDs</a> to restrict to (e.g. `['Apache-2.0', 'MIT']`), as a single string or array <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1575
2035
 
1576
2036
  #### <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
1577
2037
 
@@ -1595,10 +2055,6 @@ If you don't use conventional filenames or paths, or they're generated at build
1595
2055
  + SPDX-License-Identifier: MIT
1596
2056
  ```
1597
2057
 
1598
- #### Benefits
1599
-
1600
- Enables machine-readability for compliance scanners, SBOM generators & CI gates.
1601
-
1602
2058
  #### When not to use it
1603
2059
 
1604
2060
  If your license is injected at build time, or you use one w/ no existing SPDX identifier.
@@ -1625,11 +2081,15 @@ If your license is injected at build time, or you use one w/ no existing SPDX id
1625
2081
 
1626
2082
  <h3 id="valid-manifest-icons">
1627
2083
  <code>valid-manifest-icons</code>
1628
- <a title="Only works in 'json/json' config block" href="#usage">
1629
- <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
2084
+ <a title="JS support added in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">
2085
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
2086
+ <a title="Included in recommended config" href="#usage">
2087
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
2088
+ <a title="Works in 'json/json' config block" href="#usage">
2089
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1630
2090
  <a title="Accepts array w/ options" href="#usage">
1631
2091
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1632
- <a title="Copy rule URL" target="_blank"
2092
+ <a title="Copy rule URL" target="_blank"
1633
2093
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-manifest-icons">
1634
2094
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1635
2095
  </h3>
@@ -1640,9 +2100,9 @@ If your license is injected at build time, or you use one w/ no existing SPDX id
1640
2100
 
1641
2101
  <h4 id="valid-manifest-icons-options">Options</h4>
1642
2102
 
1643
- - `requireRecommendedSizes` (default `true`) – require all of `16`, `32`, `48`, `128`
1644
- - `checkIconExists` (default `true`) – flag icon paths that don't resolve to an existing file
1645
- - `noSVG` (default `true`) – flag SVG icon paths (unsupported by Chrome)
2103
+ - `requireRecommendedSizes` (default `true`) – require all of `16`, `32`, `48`, `128` <a title="Introduced in v2.1.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0"><img height=14 alt="[Since v2.1.0]" src="https://img.shields.io/badge/since-v2.1.0-8a9199?style=flat-square" align="middle"></a>
2104
+ - `checkIconExists` (default `true`) – flag icon paths that don't resolve to an existing file <a title="Introduced in v2.1.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0"><img height=14 alt="[Since v2.1.0]" src="https://img.shields.io/badge/since-v2.1.0-8a9199?style=flat-square" align="middle"></a>
2105
+ - `noSVG` (default `true`) – flag SVG icon paths (unsupported by Chrome) <a title="Introduced in v2.1.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0"><img height=14 alt="[Since v2.1.0]" src="https://img.shields.io/badge/since-v2.1.0-8a9199?style=flat-square" align="middle"></a>
1646
2106
 
1647
2107
  #### <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
1648
2108
 
@@ -1696,11 +2156,13 @@ If your icons are injected at build time, or you target browsers that support SV
1696
2156
 
1697
2157
  <h3 id="valid-mv3-schema">
1698
2158
  <code>valid-mv3-schema</code>
2159
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
2160
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
1699
2161
  <a title="Included in recommended config" href="#usage">
1700
2162
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1701
2163
  <a title="Works in 'json/json' config block" href="#usage">
1702
2164
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1703
- <a title="Copy rule URL" target="_blank"
2165
+ <a title="Copy rule URL" target="_blank"
1704
2166
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-mv3-schema">
1705
2167
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1706
2168
  </h3>
@@ -1765,11 +2227,13 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1765
2227
 
1766
2228
  <h3 id="valid-service-worker">
1767
2229
  <code>valid-service-worker</code>
2230
+ <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
2231
+ <img height=18 align="middle" src="https://api.iconify.design/ph/flag-banner-fold-fill.svg?color=%234a4a4a"></a>
1768
2232
  <a title="Included in recommended config" href="#usage">
1769
2233
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1770
2234
  <a title="Accepts array w/ options" href="#usage">
1771
2235
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1772
- <a title="Copy rule URL" target="_blank"
2236
+ <a title="Copy rule URL" target="_blank"
1773
2237
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-service-worker">
1774
2238
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1775
2239
  </h3>
@@ -1778,11 +2242,11 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1778
2242
 
1779
2243
  <summary>Enforces valid service worker lifecycle and isolation.</summary>
1780
2244
 
1781
- <h4 id="mit-worker-options">Options</h4>
2245
+ <h4 id="valid-service-worker-options">Options</h4>
1782
2246
 
1783
- - `checkListenerTopLevel` (default `true`) – require `chrome.*.addListener()` calls at module top level
1784
- - `checkKeepaliveTimer` (default `true`) – flag sub-30s timers used as a keepalive workaround
1785
- - `checkDOMglobals` (default `true`) – flag DOM globals (`window`, `document`, `localStorage`) inside the service worker
2247
+ - `checkListenerTopLevel` (default `true`) – require `chrome.*.addListener()` calls at module top level <a title="Introduced in v2.5.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.5.0"><img height=14 alt="[Since v2.5.0]" src="https://img.shields.io/badge/since-v2.5.0-8a9199?style=flat-square" align="middle"></a>
2248
+ - `checkKeepaliveTimer` (default `true`) – flag sub-30s timers used as a keepalive workaround <a title="Introduced in v2.5.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.5.0"><img height=14 alt="[Since v2.5.0]" src="https://img.shields.io/badge/since-v2.5.0-8a9199?style=flat-square" align="middle"></a>
2249
+ - `checkDOMglobals` (default `true`) – flag DOM globals (`window`, `document`, `localStorage`) inside the service worker <a title="Introduced in v2.5.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.5.0"><img height=14 alt="[Since v2.5.0]" src="https://img.shields.io/badge/since-v2.5.0-8a9199?style=flat-square" align="middle"></a>
1786
2250
 
1787
2251
  #### <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
1788
2252
 
@@ -1836,11 +2300,15 @@ If your background context isn't a service worker.
1836
2300
 
1837
2301
  <h3 id="valid-url-fields">
1838
2302
  <code>valid-url-fields</code>
1839
- <a title="Only works in 'json/json' config block" href="#usage">
1840
- <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
2303
+ <a title="JS support added in recent release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.6.0">
2304
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
2305
+ <a title="Included in recommended config" href="#usage">
2306
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
2307
+ <a title="Works in 'json/json' config block" href="#usage">
2308
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1841
2309
  <a title="Accepts array w/ options" href="#usage">
1842
2310
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1843
- <a title="Copy rule URL" target="_blank"
2311
+ <a title="Copy rule URL" target="_blank"
1844
2312
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-url-fields">
1845
2313
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1846
2314
  </h3>
@@ -1851,10 +2319,10 @@ If your background context isn't a service worker.
1851
2319
 
1852
2320
  <h4 id="valid-url-fields-options">Options</h4>
1853
2321
 
1854
- - `checkURLfields` (default `true`) – validate URL fields (<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/chrome-settings-override">`chrome_settings_overrides`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/homepage-url">`homepage_url`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/oauth2">`oauth2.scopes`</a>, <a target="_blank" href="https://developer.chrome.com/docs/apps/autoupdate#update_url">`update_url`</a>)
1855
- - `checkMatchPatterns` (default `true`) – validate <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">match patterns</a> (in <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts">`content_scripts`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable">`externally_connectable`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#host-permissions">`host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">`optional_host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources">`web_accessible_resources`</a>)
1856
- - `allowedSchemes` (default `['https', 'file']`) – permitted URL schemes for <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">match patterns</a>
1857
- - `allowAllURLs` (default `false`) – allow unrestricted patterns (<a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`<all_urls>`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`https://*/*`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`*://*/*`</a>)
2322
+ - `checkURLfields` (default `true`) – validate URL fields (<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/chrome-settings-override">`chrome_settings_overrides`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/homepage-url">`homepage_url`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/oauth2">`oauth2.scopes`</a>, <a target="_blank" href="https://developer.chrome.com/docs/apps/autoupdate#update_url">`update_url`</a>) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
2323
+ - `checkMatchPatterns` (default `true`) – validate <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">match patterns</a> (in <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts">`content_scripts`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable">`externally_connectable`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#host-permissions">`host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">`optional_host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources">`web_accessible_resources`</a>) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
2324
+ - `allowedSchemes` (default `['https', 'file']`) – permitted URL schemes for <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">match patterns</a> <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
2325
+ - `allowAllURLs` (default `false`) – allow unrestricted patterns (<a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`<all_urls>`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`https://*/*`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`*://*/*`</a>) <a title="Introduced in v2.4.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0"><img height=14 alt="[Since v2.4.0]" src="https://img.shields.io/badge/since-v2.4.0-8a9199?style=flat-square" align="middle"></a>
1858
2326
 
1859
2327
  #### <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
1860
2328
 
@@ -1915,7 +2383,7 @@ If your URLs or patterns are generated at build time.
1915
2383
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1916
2384
  <a title="Accepts array w/ options" href="#usage">
1917
2385
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1918
- <a title="Copy rule URL" target="_blank"
2386
+ <a title="Copy rule URL" target="_blank"
1919
2387
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-version-field">
1920
2388
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1921
2389
  </h3>
@@ -1926,15 +2394,15 @@ If your URLs or patterns are generated at build time.
1926
2394
 
1927
2395
  <h4 id="valid-version-field-options">Options</h4>
1928
2396
 
1929
- - `versionType` (default `'chrome'`) – version format to enforce (`'chrome'`, `'semver'`, `'date'`)
1930
- - `allowFutureDate` (default `false`) – allow `version` dates later than the current date
1931
- - `timezone` (default `''`) – <a target="_blank" href="https://data.iana.org/time-zones/tzdb/zone1970.tab">IANA timezone</a> used to determine the current date (when omitted, only year/month are enforced)
2397
+ - `versionType` (default `'chrome'`) – version format to enforce (`'chrome'`, `'semver'`, `'date'`) <a title="Introduced in v2.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.0.0"><img height=14 alt="[Since v2.0.0]" src="https://img.shields.io/badge/since-v2.0.0-8a9199?style=flat-square" align="middle"></a>
2398
+ - `allowFutureDate` (default `false`) – allow `version` dates later than the current date <a title="Introduced in v2.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.0.0"><img height=14 alt="[Since v2.0.0]" src="https://img.shields.io/badge/since-v2.0.0-8a9199?style=flat-square" align="middle"></a>
2399
+ - `timezone` (default `''`) – <a target="_blank" href="https://data.iana.org/time-zones/tzdb/zone1970.tab">IANA timezone</a> used to determine the current date (when omitted, only year/month are enforced) <a title="Introduced in v2.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.0.0"><img height=14 alt="[Since v2.0.0]" src="https://img.shields.io/badge/since-v2.0.0-8a9199?style=flat-square" align="middle"></a>
1932
2400
 
1933
2401
  #### <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
1934
2402
 
1935
2403
  ```diff
1936
2404
  /* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
1937
-
2405
+
1938
2406
  {
1939
2407
  "manifest_version": 3,
1940
2408
  ! "version": "2026.1.111",
@@ -1946,7 +2414,7 @@ If your URLs or patterns are generated at build time.
1946
2414
 
1947
2415
  ```diff
1948
2416
  /* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
1949
-
2417
+
1950
2418
  {
1951
2419
  "manifest_version": 3,
1952
2420
  - "version": "2026.1.111",