eslint-plugin-unicorn 48.0.0 → 49.0.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/package.json +22 -21
- package/rules/ast/is-method-call.js +7 -3
- package/rules/ast/is-reference-identifier.js +10 -0
- package/rules/better-regex.js +2 -3
- package/rules/catch-error-name.js +1 -1
- package/rules/consistent-destructuring.js +2 -2
- package/rules/custom-error-definition.js +1 -1
- package/rules/expiring-todo-comments.js +134 -111
- package/rules/filename-case.js +1 -1
- package/rules/fix/remove-argument.js +1 -1
- package/rules/import-style.js +1 -1
- package/rules/no-array-for-each.js +1 -1
- package/rules/no-array-method-this-argument.js +1 -1
- package/rules/no-console-spaces.js +1 -1
- package/rules/no-empty-file.js +1 -1
- package/rules/no-hex-escape.js +1 -1
- package/rules/no-unnecessary-await.js +1 -1
- package/rules/no-useless-switch-case.js +1 -1
- package/rules/no-useless-undefined.js +1 -1
- package/rules/no-zero-fractions.js +1 -1
- package/rules/numeric-separators-style.js +1 -1
- package/rules/prefer-default-parameters.js +2 -2
- package/rules/prefer-dom-node-dataset.js +1 -1
- package/rules/prefer-event-target.js +77 -1
- package/rules/prefer-export-from.js +1 -1
- package/rules/prefer-object-from-entries.js +1 -1
- package/rules/prefer-query-selector.js +1 -1
- package/rules/prefer-regexp-test.js +4 -0
- package/rules/prefer-spread.js +1 -1
- package/rules/prefer-string-replace-all.js +3 -2
- package/rules/prefer-switch.js +1 -1
- package/rules/prevent-abbreviations.js +1 -1
- package/rules/template-indent.js +1 -1
- package/rules/utils/escape-template-element-raw.js +1 -1
- package/rules/utils/get-ancestor.js +20 -0
- package/rules/utils/index.js +1 -0
- package/rules/utils/is-number.js +1 -1
- package/rules/utils/is-shadowed.js +1 -1
- package/rules/utils/lodash.js +1589 -0
- package/rules/utils/parentheses.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-unicorn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "49.0.0",
|
|
4
4
|
"description": "More than 100 powerful ESLint rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/eslint-plugin-unicorn",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"lint:md": "markdownlint \"**/*.md\"",
|
|
27
27
|
"lint:package-json": "npmPkgJsonLint .",
|
|
28
28
|
"run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.mjs",
|
|
29
|
+
"bundle-lodash": "echo \"export {defaultsDeep, camelCase, kebabCase, snakeCase, upperFirst, lowerFirst} from 'lodash-es';\" | npx esbuild --bundle --outfile=rules/utils/lodash.js --format=cjs",
|
|
29
30
|
"smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js",
|
|
30
31
|
"test": "npm-run-all --continue-on-error lint test:*",
|
|
31
32
|
"test:js": "c8 ava"
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"xo"
|
|
47
48
|
],
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@babel/helper-validator-identifier": "^7.22.
|
|
50
|
+
"@babel/helper-validator-identifier": "^7.22.20",
|
|
50
51
|
"@eslint-community/eslint-utils": "^4.4.0",
|
|
51
52
|
"ci-info": "^3.8.0",
|
|
52
53
|
"clean-regexp": "^1.0.0",
|
|
@@ -54,7 +55,6 @@
|
|
|
54
55
|
"indent-string": "^4.0.0",
|
|
55
56
|
"is-builtin-module": "^3.2.1",
|
|
56
57
|
"jsesc": "^3.0.2",
|
|
57
|
-
"lodash": "^4.17.21",
|
|
58
58
|
"pluralize": "^8.0.0",
|
|
59
59
|
"read-pkg-up": "^7.0.1",
|
|
60
60
|
"regexp-tree": "^0.1.27",
|
|
@@ -63,37 +63,37 @@
|
|
|
63
63
|
"strip-indent": "^3.0.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@babel/code-frame": "^7.22.
|
|
67
|
-
"@babel/core": "^7.
|
|
68
|
-
"@babel/eslint-parser": "^7.22.
|
|
66
|
+
"@babel/code-frame": "^7.22.13",
|
|
67
|
+
"@babel/core": "^7.23.2",
|
|
68
|
+
"@babel/eslint-parser": "^7.22.15",
|
|
69
69
|
"@lubien/fixture-beta-package": "^1.0.0-beta.1",
|
|
70
|
-
"@typescript-eslint/parser": "^
|
|
70
|
+
"@typescript-eslint/parser": "^6.9.0",
|
|
71
71
|
"ava": "^3.15.0",
|
|
72
|
-
"c8": "^8.0.
|
|
72
|
+
"c8": "^8.0.1",
|
|
73
73
|
"chalk": "^5.3.0",
|
|
74
|
-
"enquirer": "^2.
|
|
75
|
-
"eslint": "^8.
|
|
74
|
+
"enquirer": "^2.4.1",
|
|
75
|
+
"eslint": "^8.52.0",
|
|
76
76
|
"eslint-ava-rule-tester": "^4.0.0",
|
|
77
|
-
"eslint-doc-generator": "^1.
|
|
78
|
-
"eslint-plugin-eslint-plugin": "^5.1.
|
|
77
|
+
"eslint-doc-generator": "^1.5.2",
|
|
78
|
+
"eslint-plugin-eslint-plugin": "^5.1.1",
|
|
79
79
|
"eslint-plugin-internal-rules": "file:./scripts/internal-rules/",
|
|
80
|
-
"eslint-remote-tester": "^3.0.
|
|
80
|
+
"eslint-remote-tester": "^3.0.1",
|
|
81
81
|
"eslint-remote-tester-repositories": "^1.0.1",
|
|
82
|
-
"execa": "^
|
|
82
|
+
"execa": "^8.0.1",
|
|
83
83
|
"listr": "^0.14.3",
|
|
84
84
|
"lodash-es": "^4.17.21",
|
|
85
|
-
"markdownlint-cli": "^0.
|
|
85
|
+
"markdownlint-cli": "^0.37.0",
|
|
86
86
|
"mem": "^9.0.2",
|
|
87
87
|
"npm-package-json-lint": "^7.0.0",
|
|
88
|
-
"npm-run-
|
|
88
|
+
"npm-run-all2": "^6.1.1",
|
|
89
89
|
"outdent": "^0.8.0",
|
|
90
|
-
"typescript": "^5.
|
|
91
|
-
"vue-eslint-parser": "^9.3.
|
|
92
|
-
"xo": "^0.
|
|
93
|
-
"yaml": "^2.3.
|
|
90
|
+
"typescript": "^5.2.2",
|
|
91
|
+
"vue-eslint-parser": "^9.3.2",
|
|
92
|
+
"xo": "^0.56.0",
|
|
93
|
+
"yaml": "^2.3.3"
|
|
94
94
|
},
|
|
95
95
|
"peerDependencies": {
|
|
96
|
-
"eslint": ">=8.
|
|
96
|
+
"eslint": ">=8.52.0"
|
|
97
97
|
},
|
|
98
98
|
"ava": {
|
|
99
99
|
"files": [
|
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
"ignores": [
|
|
115
115
|
".cache-eslint-remote-tester",
|
|
116
116
|
"eslint-remote-tester-results",
|
|
117
|
+
"rules/utils/lodash.js",
|
|
117
118
|
"test/integration/{fixtures,fixtures-local}/**"
|
|
118
119
|
],
|
|
119
120
|
"rules": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const {pick} = require('lodash');
|
|
3
2
|
const isMemberExpression = require('./is-member-expression.js');
|
|
4
3
|
const {isCallExpression} = require('./call-or-new-expression.js');
|
|
5
4
|
|
|
@@ -46,11 +45,16 @@ function isMethodCall(node, options) {
|
|
|
46
45
|
|
|
47
46
|
return (
|
|
48
47
|
isCallExpression(node, {
|
|
49
|
-
|
|
48
|
+
argumentsLength: options.argumentsLength,
|
|
49
|
+
minimumArguments: options.minimumArguments,
|
|
50
|
+
maximumArguments: options.maximumArguments,
|
|
51
|
+
allowSpreadElement: options.allowSpreadElement,
|
|
50
52
|
optional: optionalCall,
|
|
51
53
|
})
|
|
52
54
|
&& isMemberExpression(node.callee, {
|
|
53
|
-
|
|
55
|
+
object: options.object,
|
|
56
|
+
objects: options.objects,
|
|
57
|
+
computed: options.computed,
|
|
54
58
|
property: method,
|
|
55
59
|
properties: methods,
|
|
56
60
|
optional: optionalMember,
|
|
@@ -115,6 +115,16 @@ function isNotReference(node) {
|
|
|
115
115
|
return parent.id === node;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
// `type Foo = { [Identifier: string]: string }`
|
|
119
|
+
case 'TSIndexSignature': {
|
|
120
|
+
return parent.parameters.includes(node);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// `type Identifier = Foo`
|
|
124
|
+
case 'TSTypeAliasDeclaration': {
|
|
125
|
+
return parent.id === node;
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
case 'TSPropertySignature': {
|
|
119
129
|
return parent.key === node;
|
|
120
130
|
}
|
package/rules/better-regex.js
CHANGED
|
@@ -28,10 +28,9 @@ const create = context => {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const {raw: original, regex} = node;
|
|
31
|
-
|
|
32
|
-
// Regular Expressions with `u` flag are not well handled by `regexp-tree`
|
|
31
|
+
// Regular Expressions with `u` and `v` flag are not well handled by `regexp-tree`
|
|
33
32
|
// https://github.com/DmitrySoshnikov/regexp-tree/issues/162
|
|
34
|
-
if (regex.flags.includes('u')) {
|
|
33
|
+
if (regex.flags.includes('u') || regex.flags.includes('v')) {
|
|
35
34
|
return;
|
|
36
35
|
}
|
|
37
36
|
|
|
@@ -89,7 +89,7 @@ const create = context => {
|
|
|
89
89
|
&& property.key.type === 'Identifier'
|
|
90
90
|
&& property.value.type === 'Identifier',
|
|
91
91
|
);
|
|
92
|
-
const lastProperty = objectPattern.properties
|
|
92
|
+
const lastProperty = objectPattern.properties.at(-1);
|
|
93
93
|
|
|
94
94
|
const hasRest = lastProperty && lastProperty.type === 'RestElement';
|
|
95
95
|
|
|
@@ -134,7 +134,7 @@ const create = context => {
|
|
|
134
134
|
},
|
|
135
135
|
* fix(fixer) {
|
|
136
136
|
const {properties} = objectPattern;
|
|
137
|
-
const lastProperty = properties
|
|
137
|
+
const lastProperty = properties.at(-1);
|
|
138
138
|
|
|
139
139
|
yield fixer.replaceText(node, newMember);
|
|
140
140
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const path = require('node:path');
|
|
2
3
|
const readPkgUp = require('read-pkg-up');
|
|
3
4
|
const semver = require('semver');
|
|
4
5
|
const ci = require('ci-info');
|
|
@@ -47,146 +48,160 @@ const messages = {
|
|
|
47
48
|
'Unexpected \'{{matchedTerm}}\' comment without any conditions: \'{{comment}}\'.',
|
|
48
49
|
};
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// package.json
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const DEPENDENCY_INCLUSION_RE = /^[+-]\s*@?\S+\/?\S+/;
|
|
63
|
-
const VERSION_COMPARISON_RE = /^(?<name>@?\S\/?\S+)@(?<condition>>|>=)(?<version>\d+(?:\.\d+){0,2}(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?)/i;
|
|
64
|
-
const PKG_VERSION_RE = /^(?<condition>>|>=)(?<version>\d+(?:\.\d+){0,2}(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?)\s*$/;
|
|
65
|
-
const ISO8601_DATE = /\d{4}-\d{2}-\d{2}/;
|
|
66
|
-
|
|
67
|
-
function parseTodoWithArguments(string, {terms}) {
|
|
68
|
-
const lowerCaseString = string.toLowerCase();
|
|
69
|
-
const lowerCaseTerms = terms.map(term => term.toLowerCase());
|
|
70
|
-
const hasTerm = lowerCaseTerms.some(term => lowerCaseString.includes(term));
|
|
71
|
-
|
|
72
|
-
if (!hasTerm) {
|
|
73
|
-
return false;
|
|
51
|
+
/** @param {string} dirname */
|
|
52
|
+
function getPackageHelpers(dirname) {
|
|
53
|
+
// We don't need to normalize the package.json data, because we are only using 2 properties and those 2 properties
|
|
54
|
+
// aren't validated by the normalization. But when this plugin is used in a monorepo, the name field in the
|
|
55
|
+
// package.json can be invalid and would make this plugin throw an error. See also #1871
|
|
56
|
+
/** @type {readPkgUp.ReadResult | undefined} */
|
|
57
|
+
let packageResult;
|
|
58
|
+
try {
|
|
59
|
+
packageResult = readPkgUp.sync({normalize: false, cwd: dirname});
|
|
60
|
+
} catch {
|
|
61
|
+
// This can happen if package.json files have comments in them etc.
|
|
62
|
+
packageResult = undefined;
|
|
74
63
|
}
|
|
75
64
|
|
|
76
|
-
const
|
|
77
|
-
const
|
|
65
|
+
const hasPackage = Boolean(packageResult);
|
|
66
|
+
const packageJson = packageResult ? packageResult.packageJson : {};
|
|
78
67
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
const packageDependencies = {
|
|
69
|
+
...packageJson.dependencies,
|
|
70
|
+
...packageJson.devDependencies,
|
|
71
|
+
};
|
|
82
72
|
|
|
83
|
-
|
|
73
|
+
function parseTodoWithArguments(string, {terms}) {
|
|
74
|
+
const lowerCaseString = string.toLowerCase();
|
|
75
|
+
const lowerCaseTerms = terms.map(term => term.toLowerCase());
|
|
76
|
+
const hasTerm = lowerCaseTerms.some(term => lowerCaseString.includes(term));
|
|
84
77
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
if (!hasTerm) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
88
81
|
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
const TODO_ARGUMENT_RE = /\[(?<rawArguments>[^}]+)]/i;
|
|
83
|
+
const result = TODO_ARGUMENT_RE.exec(string);
|
|
91
84
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
groups[type] = groups[type] || [];
|
|
96
|
-
groups[type].push(value);
|
|
97
|
-
}
|
|
85
|
+
if (!result) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
}
|
|
89
|
+
const {rawArguments} = result.groups;
|
|
101
90
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
type: 'dates',
|
|
106
|
-
value: argumentString,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
91
|
+
const parsedArguments = rawArguments
|
|
92
|
+
.split(',')
|
|
93
|
+
.map(argument => parseArgument(argument.trim()));
|
|
109
94
|
|
|
110
|
-
|
|
111
|
-
const condition = argumentString[0] === '+' ? 'in' : 'out';
|
|
112
|
-
const name = argumentString.slice(1).trim();
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
type: 'dependencies',
|
|
116
|
-
value: {
|
|
117
|
-
name,
|
|
118
|
-
condition,
|
|
119
|
-
},
|
|
120
|
-
};
|
|
95
|
+
return createArgumentGroup(parsedArguments);
|
|
121
96
|
}
|
|
122
97
|
|
|
123
|
-
|
|
124
|
-
const {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
98
|
+
function parseArgument(argumentString, dirname) {
|
|
99
|
+
const {hasPackage} = getPackageHelpers(dirname);
|
|
100
|
+
if (ISO8601_DATE.test(argumentString)) {
|
|
101
|
+
return {
|
|
102
|
+
type: 'dates',
|
|
103
|
+
value: argumentString,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
128
106
|
|
|
129
|
-
|
|
130
|
-
|
|
107
|
+
if (hasPackage && DEPENDENCY_INCLUSION_RE.test(argumentString)) {
|
|
108
|
+
const condition = argumentString[0] === '+' ? 'in' : 'out';
|
|
109
|
+
const name = argumentString.slice(1).trim();
|
|
131
110
|
|
|
132
|
-
if (hasEngineKeyword && isNodeEngine) {
|
|
133
111
|
return {
|
|
134
|
-
type: '
|
|
112
|
+
type: 'dependencies',
|
|
135
113
|
value: {
|
|
114
|
+
name,
|
|
136
115
|
condition,
|
|
137
|
-
version,
|
|
138
116
|
},
|
|
139
117
|
};
|
|
140
118
|
}
|
|
141
119
|
|
|
142
|
-
if (
|
|
120
|
+
if (hasPackage && VERSION_COMPARISON_RE.test(argumentString)) {
|
|
121
|
+
const {groups} = VERSION_COMPARISON_RE.exec(argumentString);
|
|
122
|
+
const name = groups.name.trim();
|
|
123
|
+
const condition = groups.condition.trim();
|
|
124
|
+
const version = groups.version.trim();
|
|
125
|
+
|
|
126
|
+
const hasEngineKeyword = name.indexOf('engine:') === 0;
|
|
127
|
+
const isNodeEngine = hasEngineKeyword && name === 'engine:node';
|
|
128
|
+
|
|
129
|
+
if (hasEngineKeyword && isNodeEngine) {
|
|
130
|
+
return {
|
|
131
|
+
type: 'engines',
|
|
132
|
+
value: {
|
|
133
|
+
condition,
|
|
134
|
+
version,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!hasEngineKeyword) {
|
|
140
|
+
return {
|
|
141
|
+
type: 'dependencies',
|
|
142
|
+
value: {
|
|
143
|
+
name,
|
|
144
|
+
condition,
|
|
145
|
+
version,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (hasPackage && PKG_VERSION_RE.test(argumentString)) {
|
|
152
|
+
const result = PKG_VERSION_RE.exec(argumentString);
|
|
153
|
+
const {condition, version} = result.groups;
|
|
154
|
+
|
|
143
155
|
return {
|
|
144
|
-
type: '
|
|
156
|
+
type: 'packageVersions',
|
|
145
157
|
value: {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
version,
|
|
158
|
+
condition: condition.trim(),
|
|
159
|
+
version: version.trim(),
|
|
149
160
|
},
|
|
150
161
|
};
|
|
151
162
|
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (hasPackage && PKG_VERSION_RE.test(argumentString)) {
|
|
155
|
-
const result = PKG_VERSION_RE.exec(argumentString);
|
|
156
|
-
const {condition, version} = result.groups;
|
|
157
163
|
|
|
164
|
+
// Currently being ignored as integration tests pointed
|
|
165
|
+
// some TODO comments have `[random data like this]`
|
|
158
166
|
return {
|
|
159
|
-
type: '
|
|
160
|
-
value:
|
|
161
|
-
condition: condition.trim(),
|
|
162
|
-
version: version.trim(),
|
|
163
|
-
},
|
|
167
|
+
type: 'unknowns',
|
|
168
|
+
value: argumentString,
|
|
164
169
|
};
|
|
165
170
|
}
|
|
166
171
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
172
|
+
function parseTodoMessage(todoString) {
|
|
173
|
+
// @example "TODO [...]: message here"
|
|
174
|
+
// @example "TODO [...] message here"
|
|
175
|
+
const argumentsEnd = todoString.indexOf(']');
|
|
176
|
+
|
|
177
|
+
const afterArguments = todoString.slice(argumentsEnd + 1).trim();
|
|
174
178
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
// Check if have to skip colon
|
|
180
|
+
// @example "TODO [...]: message here"
|
|
181
|
+
const dropColon = afterArguments[0] === ':';
|
|
182
|
+
if (dropColon) {
|
|
183
|
+
return afterArguments.slice(1).trim();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return afterArguments;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return {packageResult, hasPackage, packageJson, packageDependencies, parseArgument, parseTodoMessage, parseTodoWithArguments};
|
|
190
|
+
}
|
|
179
191
|
|
|
180
|
-
|
|
192
|
+
const DEPENDENCY_INCLUSION_RE = /^[+-]\s*@?\S+\/?\S+/;
|
|
193
|
+
const VERSION_COMPARISON_RE = /^(?<name>@?\S\/?\S+)@(?<condition>>|>=)(?<version>\d+(?:\.\d+){0,2}(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?)/i;
|
|
194
|
+
const PKG_VERSION_RE = /^(?<condition>>|>=)(?<version>\d+(?:\.\d+){0,2}(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?)\s*$/;
|
|
195
|
+
const ISO8601_DATE = /\d{4}-\d{2}-\d{2}/;
|
|
181
196
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
function createArgumentGroup(arguments_) {
|
|
198
|
+
const groups = {};
|
|
199
|
+
for (const {value, type} of arguments_) {
|
|
200
|
+
groups[type] = groups[type] || [];
|
|
201
|
+
groups[type].push(value);
|
|
187
202
|
}
|
|
188
203
|
|
|
189
|
-
return
|
|
204
|
+
return groups;
|
|
190
205
|
}
|
|
191
206
|
|
|
192
207
|
function reachedDate(past, now) {
|
|
@@ -263,6 +278,9 @@ const create = context => {
|
|
|
263
278
|
pattern => pattern instanceof RegExp ? pattern : new RegExp(pattern, 'u'),
|
|
264
279
|
);
|
|
265
280
|
|
|
281
|
+
const dirname = path.dirname(context.filename);
|
|
282
|
+
const {packageJson, packageDependencies, parseArgument, parseTodoMessage, parseTodoWithArguments} = getPackageHelpers(dirname);
|
|
283
|
+
|
|
266
284
|
const {sourceCode} = context;
|
|
267
285
|
const comments = sourceCode.getAllComments();
|
|
268
286
|
const unusedComments = comments
|
|
@@ -284,13 +302,18 @@ const create = context => {
|
|
|
284
302
|
// This is highly dependable on ESLint's `no-warning-comments` implementation.
|
|
285
303
|
// What we do is patch the parts we know the rule will use, `getAllComments`.
|
|
286
304
|
// Since we have priority, we leave only the comments that we didn't use.
|
|
287
|
-
const fakeContext = {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
305
|
+
const fakeContext = new Proxy(context, {
|
|
306
|
+
get(target, property, receiver) {
|
|
307
|
+
if (property === 'sourceCode') {
|
|
308
|
+
return {
|
|
309
|
+
...sourceCode,
|
|
310
|
+
getAllComments: () => options.allowWarningComments ? [] : unusedComments,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return Reflect.get(target, property, receiver);
|
|
292
315
|
},
|
|
293
|
-
};
|
|
316
|
+
});
|
|
294
317
|
const rules = baseRule.create(fakeContext);
|
|
295
318
|
|
|
296
319
|
function processComment(comment) {
|
|
@@ -485,7 +508,7 @@ const create = context => {
|
|
|
485
508
|
}
|
|
486
509
|
}
|
|
487
510
|
|
|
488
|
-
const withoutWhitespace = unknown.
|
|
511
|
+
const withoutWhitespace = unknown.replaceAll(' ', '');
|
|
489
512
|
|
|
490
513
|
if (parseArgument(withoutWhitespace).type !== 'unknowns') {
|
|
491
514
|
uses++;
|
package/rules/filename-case.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const path = require('node:path');
|
|
3
|
-
const {camelCase, kebabCase, snakeCase, upperFirst} = require('lodash');
|
|
3
|
+
const {camelCase, kebabCase, snakeCase, upperFirst} = require('./utils/lodash.js');
|
|
4
4
|
const cartesianProductSamples = require('./utils/cartesian-product-samples.js');
|
|
5
5
|
|
|
6
6
|
const MESSAGE_ID = 'filename-case';
|
|
@@ -7,7 +7,7 @@ function removeArgument(fixer, node, sourceCode) {
|
|
|
7
7
|
const index = callExpression.arguments.indexOf(node);
|
|
8
8
|
const parentheses = getParentheses(node, sourceCode);
|
|
9
9
|
const firstToken = parentheses[0] || node;
|
|
10
|
-
const lastToken = parentheses
|
|
10
|
+
const lastToken = parentheses.at(-1) || node;
|
|
11
11
|
|
|
12
12
|
let [start] = firstToken.range;
|
|
13
13
|
let [, end] = lastToken.range;
|
package/rules/import-style.js
CHANGED
|
@@ -83,7 +83,7 @@ function useBoundFunction(callExpression, sourceCode) {
|
|
|
83
83
|
const callbackParentheses = getParentheses(callback, sourceCode);
|
|
84
84
|
const isParenthesized = callbackParentheses.length > 0;
|
|
85
85
|
const callbackLastToken = isParenthesized
|
|
86
|
-
? callbackParentheses
|
|
86
|
+
? callbackParentheses.at(-1)
|
|
87
87
|
: callback;
|
|
88
88
|
if (
|
|
89
89
|
!isParenthesized
|
|
@@ -11,7 +11,7 @@ const messages = {
|
|
|
11
11
|
const hasLeadingSpace = value => value.length > 1 && value.charAt(0) === ' ' && value.charAt(1) !== ' ';
|
|
12
12
|
|
|
13
13
|
// Find exactly one trailing space, allow exactly one space
|
|
14
|
-
const hasTrailingSpace = value => value.length > 1 && value.
|
|
14
|
+
const hasTrailingSpace = value => value.length > 1 && value.at(-1) === ' ' && value.at(-2) !== ' ';
|
|
15
15
|
|
|
16
16
|
/** @param {import('eslint').Rule.RuleContext} context */
|
|
17
17
|
const create = context => {
|
package/rules/no-empty-file.js
CHANGED
|
@@ -6,7 +6,7 @@ const messages = {
|
|
|
6
6
|
[MESSAGE_ID]: 'Empty files are not allowed.',
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
const isDirective = node => node.type === 'ExpressionStatement' &&
|
|
9
|
+
const isDirective = node => node.type === 'ExpressionStatement' && typeof node.directive === 'string';
|
|
10
10
|
const isEmpty = node => isEmptyNode(node, isDirective);
|
|
11
11
|
|
|
12
12
|
const isTripleSlashDirective = node =>
|
package/rules/no-hex-escape.js
CHANGED
|
@@ -8,7 +8,7 @@ const messages = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
function checkEscape(context, node, value) {
|
|
11
|
-
const fixedValue = value.
|
|
11
|
+
const fixedValue = value.replaceAll(/(?<=(?:^|[^\\])(?:\\\\)*\\)x/g, 'u00');
|
|
12
12
|
|
|
13
13
|
if (value !== fixedValue) {
|
|
14
14
|
return {
|
|
@@ -28,7 +28,7 @@ const create = context => ({
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const {before, dotAndFractions, after} = match.groups;
|
|
31
|
-
const fixedDotAndFractions = dotAndFractions.
|
|
31
|
+
const fixedDotAndFractions = dotAndFractions.replaceAll(/[.0_]+$/g, '');
|
|
32
32
|
const formatted = ((before + fixedDotAndFractions) || '0') + after;
|
|
33
33
|
|
|
34
34
|
if (formatted === raw) {
|
|
@@ -111,7 +111,7 @@ const create = context => {
|
|
|
111
111
|
suffix = 'n';
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
const strippedNumber = number.
|
|
114
|
+
const strippedNumber = number.replaceAll('_', '');
|
|
115
115
|
const {prefix, data} = numeric.getPrefix(strippedNumber);
|
|
116
116
|
|
|
117
117
|
const {onlyIfContainsSeparator} = options[prefix.toLowerCase()];
|
|
@@ -72,7 +72,7 @@ const hasExtraReferences = (assignment, references, left) => {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
const isLastParameter = (parameters, parameter) => {
|
|
75
|
-
const lastParameter = parameters
|
|
75
|
+
const lastParameter = parameters.at(-1);
|
|
76
76
|
|
|
77
77
|
// See 'default-param-last' rule
|
|
78
78
|
return parameter && parameter === lastParameter;
|
|
@@ -122,7 +122,7 @@ const create = context => {
|
|
|
122
122
|
const functionStack = [];
|
|
123
123
|
|
|
124
124
|
const checkExpression = (node, left, right, assignment) => {
|
|
125
|
-
const currentFunction = functionStack
|
|
125
|
+
const currentFunction = functionStack.at(-1);
|
|
126
126
|
|
|
127
127
|
if (!currentFunction || !isDefaultExpression(left, right)) {
|
|
128
128
|
return;
|