eslint-plugin-chrome-extensions 2.4.1 → 2.5.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 (46) hide show
  1. package/README.md +101 -23
  2. package/package.json +4 -3
  3. package/src/data/apis.js +166 -115
  4. package/src/data/deprecations.js +7 -7
  5. package/src/data/i18n.js +11 -69
  6. package/src/data/manifest.js +61 -57
  7. package/src/data/permissions.js +29 -29
  8. package/src/data/regex.js +10 -0
  9. package/src/index.js +7 -123
  10. package/src/rules/manifest-key-order.js +8 -8
  11. package/src/rules/manifest-spacing.js +5 -5
  12. package/src/rules/no-content-style-leak.js +6 -4
  13. package/src/rules/no-deprecated-apis.js +4 -4
  14. package/src/rules/no-duplicate-manifest-keys.js +3 -4
  15. package/src/rules/no-insecure-messaging.js +4 -4
  16. package/src/rules/no-invalid-permissions.js +10 -11
  17. package/src/rules/no-missing-default-locale.js +7 -9
  18. package/src/rules/no-missing-i18n-keys.js +22 -20
  19. package/src/rules/no-missing-permissions.js +7 -5
  20. package/src/rules/no-missing-web-accessible-resources.js +7 -5
  21. package/src/rules/no-remote-code.js +12 -12
  22. package/src/rules/no-sensitive-permissions.js +75 -0
  23. package/src/rules/no-unrestricted-host-permissions.js +8 -7
  24. package/src/rules/no-unused-i18n-keys.js +11 -10
  25. package/src/rules/no-unused-permissions.js +22 -23
  26. package/src/rules/require-license-file.js +9 -8
  27. package/src/rules/require-mv3.js +4 -5
  28. package/src/rules/require-short-name-when-useful.js +4 -3
  29. package/src/rules/valid-filenames.js +3 -10
  30. package/src/rules/valid-license-file.js +18 -11
  31. package/src/rules/valid-manifest-icons.js +6 -5
  32. package/src/rules/valid-mv3-schema.js +21 -21
  33. package/src/rules/valid-service-worker.js +36 -13
  34. package/src/rules/valid-url-fields.js +10 -7
  35. package/src/rules/valid-version-field.js +4 -8
  36. package/src/utils/extension.js +51 -0
  37. package/src/utils/i18n.js +55 -0
  38. package/src/utils/init.js +105 -0
  39. package/src/utils/license.js +55 -0
  40. package/src/utils/node.js +23 -0
  41. package/src/utils/pkg.js +21 -0
  42. package/src/utils/rules.js +7 -0
  43. package/src/utils/text.js +13 -0
  44. package/src/data/license.js +0 -27
  45. package/src/data/text-parser.js +0 -11
  46. package/src/utils.js +0 -95
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <a target="_blank" href="https://www.npmjs.com/package/eslint-plugin-chrome-extensions">
6
6
  <img alt="[Latest Build]" src="https://img.shields.io/npm/v/eslint-plugin-chrome-extensions?logo=icinga&style=for-the-badge&label=Latest%20Build&color=32fcee"></a>
7
- <a href="#license">
7
+ <a href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
8
8
  <img alt="[License: MIT]" src="https://img.shields.io/badge/License-MIT-f1f20a.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
9
9
  <a target="_blank" href="https://eslint.org/">
10
10
  <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>
@@ -54,7 +54,7 @@ export default [
54
54
  'chrome-extensions/manifest-spacing': ['warn', { spaces: 4 }] // selectively tweak rule
55
55
  }
56
56
  },
57
- { files: ['**/*LICENSE*'], ...chromeExtensions.configs.license },
57
+ { files: ['**/*LICENSE*'], ...chromeExtensions.configs.license },
58
58
  { files: ['**/extension/**/*.css'], ...chromeExtensions.configs.css },
59
59
  { files: ['**/extension/**/*.html'], ...chromeExtensions.configs.html },
60
60
  { files: ['**/extension/**/*.json'], ...chromeExtensions.configs.json },
@@ -386,9 +386,8 @@ If you don't want deprecation validation at all. For individual deprecated APIs
386
386
  - "name": "Foo",
387
387
  - "name": "Bar",
388
388
  "name": "My Extension",
389
- - "version": "1.0.0",
390
- - "version": "2.0.0"
391
389
  "version": "1.0.0"
390
+ - "version": "2.0.0"
392
391
  }
393
392
  ```
394
393
 
@@ -1009,6 +1008,76 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
1009
1008
 
1010
1009
  </details>
1011
1010
 
1011
+ <h3 id="no-sensitive-permissions">
1012
+ <code>no-sensitive-permissions</code>
1013
+ <a title="Included in recommended config" href="#usage">
1014
+ <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1015
+ <a title="Included in security config" href="#usage">
1016
+ <img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
1017
+ <a title="Works in 'json/json' config block" href="#usage">
1018
+ <img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1019
+ <a title="Accepts array w/ options" href="#usage">
1020
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1021
+ <a title="Copy rule URL" target="_blank"
1022
+ href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-sensitive-permissions">
1023
+ <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
1024
+ </h3>
1025
+
1026
+ <details>
1027
+
1028
+ <summary>Flags sensitive manifest permissions that warrant security review.</summary>
1029
+
1030
+ <h4 id="no-sensitive-permissions-options">Options</h4>
1031
+
1032
+ - `allowedPermissions` (default `[]`) – sensitive permission names to explicitly allow, as a single string or array
1033
+
1034
+ #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
1035
+
1036
+ ```diff
1037
+ {
1038
+ "manifest_version": 3,
1039
+ ! "permissions": ["tabs", "cookies", "storage"]
1040
+ }
1041
+ ```
1042
+
1043
+ #### <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
1044
+
1045
+ ```diff
1046
+ {
1047
+ "manifest_version": 3,
1048
+ - "permissions": ["tabs", "cookies", "storage"]
1049
+ + "permissions": ["storage"]
1050
+ }
1051
+ ```
1052
+
1053
+ #### When not to use it
1054
+
1055
+ If you legitimately require sensitive permissions, or prefer manual security review.
1056
+
1057
+ #### Introduced in
1058
+
1059
+ v2.5.0 (Unreleased)
1060
+
1061
+ #### See also
1062
+
1063
+ - [`no-invalid-permissions`](#no-invalid-permissions)
1064
+ <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>
1065
+ <a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
1066
+ <a title="Accepts array w/ options" href="#no-invalid-permissions-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1067
+ - [`no-unused-permissions`](#no-unused-permissions)
1068
+ <a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
1069
+ - <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64">&ensp;<a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">Chrome for Developers — Declare permissions</a>
1070
+
1071
+ <div align="center">
1072
+
1073
+ [Back to index ↑][epce-rules]
1074
+
1075
+ </div>
1076
+
1077
+ ---
1078
+
1079
+ </details>
1080
+
1012
1081
  <h3 id="no-unrestricted-host-permissions">
1013
1082
  <code>no-unrestricted-host-permissions</code>
1014
1083
  <a title="Only works in 'json/json' config block" href="#usage">
@@ -1228,14 +1297,14 @@ If you access the granted API through an alias or computed property rather than
1228
1297
 
1229
1298
  <summary>Requires a license file in the extension.</summary>
1230
1299
 
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 structure
1300
+ #### <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
1232
1301
 
1233
1302
  ```diff
1234
1303
  /extension/manifest.json
1235
1304
  !
1236
1305
  ```
1237
1306
 
1238
- #### <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 structure
1307
+ #### <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
1239
1308
 
1240
1309
  ```diff
1241
1310
  /extension/manifest.json
@@ -1253,7 +1322,8 @@ If you intentionally omit a license, or it's injected at build time.
1253
1322
  #### See also
1254
1323
 
1255
1324
  - [`valid-license-file`](#valid-license-file)
1256
- <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>
1325
+ <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>
1326
+ <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>
1257
1327
  <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>
1258
1328
 
1259
1329
  <div align="center">
@@ -1428,7 +1498,7 @@ If you primarily target a browser that doesn't support `short_name`.
1428
1498
 
1429
1499
  ```diff
1430
1500
  // files
1431
- ! /extension/_metadata/app.json
1501
+ ! /extension/_metadata/extension.json
1432
1502
  ! /extension/content script.js
1433
1503
 
1434
1504
  // manifest.json
@@ -1441,8 +1511,8 @@ If you primarily target a browser that doesn't support `short_name`.
1441
1511
  #### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
1442
1512
 
1443
1513
  ```diff
1444
- - /extension/_metadata/app.json
1445
- + /extension/metadata/app.json
1514
+ - /extension/_metadata/extension.json
1515
+ + /extension/metadata/extension.json
1446
1516
  - /extension/content script.js
1447
1517
  + /extension/content-script.js
1448
1518
 
@@ -1483,8 +1553,10 @@ If you don't use conventional filenames or paths, or they're generated at build
1483
1553
 
1484
1554
  <h3 id="valid-license-file">
1485
1555
  <code>valid-license-file</code>
1486
- <a title="Only works in 'license' config block" href="#usage">
1556
+ <a title="Only works in license config block" href="#usage">
1487
1557
  <img height=18 alt="[License only]" src="https://img.shields.io/badge/License_only-559bff?style=flat-square" align="middle"></a>
1558
+ <a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
1559
+ <img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
1488
1560
  <a title="Accepts array w/ options" href="#usage">
1489
1561
  <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1490
1562
  <a title="Copy rule URL" target="_blank"
@@ -1506,13 +1578,9 @@ If you don't use conventional filenames or paths, or they're generated at build
1506
1578
  ```diff
1507
1579
  /* eslint chrome-extensions/valid-license-file: ['error', { requireSPDX: true, allowedLicenses: ['MIT'] }] */
1508
1580
 
1509
- // LICENSE.md
1510
-
1511
- MIT License
1512
-
1581
+ ! MIT License
1582
+ -----------
1513
1583
  Copyright © 2026 You
1514
-
1515
- !
1516
1584
  ```
1517
1585
 
1518
1586
  #### <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
@@ -1520,18 +1588,20 @@ If you don't use conventional filenames or paths, or they're generated at build
1520
1588
  ```diff
1521
1589
  /* eslint chrome-extensions/valid-license-file: ['error', { requireSPDX: true, allowedLicenses: ['MIT'] }] */
1522
1590
 
1523
- // LICENSE.md
1524
-
1525
1591
  MIT License
1526
-
1592
+ -----------
1527
1593
  Copyright © 2026 You
1528
-
1594
+ +
1529
1595
  + SPDX-License-Identifier: MIT
1530
1596
  ```
1531
1597
 
1598
+ #### Benefits
1599
+
1600
+ Enables machine-readability for compliance scanners, SBOM generators & CI gates.
1601
+
1532
1602
  #### When not to use it
1533
1603
 
1534
- If your license is injected at build time, or you use a license w/ no SPDX identifier.
1604
+ If your license is injected at build time, or you use one w/ no existing SPDX identifier.
1535
1605
 
1536
1606
  #### Introduced in
1537
1607
 
@@ -1697,6 +1767,8 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1697
1767
  <code>valid-service-worker</code>
1698
1768
  <a title="Included in recommended config" href="#usage">
1699
1769
  <img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
1770
+ <a title="Accepts array w/ options" href="#usage">
1771
+ <img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
1700
1772
  <a title="Copy rule URL" target="_blank"
1701
1773
  href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-service-worker">
1702
1774
  <img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
@@ -1706,6 +1778,12 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
1706
1778
 
1707
1779
  <summary>Enforces valid service worker lifecycle and isolation.</summary>
1708
1780
 
1781
+ <h4 id="mit-worker-options">Options</h4>
1782
+
1783
+ - `checkListenerTopLevel` (default `true`) – require `chrome.*.addListener()` calls at module top level
1784
+ - `checkKeepaliveTimer` (default `true`) – flag sub-30s timers used as a keepalive workaround
1785
+ - `checkDOMglobals` (default `true`) – flag DOM globals (`window`, `document`, `localStorage`) inside the service worker
1786
+
1709
1787
  #### <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
1710
1788
 
1711
1789
  ```diff
@@ -1922,7 +2000,7 @@ If you don't care about version format consistency, or your version is injected
1922
2000
  ## <img height=30 width=27 align="top" src="https://api.iconify.design/ic/baseline-account-balance.svg?color=%232b2b2a"> License
1923
2001
 
1924
2002
  <a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
1925
- <img height=85 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
2003
+ <img height=80 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
1926
2004
  <br><br>
1927
2005
 
1928
2006
  <details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-chrome-extensions",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "ESLint rules for Chrome extensions",
5
5
  "keywords": [
6
6
  "eslint",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "repository": {
19
19
  "type": "git",
20
- "url": "git+https://codeberg.org/adamlui/eslint-plugin-chrome-extensions.git"
20
+ "url": "https://codeberg.org/adamlui/eslint-plugin-chrome-extensions.git"
21
21
  },
22
22
  "funding": [
23
23
  {
@@ -62,7 +62,8 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "globals": "^17.13.0",
65
- "spdx-license-ids": "^3.0.24"
65
+ "spdx-license-ids": "^3.0.24",
66
+ "spdx-license-list": "^6.12.0"
66
67
  },
67
68
  "devDependencies": {
68
69
  "@e18e/eslint-plugin": "^0.8.1",
package/src/data/apis.js CHANGED
@@ -1,116 +1,167 @@
1
- export const apiPermissionMap = new Map([
2
- ['chrome.alarms', 'alarms'],
3
- ['chrome.bookmarks', 'bookmarks'],
4
- ['chrome.browsingData', 'browsingData'],
5
- ['chrome.contextMenus', 'contextMenus'],
6
- ['chrome.cookies', 'cookies'],
7
- ['chrome.debugger', 'debugger'],
8
- ['chrome.declarativeNetRequest', 'declarativeNetRequest'],
9
- ['chrome.downloads', 'downloads'],
10
- ['chrome.history', 'history'],
11
- ['chrome.idle', 'idle'],
12
- ['chrome.management', 'management'],
13
- ['chrome.menus', 'menus'],
14
- ['chrome.notifications', 'notifications'],
15
- ['chrome.pageCapture', 'pageCapture'],
16
- ['chrome.privacy', 'privacy'],
17
- ['chrome.proxy', 'proxy'],
18
- ['chrome.scripting', 'scripting'],
19
- ['chrome.sessions', 'sessions'],
20
- ['chrome.storage', 'storage'],
21
- ['chrome.tabCapture', 'tabCapture'],
22
- ['chrome.tabs.query', 'tabs'],
23
- ['chrome.topSites', 'topSites'],
24
- ['chrome.webRequest', 'webRequest']
25
- ])
26
-
27
- export const deprecatedAPIs = new Map([
28
- ['chrome.pageAction.show', 'chrome.action.enable'],
29
- ['chrome.pageAction.hide', 'chrome.action.disable'],
30
- ['chrome.pageAction.setIcon', 'chrome.action.setIcon'],
31
- ['chrome.pageAction.setTitle', 'chrome.action.setTitle'],
32
- ['chrome.pageAction.setPopup', 'chrome.action.setPopup'],
33
- ['chrome.pageAction.getTitle', 'chrome.action.getTitle'],
34
- ['chrome.pageAction.getPopup', 'chrome.action.getPopup'],
35
- ['chrome.browserAction', 'chrome.action'],
36
- ['chrome.pageAction', 'chrome.action'],
37
- ['chrome.extension.getBackgroundPage', 'chrome.runtime.getContexts'],
38
- ['chrome.extension.getURL', 'chrome.runtime.getURL'],
39
- ['chrome.extension.sendRequest', 'chrome.runtime.sendMessage'],
40
- ['chrome.extension.onRequest', 'chrome.runtime.onMessage'],
41
- ['chrome.extension.onRequestExternal', 'chrome.runtime.onMessageExternal'],
42
- ['chrome.extension.connect', 'chrome.runtime.connect'],
43
- ['chrome.extension.onConnect', 'chrome.runtime.onConnect'],
44
- ['chrome.extension.onConnectExternal', 'chrome.runtime.onConnectExternal'],
45
- ['chrome.tabs.executeScript', 'chrome.scripting.executeScript'],
46
- ['chrome.tabs.insertCSS', 'chrome.scripting.insertCSS'],
47
- ['chrome.tabs.removeCSS', 'chrome.scripting.removeCSS']
48
- ])
49
-
50
- export const externalMsgListeners = new Set(['chrome.runtime.onMessageExternal', 'chrome.runtime.onConnectExternal'])
51
-
52
- export const permlessAPIs = new Set([
53
- // https://developer.chrome.com/docs/extensions/reference/api/management
54
- 'chrome.management.getPermissionWarningsByManifest',
55
- 'chrome.management.getSelf',
56
- 'chrome.management.uninstallSelf',
57
- // https://developer.chrome.com/docs/extensions/reference/api/runtime
58
- 'chrome.runtime.connect',
59
- 'chrome.runtime.getManifest',
60
- 'chrome.runtime.getPlatformInfo',
61
- 'chrome.runtime.getURL',
62
- 'chrome.runtime.onBrowserUpdateAvailable', // eslint-disable-line no-secrets/no-secrets
63
- 'chrome.runtime.onConnect',
64
- 'chrome.runtime.onConnectExternal',
65
- 'chrome.runtime.onInstalled',
66
- 'chrome.runtime.onMessage',
67
- 'chrome.runtime.onMessageExternal',
68
- 'chrome.runtime.onStartup',
69
- 'chrome.runtime.onSuspend',
70
- 'chrome.runtime.onSuspendCanceled',
71
- 'chrome.runtime.onUpdateAvailable',
72
- 'chrome.runtime.openOptionsPage',
73
- 'chrome.runtime.reload',
74
- 'chrome.runtime.requestUpdateCheck',
75
- 'chrome.runtime.restart',
76
- 'chrome.runtime.restartAfterDelay',
77
- 'chrome.runtime.sendMessage',
78
- 'chrome.runtime.setUninstallURL',
79
- // https://developer.chrome.com/docs/extensions/reference/api/tabs
80
- 'chrome.tabs.captureVisibleTab',
81
- 'chrome.tabs.connect',
82
- 'chrome.tabs.create',
83
- 'chrome.tabs.detectLanguage',
84
- 'chrome.tabs.discard',
85
- 'chrome.tabs.duplicate',
86
- 'chrome.tabs.executeScript',
87
- 'chrome.tabs.get',
88
- 'chrome.tabs.getCurrent',
89
- 'chrome.tabs.goBack',
90
- 'chrome.tabs.goForward',
91
- 'chrome.tabs.highlight',
92
- 'chrome.tabs.insertCSS',
93
- 'chrome.tabs.move',
94
- 'chrome.tabs.reload',
95
- 'chrome.tabs.remove',
96
- 'chrome.tabs.removeCSS',
97
- 'chrome.tabs.sendMessage',
98
- 'chrome.tabs.update'
99
- ])
100
-
101
- export function findDeprecated(api) {
102
- for (const [deprecated, replacement] of deprecatedAPIs)
103
- if (api == deprecated || api.startsWith(`${deprecated}.`))
104
- return { deprecated, replacement }
105
- return null
1
+ export default {
2
+ deprecated: new Map([
3
+ ['chrome.browserAction', 'chrome.action'],
4
+ ['chrome.declarativeWebRequest', 'chrome.declarativeNetRequest'],
5
+ ['chrome.extension.connect', 'chrome.runtime.connect'],
6
+ ['chrome.extension.getBackgroundPage', 'chrome.runtime.getContexts'],
7
+ ['chrome.extension.getURL', 'chrome.runtime.getURL'],
8
+ ['chrome.extension.lastError', 'chrome.runtime.lastError'],
9
+ ['chrome.extension.onConnect', 'chrome.runtime.onConnect'],
10
+ ['chrome.extension.onConnectExternal', 'chrome.runtime.onConnectExternal'],
11
+ ['chrome.extension.onRequest', 'chrome.runtime.onMessage'],
12
+ ['chrome.extension.onRequestExternal', 'chrome.runtime.onMessageExternal'],
13
+ ['chrome.extension.sendRequest', 'chrome.runtime.sendMessage'],
14
+ ['chrome.fileBrowserHandler', 'File Handling API'],
15
+ ['chrome.pageAction.show', 'chrome.action.enable'],
16
+ ['chrome.pageAction.hide', 'chrome.action.disable'],
17
+ ['chrome.pageAction.setIcon', 'chrome.action.setIcon'],
18
+ ['chrome.pageAction.setTitle', 'chrome.action.setTitle'],
19
+ ['chrome.pageAction.setPopup', 'chrome.action.setPopup'],
20
+ ['chrome.pageAction.getTitle', 'chrome.action.getTitle'],
21
+ ['chrome.pageAction.getPopup', 'chrome.action.getPopup'],
22
+ ['chrome.pageAction', 'chrome.action'], // must stay after pageAction.* — prefix match
23
+ ['chrome.tabs.executeScript', 'chrome.scripting.executeScript'],
24
+ ['chrome.tabs.getAllInWindow', 'chrome.tabs.query({ currentWindow: true })'],
25
+ ['chrome.tabs.getSelected', 'chrome.tabs.query({ active: true })'],
26
+ ['chrome.tabs.insertCSS', 'chrome.scripting.insertCSS'],
27
+ ['chrome.tabs.onActiveChanged', 'chrome.tabs.onActivated'],
28
+ ['chrome.tabs.onSelectionChanged', 'chrome.tabs.onActivated'],
29
+ ['chrome.tabs.removeCSS', 'chrome.scripting.removeCSS'],
30
+ ['chrome.tabs.sendRequest', 'chrome.tabs.sendMessage']
31
+ ]),
32
+ externalMsgListeners: new Set(['chrome.runtime.onMessageExternal', 'chrome.runtime.onConnectExternal']),
33
+ permissionMap: new Map([
34
+ ['chrome.accessibilityFeatures.set', 'accessibilityFeatures.modify'],
35
+ ['chrome.accessibilityFeatures.clear', 'accessibilityFeatures.modify'],
36
+ ['chrome.accessibilityFeatures', 'accessibilityFeatures.read'],
37
+ ['chrome.alarms', 'alarms'],
38
+ ['chrome.audio', 'audio'],
39
+ ['chrome.bookmarks', 'bookmarks'],
40
+ ['chrome.browsingData', 'browsingData'],
41
+ ['chrome.certificateProvider', 'certificateProvider'],
42
+ ['chrome.contentSettings', 'contentSettings'],
43
+ ['chrome.contextMenus', 'contextMenus'],
44
+ ['chrome.cookies', 'cookies'],
45
+ ['chrome.debugger', 'debugger'],
46
+ ['chrome.declarativeContent', 'declarativeContent'],
47
+ ['chrome.declarativeNetRequest', 'declarativeNetRequest'],
48
+ ['chrome.dns', 'dns'],
49
+ ['chrome.desktopCapture', 'desktopCapture'],
50
+ ['chrome.documentScan', 'documentScan'],
51
+ ['chrome.downloads.open', 'downloads.open'],
52
+ ['chrome.downloads.setUiOptions', 'downloads.ui'],
53
+ ['chrome.downloads', 'downloads'],
54
+ ['chrome.enterprise.deviceAttributes', 'enterprise.deviceAttributes'],
55
+ ['chrome.enterprise.hardwarePlatform', 'enterprise.hardwarePlatform'],
56
+ ['chrome.enterprise.networkingAttributes','enterprise.networkingAttributes'],
57
+ ['chrome.enterprise.platformKeys', 'enterprise.platformKeys'],
58
+ ['chrome.favicon', 'favicon'],
59
+ ['chrome.fileBrowserHandler', 'fileBrowserHandler'],
60
+ ['chrome.fontSettings', 'fontSettings'],
61
+ ['chrome.gcm', 'gcm'],
62
+ ['chrome.instanceID', 'gcm'],
63
+ ['chrome.history', 'history'],
64
+ ['chrome.identity.getProfileUserInfo', 'identity.email'],
65
+ ['chrome.identity', 'identity'],
66
+ ['chrome.idle', 'idle'],
67
+ ['chrome.loginState', 'loginState'],
68
+ ['chrome.management', 'management'],
69
+ ['chrome.runtime.connectNative', 'nativeMessaging'],
70
+ ['chrome.runtime.sendNativeMessage', 'nativeMessaging'],
71
+ ['chrome.notifications', 'notifications'],
72
+ ['chrome.offscreen', 'offscreen'],
73
+ ['chrome.pageCapture', 'pageCapture'],
74
+ ['chrome.platformKeys', 'platformKeys'],
75
+ ['chrome.power', 'power'],
76
+ ['chrome.printerProvider', 'printerProvider'],
77
+ ['chrome.printingMetrics', 'printingMetrics'],
78
+ ['chrome.printing', 'printing'],
79
+ ['chrome.privacy', 'privacy'],
80
+ ['chrome.processes', 'processes'],
81
+ ['chrome.proxy', 'proxy'],
82
+ ['chrome.publicSuffix', 'publicSuffix'],
83
+ ['chrome.readingList', 'readingList'],
84
+ ['chrome.scripting', 'scripting'],
85
+ ['chrome.search', 'search'],
86
+ ['chrome.sessions', 'sessions'],
87
+ ['chrome.sidePanel', 'sidePanel'],
88
+ ['chrome.storage', 'storage'],
89
+ ['chrome.system.cpu', 'system.cpu'],
90
+ ['chrome.system.display', 'system.display'],
91
+ ['chrome.system.memory', 'system.memory'],
92
+ ['chrome.system.storage', 'system.storage'],
93
+ ['chrome.tabCapture', 'tabCapture'],
94
+ ['chrome.tabGroups', 'tabGroups'],
95
+ ['chrome.tabs.query', 'tabs'],
96
+ ['chrome.topSites', 'topSites'],
97
+ ['chrome.ttsEngine', 'ttsEngine'],
98
+ ['chrome.tts', 'tts'],
99
+ ['chrome.userScripts', 'userScripts'],
100
+ ['chrome.vpnProvider', 'vpnProvider'],
101
+ ['chrome.wallpaper', 'wallpaper'],
102
+ ['chrome.webAuthenticationProxy', 'webAuthenticationProxy'],
103
+ ['chrome.webNavigation', 'webNavigation'],
104
+ ['chrome.webRequest', 'webRequest']
105
+ ]),
106
+ permless: new Set([
107
+ 'chrome.i18n',
108
+ 'chrome.management.getPermissionWarningsByManifest',
109
+ 'chrome.management.getSelf',
110
+ 'chrome.management.uninstallSelf',
111
+ 'chrome.runtime.connect',
112
+ 'chrome.runtime.getManifest',
113
+ 'chrome.runtime.getPlatformInfo',
114
+ 'chrome.runtime.getURL',
115
+ 'chrome.runtime.onBrowserUpdateAvailable', // eslint-disable-line no-secrets/no-secrets
116
+ 'chrome.runtime.onConnect',
117
+ 'chrome.runtime.onConnectExternal',
118
+ 'chrome.runtime.onInstalled',
119
+ 'chrome.runtime.onMessage',
120
+ 'chrome.runtime.onMessageExternal',
121
+ 'chrome.runtime.onStartup',
122
+ 'chrome.runtime.onSuspend',
123
+ 'chrome.runtime.onSuspendCanceled',
124
+ 'chrome.runtime.onUpdateAvailable',
125
+ 'chrome.runtime.openOptionsPage',
126
+ 'chrome.runtime.reload',
127
+ 'chrome.runtime.requestUpdateCheck',
128
+ 'chrome.runtime.restart',
129
+ 'chrome.runtime.restartAfterDelay',
130
+ 'chrome.runtime.sendMessage',
131
+ 'chrome.runtime.setUninstallURL',
132
+ 'chrome.tabs.captureVisibleTab',
133
+ 'chrome.tabs.connect',
134
+ 'chrome.tabs.create',
135
+ 'chrome.tabs.detectLanguage',
136
+ 'chrome.tabs.discard',
137
+ 'chrome.tabs.duplicate',
138
+ 'chrome.tabs.executeScript',
139
+ 'chrome.tabs.get',
140
+ 'chrome.tabs.getCurrent',
141
+ 'chrome.tabs.goBack',
142
+ 'chrome.tabs.goForward',
143
+ 'chrome.tabs.highlight',
144
+ 'chrome.tabs.insertCSS',
145
+ 'chrome.tabs.move',
146
+ 'chrome.tabs.reload',
147
+ 'chrome.tabs.remove',
148
+ 'chrome.tabs.removeCSS',
149
+ 'chrome.tabs.sendMessage',
150
+ 'chrome.tabs.update',
151
+ 'chrome.windows'
152
+ ]),
153
+ findDeprecated(api) {
154
+ for (const [deprecated, replacement] of this.deprecated)
155
+ if (api == deprecated || api.startsWith(`${deprecated}.`))
156
+ return { deprecated, replacement }
157
+ return null
158
+ },
159
+ findPermission(api) {
160
+ if (this.permless.has(api)) return null
161
+ for (const [prefix, permission] of this.permissionMap)
162
+ if (api == prefix || api.startsWith(`${prefix}.`))
163
+ return permission
164
+ return null
165
+ },
166
+ isExternalMsgListener(api) { return this.externalMsgListeners.has(api) }
106
167
  }
107
-
108
- export function findPermission(api) {
109
- if (permlessAPIs.has(api)) return null
110
- for (const [prefix, permission] of apiPermissionMap)
111
- if (api == prefix || api.startsWith(`${prefix}.`))
112
- return permission
113
- return null
114
- }
115
-
116
- export function isExternalMessagingListener(api) { return externalMsgListeners.has(api) }
@@ -1,10 +1,10 @@
1
1
  // Delete a line to end support
2
2
 
3
- export const bundles = {
4
- 'no-invalid-permissions': ['recommended'], // 2026-10-5 announced future removal
5
- 'require-mv3': ['recommended'], // 2026-10-5 announced future removal
6
- 'valid-mv3-schema': ['recommended'], // 2026-10-5 announced future removal
7
- 'valid-version-field': ['recommended'] // 2026-10-5 announced future removal
3
+ export default {
4
+ bundles: {
5
+ 'no-invalid-permissions': ['recommended'], // 2026-10-5 announced future removal
6
+ 'require-mv3': ['recommended'], // 2026-10-5 announced future removal
7
+ 'valid-mv3-schema': ['recommended'], // 2026-10-5 announced future removal
8
+ 'valid-version-field': ['recommended'] // 2026-10-5 announced future removal
9
+ }
8
10
  }
9
-
10
- export default { bundles }