eslint-plugin-greasemonkey 1.8.4 → 1.10.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 +776 -68
- package/docs/LICENSE.md +1 -1
- package/package.json +53 -43
- package/src/data/apis.js +56 -53
- package/src/data/headers.js +65 -31
- package/src/data/regex.js +14 -0
- package/src/index.d.ts +34 -3
- package/src/index.js +5 -80
- package/src/rules/meta-order.js +5 -6
- package/src/rules/meta-spacing.js +11 -10
- package/src/rules/no-duplicate-keys.js +2 -2
- package/src/rules/no-insecure-fetch.js +108 -0
- package/src/rules/no-insecure-messaging.js +67 -0
- package/src/rules/no-invalid-grants.js +12 -10
- package/src/rules/no-invalid-headers.js +11 -11
- package/src/rules/no-missing-grants.js +6 -8
- package/src/rules/no-missing-resources.js +10 -8
- package/src/rules/no-sensitive-grants.js +81 -0
- package/src/rules/no-unused-grants.js +2 -2
- package/src/rules/no-unused-resources.js +10 -8
- package/src/rules/prefer-gm-add-style.js +67 -0
- package/src/rules/prefer-match.js +4 -3
- package/src/rules/require-homepage-pair.js +3 -4
- package/src/rules/require-license-header.js +27 -0
- package/src/rules/require-matching-localized-fields.js +2 -2
- package/src/rules/require-required-fields.js +2 -2
- package/src/rules/require-space-before-meta-key.js +4 -5
- package/src/rules/require-sri-hashing.js +3 -3
- package/src/rules/require-update-download-pair.js +3 -4
- package/src/rules/require-user-js-filename.js +2 -2
- package/src/rules/valid-field-values.js +7 -7
- package/src/rules/valid-icon-headers.js +74 -0
- package/src/rules/valid-license-header.js +73 -0
- package/src/rules/valid-url-headers.js +114 -0
- package/src/rules/valid-version-header.js +83 -0
- package/src/utils/api.js +11 -0
- package/src/utils/array.js +1 -0
- package/src/utils/deprecations.js +76 -0
- package/src/utils/init.js +106 -0
- package/src/utils/license.js +56 -0
- package/src/utils/metadata.js +31 -0
- package/src/utils/pkg.js +21 -0
- package/src/utils/rules.js +7 -0
- package/src/utils/template.js +21 -0
- package/src/utils.js +0 -119
package/docs/LICENSE.md
CHANGED
package/package.json
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-greasemonkey",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "ESLint rules for Greasemonkey/Tampermonkey userscripts",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
5
|
+
"keywords": [
|
|
6
|
+
"eslint",
|
|
7
|
+
"eslint-plugin",
|
|
8
|
+
"eslintplugin",
|
|
9
|
+
"greasemonkey",
|
|
10
|
+
"metadata",
|
|
11
|
+
"security",
|
|
12
|
+
"tampermonkey",
|
|
13
|
+
"userscript"
|
|
14
|
+
],
|
|
14
15
|
"homepage": "https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme",
|
|
15
16
|
"bugs": {
|
|
16
17
|
"url": "https://codeberg.org/adamlui/eslint-plugin-greasemonkey/issues",
|
|
17
18
|
"email": "support@adamlui.com"
|
|
18
19
|
},
|
|
19
|
-
"
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://codeberg.org/adamlui/eslint-plugin-greasemonkey.git"
|
|
23
|
+
},
|
|
20
24
|
"funding": [
|
|
21
25
|
{
|
|
22
26
|
"type": "ko-fi",
|
|
@@ -27,57 +31,63 @@
|
|
|
27
31
|
"url": "https://paypal.me/adamlui"
|
|
28
32
|
}
|
|
29
33
|
],
|
|
30
|
-
"
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"author": {
|
|
36
|
+
"name": "Adam Lui",
|
|
37
|
+
"email": "adam@kudoai.org",
|
|
38
|
+
"url": "https://codeberg.org/adamlui"
|
|
39
|
+
},
|
|
40
|
+
"type": "module",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"types": "./src/index.d.ts",
|
|
44
|
+
"default": "./src/index.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"main": "./src/index.js",
|
|
48
|
+
"types": "./src/index.d.ts",
|
|
31
49
|
"files": [
|
|
32
50
|
"docs/",
|
|
33
51
|
"src/"
|
|
34
52
|
],
|
|
35
|
-
"types": "src/index.d.ts",
|
|
36
53
|
"scripts": {
|
|
37
|
-
"lint": "eslint . --cache && yamllint .",
|
|
38
|
-
"lint:all": "eslint . && yamllint .",
|
|
39
|
-
"lint:fix": "eslint . --fix --cache && yamllint .",
|
|
40
|
-
"lint:fix-all": "eslint . --fix && yamllint .",
|
|
41
|
-
"test": "node tests/run.js",
|
|
42
|
-
"demo": "node demo/run.js",
|
|
43
|
-
"bump:patch": "bash utils/bump.sh patch",
|
|
44
|
-
"bump:minor": "bash utils/bump.sh minor",
|
|
45
54
|
"bump:feat": "npm run bump:minor",
|
|
46
|
-
"bump:major": "bash utils/bump.sh major"
|
|
55
|
+
"bump:major": "bash utils/bump.sh major",
|
|
56
|
+
"bump:minor": "bash utils/bump.sh minor",
|
|
57
|
+
"bump:patch": "bash utils/bump.sh patch",
|
|
58
|
+
"demo": "eslint demo",
|
|
59
|
+
"lint": "pre-commit run",
|
|
60
|
+
"lint:all": "pre-commit run --all-files",
|
|
61
|
+
"test": "node tests/run"
|
|
47
62
|
},
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
},
|
|
52
|
-
"keywords": [
|
|
53
|
-
"eslint",
|
|
54
|
-
"eslint-plugin",
|
|
55
|
-
"eslintplugin",
|
|
56
|
-
"greasemonkey",
|
|
57
|
-
"metadata",
|
|
58
|
-
"tampermonkey",
|
|
59
|
-
"userscript"
|
|
60
|
-
],
|
|
61
|
-
"peerDependencies": {
|
|
62
|
-
"eslint": ">=9.0.0"
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"spdx-license-ids": "^3.0.24",
|
|
65
|
+
"spdx-license-list": "^6.12.0"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
65
68
|
"@e18e/eslint-plugin": "^0.8.1",
|
|
66
|
-
"@eslint/js": "^10.0.1",
|
|
67
69
|
"@eslint/json": "^2.1.1",
|
|
68
70
|
"@eslint/markdown": "^7.5.1",
|
|
69
71
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
70
|
-
"eslint": "^10.
|
|
71
|
-
"eslint-plugin-constructors": "^1.
|
|
72
|
+
"eslint": "^10.13.0",
|
|
73
|
+
"eslint-plugin-constructors": "^1.5.0",
|
|
72
74
|
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
73
75
|
"eslint-plugin-import-x": "^4.17.1",
|
|
74
|
-
"eslint-plugin-n": "^18.
|
|
76
|
+
"eslint-plugin-n": "^18.5.0",
|
|
75
77
|
"eslint-plugin-no-secrets": "^2.3.3",
|
|
76
78
|
"eslint-plugin-no-unsanitized": "^4.1.5",
|
|
79
|
+
"eslint-plugin-package-json": "^1.10.1",
|
|
77
80
|
"eslint-plugin-promise": "^7.3.0",
|
|
78
81
|
"eslint-plugin-regexp": "^3.3.1",
|
|
79
82
|
"eslint-plugin-security": "^4.2.0",
|
|
80
|
-
"
|
|
81
|
-
"
|
|
83
|
+
"eslint-plugin-sonarjs": "^4.2.2",
|
|
84
|
+
"eslint-plugin-woodpecker": "^1.1.0",
|
|
85
|
+
"oxlint": "^1.89.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"eslint": ">=9.0.0"
|
|
89
|
+
},
|
|
90
|
+
"engines": {
|
|
91
|
+
"node": ">=18.18.0"
|
|
82
92
|
}
|
|
83
93
|
}
|
package/src/data/apis.js
CHANGED
|
@@ -1,54 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
1
|
+
const apis = {
|
|
2
|
+
ag: new Set([
|
|
3
|
+
'GM_info', 'GM.info', 'GM_setValue', 'GM.setValue', 'GM_getValue', 'GM.getValue',
|
|
4
|
+
'GM_listValues', 'GM.listValues', 'GM_deleteValue', 'GM.deleteValue',
|
|
5
|
+
'GM_getResourceURL', 'GM.getResourceUrl', 'GM_setClipboard', 'GM.setClipboard',
|
|
6
|
+
'GM_xmlhttpRequest', 'GM.xmlHttpRequest', 'GM_openInTab', 'GM.openInTab',
|
|
7
|
+
'GM_notification', 'unsafeWindow', 'GM_getResourceText', 'GM_addStyle', 'GM_log',
|
|
8
|
+
'GM_addElement', 'GM.addElement'
|
|
9
|
+
]),
|
|
10
|
+
gm: {
|
|
11
|
+
legacy: new Set([
|
|
12
|
+
'GM_addElement', 'GM_addStyle', 'GM_addValueChangeListener', 'GM_deleteValue', 'GM_download',
|
|
13
|
+
'GM_getResourceText', 'GM_getResourceURL', 'GM_getTab', 'GM_getTabs', 'GM_getValue', 'GM_getValues',
|
|
14
|
+
'GM_info', 'GM_listValues', 'GM_log', 'GM_notification', 'GM_openInTab', 'GM_registerMenuCommand',
|
|
15
|
+
'GM_removeValueChangeListener', // oxlint-disable-line no-secrets/no-secrets
|
|
16
|
+
'GM_saveTab', 'GM_setClipboard', 'GM_setValue', 'GM_setValues', 'GM_unregisterMenuCommand', 'GM_webRequest',
|
|
17
|
+
'GM_xmlhttpRequest'
|
|
18
|
+
]),
|
|
19
|
+
modern: new Set([
|
|
20
|
+
'GM.addElement', 'GM.addStyle', 'GM.addValueChangeListener', 'GM.deleteValue', 'GM.download',
|
|
21
|
+
'GM.getResourceText', 'GM.getResourceUrl', 'GM.getTab', 'GM.getTabs', 'GM.getValue', 'GM.getValues',
|
|
22
|
+
'GM.info', 'GM.listValues', 'GM.log', 'GM.notification', 'GM.openInTab', 'GM.registerMenuCommand',
|
|
23
|
+
'GM.removeValueChangeListener', 'GM.saveTab', 'GM.setClipboard', 'GM.setValue', 'GM.setValues',
|
|
24
|
+
'GM.unregisterMenuCommand', 'GM.webRequest', 'GM.xmlHttpRequest'
|
|
25
|
+
])
|
|
26
|
+
},
|
|
27
|
+
sc: new Set([
|
|
28
|
+
'CAT.agent.conversation', 'CAT.agent.dom', 'CAT.agent.mcp', 'CAT.agent.model', 'CAT.agent.opfs',
|
|
29
|
+
'CAT.agent.skills', 'CAT.agent.task', 'CAT_fileStorage', 'CAT_scriptLoaded', 'CAT_userConfig'
|
|
30
|
+
]),
|
|
31
|
+
tm: new Set([
|
|
32
|
+
'GM_getTab', 'GM_getTabs', 'GM_saveTab', 'GM_webRequest',
|
|
33
|
+
'GM.getTab', 'GM.getTabs', 'GM.saveTab', 'GM.webRequest'
|
|
34
|
+
]),
|
|
35
|
+
sensitive: new Set([
|
|
36
|
+
'GM_xmlhttpRequest', 'GM.xmlHttpRequest', 'GM_download', 'GM.download',
|
|
37
|
+
'GM_openInTab', 'GM.openInTab', 'GM_setClipboard', 'GM.setClipboard',
|
|
38
|
+
'GM_notification', 'GM.notification', 'GM_addValueChangeListener', 'GM.addValueChangeListener',
|
|
39
|
+
'GM_getResourceURL', 'GM.getResourceUrl', 'unsafeWindow'
|
|
40
|
+
]),
|
|
41
|
+
managerSensitive: new Map([
|
|
42
|
+
['tampermonkey', new Set([
|
|
43
|
+
'GM_webRequest', 'GM.webRequest', 'GM_getTab', 'GM.getTab', 'GM_getTabs', 'GM.getTabs',
|
|
44
|
+
'GM_saveTab', 'GM.saveTab'
|
|
45
|
+
])],
|
|
46
|
+
['violentmonkey', new Set([])],
|
|
47
|
+
['greasemonkey', new Set([])],
|
|
48
|
+
['scriptcat', new Set([
|
|
49
|
+
'CAT.agent.conversation', 'CAT.agent.dom', 'CAT.agent.mcp', 'CAT.agent.model', 'CAT.agent.opfs',
|
|
50
|
+
'CAT.agent.skills', 'CAT.agent.task', 'CAT_fileStorage', 'CAT_userConfig'
|
|
51
|
+
])],
|
|
52
|
+
['adguard', new Set([])]
|
|
53
|
+
])
|
|
54
54
|
}
|
|
55
|
+
apis.all = new Set([...apis.gm.legacy, ...apis.gm.modern, ...apis.sc])
|
|
56
|
+
|
|
57
|
+
export default apis
|
package/src/data/headers.js
CHANGED
|
@@ -1,36 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
'antifeature', 'author', 'compatible', 'connect', 'contributionAmount', 'contributionURL', 'copyright',
|
|
3
|
-
'defaulticon', 'description', 'downloadURL', 'exclude', 'exclude-match', 'grant', 'homepage', 'homepageURL',
|
|
4
|
-
'icon', 'icon64', 'include', 'license', 'match', 'name', 'namespace', 'noframes', 'require', 'resource',
|
|
5
|
-
'run-at', 'source', 'supportURL', 'updateURL', 'version', 'website'
|
|
6
|
-
])
|
|
1
|
+
// oxlint-disable sonarjs/no-clear-text-protocols
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
['
|
|
18
|
-
[
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
3
|
+
const headers = {
|
|
4
|
+
broadConnect: new Set([
|
|
5
|
+
'*',
|
|
6
|
+
'*.com', '*.org', '*.net', '*.io', '*.dev', '*.app', '*.co',
|
|
7
|
+
'http://*', 'https://*',
|
|
8
|
+
'http://*/*', 'https://*/*',
|
|
9
|
+
'http://*/', 'https://*/',
|
|
10
|
+
'http:*', 'https:*'
|
|
11
|
+
]),
|
|
12
|
+
localized: ['name', 'description', 'antifeature'],
|
|
13
|
+
manager: new Map([
|
|
14
|
+
['unwrap', ['tampermonkey', 'violentmonkey', 'greasemonkey', 'scriptcat']],
|
|
15
|
+
['run-in', ['tampermonkey', 'scriptcat']],
|
|
16
|
+
['nocompat', ['tampermonkey']],
|
|
17
|
+
['sandbox', ['tampermonkey']],
|
|
18
|
+
['user-agent', ['tampermonkey']],
|
|
19
|
+
['webRequest', ['tampermonkey']],
|
|
20
|
+
['inject-into', ['violentmonkey', 'scriptcat']],
|
|
21
|
+
['top-level-await', ['violentmonkey']],
|
|
22
|
+
['background', ['scriptcat']],
|
|
23
|
+
['crontab', ['scriptcat']],
|
|
24
|
+
['definition', ['scriptcat']],
|
|
25
|
+
['early-start', ['scriptcat']],
|
|
26
|
+
['require-css', ['scriptcat']],
|
|
27
|
+
['storageName', ['scriptcat']]
|
|
28
|
+
]),
|
|
29
|
+
managers: ['tampermonkey', 'violentmonkey', 'greasemonkey', 'scriptcat', 'adguard'],
|
|
30
|
+
universal: new Set([
|
|
31
|
+
'antifeature', 'author', 'compatible', 'connect', 'contributionAmount', 'contributionURL', 'copyright',
|
|
32
|
+
'defaulticon', 'description', 'downloadURL', 'exclude', 'exclude-match', 'grant', 'homepage', 'homepageURL',
|
|
33
|
+
'icon', 'icon64', 'include', 'license', 'match', 'name', 'namespace', 'noframes', 'require', 'resource',
|
|
34
|
+
'run-at', 'source', 'supportURL', 'updateURL', 'version', 'website'
|
|
35
|
+
])
|
|
36
|
+
}
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
const knownHeaders = new Set([...headers.universal, ...headers.manager.keys()])
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
headers.valid = new Map([['all', knownHeaders]])
|
|
41
|
+
for (const mgr of headers.managers) {
|
|
42
|
+
const specific = [...headers.manager]
|
|
43
|
+
.filter(([, supportedBy]) => supportedBy.includes(mgr))
|
|
34
44
|
.map(([header]) => header)
|
|
35
|
-
|
|
45
|
+
headers.valid.set(mgr, new Set([...headers.universal, ...specific]))
|
|
36
46
|
}
|
|
47
|
+
|
|
48
|
+
headers.url = new Map(Object.entries({
|
|
49
|
+
connect: 'host-pattern',
|
|
50
|
+
contributionURL: 'url',
|
|
51
|
+
defaulticon: 'url',
|
|
52
|
+
downloadURL: 'url',
|
|
53
|
+
exclude: 'pattern',
|
|
54
|
+
'exclude-match': 'pattern',
|
|
55
|
+
homepage: 'url',
|
|
56
|
+
homepageURL: 'url',
|
|
57
|
+
icon: 'url',
|
|
58
|
+
icon64: 'url',
|
|
59
|
+
include: 'pattern',
|
|
60
|
+
match: 'pattern',
|
|
61
|
+
require: 'url',
|
|
62
|
+
'require-css': 'url',
|
|
63
|
+
resource: 'named-url',
|
|
64
|
+
source: 'url',
|
|
65
|
+
supportURL: 'url',
|
|
66
|
+
updateURL: 'url',
|
|
67
|
+
website: 'url'
|
|
68
|
+
}).filter(([name]) => knownHeaders.has(name)))
|
|
69
|
+
|
|
70
|
+
export default headers
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
filename: {
|
|
3
|
+
license: // oxlint-disable-next-line security/detect-unsafe-regex
|
|
4
|
+
/^(?:[\w.-]*-)?(?:LICEN[SC]E|COPYING)(?:[-.][\w.-]+)?$/i
|
|
5
|
+
},
|
|
6
|
+
meta: {
|
|
7
|
+
block: /\/\/\s*==UserScript==([\s\S]*?)\/\/\s*==\/UserScript==/,
|
|
8
|
+
license: /^[ \t]*\/\/[ \t]*@license[ \t]+(\S.*)/m
|
|
9
|
+
},
|
|
10
|
+
newline: /\r?\n/,
|
|
11
|
+
specialChars: /[.*+?^${}()|[\]\\]/g,
|
|
12
|
+
url: /^https?:\/\//,
|
|
13
|
+
whitespace: { all: /\s+/, leading: /^\s*/ }
|
|
14
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
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
|
+
| 'tampermonkey'
|
|
9
|
+
| 'violentmonkey'
|
|
10
|
+
| 'greasemonkey'
|
|
11
|
+
| 'scriptcat'
|
|
12
|
+
| 'adguard'
|
|
13
|
+
|
|
14
|
+
interface PluginConfig {
|
|
15
|
+
plugins: Record<string, unknown>
|
|
16
|
+
rules: Record<string, RuleSetting>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface PluginRule {
|
|
20
|
+
meta: {
|
|
21
|
+
type?: 'problem' | 'suggestion' | 'layout'
|
|
22
|
+
deprecated?: boolean | {
|
|
23
|
+
message?: string
|
|
24
|
+
replacedBy?: Array<{ rule: { name: string } }>
|
|
25
|
+
}
|
|
26
|
+
docs?: Record<string, unknown>
|
|
27
|
+
}
|
|
28
|
+
create: (context: unknown) => Record<string, (...args: unknown[]) => void>
|
|
29
|
+
}
|
|
30
|
+
|
|
1
31
|
declare const plugin: {
|
|
2
|
-
|
|
3
|
-
|
|
32
|
+
meta: { name: string }
|
|
33
|
+
rules: Record<string, PluginRule>
|
|
34
|
+
configs: Record<ConfigName, PluginConfig>
|
|
4
35
|
}
|
|
5
36
|
|
|
6
|
-
export default plugin
|
|
37
|
+
export { plugin as default, plugin as greasemonkey }
|
package/src/index.js
CHANGED
|
@@ -1,84 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import init from './utils/init.js'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const plugin = init.plugin()
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import noInvalidGrants from './rules/no-invalid-grants.js'
|
|
9
|
-
import noInvalidHeaders from './rules/no-invalid-headers.js'
|
|
10
|
-
import noMissingGrants from './rules/no-missing-grants.js'
|
|
11
|
-
import noMissingResources from './rules/no-missing-resources.js'
|
|
12
|
-
import noUnusedGrants from './rules/no-unused-grants.js'
|
|
13
|
-
import noUnusedResources from './rules/no-unused-resources.js'
|
|
14
|
-
import preferMatch from './rules/prefer-match.js'
|
|
15
|
-
import requireBlankLineAfterMetaBlock from './rules/require-blank-line-after-meta-block.js'
|
|
16
|
-
import requireHomepagePair from './rules/require-homepage-pair.js'
|
|
17
|
-
import requireMatchingLocalizedFields from './rules/require-matching-localized-fields.js'
|
|
18
|
-
import requireRequiredFields from './rules/require-required-fields.js'
|
|
19
|
-
import requireSpaceBeforeMetaKey from './rules/require-space-before-meta-key.js'
|
|
20
|
-
import requireSRIhashing from './rules/require-sri-hashing.js'
|
|
21
|
-
import requireUpdateDownloadPair from './rules/require-update-download-pair.js'
|
|
22
|
-
import requireUserJsFilename from './rules/require-user-js-filename.js'
|
|
23
|
-
import validFieldValues from './rules/valid-field-values.js'
|
|
24
|
-
|
|
25
|
-
import { bundleRules, initDeprecatedAlias } from './utils.js'
|
|
26
|
-
|
|
27
|
-
const plugin = {
|
|
28
|
-
rules: {
|
|
29
|
-
'meta-order': metaOrder,
|
|
30
|
-
'meta-spacing': metaSpacing,
|
|
31
|
-
'no-duplicate-keys': noDuplicateKeys,
|
|
32
|
-
'no-invalid-grants': noInvalidGrants,
|
|
33
|
-
'no-invalid-headers': noInvalidHeaders,
|
|
34
|
-
'no-missing-grants': noMissingGrants,
|
|
35
|
-
'no-unused-grants': noUnusedGrants,
|
|
36
|
-
'no-missing-resources': noMissingResources,
|
|
37
|
-
'no-unused-resources': noUnusedResources,
|
|
38
|
-
'prefer-match': preferMatch,
|
|
39
|
-
'require-blank-line-after-meta-block': requireBlankLineAfterMetaBlock,
|
|
40
|
-
'require-homepage-pair': requireHomepagePair,
|
|
41
|
-
'require-matching-localized-fields': requireMatchingLocalizedFields,
|
|
42
|
-
'require-required-fields': requireRequiredFields,
|
|
43
|
-
'require-space-before-meta-key': requireSpaceBeforeMetaKey,
|
|
44
|
-
'require-sri-hashing': requireSRIhashing,
|
|
45
|
-
'require-update-download-pair': requireUpdateDownloadPair,
|
|
46
|
-
'require-user-js-filename': requireUserJsFilename,
|
|
47
|
-
'valid-field-values': validFieldValues
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
for (const [ruleId, rule] of Object.entries(plugin.rules))
|
|
52
|
-
rule.meta.docs.url = `https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#${ruleId}`
|
|
53
|
-
|
|
54
|
-
for (const entry of Object.entries(oldRules))
|
|
55
|
-
initDeprecatedAlias(plugin, entry)
|
|
56
|
-
|
|
57
|
-
plugin.configs = {
|
|
58
|
-
recommended: {
|
|
59
|
-
plugins: { greasemonkey: plugin },
|
|
60
|
-
rules: bundleRules(plugin.rules, rule => rule.meta.docs.recommended, 'greasemonkey')
|
|
61
|
-
},
|
|
62
|
-
strict: {
|
|
63
|
-
plugins: { greasemonkey: plugin },
|
|
64
|
-
rules: bundleRules(plugin.rules, () => true, 'greasemonkey')
|
|
65
|
-
},
|
|
66
|
-
problem: {
|
|
67
|
-
plugins: { greasemonkey: plugin },
|
|
68
|
-
rules: bundleRules(plugin.rules, rule => rule.meta.type == 'problem', 'greasemonkey')
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
for (const manager of ['tampermonkey', 'violentmonkey', 'greasemonkey', 'scriptcat', 'adguard'])
|
|
73
|
-
plugin.configs[manager] = {
|
|
74
|
-
plugins: { greasemonkey: plugin },
|
|
75
|
-
rules: {
|
|
76
|
-
...plugin.configs.recommended.rules,
|
|
77
|
-
'greasemonkey/no-invalid-grants': ['error', { target: manager }],
|
|
78
|
-
'greasemonkey/no-invalid-headers': ['error', { target: manager }],
|
|
79
|
-
...(['tampermonkey', 'scriptcat', 'adguard'].includes(manager) &&
|
|
80
|
-
{ 'greasemonkey/require-update-download-pair': 'error' })
|
|
81
|
-
}
|
|
82
|
-
}
|
|
5
|
+
init.rules(plugin)
|
|
6
|
+
init.deprecations(plugin)
|
|
7
|
+
init.configs(plugin)
|
|
83
8
|
|
|
84
9
|
export { plugin as default, plugin as greasemonkey }
|
package/src/rules/meta-order.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import metadata from '../utils/metadata.js'
|
|
2
2
|
|
|
3
3
|
const defaultOrder = [
|
|
4
4
|
'name', 'description', 'author', 'namespace', 'version', 'license', 'icon', 'icon64',
|
|
@@ -12,7 +12,7 @@ function findViolation(entries, keys) {
|
|
|
12
12
|
const key = entry.key.split(':', 1)[0]
|
|
13
13
|
return { entry, key, rank: ranks.get(key) }
|
|
14
14
|
}).filter(item => item.rank !== undefined)
|
|
15
|
-
for (let i = 1 ; i < known.length ; i++) //
|
|
15
|
+
for (let i = 1 ; i < known.length ; i++) // oxlint-disable-next-line security/detect-object-injection
|
|
16
16
|
if (known[i -1].rank > known[i].rank) return [known[i -1], known[i]]
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -30,8 +30,7 @@ export default {
|
|
|
30
30
|
type: 'layout',
|
|
31
31
|
docs: {
|
|
32
32
|
description: 'Enforce an order for metadata keys',
|
|
33
|
-
category: 'Stylistic Issues'
|
|
34
|
-
recommended: false
|
|
33
|
+
category: 'Stylistic Issues'
|
|
35
34
|
},
|
|
36
35
|
fixable: 'code',
|
|
37
36
|
schema: [{
|
|
@@ -54,12 +53,12 @@ export default {
|
|
|
54
53
|
return {
|
|
55
54
|
Program() {
|
|
56
55
|
const sourceCode = context.sourceCode,
|
|
57
|
-
entries =
|
|
56
|
+
entries = metadata.extract(sourceCode),
|
|
58
57
|
violation = findViolation(entries, master) ?? (custom.length && findViolation(entries, custom))
|
|
59
58
|
if (!violation) return
|
|
60
59
|
const [first, second] = violation
|
|
61
60
|
const sorted = sortEntries(sortEntries(entries, master), custom)
|
|
62
|
-
const replacements = //
|
|
61
|
+
const replacements = // oxlint-disable-next-line security/detect-object-injection
|
|
63
62
|
new Map(sorted.map((entry, idx) => [entries[idx], sourceCode.getText(entry.comment)]))
|
|
64
63
|
const start = entries[0].comment.range[0]
|
|
65
64
|
const end = entries.at(-1).comment.range[1]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const re = { leadingWhitespace: /^\s*/, whitespace: /\s+/ }
|
|
1
|
+
import metadata from '../utils/metadata.js'
|
|
2
|
+
import regex from '../data/regex.js'
|
|
4
3
|
|
|
5
4
|
export default {
|
|
6
5
|
meta: {
|
|
@@ -30,29 +29,31 @@ export default {
|
|
|
30
29
|
return {
|
|
31
30
|
Program() {
|
|
32
31
|
const sourceCode = context.sourceCode,
|
|
33
|
-
metaEntries =
|
|
32
|
+
metaEntries = metadata.extract(sourceCode)
|
|
34
33
|
if (!metaEntries.length) return
|
|
35
34
|
let targetCol = metaEntries.reduce((max, entry) => Math.max(max, entry.key.length), 0) + minSpaces +4
|
|
36
35
|
for (const entry of metaEntries)
|
|
37
36
|
if (entry.key == 'resource' && entry.value.trim()) {
|
|
38
|
-
const name = entry.value.trim().split(
|
|
37
|
+
const name = entry.value.trim().split(regex.whitespace.all)[0],
|
|
39
38
|
requiredCol = 4 + entry.key.length +1 + name.length + minSpaces
|
|
40
39
|
if (requiredCol > targetCol) targetCol = requiredCol
|
|
41
40
|
}
|
|
42
41
|
for (const entry of metaEntries) {
|
|
43
42
|
if (!entry.value.trim()) continue
|
|
44
43
|
const commentText = sourceCode.getText(entry.comment),
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
trimmed = commentText.trimEnd(),
|
|
45
|
+
trailingWs = commentText.slice(trimmed.length),
|
|
46
|
+
keyIdx = trimmed.indexOf(entry.key) + entry.key.length,
|
|
47
|
+
parts = entry.value.trim().split(regex.whitespace.all),
|
|
47
48
|
named = entry.key == 'resource' && parts.length >= 2,
|
|
48
49
|
prefix = named ? ` ${parts[0]} ` : '',
|
|
49
50
|
suffix = named ? parts.slice(1).join(' ') : entry.value.trim(),
|
|
50
|
-
fixedText =
|
|
51
|
+
fixedText = trimmed.slice(0, keyIdx) + prefix
|
|
51
52
|
+ ' '.repeat(targetCol - keyIdx - prefix.length) + suffix
|
|
52
|
-
if (
|
|
53
|
+
if (trimmed !== fixedText)
|
|
53
54
|
context.report({
|
|
54
55
|
node: entry.comment, messageId: 'misaligned', data: { column: targetCol },
|
|
55
|
-
fix(fixer) { return fixer.replaceText(entry.comment, fixedText) }
|
|
56
|
+
fix(fixer) { return fixer.replaceText(entry.comment, fixedText + trailingWs) }
|
|
56
57
|
})
|
|
57
58
|
}
|
|
58
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import metadata from '../utils/metadata.js'
|
|
2
2
|
|
|
3
3
|
const multiValKeys = new Set([
|
|
4
4
|
'compatible', 'connect', 'description', 'exclude', 'exclude-match', 'grant',
|
|
@@ -20,7 +20,7 @@ export default {
|
|
|
20
20
|
create(context) {
|
|
21
21
|
return {
|
|
22
22
|
Program() {
|
|
23
|
-
const metaEntries =
|
|
23
|
+
const metaEntries = metadata.extract(context.sourceCode),
|
|
24
24
|
seenEntries = new Set()
|
|
25
25
|
for (const entry of metaEntries) {
|
|
26
26
|
const baseKey = entry.key.split(':')[0]
|