eslint-plugin-chrome-extensions 2.7.0 → 2.8.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 (42) hide show
  1. package/README.md +266 -43
  2. package/package.json +9 -8
  3. package/src/data/apis.js +74 -88
  4. package/src/data/manifest.js +3 -1
  5. package/src/data/regex.js +2 -1
  6. package/src/index.d.ts +42 -0
  7. package/src/rules/css-spacing.js +29 -21
  8. package/src/rules/manifest-key-order.js +1 -1
  9. package/src/rules/manifest-spacing.js +1 -1
  10. package/src/rules/no-content-style-leak.js +12 -11
  11. package/src/rules/no-deprecated-apis.js +2 -2
  12. package/src/rules/no-host-page-selectors.js +5 -6
  13. package/src/rules/no-inline-event-handlers.js +116 -0
  14. package/src/rules/no-inline-scripts.js +65 -0
  15. package/src/rules/no-insecure-fetch.js +7 -6
  16. package/src/rules/no-insecure-messaging.js +4 -4
  17. package/src/rules/no-invalid-locales.js +3 -5
  18. package/src/rules/no-missing-default-locale.js +1 -1
  19. package/src/rules/no-missing-permissions.js +2 -3
  20. package/src/rules/no-missing-web-accessible-resources.js +2 -2
  21. package/src/rules/no-remote-code.js +77 -28
  22. package/src/rules/no-remote-objects.js +55 -0
  23. package/src/rules/no-remote-urls.js +20 -20
  24. package/src/rules/no-scrollbar-styling.js +8 -10
  25. package/src/rules/no-unrestricted-host-permissions.js +1 -1
  26. package/src/rules/no-unused-permissions.js +5 -4
  27. package/src/rules/require-license-file.js +1 -1
  28. package/src/rules/require-mv3.js +3 -2
  29. package/src/rules/valid-filenames.js +3 -3
  30. package/src/rules/valid-manifest-icons.js +2 -2
  31. package/src/rules/valid-mv3-schema.js +5 -5
  32. package/src/rules/valid-url-fields.js +2 -2
  33. package/src/rules/valid-version-field.js +2 -2
  34. package/src/utils/api.js +20 -0
  35. package/src/utils/extension.js +1 -3
  36. package/src/utils/html.js +29 -0
  37. package/src/utils/i18n.js +2 -2
  38. package/src/utils/init.js +11 -3
  39. package/src/utils/license.js +1 -1
  40. package/src/utils/node.js +3 -1
  41. package/src/utils/pkg.js +19 -2
  42. package/src/utils/rules.js +1 -1
package/README.md CHANGED
@@ -8,8 +8,8 @@
8
8
  <img alt="[License: MIT]" src="https://img.shields.io/badge/License-MIT-f1f20a.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
9
9
  <a target="_blank" href="https://getnpmstats.com/?package=eslint-plugin-chrome-extensions&range=last-year&interval=monthly">
10
10
  <img src="https://img.shields.io/npm/dm/eslint-plugin-chrome-extensions?style=for-the-badge&logo=npm&color=black"></a>
11
- <a target="_blank" href="https://eslint.org/">
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
+ <a href="#usage">
12
+ <img alt="[Supports ESLint >=9.6.0 / Oxlint >=1.65.0]" src="https://img.shields.io/badge/Supports-ESLint_%3E%3D9.6.0_%2F_Oxlint_%3E%3D1.65.0-4B32C3?style=for-the-badge&logo=eslint"></a>
13
13
  <br><br>
14
14
 
15
15
  ESLint rules for Chrome extensions.
@@ -33,6 +33,8 @@ npm i -D eslint-plugin-chrome-extensions
33
33
  Usage
34
34
  </h2>
35
35
 
36
+ ### ESLint
37
+
36
38
  Add bundled configs to your `eslint.config.*js` for each file type you need:
37
39
 
38
40
  ```js
@@ -46,31 +48,55 @@ export default [
46
48
  plugins: { 'chrome-extensions': chromeExtensions },
47
49
  rules: {
48
50
  ...chromeExtensions.configs.recommended.rules,
49
- 'chrome-extensions/no-deprecated-apis': 'off' // selectively disable rule
50
- }
51
- },
52
- {
53
- files: ['**/manifest.json'], ...chromeExtensions.configs.manifest,
54
- rules: {
55
- ...chromeExtensions.configs.manifest.rules,
56
- 'chrome-extensions/manifest-spacing': ['warn', { spaces: 4 }] // selectively tweak rule
51
+ 'chrome-extensions/no-deprecated-apis': 'off', // selectively disable rule
52
+ 'chrome-extensions/valid-version-field': ['error', { versionType: 'date' }] // selectively tweak rule
57
53
  }
58
54
  },
59
- { files: ['**/*LICENSE*'], ...chromeExtensions.configs.license },
60
- { files: ['**/extension/**/*.css'], ...chromeExtensions.configs.css },
61
- { files: ['**/extension/**/*.html'], ...chromeExtensions.configs.html },
62
- { files: ['**/extension/**/*.json'], ...chromeExtensions.configs.json },
63
- { files: ['**/extension/**/*.json5'], ...chromeExtensions.configs.json5 },
64
- { files: ['**/extension/**/*.jsonc'], ...chromeExtensions.configs.jsonc }
55
+ { files: ['**/*LICENSE*'], ...chromeExtensions.configs.license },
56
+ { files: ['**/manifest.json'], ...chromeExtensions.configs.manifest },
57
+ { files: ['**/extension/**/*.css'], ...chromeExtensions.configs.css },
58
+ { files: ['**/extension/**/*.html'], ...chromeExtensions.configs.html },
59
+ { files: ['**/extension/**/*.json'], ...chromeExtensions.configs.json },
60
+ { files: ['**/extension/**/*.json5'], ...chromeExtensions.configs.json5 },
61
+ { files: ['**/extension/**/*.jsonc'], ...chromeExtensions.configs.jsonc }
65
62
  ]
66
63
  ```
67
64
 
68
- Available bundles: `recommended`, `strict` (everything), `problem` (deterministic bugs only), `security`, `manifest`, `license`, `css`, `html`, `json`, `json5`, `jsonc`
65
+ ### Oxlint
66
+
67
+ Add a JS bundle to your `oxlint.config.ts` (non-JS parsing unsupported by Oxlint):
68
+
69
+ ```ts
70
+ ...
71
+ import chromeExtensions from 'eslint-plugin-chrome-extensions'
72
+
73
+ export default defineConfig({
74
+ // main config
75
+ overrides: [
76
+ // other overrides
77
+ {
78
+ files: ['**/extension/**/*.{cjs,js,jsx,mjs,ts,tsx}'],
79
+ jsPlugins: ['eslint-plugin-chrome-extensions'],
80
+ rules: {
81
+ ...chromeExtensions.configs.recommended.rules,
82
+ 'chrome-extensions/no-deprecated-apis': 'off', // selectively disable rule
83
+ 'chrome-extensions/no-insecure-messaging': ['error', { disallowWildcardTarget: false }] // selectively tweak rule
84
+ }
85
+ }
86
+ ]
87
+ })
88
+ ```
69
89
 
70
90
  **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
71
91
 
72
92
  ---
73
93
 
94
+ *Available JS bundles:* `recommended`, `strict` (everything), `problem` (deterministic bugs only), `security`
95
+
96
+ *Available filetype bundles (ESLint only):* `manifest`, `license`, `css`, `html`, `json`, `json5`, `jsonc`
97
+
98
+ ---
99
+
74
100
  <h2 id="supported-rules">
75
101
  <img height=30 width=27 align="top" src="https://api.iconify.design/mdi/format-list-checks.svg?color=%232b2b2a">
76
102
  Supported rules
@@ -78,8 +104,6 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
78
104
 
79
105
  <h3 id="css-spacing">
80
106
  <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
107
  <a title="Only works in 'css/css' config block" href="#usage">
84
108
  <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
85
109
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
@@ -506,8 +530,6 @@ If you rely on a Chromium fork resolving duplicate keys in a specific order.
506
530
 
507
531
  <h3 id="no-global-keyframes">
508
532
  <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
533
  <a title="Only works in 'css/css' config block" href="#usage">
512
534
  <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
513
535
  <a title="Accepts array w/ options" href="#usage">
@@ -568,10 +590,155 @@ If your CSS is scoped inside a Shadow DOM root.
568
590
 
569
591
  </details>
570
592
 
593
+ <h3 id="no-inline-event-handlers">
594
+ <code>no-inline-event-handlers</code>
595
+ <a title="Introduced in latest minor release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">
596
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
597
+ <a title="Only works in 'html/html' config block" href="#usage">
598
+ <img height=18 alt="[HTML only]" src="https://img.shields.io/badge/HTML_only-a8d8ea?style=flat-square" align="middle"></a>
599
+ <a title="Accepts array w/ options" href="#usage">
600
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
601
+ <a title="Copy rule URL" target="_blank"
602
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-inline-event-handlers">
603
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
604
+ </h3>
605
+
606
+ <details>
607
+
608
+ <summary>Disallows inline event handlers (e.g. <code>onclick</code>, <code>onload</code>) in HTML (blocked by MV3's <code>script-src 'self'</code> at runtime).</summary>
609
+
610
+ <h4 id="no-inline-event-handlers-options">Options</h4>
611
+
612
+ - `allowedAttributes` (default `[]`) – inline event handler attributes to permit (e.g. `['onafterprint']`), as a single string or array <a title="Introduced in v2.8.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0"><img height=14 alt="[Since v2.8.0]" src="https://img.shields.io/badge/since-v2.8.0-8a9199?style=flat-square" align="middle"></a>
613
+
614
+ #### <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
615
+
616
+ ```diff
617
+ ! <button onclick="alert('hi')">Click</button>
618
+ ! <body onload="init()">
619
+ ! <img src="logo.png" onerror="this.hidden = true">
620
+ ```
621
+
622
+ #### <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
623
+
624
+ ```diff
625
+ - <button onclick="alert('hi')">Click</button>
626
+ + <button id="myButton">Click</button>
627
+ - <body onload="init()">
628
+ + <body>
629
+ - <img src="logo.png" onerror="this.hidden = true">
630
+ + <img src="logo.png" id="logo">
631
+
632
+ // popup.js
633
+ + document.getElementById('myButton').addEventListener('click', () => alert('hi'))
634
+ + document.addEventListener('DOMContentLoaded', init)
635
+ + document.getElementById('logo').addEventListener('error', event => event.target.hidden = true)
636
+ ```
637
+
638
+ #### When not to use it
639
+
640
+ If your HTML is a <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/sandbox">sandbox page</a> (where the CSP is intentionally relaxed). For individual handlers you still need, prefer `allowedAttributes` over disabling the rule.
641
+
642
+ #### Introduced in
643
+
644
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">v2.8.0</a> (October 20, 2026)
645
+
646
+ #### See also
647
+
648
+ - [`no-inline-scripts`](#no-inline-scripts)
649
+ <a title="Only works in 'html/html' config block" href="#usage"><img height=14 alt="[HTML only]" src="https://img.shields.io/badge/HTML_only-a8d8ea?style=flat-square" align="middle"></a>
650
+ <a title="Accepts array w/ options" href="#no-inline-scripts-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
651
+ - [`no-remote-code`](#no-remote-code)
652
+ <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>
653
+ <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>
654
+ <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>
655
+ - <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>
656
+ - <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/HTTP/Reference/Headers/Content-Security-Policy/script-src">MDN — CSP `script-src`</a>
657
+ - <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/EventTarget/addEventListener">MDN — `addEventListener()`</a>
658
+
659
+ <div align="center">
660
+
661
+ [Back to index ↑][epce-rules]
662
+
663
+ </div>
664
+
665
+ ---
666
+
667
+ </details>
668
+
669
+ <h3 id="no-inline-scripts">
670
+ <code>no-inline-scripts</code>
671
+ <a title="Introduced in latest minor release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">
672
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
673
+ <a title="Only works in 'html/html' config block" href="#usage">
674
+ <img height=18 alt="[HTML only]" src="https://img.shields.io/badge/HTML_only-a8d8ea?style=flat-square" align="middle"></a>
675
+ <a title="Accepts array w/ options" href="#usage">
676
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
677
+ <a title="Copy rule URL" target="_blank"
678
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-inline-scripts">
679
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
680
+ </h3>
681
+
682
+ <details>
683
+
684
+ <summary>Disallows inline <code>&lt;script&gt;</code> bodies and remote <code>&lt;script src&gt;</code> in HTML (blocked by MV3's <code>script-src 'self'</code> at runtime).</summary>
685
+
686
+ <h4 id="no-inline-scripts-options">Options</h4>
687
+
688
+ - `allowedSrcPrefixes` (default `['chrome-extension://']`) – additional `src` prefixes to permit, as a single string or array <a title="Introduced in v2.8.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0"><img height=14 alt="[Since v2.8.0]" src="https://img.shields.io/badge/since-v2.8.0-8a9199?style=flat-square" align="middle"></a>
689
+
690
+ #### <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
691
+
692
+ ```diff
693
+ ! <script>alert('hi')</script>
694
+ ! <script src="https://cdn.example.com/lib.js"></script>
695
+ ! <script src="//cdn.example.com/lib.js"></script>
696
+ ! <script src="data:text/javascript;base64,YWxlcnQoMSk="></script>
697
+ ```
698
+
699
+ #### <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
700
+
701
+ ```diff
702
+ - <script>alert('hi')</script>
703
+ + <script src="popup.js"></script>
704
+ - <script src="https://cdn.example.com/lib.js"></script>
705
+ + <script src="./vendor/lib.js"></script>
706
+ - <script src="//cdn.example.com/lib.js"></script>
707
+ + <script type="module" src="popup.js"></script>
708
+ - <script src="data:text/javascript;base64,YWxlcnQoMSk="></script>
709
+ + <script src="chrome-extension://abc123/popup.js"></script>
710
+ ```
711
+
712
+ #### When not to use it
713
+
714
+ If your HTML is a <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/sandbox">sandbox page</a> (where the CSP is intentionally relaxed).
715
+
716
+ #### Introduced in
717
+
718
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">v2.8.0</a> (October 20, 2026)
719
+
720
+ #### See also
721
+
722
+ - [`no-remote-code`](#no-remote-code)
723
+ <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>
724
+ <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>
725
+ <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>
726
+ - <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>
727
+ - <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/HTTP/Reference/Headers/Content-Security-Policy/script-src">MDN — CSP `script-src`</a>
728
+ - <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/HTML/Reference/Elements/script">MDN — `<script>` element</a>
729
+
730
+ <div align="center">
731
+
732
+ [Back to index ↑][epce-rules]
733
+
734
+ </div>
735
+
736
+ ---
737
+
738
+ </details>
739
+
571
740
  <h3 id="no-host-page-selectors">
572
741
  <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
742
  <a title="Only works in 'css/css' config block" href="#usage">
576
743
  <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
577
744
  <a title="Accepts array w/ options" href="#usage">
@@ -681,7 +848,10 @@ If you intentionally target HTTP endpoints.
681
848
 
682
849
  #### See also
683
850
 
851
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=rfc-editor.org&sz=64">&ensp;<a target="_blank" href="https://www.rfc-editor.org/info/rfc9110/">RFC 9110 — HTTP Semantics</a>
684
852
  - <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>
853
+ - <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/XMLHttpRequest/open">MDN — `XMLHttpRequest.open()`</a>
854
+ - <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/fetch">MDN — `fetch()`</a>
685
855
 
686
856
  <div align="center">
687
857
 
@@ -929,8 +1099,6 @@ If you don't want permission validation at all. For custom permissions from a Ch
929
1099
 
930
1100
  <h3 id="no-missing-default-locale">
931
1101
  <code>no-missing-default-locale</code>
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
1102
  <a title="Included in recommended config" href="#usage">
935
1103
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
936
1104
  <a title="Works in 'json/json' config block" href="#usage">
@@ -1257,7 +1425,7 @@ If your paths are built at runtime.
1257
1425
 
1258
1426
  <h4 id="no-remote-code-options">Options</h4>
1259
1427
 
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>
1428
+ - `patterns` (default `['dynamic-import', 'eval', 'execute-script-url', 'inline-event-handler', 'inline-script-body', 'new-function', 'remote-script-src', 'string-timer']`) – 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
1429
  - `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>
1262
1430
 
1263
1431
  #### <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
@@ -1306,10 +1474,76 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
1306
1474
 
1307
1475
  </details>
1308
1476
 
1477
+ <h3 id="no-remote-objects">
1478
+ <code>no-remote-objects</code>
1479
+ <a title="Introduced in latest minor release" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">
1480
+ <img height=16 align="middle" src="https://api.iconify.design/mdi/sprout.svg?color=%234a4a4a"></a>
1481
+ <a title="Only works in 'html/html' config block" href="#usage">
1482
+ <img height=18 alt="[HTML only]" src="https://img.shields.io/badge/HTML_only-a8d8ea?style=flat-square" align="middle"></a>
1483
+ <a title="Accepts array w/ options" href="#usage">
1484
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1485
+ <a title="Copy rule URL" target="_blank"
1486
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-remote-objects">
1487
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1488
+ </h3>
1489
+
1490
+ <details>
1491
+
1492
+ <summary>Disallows remote <code>&lt;object data&gt;</code> and <code>&lt;embed src&gt;</code> in HTML (blocked by MV3's <code>object-src 'self'</code> at runtime).</summary>
1493
+
1494
+ <h4 id="no-remote-objects-options">Options</h4>
1495
+
1496
+ - `allowedPrefixes` (default `['chrome-extension://']`) – additional URL prefixes to permit, as a single string or array <a title="Introduced in v2.8.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0"><img height=14 alt="[Since v2.8.0]" src="https://img.shields.io/badge/since-v2.8.0-8a9199?style=flat-square" align="middle"></a>
1497
+
1498
+ #### <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
1499
+
1500
+ ```diff
1501
+ ! <object data="https://cdn.example.com/report.pdf"></object>
1502
+ ! <embed src="http://cdn.example.com/game.swf">
1503
+ ! <object data="//cdn.example.com/chart.svg"></object>
1504
+ ```
1505
+
1506
+ #### <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
1507
+
1508
+ ```diff
1509
+ - <object data="https://cdn.example.com/report.pdf"></object>
1510
+ + <object data="report.pdf"></object>
1511
+ - <embed src="http://cdn.example.com/game.swf">
1512
+ + <embed src="./vendor/game.swf">
1513
+ - <object data="//cdn.example.com/chart.svg"></object>
1514
+ + <object data="chrome-extension://abc123/chart.svg"></object>
1515
+ ```
1516
+
1517
+ #### When not to use it
1518
+
1519
+ If your HTML is a <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/sandbox">sandbox page</a> (where the CSP is intentionally relaxed).
1520
+
1521
+ #### Introduced in
1522
+
1523
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.8.0">v2.8.0</a> (October 20, 2026)
1524
+
1525
+ #### See also
1526
+
1527
+ - [`no-inline-scripts`](#no-inline-scripts)
1528
+ <a title="Only works in 'html/html' config block" href="#usage"><img height=14 alt="[HTML only]" src="https://img.shields.io/badge/HTML_only-a8d8ea?style=flat-square" align="middle"></a>
1529
+ <a title="Accepts array w/ options" href="#no-inline-scripts-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1530
+ - <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>
1531
+ - <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/HTTP/Reference/Headers/Content-Security-Policy/object-src">MDN — CSP `object-src`</a>
1532
+ - <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/HTML/Reference/Elements/object">MDN — `<object>` element</a>
1533
+ - <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/HTML/Reference/Elements/embed">MDN — `<embed>` element</a>
1534
+
1535
+ <div align="center">
1536
+
1537
+ [Back to index ↑][epce-rules]
1538
+
1539
+ </div>
1540
+
1541
+ ---
1542
+
1543
+ </details>
1544
+
1309
1545
  <h3 id="no-remote-urls">
1310
1546
  <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
1547
  <a title="Only works in 'css/css' config block" href="#usage">
1314
1548
  <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1315
1549
  <a title="Accepts array w/ options" href="#usage">
@@ -1386,8 +1620,6 @@ If you intentionally reference remote stylesheets, fonts, or images (e.g. Google
1386
1620
 
1387
1621
  <h3 id="no-scrollbar-styling">
1388
1622
  <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
1623
  <a title="Only works in 'css/css' config block" href="#usage">
1392
1624
  <img height=18 alt="[CSS only]" src="https://img.shields.io/badge/CSS_only-dcd6f7?style=flat-square" align="middle"></a>
1393
1625
  <a title="Accepts array w/ options" href="#usage">
@@ -1530,8 +1762,6 @@ If you legitimately require sensitive permissions, or prefer manual security rev
1530
1762
 
1531
1763
  <h3 id="no-unrestricted-host-permissions">
1532
1764
  <code>no-unrestricted-host-permissions</code>
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
1765
  <a title="Included in recommended config" href="#usage">
1536
1766
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1537
1767
  <a title="Included in security config" href="#usage">
@@ -1675,8 +1905,6 @@ If your i18n keys are referenced dynamically.
1675
1905
  <code>no-unused-permissions</code>
1676
1906
  <a title="Introduced in v1.0.0" target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v1.0.0">
1677
1907
  <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
1908
  <a title="Included in recommended config" href="#usage">
1681
1909
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1682
1910
  <a title="Works in 'json/json' config block" href="#usage">
@@ -1755,14 +1983,13 @@ If you access the granted API through an alias or computed property rather than
1755
1983
 
1756
1984
  <summary>Requires a license file.</summary>
1757
1985
 
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
1986
+ #### <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 dir structure
1759
1987
 
1760
1988
  ```diff
1761
1989
  /extension/manifest.json
1762
- !
1763
1990
  ```
1764
1991
 
1765
- #### <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 directory structure
1992
+ #### <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 dir structure
1766
1993
 
1767
1994
  ```diff
1768
1995
  /extension/manifest.json
@@ -2081,8 +2308,6 @@ If your license is injected at build time, or you use one w/ no existing SPDX id
2081
2308
 
2082
2309
  <h3 id="valid-manifest-icons">
2083
2310
  <code>valid-manifest-icons</code>
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
2311
  <a title="Included in recommended config" href="#usage">
2087
2312
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
2088
2313
  <a title="Works in 'json/json' config block" href="#usage">
@@ -2300,8 +2525,6 @@ If your background context isn't a service worker.
2300
2525
 
2301
2526
  <h3 id="valid-url-fields">
2302
2527
  <code>valid-url-fields</code>
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
2528
  <a title="Included in recommended config" href="#usage">
2306
2529
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
2307
2530
  <a title="Works in 'json/json' config block" href="#usage">
@@ -2467,8 +2690,8 @@ If you don't care about version format consistency, or your version is injected
2467
2690
 
2468
2691
  ## <img height=30 width=27 align="top" src="https://api.iconify.design/ic/baseline-account-balance.svg?color=%232b2b2a"> License
2469
2692
 
2470
- <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
2471
- <img height=80 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
2693
+ <a href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
2694
+ <img height=88 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-chrome-extensions/d79e1db7e2/assets/images/banners/mit-license/banner.png"></a>
2472
2695
  <br><br>
2473
2696
 
2474
2697
  <details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-chrome-extensions",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "ESLint rules for Chrome extensions",
5
5
  "keywords": [
6
6
  "eslint",
@@ -53,10 +53,10 @@
53
53
  "bump:major": "bash utils/bump.sh major",
54
54
  "bump:minor": "bash utils/bump.sh minor",
55
55
  "bump:patch": "bash utils/bump.sh patch",
56
- "demo": "node demo/run.js",
56
+ "demo": "eslint demo",
57
57
  "lint": "pre-commit run",
58
58
  "lint:all": "pre-commit run --all-files",
59
- "test": "node tests/run.js"
59
+ "test": "node tests/run"
60
60
  },
61
61
  "dependencies": {
62
62
  "globals": "^17.13.0",
@@ -65,14 +65,13 @@
65
65
  },
66
66
  "devDependencies": {
67
67
  "@e18e/eslint-plugin": "^0.8.1",
68
- "@eslint/css": "^2.0.0",
69
- "@eslint/js": "^10.0.1",
68
+ "@eslint/css": "^2.0.1",
70
69
  "@eslint/json": "^2.1.1",
71
70
  "@eslint/markdown": "^7.5.1",
72
71
  "@html-eslint/eslint-plugin": "^0.67.0",
73
72
  "@stylistic/eslint-plugin": "^5.10.0",
74
- "eslint": "^10.12.0",
75
- "eslint-plugin-constructors": "^1.4.3",
73
+ "eslint": "^10.13.0",
74
+ "eslint-plugin-constructors": "^1.5.0",
76
75
  "eslint-plugin-eslint-plugin": "^7.6.2",
77
76
  "eslint-plugin-import-x": "^4.17.1",
78
77
  "eslint-plugin-n": "^18.4.1",
@@ -82,7 +81,9 @@
82
81
  "eslint-plugin-promise": "^7.3.0",
83
82
  "eslint-plugin-regexp": "^3.3.1",
84
83
  "eslint-plugin-security": "^4.2.0",
85
- "eslint-plugin-woodpecker": "^1.0.0"
84
+ "eslint-plugin-sonarjs": "^4.2.2",
85
+ "eslint-plugin-woodpecker": "^1.1.0",
86
+ "oxlint": "^1.89.0"
86
87
  },
87
88
  "peerDependencies": {
88
89
  "@eslint/css": ">=0.5.0",