eslint-plugin-chrome-extensions 2.6.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 (50) hide show
  1. package/README.md +648 -33
  2. package/package.json +11 -9
  3. package/src/data/apis.js +74 -88
  4. package/src/data/manifest.js +3 -1
  5. package/src/data/regex.js +3 -1
  6. package/src/index.d.ts +42 -0
  7. package/src/index.js +0 -4
  8. package/src/rules/css-spacing.js +375 -0
  9. package/src/rules/manifest-key-order.js +1 -2
  10. package/src/rules/manifest-spacing.js +1 -2
  11. package/src/rules/no-content-style-leak.js +12 -11
  12. package/src/rules/no-deprecated-apis.js +2 -2
  13. package/src/rules/no-duplicate-manifest-keys.js +0 -1
  14. package/src/rules/no-global-keyframes.js +84 -0
  15. package/src/rules/no-host-page-selectors.js +105 -0
  16. package/src/rules/no-inline-event-handlers.js +116 -0
  17. package/src/rules/no-inline-scripts.js +65 -0
  18. package/src/rules/no-insecure-fetch.js +7 -6
  19. package/src/rules/no-insecure-messaging.js +4 -4
  20. package/src/rules/no-invalid-locales.js +3 -5
  21. package/src/rules/no-missing-default-locale.js +1 -1
  22. package/src/rules/no-missing-permissions.js +2 -3
  23. package/src/rules/no-missing-web-accessible-resources.js +2 -2
  24. package/src/rules/no-remote-code.js +77 -28
  25. package/src/rules/no-remote-objects.js +55 -0
  26. package/src/rules/no-remote-urls.js +102 -0
  27. package/src/rules/no-scrollbar-styling.js +71 -0
  28. package/src/rules/no-unrestricted-host-permissions.js +1 -1
  29. package/src/rules/no-unused-i18n-keys.js +0 -1
  30. package/src/rules/no-unused-permissions.js +5 -4
  31. package/src/rules/require-license-file.js +1 -2
  32. package/src/rules/require-mv3.js +3 -2
  33. package/src/rules/require-short-name-when-useful.js +0 -1
  34. package/src/rules/valid-filenames.js +3 -3
  35. package/src/rules/valid-license-file.js +2 -4
  36. package/src/rules/valid-manifest-icons.js +2 -2
  37. package/src/rules/valid-mv3-schema.js +5 -5
  38. package/src/rules/valid-url-fields.js +2 -2
  39. package/src/rules/valid-version-field.js +2 -2
  40. package/src/utils/api.js +20 -0
  41. package/src/utils/array.js +1 -0
  42. package/src/utils/extension.js +1 -3
  43. package/src/utils/html.js +29 -0
  44. package/src/utils/i18n.js +2 -2
  45. package/src/utils/init.js +21 -9
  46. package/src/utils/license.js +1 -1
  47. package/src/utils/node.js +3 -1
  48. package/src/utils/pkg.js +19 -2
  49. package/src/utils/rules.js +1 -1
  50. package/src/data/deprecations.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-chrome-extensions",
3
- "version": "2.6.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
- "@html-eslint/eslint-plugin": "^0.66.1",
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",
@@ -81,7 +80,10 @@
81
80
  "eslint-plugin-package-json": "^1.10.1",
82
81
  "eslint-plugin-promise": "^7.3.0",
83
82
  "eslint-plugin-regexp": "^3.3.1",
84
- "eslint-plugin-security": "^4.2.0"
83
+ "eslint-plugin-security": "^4.2.0",
84
+ "eslint-plugin-sonarjs": "^4.2.2",
85
+ "eslint-plugin-woodpecker": "^1.1.0",
86
+ "oxlint": "^1.89.0"
85
87
  },
86
88
  "peerDependencies": {
87
89
  "@eslint/css": ">=0.5.0",
package/src/data/apis.js CHANGED
@@ -19,7 +19,7 @@ export default {
19
19
  ['chrome.pageAction.setPopup', 'chrome.action.setPopup'],
20
20
  ['chrome.pageAction.getTitle', 'chrome.action.getTitle'],
21
21
  ['chrome.pageAction.getPopup', 'chrome.action.getPopup'],
22
- ['chrome.pageAction', 'chrome.action'], // must stay after pageAction.* — prefix match
22
+ ['chrome.pageAction', 'chrome.action'],
23
23
  ['chrome.tabs.executeScript', 'chrome.scripting.executeScript'],
24
24
  ['chrome.tabs.getAllInWindow', 'chrome.tabs.query({ currentWindow: true })'],
25
25
  ['chrome.tabs.getSelected', 'chrome.tabs.query({ active: true })'],
@@ -31,77 +31,77 @@ export default {
31
31
  ]),
32
32
  externalMsgListeners: new Set(['chrome.runtime.onMessageExternal', 'chrome.runtime.onConnectExternal']),
33
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']
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
105
  ]),
106
106
  permless: new Set([
107
107
  'chrome.i18n',
@@ -112,7 +112,7 @@ export default {
112
112
  'chrome.runtime.getManifest',
113
113
  'chrome.runtime.getPlatformInfo',
114
114
  'chrome.runtime.getURL',
115
- 'chrome.runtime.onBrowserUpdateAvailable', // eslint-disable-line no-secrets/no-secrets
115
+ 'chrome.runtime.onBrowserUpdateAvailable', // oxlint-disable-line no-secrets/no-secrets
116
116
  'chrome.runtime.onConnect',
117
117
  'chrome.runtime.onConnectExternal',
118
118
  'chrome.runtime.onInstalled',
@@ -149,19 +149,5 @@ export default {
149
149
  'chrome.tabs.sendMessage',
150
150
  'chrome.tabs.update',
151
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) }
152
+ ])
167
153
  }
@@ -60,6 +60,8 @@ export default {
60
60
  },
61
61
  patterns: {
62
62
  remoteCode: [
63
- 'eval', 'new-function', 'string-timer', 'dynamic-import', 'remote-script-src', 'execute-script-url']
63
+ 'dynamic-import', 'eval', 'execute-script-url', 'inline-event-handler', 'inline-script-body',
64
+ 'new-function', 'remote-script-src', 'string-timer'
65
+ ]
64
66
  }
65
67
  }
package/src/data/regex.js CHANGED
@@ -1,10 +1,12 @@
1
1
  export default {
2
2
  filename: {
3
3
  css: /\.css$/i,
4
- license: // eslint-disable-next-line security/detect-unsafe-regex
4
+ license: // oxlint-disable-next-line security/detect-unsafe-regex
5
5
  /^(?:[\w.-]*-)?(?:LICEN[SC]E|COPYING)(?:[-.][\w.-]+)?$/i,
6
6
  manifest: /manifest\.json$/,
7
7
  script: /\.[cm]?[jt]sx?$/i
8
8
  },
9
+ prefix: { at: /^@/, css: /^CSS/ },
10
+ scheme: /^(?:([a-z][a-z0-9+.-]*):|\/\/)/i,
9
11
  url: /^https?:\/\//
10
12
  }
package/src/index.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ type RuleSeverity = 0 | 1 | 2 | 'off' | 'warn' | 'error'
2
+ type RuleSetting = RuleSeverity | [RuleSeverity, ...unknown[]]
3
+
4
+ type ConfigName =
5
+ | 'recommended'
6
+ | 'strict'
7
+ | 'problem'
8
+ | 'security'
9
+ | 'manifest'
10
+ | 'license'
11
+ | 'css'
12
+ | 'html'
13
+ | 'json'
14
+ | 'json5'
15
+ | 'jsonc'
16
+
17
+ interface PluginConfig {
18
+ plugins: Record<string, unknown>
19
+ rules: Record<string, RuleSetting>
20
+ language?: string
21
+ languageOptions?: Record<string, unknown>
22
+ }
23
+
24
+ interface PluginRule {
25
+ meta: {
26
+ type?: 'problem' | 'suggestion' | 'layout'
27
+ deprecated?: boolean | {
28
+ message?: string
29
+ replacedBy?: Array<{ rule: { name: string } }>
30
+ }
31
+ docs?: Record<string, unknown>
32
+ }
33
+ create: (context: unknown) => Record<string, (...args: unknown[]) => void>
34
+ }
35
+
36
+ declare const plugin: {
37
+ meta: { name: string }
38
+ rules: Record<string, PluginRule>
39
+ configs: Record<ConfigName, PluginConfig>
40
+ }
41
+
42
+ export { plugin as default, plugin as chromeExtensions }
package/src/index.js CHANGED
@@ -1,12 +1,8 @@
1
1
  import init from './utils/init.js'
2
- import deprecations from './data/deprecations.js'
3
2
 
4
3
  const plugin = init.plugin()
5
4
 
6
5
  init.rules(plugin)
7
6
  init.configs(plugin)
8
7
 
9
- for (const entry of Object.entries(deprecations.bundles))
10
- init.bundleDeprecation(plugin, entry, 'chrome-extensions')
11
-
12
8
  export { plugin as default, plugin as chromeExtensions }