eslint-plugin-greasemonkey 1.10.4 → 1.10.6
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/package.json +15 -12
- package/src/rules/no-invalid-headers.js +6 -5
- package/src/rules/valid-field-values.js +8 -8
- package/src/rules/valid-icon-headers.js +2 -2
- package/src/rules/valid-url-headers.js +1 -1
- package/src/rules/valid-version-header.js +5 -5
- package/src/utils/deprecations.js +7 -5
- package/src/utils/license.js +2 -2
- package/src/utils/template.js +17 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-greasemonkey",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.6",
|
|
4
4
|
"description": "ESLint rules for Greasemonkey/Tampermonkey userscripts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -61,14 +61,17 @@
|
|
|
61
61
|
"test": "node tests/run"
|
|
62
62
|
},
|
|
63
63
|
"overrides": {
|
|
64
|
-
"@eslint/
|
|
65
|
-
"
|
|
64
|
+
"@eslint/markdown": {
|
|
65
|
+
"katex": "^0.19.1"
|
|
66
66
|
},
|
|
67
|
-
"
|
|
68
|
-
"minimatch": "^11.0.
|
|
67
|
+
"eslint": {
|
|
68
|
+
"minimatch": "^11.0.8"
|
|
69
|
+
},
|
|
70
|
+
"eslint-plugin-import-x": {
|
|
71
|
+
"minimatch": "^11.0.8"
|
|
69
72
|
},
|
|
70
73
|
"eslint-plugin-sonarjs": {
|
|
71
|
-
"minimatch": "^11.0.
|
|
74
|
+
"minimatch": "^11.0.8"
|
|
72
75
|
}
|
|
73
76
|
},
|
|
74
77
|
"dependencies": {
|
|
@@ -78,14 +81,14 @@
|
|
|
78
81
|
"devDependencies": {
|
|
79
82
|
"@e18e/eslint-plugin": "^0.8.1",
|
|
80
83
|
"@eslint/json": "^2.1.1",
|
|
81
|
-
"@eslint/markdown": "^
|
|
84
|
+
"@eslint/markdown": "^8.0.3",
|
|
82
85
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
83
|
-
"@typescript-eslint/parser": "^8.72.
|
|
84
|
-
"@typescript-eslint/utils": "^8.72.
|
|
86
|
+
"@typescript-eslint/parser": "^8.72.2",
|
|
87
|
+
"@typescript-eslint/utils": "^8.72.2",
|
|
85
88
|
"eslint": "^10.14.0",
|
|
86
89
|
"eslint-plugin-constructors": "^1.7.2",
|
|
87
90
|
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
88
|
-
"eslint-plugin-import-x": "^4.18.
|
|
91
|
+
"eslint-plugin-import-x": "^4.18.1",
|
|
89
92
|
"eslint-plugin-n": "^18.5.0",
|
|
90
93
|
"eslint-plugin-no-secrets": "^2.3.3",
|
|
91
94
|
"eslint-plugin-no-unsanitized": "^4.1.5",
|
|
@@ -94,8 +97,8 @@
|
|
|
94
97
|
"eslint-plugin-regexp": "^3.3.3",
|
|
95
98
|
"eslint-plugin-security": "^4.2.1",
|
|
96
99
|
"eslint-plugin-sonarjs": "^4.2.2",
|
|
97
|
-
"eslint-plugin-woodpecker": "^1.1.
|
|
98
|
-
"oxlint": "^1.
|
|
100
|
+
"eslint-plugin-woodpecker": "^1.1.6",
|
|
101
|
+
"oxlint": "^1.93.0",
|
|
99
102
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
100
103
|
"typescript-latest": "npm:typescript@^7.0.2"
|
|
101
104
|
},
|
|
@@ -52,7 +52,7 @@ export default {
|
|
|
52
52
|
allowedExact = new Set(),
|
|
53
53
|
allowedRegexes = [],
|
|
54
54
|
validSet = targets.includes('all') ? headers.valid.get('all')
|
|
55
|
-
: new Set(targets.flatMap(
|
|
55
|
+
: new Set(targets.flatMap(mgr => [...headers.valid.get(mgr)]))
|
|
56
56
|
for (const entry of allowedList) {
|
|
57
57
|
if (entry instanceof RegExp) allowedRegexes.push(entry)
|
|
58
58
|
else if (typeof entry == 'string') {
|
|
@@ -65,10 +65,11 @@ export default {
|
|
|
65
65
|
Program() {
|
|
66
66
|
const metaEntries = metadata.extract(context.sourceCode)
|
|
67
67
|
for (const entry of metaEntries) {
|
|
68
|
-
if (allowedExact.has(entry.key)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
if (allowedExact.has(entry.key)
|
|
69
|
+
|| allowedRegexes.some(re => re.test(entry.key))
|
|
70
|
+
|| headers.localized.includes(entry.key.split(':')[0])
|
|
71
|
+
|| validSet.has(entry.key)
|
|
72
|
+
) continue
|
|
72
73
|
const supporting = headers.manager.get(entry.key)
|
|
73
74
|
if (supporting)
|
|
74
75
|
context.report({ node: entry.comment, messageId: 'unsupportedHeader',
|
|
@@ -2,11 +2,11 @@ import metadata from '../utils/metadata.js'
|
|
|
2
2
|
import regex from '../data/regex.js'
|
|
3
3
|
|
|
4
4
|
const defaultOptions = { versionType: 'semver', allowedGrants: [], allowFutureDate: false },
|
|
5
|
-
urlKeys = ['homepage', 'icon', 'icon64', 'require', 'source', 'website']
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} // oxlint-enable security/detect-unsafe-regex
|
|
5
|
+
urlKeys = new Set(['homepage', 'icon', 'icon64', 'require', 'source', 'website']),
|
|
6
|
+
re = { // oxlint-disable security/detect-unsafe-regex
|
|
7
|
+
semVer: /^\d+\.\d+\.\d+(?:-[\da-z.-]+)?(?:\+[\da-z.-]+)?$/i,
|
|
8
|
+
dateVer: /^\d{4}\.(?:0?[1-9]|1[0-2])\.(?:0?[1-9]|[12]\d|3[01])(?:\.\d+)?$/
|
|
9
|
+
} // oxlint-enable security/detect-unsafe-regex
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
meta: {
|
|
@@ -68,12 +68,12 @@ export default {
|
|
|
68
68
|
context.report({ node: entry.comment, messageId: 'invalidGrant', data: { grant: entry.value }})
|
|
69
69
|
else if (entry.key == 'resource') {
|
|
70
70
|
const url = entry.value.trim().split(regex.whitespace.all)[1]
|
|
71
|
-
if (url) try { new URL(url) }
|
|
71
|
+
if (url) try { new URL(url) } // oxlint-disable-line no-new -- validates URL via throw
|
|
72
72
|
catch {
|
|
73
73
|
context.report({ node: entry.comment, messageId: 'invalidURL', data: { field: entry.key }})
|
|
74
74
|
}
|
|
75
|
-
} else if (urlKeys.
|
|
76
|
-
try { new URL(entry.value) }
|
|
75
|
+
} else if (urlKeys.has(entry.key) || entry.key.toLowerCase().endsWith('url'))
|
|
76
|
+
try { new URL(entry.value) } // oxlint-disable-line no-new -- validates URL via throw
|
|
77
77
|
catch {
|
|
78
78
|
context.report({ node: entry.comment, messageId: 'invalidURL', data: { field: entry.key }})
|
|
79
79
|
}
|
|
@@ -30,10 +30,10 @@ export default {
|
|
|
30
30
|
function validate(value, header, line, col) {
|
|
31
31
|
const loc = { start: { line, column: col }, end: { line, column: col + value.length }}
|
|
32
32
|
const schemeMatch = value.match(re.scheme)
|
|
33
|
-
if (!schemeMatch) return //
|
|
33
|
+
if (!schemeMatch) return // rel path — accepted
|
|
34
34
|
const scheme = schemeMatch[1].toLowerCase()
|
|
35
35
|
if (scheme == 'http' || scheme == 'https') {
|
|
36
|
-
try { new URL(value) }
|
|
36
|
+
try { new URL(value) } // oxlint-disable-line no-new -- validates URL via throw
|
|
37
37
|
catch { return context.report({ loc, messageId: 'malformedURL', data: { header }}) }
|
|
38
38
|
return
|
|
39
39
|
}
|
|
@@ -84,7 +84,7 @@ export default {
|
|
|
84
84
|
context.report({ node, messageId: 'allURLs', data: { field, value }})
|
|
85
85
|
}
|
|
86
86
|
function validateURL(url, field, node) {
|
|
87
|
-
try { new URL(url) }
|
|
87
|
+
try { new URL(url) } // oxlint-disable-line no-new -- validates URL via throw
|
|
88
88
|
catch { context.report({ node, messageId: 'invalidURL', data: { field, value: url }}) }
|
|
89
89
|
}
|
|
90
90
|
return {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import metadata from '../utils/metadata.js'
|
|
2
2
|
|
|
3
3
|
const defaultOptions = { versionType: 'semver', allowFutureDate: false, timezone: '' },
|
|
4
|
-
examples = { date: 'YYYY.M.D or YYYY.M.D.N', semver: '1.2.3' }
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} // oxlint-enable security/detect-unsafe-regex
|
|
4
|
+
examples = { date: 'YYYY.M.D or YYYY.M.D.N', semver: '1.2.3' },
|
|
5
|
+
re = { // oxlint-disable security/detect-unsafe-regex
|
|
6
|
+
date: /^\d{4}\.(?:0?[1-9]|1[0-2])\.(?:0?[1-9]|[12]\d|3[01])(?:\.\d+)?$/,
|
|
7
|
+
semver: /^\d+\.\d+\.\d+(?:-[\da-z.-]+)?(?:\+[\da-z.-]+)?$/i
|
|
8
|
+
} // oxlint-enable security/detect-unsafe-regex
|
|
9
9
|
|
|
10
10
|
export default {
|
|
11
11
|
meta: {
|
|
@@ -26,8 +26,9 @@ export default {
|
|
|
26
26
|
},
|
|
27
27
|
create(context) {
|
|
28
28
|
const opts = context.options[0],
|
|
29
|
-
isObj = opts?.constructor === Object
|
|
30
|
-
|
|
29
|
+
isObj = opts?.constructor === Object,
|
|
30
|
+
result = {}
|
|
31
|
+
for (const [targetName, mapping] of Object.entries(routes)) {
|
|
31
32
|
let newOpts = opts, deprecation
|
|
32
33
|
if (mapping) {
|
|
33
34
|
const entries = Object.entries(mapping),
|
|
@@ -60,7 +61,7 @@ export default {
|
|
|
60
61
|
const aliasContext = Object.create(context)
|
|
61
62
|
Object.defineProperty(aliasContext, 'options',
|
|
62
63
|
{ value: [newOpts], writable: true, configurable: true, enumerable: true })
|
|
63
|
-
const visitors =
|
|
64
|
+
const visitors = originals[targetName].create(aliasContext)
|
|
64
65
|
if (deprecation) {
|
|
65
66
|
const ruleProgram = visitors.Program
|
|
66
67
|
visitors.Program = function(node) {
|
|
@@ -68,8 +69,9 @@ export default {
|
|
|
68
69
|
if (ruleProgram) ruleProgram.call(this, node)
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
-
}
|
|
72
|
+
Object.assign(result, visitors)
|
|
73
|
+
}
|
|
74
|
+
return result
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
} // oxlint-enable security/detect-object-injection
|
package/src/utils/license.js
CHANGED
|
@@ -12,7 +12,7 @@ const re = { spdxTag: /SPDX-License-Identifier:\s*([\w.-]+)/i },
|
|
|
12
12
|
spdxIDs = new Set(require('spdx-license-ids')),
|
|
13
13
|
spdxNames = Object.entries(require('spdx-license-list'))
|
|
14
14
|
.map(([id, { name }]) => ({ id, name }))
|
|
15
|
-
.sort((a, b) => b.name.length - a.name.length)
|
|
15
|
+
.sort((a, b) => b.name.length - a.name.length) // oxlint-disable-line unicorn/no-array-sort
|
|
16
16
|
|
|
17
17
|
function tryReaddir(dir) { try { return fs.readdirSync(dir, { withFileTypes: true }) } catch { return null }}
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ export default {
|
|
|
24
24
|
if (!entries) continue
|
|
25
25
|
for (const entry of entries) {
|
|
26
26
|
if (entry.name.startsWith('.') || skipDirs.has(entry.name)) continue
|
|
27
|
-
if (entry.isFile() &&
|
|
27
|
+
if (entry.isFile() && regex.filename.license.test(entry.name)) return path.join(dir, entry.name)
|
|
28
28
|
if (entry.isDirectory()) queue.push(path.join(dir, entry.name))
|
|
29
29
|
}
|
|
30
30
|
}
|
package/src/utils/template.js
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}, [''])
|
|
17
|
-
else return null
|
|
18
|
-
}
|
|
19
|
-
return walk(node)
|
|
20
|
-
}
|
|
1
|
+
function walk(node) {
|
|
2
|
+
if (node.type == 'ConditionalExpression') {
|
|
3
|
+
const branches = [node.consequent, node.alternate].map(walk)
|
|
4
|
+
return branches.every(Boolean) ? branches.flat() : null
|
|
5
|
+
} else if (node.type == 'Literal' && ['number', 'string'].includes(typeof node.value))
|
|
6
|
+
return [String(node.value)]
|
|
7
|
+
else if (node.type == 'TemplateLiteral')
|
|
8
|
+
return node.quasis.reduce((combos, quasi, idx) => {
|
|
9
|
+
if (!combos) return null
|
|
10
|
+
const withQuasi = combos.map(combo => combo + quasi.value.raw)
|
|
11
|
+
if (idx >= node.expressions.length) return withQuasi
|
|
12
|
+
const vals = walk(node.expressions[idx]) // oxlint-disable-line security/detect-object-injection
|
|
13
|
+
return vals ? withQuasi.flatMap(combo => vals.map(val => combo + val)) : null
|
|
14
|
+
}, [''])
|
|
15
|
+
else return null
|
|
21
16
|
}
|
|
17
|
+
|
|
18
|
+
export default { resolve(node) { return walk(node) }}
|