eslint-plugin-chrome-extensions 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,17 +31,16 @@ npm i -D eslint-plugin-chrome-extensions
31
31
  Usage
32
32
  </h2>
33
33
 
34
- Add bundled configs to your `eslint.config.*js`:
34
+ Add bundled configs to your `eslint.config.*js` for each file type you need:
35
35
 
36
36
  ```js
37
37
  ...
38
38
  import chromeExtensions from 'eslint-plugin-chrome-extensions'
39
- import json from '@eslint/json'
40
39
 
41
40
  export default [
42
41
  // other configs
43
42
  {
44
- files: ['**/extension/**/*.js'],
43
+ files: ['**/*extension/**/*.{cjs,js,jsx,mjs,ts,tsx}'],
45
44
  plugins: { 'chrome-extensions': chromeExtensions },
46
45
  rules: {
47
46
  ...chromeExtensions.configs.recommended.rules,
@@ -49,17 +48,22 @@ export default [
49
48
  }
50
49
  },
51
50
  {
52
- files: ['**/manifest.json'], language: 'json/json',
53
- plugins: { 'chrome-extensions': chromeExtensions, json },
51
+ files: ['**/manifest.json'], ...chromeExtensions.configs.manifest,
54
52
  rules: {
55
53
  ...chromeExtensions.configs.manifest.rules,
56
- 'chrome-extensions/valid-version-field': ['error', { versionType: 'date' }] // selectively tweak rule
54
+ 'chrome-extensions/manifest-spacing': ['warn', { spaces: 4 }] // selectively tweak rule
57
55
  }
58
- }
56
+ },
57
+ { files: ['**/*LICENSE*'], ...chromeExtensions.configs.license },
58
+ { files: ['**/*extension/**/*.css'], ...chromeExtensions.configs.css },
59
+ { files: ['**/*extension/**/*.html'], ...chromeExtensions.configs.html },
60
+ { files: ['**/*extension/**/*.json'], ...chromeExtensions.configs.json },
61
+ { files: ['**/*extension/**/*.json5'], ...chromeExtensions.configs.json5 },
62
+ { files: ['**/*extension/**/*.jsonc'], ...chromeExtensions.configs.jsonc }
59
63
  ]
60
64
  ```
61
65
 
62
- Available bundles: `recommended`, `strict` (everything), `problem` (deterministic bugs only), `security`, `manifest`
66
+ Available bundles: `recommended`, `strict` (everything), `problem` (deterministic bugs only), `security`, `manifest`, `license`, `css`, `html`, `json`, `json5`, `jsonc`
63
67
 
64
68
  **Note:** Rule config is either a severity string (`'off'`, `'warn'`, `'error'`) or an array `[severity, options]` when the rule accepts options.
65
69
 
@@ -72,7 +76,7 @@ Available bundles: `recommended`, `strict` (everything), `problem` (deterministi
72
76
 
73
77
  <h3 id="manifest-key-order">
74
78
  <code>manifest-key-order</code>
75
- <a title="Only works w/ 'json/json' config block" href="#usage">
79
+ <a title="Only works in 'json/json' config block" href="#usage">
76
80
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
77
81
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
78
82
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
@@ -130,10 +134,10 @@ If you don't care about the order of manifest keys.
130
134
 
131
135
  - [`require-mv3`](#require-mv3)
132
136
  <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>
137
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
134
138
  - [`valid-mv3-schema`](#valid-mv3-schema)
135
139
  <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>
140
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
137
141
 
138
142
  <div align="center">
139
143
 
@@ -147,7 +151,7 @@ If you don't care about the order of manifest keys.
147
151
 
148
152
  <h3 id="manifest-spacing">
149
153
  <code>manifest-spacing</code>
150
- <a title="Only works w/ 'json/json' config block" href="#usage">
154
+ <a title="Only works in 'json/json' config block" href="#usage">
151
155
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
152
156
  <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
153
157
  <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
@@ -215,12 +219,12 @@ If you don't care about visual consistency in your manifest.
215
219
  #### See also
216
220
 
217
221
  - [`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>
222
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
219
223
  <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
224
  <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
225
  <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
226
  - [`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>
227
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
224
228
 
225
229
  <div align="center">
226
230
 
@@ -351,7 +355,7 @@ If you don't want deprecation validation at all. For individual deprecated APIs
351
355
 
352
356
  <h3 id="no-duplicate-manifest-keys">
353
357
  <code>no-duplicate-manifest-keys</code>
354
- <a title="Only works w/ 'json/json' config block" href="#usage">
358
+ <a title="Only works in 'json/json' config block" href="#usage">
355
359
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
356
360
  <a title="Copy rule URL" target="_blank"
357
361
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-duplicate-manifest-keys">
@@ -399,12 +403,12 @@ If you rely on a Chromium fork resolving duplicate keys in a specific order.
399
403
  #### See also
400
404
 
401
405
  - [`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>
406
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
403
407
  <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
408
  <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
409
  <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
410
  - [`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>
411
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
408
412
 
409
413
  <div align="center">
410
414
 
@@ -558,7 +562,7 @@ If you trust every external caller and open tab, or you intentionally broadcast
558
562
  <code>no-invalid-permissions</code>
559
563
  <a title="Included in recommended config" href="#usage">
560
564
  <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">
565
+ <a title="Works in 'json/json' config block" href="#usage">
562
566
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
563
567
  <a title="Accepts array w/ options" href="#usage">
564
568
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -613,7 +617,186 @@ If you don't want permission validation at all. For custom permissions from a Ch
613
617
  - [`no-missing-permissions`](#no-missing-permissions)
614
618
  <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>
615
619
  - [`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>
620
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
621
+
622
+ <div align="center">
623
+
624
+ [Back to index ↑][epce-rules]
625
+
626
+ </div>
627
+
628
+ ---
629
+
630
+ </details>
631
+
632
+ <h3 id="no-missing-default-locale">
633
+ <code>no-missing-default-locale</code>
634
+ <a title="Only works in 'json/json' config block" href="#usage">
635
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
636
+ <a title="Accepts array w/ options" href="#usage">
637
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
638
+ <a title="Copy rule URL" target="_blank"
639
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-default-locale">
640
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
641
+ </h3>
642
+
643
+ <details>
644
+
645
+ <summary>Ensures <code>default_locale</code> is declared and every <code>_locales</code> key exists in it.</summary>
646
+
647
+ <h4 id="no-missing-default-locale-options">Options</h4>
648
+
649
+ - `ignoreKeys` (default `[]`) – keys to skip when checking the default locale
650
+
651
+ #### <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
652
+
653
+ ```diff
654
+ // manifest.json
655
+ {
656
+ "manifest_version": 3,
657
+ "default_locale": "en",
658
+ "name": "__MSG_extName__"
659
+ }
660
+
661
+ // _locales/en/messages.json
662
+ {
663
+ "extName": { "message": "My Extension" }
664
+ }
665
+
666
+ // _locales/de/messages.json
667
+ {
668
+ "extName": { "message": "Meine Erweiterung" },
669
+ ! "welcomeMsg": { "message": "Willkommen" }
670
+ }
671
+ ```
672
+
673
+ #### <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
674
+
675
+ ```diff
676
+ // manifest.json
677
+ {
678
+ "manifest_version": 3,
679
+ "default_locale": "en",
680
+ "name": "__MSG_extName__"
681
+ }
682
+
683
+ // _locales/en/messages.json
684
+ {
685
+ "extName": { "message": "My Extension" },
686
+ + "welcomeMsg": { "message": "Welcome" }
687
+ }
688
+
689
+ // _locales/de/messages.json
690
+ {
691
+ "extName": { "message": "Meine Erweiterung" },
692
+ "welcomeMsg": { "message": "Willkommen" }
693
+ }
694
+ ```
695
+
696
+ #### When not to use it
697
+
698
+ If your `_locales/` is externally populated at build time.
699
+
700
+ #### Introduced in
701
+
702
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
703
+
704
+ #### See also
705
+
706
+ - <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/default-locale">Chrome for Developers — `default_locale`</a>
707
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/i18n">Chrome for Developers — `i18n`</a>
708
+
709
+ <div align="center">
710
+
711
+ [Back to index ↑][epce-rules]
712
+
713
+ </div>
714
+
715
+ ---
716
+
717
+ </details>
718
+
719
+ <h3 id="no-missing-i18n-keys">
720
+ <code>no-missing-i18n-keys</code>
721
+ <a title="Included in recommended config" href="#usage">
722
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
723
+ <a title="Works in 'json/json' config block" href="#usage">
724
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
725
+ <a title="Works in 'css/css' config block" href="#usage">
726
+ <img height=18 alt="[CSS]" src="https://img.shields.io/badge/CSS-dcd6f7?style=flat-square" align="middle"></a>
727
+ <a title="Works in 'html/html' config block" href="#usage">
728
+ <img height=18 alt="[HTML]" src="https://img.shields.io/badge/HTML-a8d8ea?style=flat-square" align="middle"></a>
729
+ <a title="Works in 'json/json' config block" href="#usage">
730
+ <img height=18 alt="[JSON]" src="https://img.shields.io/badge/JSON-a8e6cf?style=flat-square" align="middle"></a>
731
+ <a title="Works in 'json5' config block" href="#usage">
732
+ <img height=18 alt="[JSON5]" src="https://img.shields.io/badge/JSON5-c7e6b8?style=flat-square" align="middle"></a>
733
+ <a title="Works in 'jsonc' config block" href="#usage">
734
+ <img height=18 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
735
+ <a title="Accepts array w/ options" href="#usage">
736
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
737
+ <a title="Copy rule URL" target="_blank"
738
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-missing-i18n-keys">
739
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
740
+ </h3>
741
+
742
+ <details>
743
+
744
+ <summary>Flags i18n keys used but missing from <code>_locales/&lt;default_locale&gt;/messages.json</code>.</summary>
745
+
746
+ <h4 id="no-missing-i18n-keys-options">Options</h4>
747
+
748
+ - `ignoreKeys` (default `[]`) – keys to skip (e.g. `['customKey']`)
749
+
750
+ #### <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
751
+
752
+ ```diff
753
+ // content.js
754
+ ! chrome.i18n.getMessage('greeting')
755
+
756
+ // manifest.json
757
+ {
758
+ "manifest_version": 3,
759
+ ! "name": "__MSG_extName__"
760
+ }
761
+
762
+ // _locales/en/messages.json
763
+ { "unrelated": { "message": "…" }}
764
+ ```
765
+
766
+ #### <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
767
+
768
+ ```diff
769
+ // content.js
770
+ chrome.i18n.getMessage('greeting')
771
+
772
+ // manifest.json
773
+ {
774
+ "manifest_version": 3,
775
+ "name": "__MSG_extName__"
776
+ }
777
+
778
+ // _locales/en/messages.json
779
+ - { "unrelated": { "message": "…" }}
780
+ + {
781
+ + "greeting": { "message": "Hello" },
782
+ + "extName": { "message": "My Extension" }
783
+ + }
784
+ ```
785
+
786
+ #### When not to use it
787
+
788
+ If your `_locales/` is externally populated at build time.
789
+
790
+ #### Introduced in
791
+
792
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
793
+
794
+ #### See also
795
+
796
+ - [`no-unused-i18n-keys`](#no-unused-i18n-keys)
797
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
798
+ <a title="Accepts array w/ options" href="#no-unused-i18n-keys-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
799
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/i18n">Chrome for Developers — `i18n`</a>
617
800
 
618
801
  <div align="center">
619
802
 
@@ -677,10 +860,10 @@ If you use APIs through aliases or wrappers that obscure the original call site.
677
860
 
678
861
  - [`no-invalid-permissions`](#no-invalid-permissions)
679
862
  <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>
863
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
681
864
  <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>
682
865
  - [`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>
866
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
684
867
 
685
868
  <div align="center">
686
869
 
@@ -811,10 +994,10 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
811
994
 
812
995
  - [`require-mv3`](#require-mv3)
813
996
  <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>
997
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
815
998
  - [`valid-mv3-schema`](#valid-mv3-schema)
816
999
  <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>
1000
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
818
1001
 
819
1002
  <div align="center">
820
1003
 
@@ -828,7 +1011,7 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
828
1011
 
829
1012
  <h3 id="no-unrestricted-host-permissions">
830
1013
  <code>no-unrestricted-host-permissions</code>
831
- <a title="Only works w/ 'json/json' config block" href="#usage">
1014
+ <a title="Only works in 'json/json' config block" href="#usage">
832
1015
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
833
1016
  <a title="Accepts array w/ options" href="#usage">
834
1017
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -890,9 +1073,86 @@ If you legitimately need broad access (e.g. ad blockers or dev tools).
890
1073
 
891
1074
  </details>
892
1075
 
1076
+ <h3 id="no-unused-i18n-keys">
1077
+ <code>no-unused-i18n-keys</code>
1078
+ <a title="Only works in 'json/json' config block" href="#usage">
1079
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1080
+ <a title="Accepts array w/ options" href="#usage">
1081
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1082
+ <a title="Copy rule URL" target="_blank"
1083
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-i18n-keys">
1084
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1085
+ </h3>
1086
+
1087
+ <details>
1088
+
1089
+ <summary>Flags i18n keys in <code>_locales/&lt;default_locale&gt;/messages.json</code> that are never referenced.</summary>
1090
+
1091
+ <h4 id="no-unused-i18n-keys-options">Options</h4>
1092
+
1093
+ - `ignoreKeys` (default `[]`) – keys to always treat as used (e.g. `['customKey']`)
1094
+ - `scanExtensions` (default `['cjs', 'css', 'htm', 'html', 'js', 'json', 'jsx', 'md', 'mjs', 'svg', 'ts', 'tsx', 'txt']`) – file extensions to scan for references
1095
+
1096
+ #### <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
1097
+
1098
+ ```diff
1099
+ // _locales/en/messages.json
1100
+ {
1101
+ "usedKey": { "message": "Used message" },
1102
+ ! "unusedKey": { "message": "Unused message" }
1103
+ }
1104
+
1105
+ // content.js
1106
+ chrome.i18n.getMessage('usedKey')
1107
+ ```
1108
+
1109
+ #### <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
1110
+
1111
+ ```diff
1112
+ // _locales/en/messages.json
1113
+ {
1114
+ "usedKey": { "message": "Used message" }
1115
+ - "unusedKey": { "message": "Unused message" }
1116
+ }
1117
+
1118
+ // content.js
1119
+ chrome.i18n.getMessage('usedKey')
1120
+ ```
1121
+
1122
+ #### When not to use it
1123
+
1124
+ If your i18n keys are referenced dynamically.
1125
+
1126
+ #### Introduced in
1127
+
1128
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1129
+
1130
+ #### See also
1131
+
1132
+ - [`no-missing-i18n-keys`](#no-missing-i18n-keys)
1133
+ <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>
1134
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1135
+ <a title="Works in 'css/css' config block" href="#usage"><img height=14 alt="[CSS]" src="https://img.shields.io/badge/CSS-dcd6f7?style=flat-square" align="middle"></a>
1136
+ <a title="Works in 'html/html' config block" href="#usage"><img height=14 alt="[HTML]" src="https://img.shields.io/badge/HTML-a8d8ea?style=flat-square" align="middle"></a>
1137
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[JSON]" src="https://img.shields.io/badge/JSON-a8e6cf?style=flat-square" align="middle"></a>
1138
+ <a title="Works in 'json5' config block" href="#usage"><img height=14 alt="[JSON5]" src="https://img.shields.io/badge/JSON5-c7e6b8?style=flat-square" align="middle"></a>
1139
+ <a title="Works in 'jsonc' config block" href="#usage"><img height=14 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
1140
+ <a title="Accepts array w/ options" href="#no-missing-i18n-keys-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1141
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/api/i18n">Chrome for Developers — `i18n`</a>
1142
+
1143
+ <div align="center">
1144
+
1145
+ [Back to index ↑][epce-rules]
1146
+
1147
+ </div>
1148
+
1149
+ ---
1150
+
1151
+ </details>
1152
+
893
1153
  <h3 id="no-unused-permissions">
894
1154
  <code>no-unused-permissions</code>
895
- <a title="Only works w/ 'json/json' config block" href="#usage">
1155
+ <a title="Only works in 'json/json' config block" href="#usage">
896
1156
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
897
1157
  <a title="Copy rule URL" target="_blank"
898
1158
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-unused-permissions">
@@ -940,7 +1200,7 @@ If you access the granted API through an alias or computed property rather than
940
1200
 
941
1201
  - [`no-invalid-permissions`](#no-invalid-permissions)
942
1202
  <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>
1203
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
944
1204
  <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>
945
1205
  - [`no-missing-permissions`](#no-missing-permissions)
946
1206
  <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>
@@ -955,11 +1215,64 @@ If you access the granted API through an alias or computed property rather than
955
1215
 
956
1216
  </details>
957
1217
 
1218
+ <h3 id="require-license-file">
1219
+ <code>require-license-file</code>
1220
+ <a title="Only works in 'json/json' config block" href="#usage">
1221
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1222
+ <a title="Copy rule URL" target="_blank"
1223
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-license-file">
1224
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1225
+ </h3>
1226
+
1227
+ <details>
1228
+
1229
+ <summary>Requires a license file in the extension.</summary>
1230
+
1231
+ #### <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
1232
+
1233
+ ```diff
1234
+ // files
1235
+ /extension/manifest.json
1236
+ !
1237
+ ```
1238
+
1239
+ #### <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
1240
+
1241
+ ```diff
1242
+ // files
1243
+ /extension/manifest.json
1244
+ + /extension/LICENSE
1245
+ ```
1246
+
1247
+ #### When not to use it
1248
+
1249
+ If you intentionally omit a license, or it's injected at build time.
1250
+
1251
+ #### Introduced in
1252
+
1253
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1254
+
1255
+ #### See also
1256
+
1257
+ - [`valid-license-file`](#valid-license-file)
1258
+ <a title="Only works in 'license' config block" href="#usage"><img height=14 alt="[License only]" src="https://img.shields.io/badge/License_only-559bff?style=flat-square" align="middle"></a>
1259
+ <a title="Accepts array w/ options" href="#valid-license-file-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1260
+
1261
+ <div align="center">
1262
+
1263
+ [Back to index ↑][epce-rules]
1264
+
1265
+ </div>
1266
+
1267
+ ---
1268
+
1269
+ </details>
1270
+
958
1271
  <h3 id="require-mv3">
959
1272
  <code>require-mv3</code>
960
1273
  <a title="Included in recommended config" href="#usage">
961
1274
  <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">
1275
+ <a title="Works in 'json/json' config block" href="#usage">
963
1276
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
964
1277
  <a title="Copy rule URL" target="_blank"
965
1278
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-mv3">
@@ -1003,7 +1316,234 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1003
1316
 
1004
1317
  - [`valid-mv3-schema`](#valid-mv3-schema)
1005
1318
  <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>
1319
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1320
+
1321
+ <div align="center">
1322
+
1323
+ [Back to index ↑][epce-rules]
1324
+
1325
+ </div>
1326
+
1327
+ ---
1328
+
1329
+ </details>
1330
+
1331
+ <h3 id="require-short-name-when-useful">
1332
+ <code>require-short-name-when-useful</code>
1333
+ <a title="Only works in 'json/json' config block" href="#usage">
1334
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1335
+ <a title="Accepts array w/ options" href="#usage">
1336
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1337
+ <a title="Copy rule URL" target="_blank"
1338
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23require-short-name-when-useful">
1339
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1340
+ </h3>
1341
+
1342
+ <details>
1343
+
1344
+ <summary>Requires <code>short_name</code> when <code>name</code> exceeds 12 chars.</summary>
1345
+
1346
+ <h4 id="require-short-name-when-useful-options">Options</h4>
1347
+
1348
+ - `maxNameLength` (default `12`) – length of `name` above which `short_name` is required
1349
+ - `always` (default `false`) – require `short_name` regardless of `name` length
1350
+ - `checkRedundant` (default `false`) – also flag `short_name` that duplicates `name`
1351
+
1352
+ #### <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
1353
+
1354
+ ```diff
1355
+ {
1356
+ "manifest_version": 3,
1357
+ ! "name": "Extension Infinity"
1358
+ }
1359
+ ```
1360
+
1361
+ #### <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
1362
+
1363
+ ```diff
1364
+ {
1365
+ "manifest_version": 3,
1366
+ "name": "Extension Infinity",
1367
+ + "short_name": "Extension ∞"
1368
+ }
1369
+ ```
1370
+
1371
+ #### When not to use it
1372
+
1373
+ If you primarily target a browser that doesn't support `short_name`.
1374
+
1375
+ #### Introduced in
1376
+
1377
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1378
+
1379
+ #### See also
1380
+
1381
+ - <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/short-name">Chrome for Developers — `short_name`</a>
1382
+ - <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/name">Chrome for Developers — `name`</a>
1383
+
1384
+ <div align="center">
1385
+
1386
+ [Back to index ↑][epce-rules]
1387
+
1388
+ </div>
1389
+
1390
+ ---
1391
+
1392
+ </details>
1393
+
1394
+ <h3 id="valid-filenames">
1395
+ <code>valid-filenames</code>
1396
+ <a title="Included in recommended config" href="#usage">
1397
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1398
+ <a title="Works in 'json/json' config block" href="#usage">
1399
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1400
+ <a title="Works in 'css/css' config block" href="#usage">
1401
+ <img height=18 alt="[CSS]" src="https://img.shields.io/badge/CSS-dcd6f7?style=flat-square" align="middle"></a>
1402
+ <a title="Works in 'html/html' config block" href="#usage">
1403
+ <img height=18 alt="[HTML]" src="https://img.shields.io/badge/HTML-a8d8ea?style=flat-square" align="middle"></a>
1404
+ <a title="Works in 'json/json' config block" href="#usage">
1405
+ <img height=18 alt="[JSON]" src="https://img.shields.io/badge/JSON-a8e6cf?style=flat-square" align="middle"></a>
1406
+ <a title="Works in 'json5' config block" href="#usage">
1407
+ <img height=18 alt="[JSON5]" src="https://img.shields.io/badge/JSON5-c7e6b8?style=flat-square" align="middle"></a>
1408
+ <a title="Works in 'jsonc' config block" href="#usage">
1409
+ <img height=18 alt="[JSONC]" src="https://img.shields.io/badge/JSONC-e6e6a8?style=flat-square" align="middle"></a>
1410
+ <a title="Accepts array w/ options" href="#usage">
1411
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1412
+ <a title="Copy rule URL" target="_blank"
1413
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-filenames">
1414
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1415
+ </h3>
1416
+
1417
+ <details>
1418
+
1419
+ <summary>Enforces valid filenames and paths.</summary>
1420
+
1421
+ <h4 id="valid-filenames-options">Options</h4>
1422
+
1423
+ - `noReservedPrefix` (default `true`) – disallow filenames/dirs starting w/ `_` (except `_locales`)
1424
+ - `noSpecialChars` (default `true`) – warn on chars outside `a-z`, `0-9`, `-`, `_`, `.`
1425
+ - `checkFileExists` (default `true`) – verify files referenced in `manifest.json` actually exist
1426
+ - `enforceCaseSensitivity` (default `true`) – verify manifest references match actual file case
1427
+ - `maxFullPathLength` (default `260`) – max full path char length
1428
+
1429
+ #### <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
1430
+
1431
+ ```diff
1432
+ // files
1433
+ ! /extension/_metadata/app.json
1434
+ ! /extension/content script.js
1435
+
1436
+ // manifest.json
1437
+ {
1438
+ ! "icons": { "16": "Icon16.png" },
1439
+ ! "background": { "service_worker": "missing-worker.js" }
1440
+ }
1441
+ ```
1442
+
1443
+ #### <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
1444
+
1445
+ ```diff
1446
+ - /extension/_metadata/app.json
1447
+ + /extension/metadata/app.json
1448
+ - /extension/content script.js
1449
+ + /extension/content-script.js
1450
+
1451
+ // manifest.json
1452
+ {
1453
+ - "icons": { "16": "Icon16.png" },
1454
+ + "icons": { "16": "icon16.png" },
1455
+ - "background": { "service_worker": "missing-worker.js" }
1456
+ + "background": { "service_worker": "service-worker.js" }
1457
+ }
1458
+ ```
1459
+
1460
+ #### When not to use it
1461
+
1462
+ If you don't use conventional filenames or paths, or they're generated at build time.
1463
+
1464
+ #### Introduced in
1465
+
1466
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1467
+
1468
+ #### See also
1469
+
1470
+ - [`no-missing-web-accessible-resources`](#no-missing-web-accessible-resources)
1471
+ <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>
1472
+ - [`valid-manifest-icons`](#valid-manifest-icons)
1473
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1474
+ <a title="Accepts array w/ options" href="#valid-manifest-icons-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1475
+
1476
+ <div align="center">
1477
+
1478
+ [Back to index ↑][epce-rules]
1479
+
1480
+ </div>
1481
+
1482
+ ---
1483
+
1484
+ </details>
1485
+
1486
+ <h3 id="valid-license-file">
1487
+ <code>valid-license-file</code>
1488
+ <a title="Only works in 'license' config block" href="#usage">
1489
+ <img height=18 alt="[License only]" src="https://img.shields.io/badge/License_only-559bff?style=flat-square" align="middle"></a>
1490
+ <a title="Accepts array w/ options" href="#usage">
1491
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1492
+ <a title="Copy rule URL" target="_blank"
1493
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-license-file">
1494
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1495
+ </h3>
1496
+
1497
+ <details>
1498
+
1499
+ <summary>Validates SPDX identifiers in license files.</summary>
1500
+
1501
+ <h4 id="valid-license-file-options">Options</h4>
1502
+
1503
+ - `requireSPDX` (default `false`) – require <a target="_blank" href="https://spdx.dev/learn/handling-license-info/">`SPDX-License-Identifier`</a> in the license
1504
+ - `allowedLicenses` (default `[]`) – <a target="_blank" href="https://spdx.org/licenses/">SPDX license IDs</a> to restrict to (e.g. `['Apache-2.0', 'MIT']`), as a single string or array
1505
+
1506
+ #### <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
1507
+
1508
+ ```diff
1509
+ /* eslint chrome-extensions/valid-license-file: ['error', { requireSPDX: true, allowedLicenses: ['MIT'] }] */
1510
+
1511
+ // LICENSE.md
1512
+
1513
+ MIT License
1514
+
1515
+ Copyright © 2026 You
1516
+
1517
+ !
1518
+ ```
1519
+
1520
+ #### <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
1521
+
1522
+ ```diff
1523
+ /* eslint chrome-extensions/valid-license-file: ['error', { requireSPDX: true, allowedLicenses: ['MIT'] }] */
1524
+
1525
+ // LICENSE.md
1526
+
1527
+ MIT License
1528
+
1529
+ Copyright © 2026 You
1530
+
1531
+ + SPDX-License-Identifier: MIT
1532
+ ```
1533
+
1534
+ #### When not to use it
1535
+
1536
+ If your license is injected at build time, or you use a license w/ no SPDX identifier.
1537
+
1538
+ #### Introduced in
1539
+
1540
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1541
+
1542
+ #### See also
1543
+
1544
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=spdx.org&sz=64">&ensp;<a target="_blank" href="https://spdx.org/licenses/">SPDX — License List</a>
1545
+ - [`require-license-file`](#require-license-file)
1546
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1007
1547
 
1008
1548
  <div align="center">
1009
1549
 
@@ -1017,7 +1557,7 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1017
1557
 
1018
1558
  <h3 id="valid-manifest-icons">
1019
1559
  <code>valid-manifest-icons</code>
1020
- <a title="Only works w/ 'json/json' config block" href="#usage">
1560
+ <a title="Only works in 'json/json' config block" href="#usage">
1021
1561
  <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1022
1562
  <a title="Accepts array w/ options" href="#usage">
1023
1563
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
@@ -1090,7 +1630,7 @@ If your icons are injected at build time, or you target browsers that support SV
1090
1630
  <code>valid-mv3-schema</code>
1091
1631
  <a title="Included in recommended config" href="#usage">
1092
1632
  <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">
1633
+ <a title="Works in 'json/json' config block" href="#usage">
1094
1634
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1095
1635
  <a title="Copy rule URL" target="_blank"
1096
1636
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-mv3-schema">
@@ -1140,7 +1680,7 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1140
1680
 
1141
1681
  - [`require-mv3`](#require-mv3)
1142
1682
  <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>
1683
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1144
1684
  - [`no-deprecated-apis`](#no-deprecated-apis)
1145
1685
  <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
1686
  <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>
@@ -1202,7 +1742,7 @@ If your background context isn't a service worker.
1202
1742
 
1203
1743
  - [`require-mv3`](#require-mv3)
1204
1744
  <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>
1745
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1206
1746
  - [`no-remote-code`](#no-remote-code)
1207
1747
  <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
1748
  <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>
@@ -1218,11 +1758,84 @@ If your background context isn't a service worker.
1218
1758
 
1219
1759
  </details>
1220
1760
 
1761
+ <h3 id="valid-url-fields">
1762
+ <code>valid-url-fields</code>
1763
+ <a title="Only works in 'json/json' config block" href="#usage">
1764
+ <img height=18 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1765
+ <a title="Accepts array w/ options" href="#usage">
1766
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1767
+ <a title="Copy rule URL" target="_blank"
1768
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-url-fields">
1769
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1770
+ </h3>
1771
+
1772
+ <details>
1773
+
1774
+ <summary>Validates URLs and match patterns in manifest fields.</summary>
1775
+
1776
+ <h4 id="valid-url-fields-options">Options</h4>
1777
+
1778
+ - `checkURLfields` (default `true`) – validate URL fields (<a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/chrome-settings-override">`chrome_settings_overrides`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/homepage-url">`homepage_url`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/oauth2">`oauth2.scopes`</a>, <a target="_blank" href="https://developer.chrome.com/docs/apps/autoupdate#update_url">`update_url`</a>)
1779
+ - `checkMatchPatterns` (default `true`) – validate match patterns (in <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts">`content_scripts`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable">`externally_connectable`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#host-permissions">`host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">`optional_host_permissions`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources">`web_accessible_resources`</a>)
1780
+ - `allowedSchemes` (default `['https', 'file']`) – permitted URL schemes for <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">match patterns</a>
1781
+ - `allowAllURLs` (default `false`) – allow unrestricted patterns (<a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`<all_urls>`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`https://*/*`</a>, <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns">`*://*/*`</a>)
1782
+
1783
+ #### <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
1784
+
1785
+ ```diff
1786
+ {
1787
+ "manifest_version": 3,
1788
+ ! "homepage_url": "not-a-url",
1789
+ ! "host_permissions": ["https://*"],
1790
+ ! "content_scripts": [{ "js": ["content.js"], "matches": ["*://*foo.com/*"] }],
1791
+ ! "web_accessible_resources": [{ "resources": ["logo.png"], "matches": ["https://example.com/specific-path"] }]
1792
+ }
1793
+ ```
1794
+
1795
+ #### <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
1796
+
1797
+ ```diff
1798
+ {
1799
+ "manifest_version": 3,
1800
+ - "homepage_url": "not-a-url",
1801
+ + "homepage_url": "https://example.com",
1802
+ - "host_permissions": ["https://*"],
1803
+ + "host_permissions": ["https://example.com/*"],
1804
+ - "content_scripts": [{ "js": ["content.js"], "matches": ["*://*foo.com/*"] }],
1805
+ + "content_scripts": [{ "js": ["content.js"], "matches": ["*://*.foo.com/*"] }],
1806
+ - "web_accessible_resources": [{ "resources": ["logo.png"], "matches": ["https://example.com/specific-path"] }]
1807
+ + "web_accessible_resources": [{ "resources": ["logo.png"], "matches": ["https://example.com/*"] }]
1808
+ }
1809
+ ```
1810
+
1811
+ #### When not to use it
1812
+
1813
+ If your URLs or match patterns are generated at build time.
1814
+
1815
+ #### Introduced in
1816
+
1817
+ <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/releases/tag/v2.4.0">v2.4.0</a> (October 13, 2026)
1818
+
1819
+ #### See also
1820
+
1821
+ - <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>
1822
+ - <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>
1823
+
1824
+ <div align="center">
1825
+
1826
+ [Back to index ↑][epce-rules]
1827
+
1828
+ </div>
1829
+
1830
+ ---
1831
+
1832
+ </details>
1833
+
1221
1834
  <h3 id="valid-version-field">
1222
1835
  <code>valid-version-field</code>
1223
1836
  <a title="Included in recommended config" href="#usage">
1224
1837
  <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">
1838
+ <a title="Works in 'json/json' config block" href="#usage">
1226
1839
  <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1227
1840
  <a title="Accepts array w/ options" href="#usage">
1228
1841
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>