eslint-plugin-chrome-extensions 2.0.0 → 2.1.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 +377 -28
- package/package.json +2 -2
- package/src/data/deprecations.js +10 -0
- package/src/index.js +25 -3
- package/src/rules/manifest-key-order.js +3 -2
- package/src/rules/no-duplicate-manifest-keys.js +36 -0
- package/src/rules/no-insecure-fetch.js +52 -0
- package/src/rules/no-insecure-messaging.js +44 -7
- package/src/rules/no-invalid-permissions.js +2 -2
- package/src/rules/no-missing-web-accessible-resources.js +51 -0
- package/src/rules/no-remote-code.js +11 -9
- package/src/rules/no-unrestricted-host-permissions.js +54 -0
- package/src/rules/no-unused-permissions.js +1 -1
- package/src/rules/require-mv3.js +2 -2
- package/src/rules/valid-manifest-icons.js +85 -0
- package/src/rules/valid-mv3-schema.js +3 -2
- package/src/rules/valid-service-worker.js +1 -1
- package/src/rules/valid-version-field.js +3 -3
- package/src/utils.js +16 -2
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/
|
|
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
|
|
|
@@ -45,8 +45,7 @@ export default [
|
|
|
45
45
|
plugins: { 'chrome-extensions': chromeExtensions },
|
|
46
46
|
rules: {
|
|
47
47
|
...chromeExtensions.configs.recommended.rules,
|
|
48
|
-
'chrome-extensions/no-
|
|
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
|
{
|
|
@@ -54,14 +53,13 @@ export default [
|
|
|
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-32fcee?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">
|
|
@@ -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
|
-
|
|
103
|
-
|
|
102
|
+
! "manifest_version": 3,
|
|
103
|
+
"name": "My Extension",
|
|
104
104
|
"version": "1.0.0"
|
|
105
105
|
}
|
|
106
106
|
```
|
|
@@ -133,7 +133,7 @@ If you don't care about the order of manifest keys.
|
|
|
133
133
|
|
|
134
134
|
<div align="center">
|
|
135
135
|
|
|
136
|
-
[Back to index ↑][
|
|
136
|
+
[Back to index ↑][epce-rules]
|
|
137
137
|
|
|
138
138
|
</div>
|
|
139
139
|
|
|
@@ -185,7 +185,7 @@ If you intentionally interact w/ host page styles.
|
|
|
185
185
|
|
|
186
186
|
<div align="center">
|
|
187
187
|
|
|
188
|
-
[Back to index ↑][
|
|
188
|
+
[Back to index ↑][epce-rules]
|
|
189
189
|
|
|
190
190
|
</div>
|
|
191
191
|
|
|
@@ -250,7 +250,123 @@ If you don't want deprecation validation at all. For individual deprecated APIs
|
|
|
250
250
|
|
|
251
251
|
<div align="center">
|
|
252
252
|
|
|
253
|
-
[Back to index ↑][
|
|
253
|
+
[Back to index ↑][epce-rules]
|
|
254
|
+
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
</details>
|
|
260
|
+
|
|
261
|
+
<h3 id="no-duplicate-manifest-keys">
|
|
262
|
+
<code>no-duplicate-manifest-keys</code>
|
|
263
|
+
<a title="Only works w/ 'json/json' config block" href="#usage">
|
|
264
|
+
<img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-32fcee?style=flat-square" align="middle"></a>
|
|
265
|
+
<a title="Copy rule URL" target="_blank"
|
|
266
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-duplicate-manifest-keys">
|
|
267
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
268
|
+
</h3>
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
|
|
272
|
+
<summary>Disallows duplicate keys in <code>manifest.json</code>.</summary>
|
|
273
|
+
|
|
274
|
+
#### <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
|
+
|
|
276
|
+
```diff
|
|
277
|
+
{
|
|
278
|
+
"manifest_version": 3,
|
|
279
|
+
! "name": "Foo",
|
|
280
|
+
! "name": "Bar",
|
|
281
|
+
! "version": "1.0.0",
|
|
282
|
+
! "version": "2.0.0"
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### <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
|
|
287
|
+
|
|
288
|
+
```diff
|
|
289
|
+
{
|
|
290
|
+
"manifest_version": 3,
|
|
291
|
+
- "name": "Foo",
|
|
292
|
+
- "name": "Bar",
|
|
293
|
+
"name": "My Extension",
|
|
294
|
+
- "version": "1.0.0",
|
|
295
|
+
- "version": "2.0.0"
|
|
296
|
+
"version": "1.0.0"
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### When not to use it
|
|
301
|
+
|
|
302
|
+
If you rely on a Chromium fork resolving duplicate keys in a specific order.
|
|
303
|
+
|
|
304
|
+
#### Introduced in
|
|
305
|
+
|
|
306
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
|
|
307
|
+
|
|
308
|
+
#### See also
|
|
309
|
+
|
|
310
|
+
- [`manifest-key-order`](#manifest-key-order)
|
|
311
|
+
- [`no-unused-permissions`](#no-unused-permissions)
|
|
312
|
+
|
|
313
|
+
<div align="center">
|
|
314
|
+
|
|
315
|
+
[Back to index ↑][epce-rules]
|
|
316
|
+
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
</details>
|
|
322
|
+
|
|
323
|
+
<h3 id="no-insecure-fetch">
|
|
324
|
+
<code>no-insecure-fetch</code>
|
|
325
|
+
<a title="Included in recommended config" href="#usage">
|
|
326
|
+
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
327
|
+
<a title="Included in security config" href="#usage">
|
|
328
|
+
<img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
|
|
329
|
+
<a title="Copy rule URL" target="_blank"
|
|
330
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-fetch">
|
|
331
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
332
|
+
</h3>
|
|
333
|
+
|
|
334
|
+
<details>
|
|
335
|
+
|
|
336
|
+
<summary>Flags <code>fetch()</code> and <code>XMLHttpRequest.open()</code> calls that use <code>http://</code>.</summary>
|
|
337
|
+
|
|
338
|
+
#### <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
|
|
339
|
+
|
|
340
|
+
```diff
|
|
341
|
+
! fetch('http://api.example.com/data')
|
|
342
|
+
! xhr.open('GET', 'http://cdn.example.com/lib.js')
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### <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
|
|
346
|
+
|
|
347
|
+
```diff
|
|
348
|
+
- fetch('http://api.example.com/data')
|
|
349
|
+
+ fetch('https://api.example.com/data')
|
|
350
|
+
- xhr.open('GET', 'http://cdn.example.com/lib.js')
|
|
351
|
+
+ xhr.open('GET', 'https://cdn.example.com/lib.js')
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### When not to use it
|
|
355
|
+
|
|
356
|
+
If you intentionally target HTTP endpoints.
|
|
357
|
+
|
|
358
|
+
#### Introduced in
|
|
359
|
+
|
|
360
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
|
|
361
|
+
|
|
362
|
+
#### See also
|
|
363
|
+
|
|
364
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/network-requests">Chrome for Developers — Cross-origin network requests</a>
|
|
365
|
+
- [`no-remote-code`](#no-remote-code)
|
|
366
|
+
|
|
367
|
+
<div align="center">
|
|
368
|
+
|
|
369
|
+
[Back to index ↑][epce-rules]
|
|
254
370
|
|
|
255
371
|
</div>
|
|
256
372
|
|
|
@@ -262,6 +378,10 @@ If you don't want deprecation validation at all. For individual deprecated APIs
|
|
|
262
378
|
<code>no-insecure-messaging</code>
|
|
263
379
|
<a title="Included in recommended config" href="#usage">
|
|
264
380
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
381
|
+
<a title="Included in security config" href="#usage">
|
|
382
|
+
<img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
|
|
383
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
384
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
265
385
|
<a title="Copy rule URL" target="_blank"
|
|
266
386
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-insecure-messaging">
|
|
267
387
|
<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 +389,11 @@ If you don't want deprecation validation at all. For individual deprecated APIs
|
|
|
269
389
|
|
|
270
390
|
<details>
|
|
271
391
|
|
|
272
|
-
<summary>Requires
|
|
392
|
+
<summary>Requires sender/origin validation + filtered <code>tabs.query()</code> + explicit <code>window.postMessage()</code> target.</summary>
|
|
393
|
+
|
|
394
|
+
#### Options
|
|
395
|
+
|
|
396
|
+
- `disallowWildcardTarget` (default `true`) – flag <code>postMessage()</code> calls that use <code>'*'</code> as <code>targetOrigin</code>
|
|
273
397
|
|
|
274
398
|
#### <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
399
|
|
|
@@ -278,9 +402,15 @@ If you don't want deprecation validation at all. For individual deprecated APIs
|
|
|
278
402
|
! handle(msg)
|
|
279
403
|
})
|
|
280
404
|
|
|
405
|
+
window.addEventListener('message', event => {
|
|
406
|
+
! handle(event.data)
|
|
407
|
+
})
|
|
408
|
+
|
|
281
409
|
! chrome.tabs.query({})
|
|
282
410
|
.then(tabs => tabs.forEach(tab =>
|
|
283
411
|
chrome.tabs.sendMessage(tab.id, { action: 'ping' })))
|
|
412
|
+
|
|
413
|
+
! window.postMessage(payload, '*')
|
|
284
414
|
```
|
|
285
415
|
|
|
286
416
|
#### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
|
|
@@ -291,15 +421,23 @@ If you don't want deprecation validation at all. For individual deprecated APIs
|
|
|
291
421
|
handle(msg)
|
|
292
422
|
})
|
|
293
423
|
|
|
424
|
+
window.addEventListener('message', event => {
|
|
425
|
+
+ if (event.origin != 'https://allowed-origin.com') return
|
|
426
|
+
handle(event.data)
|
|
427
|
+
})
|
|
428
|
+
|
|
294
429
|
- chrome.tabs.query({})
|
|
295
430
|
+ chrome.tabs.query({ url: 'https://allowed-origin.com/*' })
|
|
296
431
|
.then(tabs => tabs.forEach(tab =>
|
|
297
432
|
chrome.tabs.sendMessage(tab.id, { action: 'ping' })))
|
|
433
|
+
|
|
434
|
+
- window.postMessage(payload, '*')
|
|
435
|
+
+ window.postMessage(payload, 'https://allowed-origin.com')
|
|
298
436
|
```
|
|
299
437
|
|
|
300
438
|
#### When not to use it
|
|
301
439
|
|
|
302
|
-
If you trust every external caller and open tab.
|
|
440
|
+
If you trust every external caller and open tab, or you intentionally broadcast to any origin.
|
|
303
441
|
|
|
304
442
|
#### Introduced in
|
|
305
443
|
|
|
@@ -309,10 +447,11 @@ If you trust every external caller and open tab.
|
|
|
309
447
|
|
|
310
448
|
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/runtime#event-onMessageExternal">Chrome for Developers — `runtime.onMessageExternal`</a>
|
|
311
449
|
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/tabs#method-query">Chrome for Developers — `tabs.query()`</a>
|
|
450
|
+
- <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns">MDN — `window.postMessage()` security concerns</a>
|
|
312
451
|
|
|
313
452
|
<div align="center">
|
|
314
453
|
|
|
315
|
-
[Back to index ↑][
|
|
454
|
+
[Back to index ↑][epce-rules]
|
|
316
455
|
|
|
317
456
|
</div>
|
|
318
457
|
|
|
@@ -324,6 +463,8 @@ If you trust every external caller and open tab.
|
|
|
324
463
|
<code>no-invalid-permissions</code>
|
|
325
464
|
<a title="Included in recommended config" href="#usage">
|
|
326
465
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
466
|
+
<a title="Works w/ 'json/json' config block" href="#usage">
|
|
467
|
+
<img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-32fcee?style=flat-square" align="middle"></a>
|
|
327
468
|
<a title="Accepts array w/ options" href="#usage">
|
|
328
469
|
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
329
470
|
<a title="Copy rule URL" target="_blank"
|
|
@@ -379,7 +520,7 @@ If you don't want permission validation at all. For custom permissions from a Ch
|
|
|
379
520
|
|
|
380
521
|
<div align="center">
|
|
381
522
|
|
|
382
|
-
[Back to index ↑][
|
|
523
|
+
[Back to index ↑][epce-rules]
|
|
383
524
|
|
|
384
525
|
</div>
|
|
385
526
|
|
|
@@ -442,7 +583,70 @@ If you use APIs through aliases or wrappers that obscure the original call site.
|
|
|
442
583
|
|
|
443
584
|
<div align="center">
|
|
444
585
|
|
|
445
|
-
[Back to index ↑][
|
|
586
|
+
[Back to index ↑][epce-rules]
|
|
587
|
+
|
|
588
|
+
</div>
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
</details>
|
|
593
|
+
|
|
594
|
+
<h3 id="no-missing-web-accessible-resources">
|
|
595
|
+
<code>no-missing-web-accessible-resources</code>
|
|
596
|
+
<a title="Included in recommended config" href="#usage">
|
|
597
|
+
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
598
|
+
<a title="Copy rule URL" target="_blank"
|
|
599
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-web-accessible-resources">
|
|
600
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
601
|
+
</h3>
|
|
602
|
+
|
|
603
|
+
<details>
|
|
604
|
+
|
|
605
|
+
<summary>Flags <code>chrome.runtime.getURL()</code> paths missing from <code>web_accessible_resources</code>.</summary>
|
|
606
|
+
|
|
607
|
+
#### <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
|
|
608
|
+
|
|
609
|
+
```diff
|
|
610
|
+
// manifest.json
|
|
611
|
+
{
|
|
612
|
+
"manifest_version": 3,
|
|
613
|
+
! "web_accessible_resources": []
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// content.js
|
|
617
|
+
! img.src = chrome.runtime.getURL('logo.png')
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### <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
|
|
621
|
+
|
|
622
|
+
```diff
|
|
623
|
+
// manifest.json
|
|
624
|
+
{
|
|
625
|
+
"manifest_version": 3,
|
|
626
|
+
- "web_accessible_resources": []
|
|
627
|
+
+ "web_accessible_resources": [{ "resources": ["logo.png"], "matches": ["<all_urls>"] }]
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// content.js
|
|
631
|
+
img.src = chrome.runtime.getURL('logo.png')
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### When not to use it
|
|
635
|
+
|
|
636
|
+
If your paths are built at runtime.
|
|
637
|
+
|
|
638
|
+
#### Introduced in
|
|
639
|
+
|
|
640
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
|
|
641
|
+
|
|
642
|
+
#### See also
|
|
643
|
+
|
|
644
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources">Chrome for Developers — `web_accessible_resources`</a>
|
|
645
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/runtime#method-getURL">Chrome for Developers — `runtime.getURL()`</a>
|
|
646
|
+
|
|
647
|
+
<div align="center">
|
|
648
|
+
|
|
649
|
+
[Back to index ↑][epce-rules]
|
|
446
650
|
|
|
447
651
|
</div>
|
|
448
652
|
|
|
@@ -454,6 +658,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
|
|
|
454
658
|
<code>no-remote-code</code>
|
|
455
659
|
<a title="Included in recommended config" href="#usage">
|
|
456
660
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
661
|
+
<a title="Included in security config" href="#usage">
|
|
662
|
+
<img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
|
|
457
663
|
<a title="Accepts array w/ options" href="#usage">
|
|
458
664
|
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
459
665
|
<a title="Copy rule URL" target="_blank"
|
|
@@ -492,6 +698,10 @@ If you use APIs through aliases or wrappers that obscure the original call site.
|
|
|
492
698
|
+ chrome.scripting.executeScript({ target: { tabId }, func: doThing, args: [value] })
|
|
493
699
|
```
|
|
494
700
|
|
|
701
|
+
#### When not to use it
|
|
702
|
+
|
|
703
|
+
If you intentionally target forks w/ relaxed CSPs. For individual patterns you still need, prefer narrowing via `patterns` over disabling the rule.
|
|
704
|
+
|
|
495
705
|
#### Introduced in
|
|
496
706
|
|
|
497
707
|
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">v1.0.0</a> (October 2, 2026)
|
|
@@ -503,7 +713,71 @@ If you use APIs through aliases or wrappers that obscure the original call site.
|
|
|
503
713
|
|
|
504
714
|
<div align="center">
|
|
505
715
|
|
|
506
|
-
[Back to index ↑][
|
|
716
|
+
[Back to index ↑][epce-rules]
|
|
717
|
+
|
|
718
|
+
</div>
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
</details>
|
|
723
|
+
|
|
724
|
+
<h3 id="no-unrestricted-host-permissions">
|
|
725
|
+
<code>no-unrestricted-host-permissions</code>
|
|
726
|
+
<a title="Only works w/ 'json/json' config block" href="#usage">
|
|
727
|
+
<img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-32fcee?style=flat-square" align="middle"></a>
|
|
728
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
729
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
730
|
+
<a title="Copy rule URL" target="_blank"
|
|
731
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unrestricted-host-permissions">
|
|
732
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
733
|
+
</h3>
|
|
734
|
+
|
|
735
|
+
<details>
|
|
736
|
+
|
|
737
|
+
<summary>Disallows broad host permissions that grant access to every site.</summary>
|
|
738
|
+
|
|
739
|
+
#### Options
|
|
740
|
+
|
|
741
|
+
- `allowedPatterns` (default `[]`) – host patterns to explicitly allow (e.g. `['<all_urls>']`)
|
|
742
|
+
|
|
743
|
+
#### <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
|
|
744
|
+
|
|
745
|
+
```diff
|
|
746
|
+
{
|
|
747
|
+
"manifest_version": 3,
|
|
748
|
+
! "host_permissions": ["<all_urls>"],
|
|
749
|
+
! "optional_host_permissions": ["*://*/*"]
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
#### <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
|
|
754
|
+
|
|
755
|
+
```diff
|
|
756
|
+
{
|
|
757
|
+
"manifest_version": 3,
|
|
758
|
+
- "host_permissions": ["<all_urls>"],
|
|
759
|
+
+ "host_permissions": ["https://example.com/*", "https://*.trusted.com/*"],
|
|
760
|
+
- "optional_host_permissions": ["*://*/*"]
|
|
761
|
+
+ "optional_host_permissions": ["https://user-content.example.com/*"]
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
#### When not to use it
|
|
766
|
+
|
|
767
|
+
If you legitimately need broad access (e.g. ad blockers or dev tools).
|
|
768
|
+
|
|
769
|
+
#### Introduced in
|
|
770
|
+
|
|
771
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
|
|
772
|
+
|
|
773
|
+
#### See also
|
|
774
|
+
|
|
775
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">Chrome for Developers — Declare permissions</a>
|
|
776
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">Chrome for Developers — Match patterns</a>
|
|
777
|
+
|
|
778
|
+
<div align="center">
|
|
779
|
+
|
|
780
|
+
[Back to index ↑][epce-rules]
|
|
507
781
|
|
|
508
782
|
</div>
|
|
509
783
|
|
|
@@ -513,8 +787,8 @@ If you use APIs through aliases or wrappers that obscure the original call site.
|
|
|
513
787
|
|
|
514
788
|
<h3 id="no-unused-permissions">
|
|
515
789
|
<code>no-unused-permissions</code>
|
|
516
|
-
<a title="
|
|
517
|
-
<img height=18 alt="[
|
|
790
|
+
<a title="Only works w/ 'json/json' config block" href="#usage">
|
|
791
|
+
<img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-32fcee?style=flat-square" align="middle"></a>
|
|
518
792
|
<a title="Copy rule URL" target="_blank"
|
|
519
793
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-permissions">
|
|
520
794
|
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
@@ -564,7 +838,7 @@ If you access the granted API through an alias or computed property rather than
|
|
|
564
838
|
|
|
565
839
|
<div align="center">
|
|
566
840
|
|
|
567
|
-
[Back to index ↑][
|
|
841
|
+
[Back to index ↑][epce-rules]
|
|
568
842
|
|
|
569
843
|
</div>
|
|
570
844
|
|
|
@@ -576,6 +850,8 @@ If you access the granted API through an alias or computed property rather than
|
|
|
576
850
|
<code>require-mv3</code>
|
|
577
851
|
<a title="Included in recommended config" href="#usage">
|
|
578
852
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
853
|
+
<a title="Works w/ 'json/json' config block" href="#usage">
|
|
854
|
+
<img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-32fcee?style=flat-square" align="middle"></a>
|
|
579
855
|
<a title="Copy rule URL" target="_blank"
|
|
580
856
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-mv3">
|
|
581
857
|
<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 +884,7 @@ If you access the granted API through an alias or computed property rather than
|
|
|
608
884
|
|
|
609
885
|
#### When not to use it
|
|
610
886
|
|
|
611
|
-
If you intentionally target MV2 for a
|
|
887
|
+
If you intentionally target MV2 for a browser that still supports it (e.g. Firefox).
|
|
612
888
|
|
|
613
889
|
#### Introduced in
|
|
614
890
|
|
|
@@ -620,7 +896,78 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
|
|
|
620
896
|
|
|
621
897
|
<div align="center">
|
|
622
898
|
|
|
623
|
-
[Back to index ↑][
|
|
899
|
+
[Back to index ↑][epce-rules]
|
|
900
|
+
|
|
901
|
+
</div>
|
|
902
|
+
|
|
903
|
+
---
|
|
904
|
+
|
|
905
|
+
</details>
|
|
906
|
+
|
|
907
|
+
<h3 id="valid-manifest-icons">
|
|
908
|
+
<code>valid-manifest-icons</code>
|
|
909
|
+
<a title="Only works w/ 'json/json' config block" href="#usage">
|
|
910
|
+
<img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-32fcee?style=flat-square" align="middle"></a>
|
|
911
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
912
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
913
|
+
<a title="Copy rule URL" target="_blank"
|
|
914
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-manifest-icons">
|
|
915
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
916
|
+
</h3>
|
|
917
|
+
|
|
918
|
+
<details>
|
|
919
|
+
|
|
920
|
+
<summary>Ensures manifest <code>icons</code> exist and use the recommended sizes.</summary>
|
|
921
|
+
|
|
922
|
+
#### Options
|
|
923
|
+
|
|
924
|
+
- `requireRecommendedSizes` (default `true`) – require all of `16`, `32`, `48`, `128`
|
|
925
|
+
- `checkIconExists` (default `true`) – flag icon paths that don't resolve to an existing file
|
|
926
|
+
- `noSVG` (default `true`) – flag SVG icon paths (unsupported by Chrome)
|
|
927
|
+
|
|
928
|
+
#### <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
|
|
929
|
+
|
|
930
|
+
```diff
|
|
931
|
+
{
|
|
932
|
+
"manifest_version": 3,
|
|
933
|
+
"icons": {
|
|
934
|
+
! "48": "icon48.svg",
|
|
935
|
+
"256": "icon256.png"
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
#### <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
|
|
941
|
+
|
|
942
|
+
```diff
|
|
943
|
+
{
|
|
944
|
+
"manifest_version": 3,
|
|
945
|
+
"icons": {
|
|
946
|
+
+ "16": "icon16.png",
|
|
947
|
+
+ "32": "icon32.png",
|
|
948
|
+
- "48": "icon48.svg",
|
|
949
|
+
+ "48": "icon48.png",
|
|
950
|
+
+ "128": "icon128.png",
|
|
951
|
+
"256": "icon256.png"
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
#### When not to use it
|
|
957
|
+
|
|
958
|
+
If your icons are injected at build time, or you target browsers that support SVGs (e.g. Firefox).
|
|
959
|
+
|
|
960
|
+
#### Introduced in
|
|
961
|
+
|
|
962
|
+
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.1.0">v2.1.0</a> (October 5, 2026)
|
|
963
|
+
|
|
964
|
+
#### See also
|
|
965
|
+
|
|
966
|
+
- <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/icons">Chrome for Developers — `icons`</a>
|
|
967
|
+
|
|
968
|
+
<div align="center">
|
|
969
|
+
|
|
970
|
+
[Back to index ↑][epce-rules]
|
|
624
971
|
|
|
625
972
|
</div>
|
|
626
973
|
|
|
@@ -632,6 +979,8 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
|
|
|
632
979
|
<code>valid-mv3-schema</code>
|
|
633
980
|
<a title="Included in recommended config" href="#usage">
|
|
634
981
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
982
|
+
<a title="Works w/ 'json/json' config block" href="#usage">
|
|
983
|
+
<img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-32fcee?style=flat-square" align="middle"></a>
|
|
635
984
|
<a title="Copy rule URL" target="_blank"
|
|
636
985
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-mv3-schema">
|
|
637
986
|
<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 +1019,7 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
|
|
|
670
1019
|
|
|
671
1020
|
#### When not to use it
|
|
672
1021
|
|
|
673
|
-
If you intentionally target MV2 for a
|
|
1022
|
+
If you intentionally target MV2 for a browser that still supports it (e.g. Firefox).
|
|
674
1023
|
|
|
675
1024
|
#### Introduced in
|
|
676
1025
|
|
|
@@ -683,7 +1032,7 @@ If you intentionally target MV2 for a Chromium fork that still supports it.
|
|
|
683
1032
|
|
|
684
1033
|
<div align="center">
|
|
685
1034
|
|
|
686
|
-
[Back to index ↑][
|
|
1035
|
+
[Back to index ↑][epce-rules]
|
|
687
1036
|
|
|
688
1037
|
</div>
|
|
689
1038
|
|
|
@@ -741,7 +1090,7 @@ If your background context isn't a service worker.
|
|
|
741
1090
|
|
|
742
1091
|
<div align="center">
|
|
743
1092
|
|
|
744
|
-
[Back to index ↑][
|
|
1093
|
+
[Back to index ↑][epce-rules]
|
|
745
1094
|
|
|
746
1095
|
</div>
|
|
747
1096
|
|
|
@@ -753,6 +1102,8 @@ If your background context isn't a service worker.
|
|
|
753
1102
|
<code>valid-version-field</code>
|
|
754
1103
|
<a title="Included in recommended config" href="#usage">
|
|
755
1104
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
1105
|
+
<a title="Works w/ 'json/json' config block" href="#usage">
|
|
1106
|
+
<img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-32fcee?style=flat-square" align="middle"></a>
|
|
756
1107
|
<a title="Accepts array w/ options" href="#usage">
|
|
757
1108
|
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
758
1109
|
<a title="Copy rule URL" target="_blank"
|
|
@@ -775,7 +1126,6 @@ If your background context isn't a service worker.
|
|
|
775
1126
|
```diff
|
|
776
1127
|
/* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
|
|
777
1128
|
|
|
778
|
-
// manifest.json
|
|
779
1129
|
{
|
|
780
1130
|
"manifest_version": 3,
|
|
781
1131
|
! "version": "2026.1.111",
|
|
@@ -788,7 +1138,6 @@ If your background context isn't a service worker.
|
|
|
788
1138
|
```diff
|
|
789
1139
|
/* eslint chrome-extensions/valid-version-field: ['error', { versionType: 'date' }] */
|
|
790
1140
|
|
|
791
|
-
// manifest.json
|
|
792
1141
|
{
|
|
793
1142
|
"manifest_version": 3,
|
|
794
1143
|
- "version": "2026.1.111",
|
|
@@ -811,7 +1160,7 @@ If you don't care about version format consistency, or your version is injected
|
|
|
811
1160
|
|
|
812
1161
|
<div align="center">
|
|
813
1162
|
|
|
814
|
-
[Back to index ↑][
|
|
1163
|
+
[Back to index ↑][epce-rules]
|
|
815
1164
|
|
|
816
1165
|
</div>
|
|
817
1166
|
|
|
@@ -902,4 +1251,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
902
1251
|
|
|
903
1252
|
<!-- Links -->
|
|
904
1253
|
|
|
905
|
-
[
|
|
1254
|
+
[epce-rules]: #supported-rules
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-chrome-extensions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "ESLint rules for Chrome extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@eslint/markdown": "^8.0.3",
|
|
69
69
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
70
70
|
"eslint": "^10.12.0",
|
|
71
|
-
"eslint-plugin-constructors": "^1.4.
|
|
71
|
+
"eslint-plugin-constructors": "^1.4.1",
|
|
72
72
|
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
73
73
|
"eslint-plugin-import-x": "^4.17.1",
|
|
74
74
|
"eslint-plugin-n": "^18.4.1",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Delete a line to end support
|
|
2
|
+
|
|
3
|
+
export const bundles = { // ruleId: [bundleName, note]
|
|
4
|
+
'no-invalid-permissions': ['recommended'],
|
|
5
|
+
'require-mv3': ['recommended'],
|
|
6
|
+
'valid-mv3-schema': ['recommended'],
|
|
7
|
+
'valid-version-field': ['recommended']
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default { bundles }
|