eslint-plugin-chrome-extensions 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  ESLint rules for Chrome extensions.
14
14
 
15
- <img src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-chrome-extensions/0b5e3e49/assets/images/screenshots/vs-code/squiggles.png">
15
+ <img src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-chrome-extensions/04d2f53b22/assets/images/screenshots/vs-code/squiggles.png">
16
16
 
17
17
  ---
18
18
 
@@ -41,27 +41,25 @@ import json from '@eslint/json'
41
41
  export default [
42
42
  // other configs
43
43
  {
44
- files: ['extension/**/*.js'],
44
+ files: ['**/extension/**/*.js'],
45
45
  plugins: { 'chrome-extensions': chromeExtensions },
46
46
  rules: {
47
47
  ...chromeExtensions.configs.recommended.rules,
48
- 'chrome-extensions/no-insecure-messaging': 'off', // selectively disable rule
49
- 'chrome-extensions/no-deprecated-apis': ['error', { target: 'mv3' }] // selectively tweak rule
48
+ 'chrome-extensions/no-deprecated-apis': 'off' // selectively disable rule
50
49
  }
51
50
  },
52
51
  {
53
- files: ['extension/manifest.json'], language: 'json/json',
52
+ files: ['**/manifest.json'], language: 'json/json',
54
53
  plugins: { 'chrome-extensions': chromeExtensions, json },
55
54
  rules: {
56
55
  ...chromeExtensions.configs.manifest.rules,
57
- 'chrome-extensions/require-mv3': 'off', // selectively disable rule
58
56
  'chrome-extensions/valid-version-field': ['error', { versionType: 'date' }] // selectively tweak rule
59
57
  }
60
58
  }
61
59
  ]
62
60
  ```
63
61
 
64
- Available bundles: `recommended`, `strict` (everything), `problem` (deterministic bugs only), `manifest`
62
+ Available bundles: `recommended`, `strict` (everything), `problem` (deterministic bugs only), `security`, `manifest`
65
63
 
66
64
  **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
67
65
 
@@ -74,6 +72,8 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
74
72
 
75
73
  <h3 id="manifest-key-order">
76
74
  <code>manifest-key-order</code>
75
+ <a title="Only works w/ 'json/json' config block" href="#usage">
76
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
77
77
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
78
78
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
79
79
  <a title="Doesn't prevent bugs" href="#manifest-key-order">
@@ -89,7 +89,7 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
89
89
 
90
90
  <summary>Enforces a preferred order for manifest keys.</summary>
91
91
 
92
- #### Options
92
+ <h4 id="manifest-key-order-options">Options</h4>
93
93
 
94
94
  - `order` (default `[]`) – manifest keys in custom order (e.g. `['name', 'manifest_version']`) to selectively override built-in order with
95
95
 
@@ -99,8 +99,8 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
99
99
  /* eslint chrome-extensions/manifest-key-order: ['error', { order: ['name', 'manifest_version'] }] */
100
100
 
101
101
  {
102
- "manifest_version": 3,
103
- ! "name": "My Extension",
102
+ ! "manifest_version": 3,
103
+ "name": "My Extension",
104
104
  "version": "1.0.0"
105
105
  }
106
106
  ```
@@ -129,11 +129,102 @@ If you don't care about the order of manifest keys.
129
129
  #### See also
130
130
 
131
131
  - [`require-mv3`](#require-mv3)
132
+ <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>
133
+ <a title="Works w/ '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>
132
134
  - [`valid-mv3-schema`](#valid-mv3-schema)
135
+ <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>
136
+ <a title="Works w/ '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>
133
137
 
134
138
  <div align="center">
135
139
 
136
- [Back to index ↑][epc-rules]
140
+ [Back to index ↑][epce-rules]
141
+
142
+ </div>
143
+
144
+ ---
145
+
146
+ </details>
147
+
148
+ <h3 id="manifest-spacing">
149
+ <code>manifest-spacing</code>
150
+ <a title="Only works w/ 'json/json' config block" href="#usage">
151
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
152
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
153
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
154
+ <a title="Doesn't prevent bugs" href="#manifest-spacing">
155
+ <img height=18 alt="[Stylistic]" src="https://img.shields.io/badge/Stylistic-af68ff?style=flat-square" align="middle"></a>
156
+ <a title="Accepts array w/ options" href="#usage">
157
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
158
+ <a title="Copy rule URL" target="_blank"
159
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23manifest-spacing">
160
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
161
+ </h3>
162
+
163
+ <details>
164
+
165
+ <summary>Enforces consistent indentation and spacing in <code>manifest.json</code>.</summary>
166
+
167
+ <h4 id="manifest-spacing-options">Options</h4>
168
+
169
+ - `spaces` (default `2`) – number of spaces per indent level
170
+ - `checkColons` (default `true`) – enforce 0 spaces before and 1 space after `:` in key/value pairs
171
+ - `checkCommas` (default `true`) – enforce 0 spaces before and 1 space after `,` in inline objects
172
+ - `checkBraces` (default `true`) – enforce 1 space after `{` and before `}` in inline objects
173
+ - `checkBrackets` (default `true`) – enforce 0 spaces after `[` and before `]` in inline arrays
174
+
175
+ #### <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
176
+
177
+ ```diff
178
+ /* eslint chrome-extensions/manifest-spacing: ['error', { spaces: 2 }] */
179
+
180
+ {
181
+ ! "manifest_version": 3,
182
+ ! "version" : "1.0.0",
183
+ ! "permissions": [ "tabs","cookies" ],
184
+ ! "icons": {"16": "icon16.png"},
185
+ "name": "My Extension"
186
+ }
187
+ ```
188
+
189
+ #### <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
190
+
191
+ ```diff
192
+ /* eslint chrome-extensions/manifest-spacing: ['error', { spaces: 2 }] */
193
+
194
+ {
195
+ - "manifest_version": 3,
196
+ + "manifest_version": 3,
197
+ - "version" : "1.0.0",
198
+ + "version": "1.0.0",
199
+ - "permissions": [ "tabs","cookies" ],
200
+ + "permissions": ["tabs", "cookies"],
201
+ - "icons": {"16": "icon16.png"},
202
+ + "icons": { "16": "icon16.png" },
203
+ "name": "My Extension"
204
+ }
205
+ ```
206
+
207
+ #### When not to use it
208
+
209
+ If you don't care about visual consistency in your manifest.
210
+
211
+ #### Introduced in
212
+
213
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.2.0">v2.2.0</a> (October 12, 2026)
214
+
215
+ #### See also
216
+
217
+ - [`manifest-key-order`](#manifest-key-order)
218
+ <a title="Only works w/ '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>
219
+ <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>
220
+ <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>
221
+ <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>
222
+ - [`no-duplicate-manifest-keys`](#no-duplicate-manifest-keys)
223
+ <a title="Only works w/ '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>
224
+
225
+ <div align="center">
226
+
227
+ [Back to index ↑][epce-rules]
137
228
 
138
229
  </div>
139
230
 
@@ -180,12 +271,12 @@ If you intentionally interact w/ host page styles.
180
271
 
181
272
  #### See also
182
273
 
183
- - <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts">Chrome for Developers — Content scripts</a>
184
- - <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM">MDN — Using shadow DOM</a>
274
+ - <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/content-scripts">Chrome for Developers — Content scripts</a>
275
+ - <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>
185
276
 
186
277
  <div align="center">
187
278
 
188
- [Back to index ↑][epc-rules]
279
+ [Back to index ↑][epce-rules]
189
280
 
190
281
  </div>
191
282
 
@@ -208,7 +299,7 @@ If you intentionally interact w/ host page styles.
208
299
 
209
300
  <summary>Disallows deprecated <code>chrome</code> API calls.</summary>
210
301
 
211
- #### Options
302
+ <h4 id="no-deprecated-apis-options">Options</h4>
212
303
 
213
304
  - `target` (default `'mv3'`) – Chrome extension manifest version whose deprecations to validate against (`'mv3'`, `'mv2'`)
214
305
  - `allowedAPIs` (default `[]`) – additional deprecated API namespaces to allow, as a single string or array
@@ -246,11 +337,131 @@ If you don't want deprecation validation at all. For individual deprecated APIs
246
337
 
247
338
  #### See also
248
339
 
249
- - <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api">Chrome for Developers — API reference</a>
340
+ - <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">Chrome for Developers — API reference</a>
250
341
 
251
342
  <div align="center">
252
343
 
253
- [Back to index ↑][epc-rules]
344
+ [Back to index ↑][epce-rules]
345
+
346
+ </div>
347
+
348
+ ---
349
+
350
+ </details>
351
+
352
+ <h3 id="no-duplicate-manifest-keys">
353
+ <code>no-duplicate-manifest-keys</code>
354
+ <a title="Only works w/ 'json/json' config block" href="#usage">
355
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
356
+ <a title="Copy rule URL" target="_blank"
357
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-duplicate-manifest-keys">
358
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
359
+ </h3>
360
+
361
+ <details>
362
+
363
+ <summary>Disallows duplicate keys in <code>manifest.json</code>.</summary>
364
+
365
+ #### <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
366
+
367
+ ```diff
368
+ {
369
+ "manifest_version": 3,
370
+ ! "name": "Foo",
371
+ ! "name": "Bar",
372
+ ! "version": "1.0.0",
373
+ ! "version": "2.0.0"
374
+ }
375
+ ```
376
+
377
+ #### <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
378
+
379
+ ```diff
380
+ {
381
+ "manifest_version": 3,
382
+ - "name": "Foo",
383
+ - "name": "Bar",
384
+ "name": "My Extension",
385
+ - "version": "1.0.0",
386
+ - "version": "2.0.0"
387
+ "version": "1.0.0"
388
+ }
389
+ ```
390
+
391
+ #### When not to use it
392
+
393
+ If you rely on a Chromium fork resolving duplicate keys in a specific order.
394
+
395
+ #### Introduced in
396
+
397
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
398
+
399
+ #### See also
400
+
401
+ - [`manifest-key-order`](#manifest-key-order)
402
+ <a title="Only works w/ '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>
403
+ <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>
404
+ <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>
405
+ <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>
406
+ - [`no-unused-permissions`](#no-unused-permissions)
407
+ <a title="Only works w/ '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>
408
+
409
+ <div align="center">
410
+
411
+ [Back to index ↑][epce-rules]
412
+
413
+ </div>
414
+
415
+ ---
416
+
417
+ </details>
418
+
419
+ <h3 id="no-insecure-fetch">
420
+ <code>no-insecure-fetch</code>
421
+ <a title="Included in recommended config" href="#usage">
422
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
423
+ <a title="Included in security config" href="#usage">
424
+ <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
425
+ <a title="Copy rule URL" target="_blank"
426
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-fetch">
427
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
428
+ </h3>
429
+
430
+ <details>
431
+
432
+ <summary>Flags <code>fetch()</code> and <code>XMLHttpRequest.open()</code> calls that use <code>http://</code>.</summary>
433
+
434
+ #### <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
435
+
436
+ ```diff
437
+ ! fetch('http://api.example.com/data')
438
+ ! xhr.open('GET', 'http://cdn.example.com/lib.js')
439
+ ```
440
+
441
+ #### <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
442
+
443
+ ```diff
444
+ - fetch('http://api.example.com/data')
445
+ + fetch('https://api.example.com/data')
446
+ - xhr.open('GET', 'http://cdn.example.com/lib.js')
447
+ + xhr.open('GET', 'https://cdn.example.com/lib.js')
448
+ ```
449
+
450
+ #### When not to use it
451
+
452
+ If you intentionally target HTTP endpoints.
453
+
454
+ #### Introduced in
455
+
456
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
457
+
458
+ #### See also
459
+
460
+ - <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/network-requests">Chrome for Developers — Cross-origin network requests</a>
461
+
462
+ <div align="center">
463
+
464
+ [Back to index ↑][epce-rules]
254
465
 
255
466
  </div>
256
467
 
@@ -262,6 +473,10 @@ If you don't want deprecation validation at all. For individual deprecated APIs
262
473
  <code>no-insecure-messaging</code>
263
474
  <a title="Included in recommended config" href="#usage">
264
475
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
476
+ <a title="Included in security config" href="#usage">
477
+ <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
478
+ <a title="Accepts array w/ options" href="#usage">
479
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
265
480
  <a title="Copy rule URL" target="_blank"
266
481
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-messaging">
267
482
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
@@ -269,7 +484,11 @@ If you don't want deprecation validation at all. For individual deprecated APIs
269
484
 
270
485
  <details>
271
486
 
272
- <summary>Requires external message handlers validate <code>sender</code> + flags unfiltered <code>tabs.query()</code>.</summary>
487
+ <summary>Requires sender/origin validation + filtered <code>tabs.query()</code> + explicit <code>window.postMessage()</code> target.</summary>
488
+
489
+ <h4 id="no-insecure-messaging-options">Options</h4>
490
+
491
+ - `disallowWildcardTarget` (default `true`) – flag <code>postMessage()</code> calls that use <code>'*'</code> as <code>targetOrigin</code>
273
492
 
274
493
  #### <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
275
494
 
@@ -278,9 +497,15 @@ If you don't want deprecation validation at all. For individual deprecated APIs
278
497
  ! handle(msg)
279
498
  })
280
499
 
500
+ window.addEventListener('message', event => {
501
+ ! handle(event.data)
502
+ })
503
+
281
504
  ! chrome.tabs.query({})
282
505
  .then(tabs => tabs.forEach(tab =>
283
506
  chrome.tabs.sendMessage(tab.id, { action: 'ping' })))
507
+
508
+ ! window.postMessage(payload, '*')
284
509
  ```
285
510
 
286
511
  #### <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
@@ -291,15 +516,23 @@ If you don't want deprecation validation at all. For individual deprecated APIs
291
516
  handle(msg)
292
517
  })
293
518
 
519
+ window.addEventListener('message', event => {
520
+ + if (event.origin != 'https://allowed-origin.com') return
521
+ handle(event.data)
522
+ })
523
+
294
524
  - chrome.tabs.query({})
295
525
  + chrome.tabs.query({ url: 'https://allowed-origin.com/*' })
296
526
  .then(tabs => tabs.forEach(tab =>
297
527
  chrome.tabs.sendMessage(tab.id, { action: 'ping' })))
528
+
529
+ - window.postMessage(payload, '*')
530
+ + window.postMessage(payload, 'https://allowed-origin.com')
298
531
  ```
299
532
 
300
533
  #### When not to use it
301
534
 
302
- If you trust every external caller and open tab.
535
+ If you trust every external caller and open tab, or you intentionally broadcast to any origin.
303
536
 
304
537
  #### Introduced in
305
538
 
@@ -307,12 +540,13 @@ If you trust every external caller and open tab.
307
540
 
308
541
  #### See also
309
542
 
310
- - <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onMessageExternal">Chrome for Developers — `runtime.onMessageExternal`</a>
311
- - <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/tabs#method-query">Chrome for Developers — `tabs.query()`</a>
543
+ - <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/runtime#event-onMessageExternal">Chrome for Developers — `runtime.onMessageExternal`</a>
544
+ - <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/tabs#method-query">Chrome for Developers — `tabs.query()`</a>
545
+ - <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/Window/postMessage#security_concerns">MDN — `window.postMessage()` security concerns</a>
312
546
 
313
547
  <div align="center">
314
548
 
315
- [Back to index ↑][epc-rules]
549
+ [Back to index ↑][epce-rules]
316
550
 
317
551
  </div>
318
552
 
@@ -324,6 +558,8 @@ If you trust every external caller and open tab.
324
558
  <code>no-invalid-permissions</code>
325
559
  <a title="Included in recommended config" href="#usage">
326
560
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
561
+ <a title="Works w/ 'json/json' config block" href="#usage">
562
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
327
563
  <a title="Accepts array w/ options" href="#usage">
328
564
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
329
565
  <a title="Copy rule URL" target="_blank"
@@ -335,7 +571,7 @@ If you trust every external caller and open tab.
335
571
 
336
572
  <summary>Disallows invalid or unsupported manifest permission names.</summary>
337
573
 
338
- #### Options
574
+ <h4 id="no-invalid-permissions-options">Options</h4>
339
575
 
340
576
  - `target` (default `'mv3'`) – Chrome manifest version whose permissions to validate against (`'mv3'`, `'mv2'`)
341
577
  - `allowedPermissions` (default `[]`) – additional permission names to allow beyond the built-in list, as a single string or array
@@ -375,11 +611,13 @@ If you don't want permission validation at all. For custom permissions from a Ch
375
611
  #### See also
376
612
 
377
613
  - [`no-missing-permissions`](#no-missing-permissions)
614
+ <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>
378
615
  - [`no-unused-permissions`](#no-unused-permissions)
616
+ <a title="Only works w/ '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>
379
617
 
380
618
  <div align="center">
381
619
 
382
- [Back to index ↑][epc-rules]
620
+ [Back to index ↑][epce-rules]
383
621
 
384
622
  </div>
385
623
 
@@ -438,11 +676,78 @@ If you use APIs through aliases or wrappers that obscure the original call site.
438
676
  #### See also
439
677
 
440
678
  - [`no-invalid-permissions`](#no-invalid-permissions)
679
+ <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>
680
+ <a title="Works w/ '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>
681
+ <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>
441
682
  - [`no-unused-permissions`](#no-unused-permissions)
683
+ <a title="Only works w/ '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>
442
684
 
443
685
  <div align="center">
444
686
 
445
- [Back to index ↑][epc-rules]
687
+ [Back to index ↑][epce-rules]
688
+
689
+ </div>
690
+
691
+ ---
692
+
693
+ </details>
694
+
695
+ <h3 id="no-missing-web-accessible-resources">
696
+ <code>no-missing-web-accessible-resources</code>
697
+ <a title="Included in recommended config" href="#usage">
698
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
699
+ <a title="Copy rule URL" target="_blank"
700
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-web-accessible-resources">
701
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
702
+ </h3>
703
+
704
+ <details>
705
+
706
+ <summary>Flags <code>chrome.runtime.getURL()</code> paths missing from <code>web_accessible_resources</code>.</summary>
707
+
708
+ #### <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
709
+
710
+ ```diff
711
+ // manifest.json
712
+ {
713
+ "manifest_version": 3,
714
+ ! "web_accessible_resources": []
715
+ }
716
+
717
+ // content.js
718
+ ! img.src = chrome.runtime.getURL('logo.png')
719
+ ```
720
+
721
+ #### <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
722
+
723
+ ```diff
724
+ // manifest.json
725
+ {
726
+ "manifest_version": 3,
727
+ - "web_accessible_resources": []
728
+ + "web_accessible_resources": [{ "resources": ["logo.png"], "matches": ["<all_urls>"] }]
729
+ }
730
+
731
+ // content.js
732
+ img.src = chrome.runtime.getURL('logo.png')
733
+ ```
734
+
735
+ #### When not to use it
736
+
737
+ If your paths are built at runtime.
738
+
739
+ #### Introduced in
740
+
741
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
742
+
743
+ #### See also
744
+
745
+ - <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>
746
+ - <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/runtime#method-getURL">Chrome for Developers — `runtime.getURL()`</a>
747
+
748
+ <div align="center">
749
+
750
+ [Back to index ↑][epce-rules]
446
751
 
447
752
  </div>
448
753
 
@@ -454,6 +759,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
454
759
  <code>no-remote-code</code>
455
760
  <a title="Included in recommended config" href="#usage">
456
761
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
762
+ <a title="Included in security config" href="#usage">
763
+ <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
457
764
  <a title="Accepts array w/ options" href="#usage">
458
765
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
459
766
  <a title="Copy rule URL" target="_blank"
@@ -465,7 +772,7 @@ If you use APIs through aliases or wrappers that obscure the original call site.
465
772
 
466
773
  <summary>Disallows remote or dynamically-evaluated code (blocked by MV3's CSP at runtime).</summary>
467
774
 
468
- #### Options
775
+ <h4 id="no-remote-code-options">Options</h4>
469
776
 
470
777
  - `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
471
778
  - `checkExecuteScriptClosures` (default `true`) – additionally flag <code>chrome.scripting.executeScript({ func })</code> bodies that capture outer-scope variables
@@ -492,6 +799,10 @@ If you use APIs through aliases or wrappers that obscure the original call site.
492
799
  + chrome.scripting.executeScript({ target: { tabId }, func: doThing, args: [value] })
493
800
  ```
494
801
 
802
+ #### When not to use it
803
+
804
+ If you intentionally target forks w/ relaxed CSPs. For individual patterns you still need, prefer narrowing via `patterns` over disabling the rule.
805
+
495
806
  #### Introduced in
496
807
 
497
808
  <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">v1.0.0</a> (October 2, 2026)
@@ -499,11 +810,79 @@ If you use APIs through aliases or wrappers that obscure the original call site.
499
810
  #### See also
500
811
 
501
812
  - [`require-mv3`](#require-mv3)
813
+ <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>
814
+ <a title="Works w/ '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>
502
815
  - [`valid-mv3-schema`](#valid-mv3-schema)
816
+ <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>
817
+ <a title="Works w/ '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>
818
+
819
+ <div align="center">
820
+
821
+ [Back to index ↑][epce-rules]
822
+
823
+ </div>
824
+
825
+ ---
826
+
827
+ </details>
828
+
829
+ <h3 id="no-unrestricted-host-permissions">
830
+ <code>no-unrestricted-host-permissions</code>
831
+ <a title="Only works w/ 'json/json' config block" href="#usage">
832
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
833
+ <a title="Accepts array w/ options" href="#usage">
834
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
835
+ <a title="Copy rule URL" target="_blank"
836
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unrestricted-host-permissions">
837
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
838
+ </h3>
839
+
840
+ <details>
841
+
842
+ <summary>Disallows broad host permissions that grant access to every site.</summary>
843
+
844
+ <h4 id="no-unrestricted-host-permissions-options">Options</h4>
845
+
846
+ - `allowedPatterns` (default `[]`) – host patterns to explicitly allow (e.g. `['<all_urls>']`)
847
+
848
+ #### <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
849
+
850
+ ```diff
851
+ {
852
+ "manifest_version": 3,
853
+ ! "host_permissions": ["<all_urls>"],
854
+ ! "optional_host_permissions": ["*://*/*"]
855
+ }
856
+ ```
857
+
858
+ #### <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
859
+
860
+ ```diff
861
+ {
862
+ "manifest_version": 3,
863
+ - "host_permissions": ["<all_urls>"],
864
+ + "host_permissions": ["https://example.com/*", "https://*.trusted.com/*"],
865
+ - "optional_host_permissions": ["*://*/*"]
866
+ + "optional_host_permissions": ["https://user-content.example.com/*"]
867
+ }
868
+ ```
869
+
870
+ #### When not to use it
871
+
872
+ If you legitimately need broad access (e.g. ad blockers or dev tools).
873
+
874
+ #### Introduced in
875
+
876
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
877
+
878
+ #### See also
879
+
880
+ - <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>
881
+ - <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/match-patterns">Chrome for Developers — Match patterns</a>
503
882
 
504
883
  <div align="center">
505
884
 
506
- [Back to index ↑][epc-rules]
885
+ [Back to index ↑][epce-rules]
507
886
 
508
887
  </div>
509
888
 
@@ -513,8 +892,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
513
892
 
514
893
  <h3 id="no-unused-permissions">
515
894
  <code>no-unused-permissions</code>
516
- <a title="Included in recommended + strict configs" href="#usage">
517
- <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
895
+ <a title="Only works w/ 'json/json' config block" href="#usage">
896
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
518
897
  <a title="Copy rule URL" target="_blank"
519
898
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-permissions">
520
899
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
@@ -560,11 +939,15 @@ If you access the granted API through an alias or computed property rather than
560
939
  #### See also
561
940
 
562
941
  - [`no-invalid-permissions`](#no-invalid-permissions)
942
+ <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>
943
+ <a title="Works w/ '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>
944
+ <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>
563
945
  - [`no-missing-permissions`](#no-missing-permissions)
946
+ <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>
564
947
 
565
948
  <div align="center">
566
949
 
567
- [Back to index ↑][epc-rules]
950
+ [Back to index ↑][epce-rules]
568
951
 
569
952
  </div>
570
953
 
@@ -576,6 +959,8 @@ If you access the granted API through an alias or computed property rather than
576
959
  <code>require-mv3</code>
577
960
  <a title="Included in recommended config" href="#usage">
578
961
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
962
+ <a title="Works w/ 'json/json' config block" href="#usage">
963
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
579
964
  <a title="Copy rule URL" target="_blank"
580
965
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-mv3">
581
966
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
@@ -608,7 +993,7 @@ If you access the granted API through an alias or computed property rather than
608
993
 
609
994
  #### When not to use it
610
995
 
611
- If you intentionally target MV2 for a Chromium fork that still supports it.
996
+ If you intentionally target MV2 for a browser that still supports it (e.g. Firefox).
612
997
 
613
998
  #### Introduced in
614
999
 
@@ -617,10 +1002,83 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
617
1002
  #### See also
618
1003
 
619
1004
  - [`valid-mv3-schema`](#valid-mv3-schema)
1005
+ <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>
1006
+ <a title="Works w/ '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>
1007
+
1008
+ <div align="center">
1009
+
1010
+ [Back to index ↑][epce-rules]
1011
+
1012
+ </div>
1013
+
1014
+ ---
1015
+
1016
+ </details>
1017
+
1018
+ <h3 id="valid-manifest-icons">
1019
+ <code>valid-manifest-icons</code>
1020
+ <a title="Only works w/ 'json/json' config block" href="#usage">
1021
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1022
+ <a title="Accepts array w/ options" href="#usage">
1023
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1024
+ <a title="Copy rule URL" target="_blank"
1025
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-manifest-icons">
1026
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1027
+ </h3>
1028
+
1029
+ <details>
1030
+
1031
+ <summary>Ensures manifest <code>icons</code> exist and use the recommended sizes.</summary>
1032
+
1033
+ <h4 id="valid-manifest-icons-options">Options</h4>
1034
+
1035
+ - `requireRecommendedSizes` (default `true`) – require all of `16`, `32`, `48`, `128`
1036
+ - `checkIconExists` (default `true`) – flag icon paths that don't resolve to an existing file
1037
+ - `noSVG` (default `true`) – flag SVG icon paths (unsupported by Chrome)
1038
+
1039
+ #### <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
1040
+
1041
+ ```diff
1042
+ {
1043
+ "manifest_version": 3,
1044
+ "icons": {
1045
+ ! "48": "icon48.svg",
1046
+ "256": "icon256.png"
1047
+ }
1048
+ }
1049
+ ```
1050
+
1051
+ #### <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
1052
+
1053
+ ```diff
1054
+ {
1055
+ "manifest_version": 3,
1056
+ "icons": {
1057
+ + "16": "icon16.png",
1058
+ + "32": "icon32.png",
1059
+ - "48": "icon48.svg",
1060
+ + "48": "icon48.png",
1061
+ + "128": "icon128.png",
1062
+ "256": "icon256.png"
1063
+ }
1064
+ }
1065
+ ```
1066
+
1067
+ #### When not to use it
1068
+
1069
+ If your icons are injected at build time, or you target browsers that support SVGs (e.g. Firefox).
1070
+
1071
+ #### Introduced in
1072
+
1073
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
1074
+
1075
+ #### See also
1076
+
1077
+ - <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/icons">Chrome for Developers — `icons`</a>
620
1078
 
621
1079
  <div align="center">
622
1080
 
623
- [Back to index ↑][epc-rules]
1081
+ [Back to index ↑][epce-rules]
624
1082
 
625
1083
  </div>
626
1084
 
@@ -632,6 +1090,8 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
632
1090
  <code>valid-mv3-schema</code>
633
1091
  <a title="Included in recommended config" href="#usage">
634
1092
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1093
+ <a title="Works w/ 'json/json' config block" href="#usage">
1094
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
635
1095
  <a title="Copy rule URL" target="_blank"
636
1096
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-mv3-schema">
637
1097
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
@@ -670,7 +1130,7 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
670
1130
 
671
1131
  #### When not to use it
672
1132
 
673
- If you intentionally target MV2 for a Chromium fork that still supports it.
1133
+ If you intentionally target MV2 for a browser that still supports it (e.g. Firefox).
674
1134
 
675
1135
  #### Introduced in
676
1136
 
@@ -679,11 +1139,15 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
679
1139
  #### See also
680
1140
 
681
1141
  - [`require-mv3`](#require-mv3)
1142
+ <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>
1143
+ <a title="Works w/ '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>
682
1144
  - [`no-deprecated-apis`](#no-deprecated-apis)
1145
+ <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>
1146
+ <a title="Accepts array w/ options" href="#no-deprecated-apis-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
683
1147
 
684
1148
  <div align="center">
685
1149
 
686
- [Back to index ↑][epc-rules]
1150
+ [Back to index ↑][epce-rules]
687
1151
 
688
1152
  </div>
689
1153
 
@@ -737,11 +1201,16 @@ If your background context isn't a service worker.
737
1201
  #### See also
738
1202
 
739
1203
  - [`require-mv3`](#require-mv3)
1204
+ <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>
1205
+ <a title="Works w/ '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>
740
1206
  - [`no-remote-code`](#no-remote-code)
1207
+ <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>
1208
+ <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>
1209
+ <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>
741
1210
 
742
1211
  <div align="center">
743
1212
 
744
- [Back to index ↑][epc-rules]
1213
+ [Back to index ↑][epce-rules]
745
1214
 
746
1215
  </div>
747
1216
 
@@ -753,6 +1222,8 @@ If your background context isn't a service worker.
753
1222
  <code>valid-version-field</code>
754
1223
  <a title="Included in recommended config" href="#usage">
755
1224
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1225
+ <a title="Works w/ 'json/json' config block" href="#usage">
1226
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
756
1227
  <a title="Accepts array w/ options" href="#usage">
757
1228
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
758
1229
  <a title="Copy rule URL" target="_blank"
@@ -764,7 +1235,7 @@ If your background context isn't a service worker.
764
1235
 
765
1236
  <summary>Validates the manifest <code>version</code> field.</summary>
766
1237
 
767
- #### Options
1238
+ <h4 id="valid-version-field-options">Options</h4>
768
1239
 
769
1240
  - `versionType` (default `'chrome'`) – version format to enforce (`'chrome'`, `'semver'`, `'date'`)
770
1241
  - `allowFutureDate` (default `false`) – allow `version` dates later than the current date
@@ -775,7 +1246,6 @@ If your background context isn't a service worker.
775
1246
  ```diff
776
1247
  /* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
777
1248
 
778
- // manifest.json
779
1249
  {
780
1250
  "manifest_version": 3,
781
1251
  ! "version": "2026.1.111",
@@ -788,7 +1258,6 @@ If your background context isn't a service worker.
788
1258
  ```diff
789
1259
  /* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
790
1260
 
791
- // manifest.json
792
1261
  {
793
1262
  "manifest_version": 3,
794
1263
  - "version": "2026.1.111",
@@ -807,11 +1276,11 @@ If you don't care about version format consistency, or your version is injected
807
1276
 
808
1277
  #### See also
809
1278
 
810
- - <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/version">Chrome for Developers — `version`</a>
1279
+ - <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/version">Chrome for Developers — `version`</a>
811
1280
 
812
1281
  <div align="center">
813
1282
 
814
- [Back to index ↑][epc-rules]
1283
+ [Back to index ↑][epce-rules]
815
1284
 
816
1285
  </div>
817
1286
 
@@ -902,4 +1371,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
902
1371
 
903
1372
  <!-- Links -->
904
1373
 
905
- [epc-rules]: #supported-rules
1374
+ [epce-rules]: #supported-rules