eslint 8.6.0 → 8.7.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 +3 -3
- package/bin/eslint.js +7 -1
- package/lib/cli-engine/cli-engine.js +4 -1
- package/lib/eslint/eslint.js +1 -0
- package/lib/rule-tester/rule-tester.js +5 -5
- package/lib/rules/camelcase.js +7 -1
- package/lib/rules/id-match.js +1 -1
- package/lib/rules/keyword-spacing.js +32 -0
- package/lib/rules/no-constant-condition.js +23 -4
- package/lib/rules/no-invalid-this.js +50 -53
- package/lib/rules/no-restricted-exports.js +9 -3
- package/lib/rules/no-restricted-imports.js +24 -7
- package/lib/rules/no-restricted-modules.js +2 -1
- package/lib/rules/no-useless-rename.js +8 -4
- package/lib/rules/quotes.js +12 -1
- package/lib/rules/utils/ast-utils.js +21 -1
- package/messages/no-config-found.js +1 -1
- package/package.json +5 -6
- package/lib/init/autoconfig.js +0 -351
- package/lib/init/config-file.js +0 -144
- package/lib/init/config-initializer.js +0 -709
- package/lib/init/config-rule.js +0 -316
- package/lib/init/npm-utils.js +0 -179
- package/lib/init/source-code-utils.js +0 -110
package/README.md
CHANGED
@@ -54,7 +54,7 @@ $ npm install eslint --save-dev
|
|
54
54
|
You should then set up a configuration file:
|
55
55
|
|
56
56
|
```sh
|
57
|
-
$
|
57
|
+
$ npm init @eslint/config
|
58
58
|
```
|
59
59
|
|
60
60
|
After that, you can run ESLint on any file or directory like this:
|
@@ -65,7 +65,7 @@ $ ./node_modules/.bin/eslint yourfile.js
|
|
65
65
|
|
66
66
|
## <a name="configuration"></a>Configuration
|
67
67
|
|
68
|
-
After running `
|
68
|
+
After running `npm init @eslint/config`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
|
69
69
|
|
70
70
|
```json
|
71
71
|
{
|
@@ -294,7 +294,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
294
294
|
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
295
295
|
<p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
|
296
296
|
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
|
297
|
-
<p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.
|
297
|
+
<p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
|
298
298
|
<!--sponsorsend-->
|
299
299
|
|
300
300
|
## <a name="technology-sponsors"></a>Technology Sponsors
|
package/bin/eslint.js
CHANGED
@@ -124,7 +124,13 @@ ${message}`);
|
|
124
124
|
|
125
125
|
// Call the config initializer if `--init` is present.
|
126
126
|
if (process.argv.includes("--init")) {
|
127
|
-
|
127
|
+
|
128
|
+
// `eslint --init` has been moved to `@eslint/create-config`
|
129
|
+
console.warn("You can also run this command directly using 'npm init @eslint/config'.");
|
130
|
+
|
131
|
+
const spawn = require("cross-spawn");
|
132
|
+
|
133
|
+
spawn.sync("npm", ["init", "@eslint/config"], { encoding: "utf8", stdio: "inherit" });
|
128
134
|
return;
|
129
135
|
}
|
130
136
|
|
@@ -92,6 +92,7 @@ const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
|
|
92
92
|
* @property {string} filePath The path to the file that was linted.
|
93
93
|
* @property {LintMessage[]} messages All of the messages for the result.
|
94
94
|
* @property {number} errorCount Number of errors for the result.
|
95
|
+
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
95
96
|
* @property {number} warningCount Number of warnings for the result.
|
96
97
|
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
97
98
|
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
@@ -104,6 +105,7 @@ const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
|
|
104
105
|
* @typedef {Object} LintReport
|
105
106
|
* @property {LintResult[]} results All of the result.
|
106
107
|
* @property {number} errorCount Number of errors for the result.
|
108
|
+
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
107
109
|
* @property {number} warningCount Number of warnings for the result.
|
108
110
|
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
109
111
|
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
@@ -308,6 +310,7 @@ function createIgnoreResult(filePath, baseDir) {
|
|
308
310
|
}
|
309
311
|
],
|
310
312
|
errorCount: 0,
|
313
|
+
fatalErrorCount: 0,
|
311
314
|
warningCount: 1,
|
312
315
|
fixableErrorCount: 0,
|
313
316
|
fixableWarningCount: 0
|
@@ -408,7 +411,7 @@ function isErrorMessage(message) {
|
|
408
411
|
* a directory or looks like a directory (ends in `path.sep`), in which case the file
|
409
412
|
* name will be the `cacheFile/.cache_hashOfCWD`
|
410
413
|
*
|
411
|
-
* if cacheFile points to a file or looks like a file then
|
414
|
+
* if cacheFile points to a file or looks like a file then it will just use that file
|
412
415
|
* @param {string} cacheFile The name of file to be used to store the cache
|
413
416
|
* @param {string} cwd Current working directory
|
414
417
|
* @returns {string} the resolved path to the cache file
|
package/lib/eslint/eslint.js
CHANGED
@@ -79,6 +79,7 @@ const { version } = require("../../package.json");
|
|
79
79
|
* @property {string} filePath The path to the file that was linted.
|
80
80
|
* @property {LintMessage[]} messages All of the messages for the result.
|
81
81
|
* @property {number} errorCount Number of errors for the result.
|
82
|
+
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
82
83
|
* @property {number} warningCount Number of warnings for the result.
|
83
84
|
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
84
85
|
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
@@ -977,10 +977,10 @@ class RuleTester {
|
|
977
977
|
* This creates a mocha test suite and pipes all supplied info through
|
978
978
|
* one of the templates above.
|
979
979
|
*/
|
980
|
-
|
981
|
-
|
980
|
+
this.constructor.describe(ruleName, () => {
|
981
|
+
this.constructor.describe("valid", () => {
|
982
982
|
test.valid.forEach(valid => {
|
983
|
-
|
983
|
+
this.constructor[valid.only ? "itOnly" : "it"](
|
984
984
|
sanitize(typeof valid === "object" ? valid.name || valid.code : valid),
|
985
985
|
() => {
|
986
986
|
testValidTemplate(valid);
|
@@ -989,9 +989,9 @@ class RuleTester {
|
|
989
989
|
});
|
990
990
|
});
|
991
991
|
|
992
|
-
|
992
|
+
this.constructor.describe("invalid", () => {
|
993
993
|
test.invalid.forEach(invalid => {
|
994
|
-
|
994
|
+
this.constructor[invalid.only ? "itOnly" : "it"](
|
995
995
|
sanitize(invalid.name || invalid.code),
|
996
996
|
() => {
|
997
997
|
testInvalidTemplate(invalid);
|
package/lib/rules/camelcase.js
CHANGED
@@ -5,6 +5,12 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
8
14
|
//------------------------------------------------------------------------------
|
9
15
|
// Rule Definition
|
10
16
|
//------------------------------------------------------------------------------
|
@@ -165,7 +171,7 @@ module.exports = {
|
|
165
171
|
case "ImportSpecifier":
|
166
172
|
return (
|
167
173
|
parent.local === node &&
|
168
|
-
parent.imported
|
174
|
+
astUtils.getModuleExportName(parent.imported) === localName
|
169
175
|
);
|
170
176
|
|
171
177
|
default:
|
package/lib/rules/id-match.js
CHANGED
@@ -250,7 +250,7 @@ module.exports = {
|
|
250
250
|
}
|
251
251
|
|
252
252
|
// never check properties or always ignore destructuring
|
253
|
-
if (!checkProperties || (ignoreDestructuring && isInsideObjectPattern(node))) {
|
253
|
+
if ((!checkProperties && !parent.computed) || (ignoreDestructuring && isInsideObjectPattern(node))) {
|
254
254
|
return;
|
255
255
|
}
|
256
256
|
|
@@ -469,6 +469,7 @@ module.exports = {
|
|
469
469
|
const asToken = sourceCode.getTokenBefore(node.exported);
|
470
470
|
|
471
471
|
checkSpacingBefore(asToken, PREV_TOKEN_M);
|
472
|
+
checkSpacingAfter(asToken, NEXT_TOKEN_M);
|
472
473
|
}
|
473
474
|
|
474
475
|
if (node.source) {
|
@@ -479,6 +480,35 @@ module.exports = {
|
|
479
480
|
}
|
480
481
|
}
|
481
482
|
|
483
|
+
/**
|
484
|
+
* Reports `as` keyword of a given node if usage of spacing around this
|
485
|
+
* keyword is invalid.
|
486
|
+
* @param {ASTNode} node An `ImportSpecifier` node to check.
|
487
|
+
* @returns {void}
|
488
|
+
*/
|
489
|
+
function checkSpacingForImportSpecifier(node) {
|
490
|
+
if (node.imported.range[0] !== node.local.range[0]) {
|
491
|
+
const asToken = sourceCode.getTokenBefore(node.local);
|
492
|
+
|
493
|
+
checkSpacingBefore(asToken, PREV_TOKEN_M);
|
494
|
+
}
|
495
|
+
}
|
496
|
+
|
497
|
+
/**
|
498
|
+
* Reports `as` keyword of a given node if usage of spacing around this
|
499
|
+
* keyword is invalid.
|
500
|
+
* @param {ASTNode} node An `ExportSpecifier` node to check.
|
501
|
+
* @returns {void}
|
502
|
+
*/
|
503
|
+
function checkSpacingForExportSpecifier(node) {
|
504
|
+
if (node.local.range[0] !== node.exported.range[0]) {
|
505
|
+
const asToken = sourceCode.getTokenBefore(node.exported);
|
506
|
+
|
507
|
+
checkSpacingBefore(asToken, PREV_TOKEN_M);
|
508
|
+
checkSpacingAfter(asToken, NEXT_TOKEN_M);
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
482
512
|
/**
|
483
513
|
* Reports `as` keyword of a given node if usage of spacing around this
|
484
514
|
* keyword is invalid.
|
@@ -588,6 +618,8 @@ module.exports = {
|
|
588
618
|
YieldExpression: checkSpacingBeforeFirstToken,
|
589
619
|
|
590
620
|
// Others
|
621
|
+
ImportSpecifier: checkSpacingForImportSpecifier,
|
622
|
+
ExportSpecifier: checkSpacingForExportSpecifier,
|
591
623
|
ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
|
592
624
|
MethodDefinition: checkSpacingForProperty,
|
593
625
|
PropertyDefinition: checkSpacingForProperty,
|
@@ -124,7 +124,8 @@ module.exports = {
|
|
124
124
|
* Checks if a node has a constant truthiness value.
|
125
125
|
* @param {ASTNode} node The AST node to check.
|
126
126
|
* @param {boolean} inBooleanPosition `false` if checking branch of a condition.
|
127
|
-
* `true` in all other cases
|
127
|
+
* `true` in all other cases. When `false`, checks if -- for both string and
|
128
|
+
* number -- if coerced to that type, the value will be constant.
|
128
129
|
* @returns {Bool} true when node's truthiness is constant
|
129
130
|
* @private
|
130
131
|
*/
|
@@ -138,15 +139,31 @@ module.exports = {
|
|
138
139
|
case "Literal":
|
139
140
|
case "ArrowFunctionExpression":
|
140
141
|
case "FunctionExpression":
|
141
|
-
|
142
|
+
return true;
|
142
143
|
case "ClassExpression":
|
144
|
+
case "ObjectExpression":
|
145
|
+
|
146
|
+
/**
|
147
|
+
* In theory objects like:
|
148
|
+
*
|
149
|
+
* `{toString: () => a}`
|
150
|
+
* `{valueOf: () => a}`
|
151
|
+
*
|
152
|
+
* Or a classes like:
|
153
|
+
*
|
154
|
+
* `class { static toString() { return a } }`
|
155
|
+
* `class { static valueOf() { return a } }`
|
156
|
+
*
|
157
|
+
* Are not constant verifiably when `inBooleanPosition` is
|
158
|
+
* false, but it's an edge case we've opted not to handle.
|
159
|
+
*/
|
143
160
|
return true;
|
144
161
|
case "TemplateLiteral":
|
145
162
|
return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) ||
|
146
|
-
node.expressions.every(exp => isConstant(exp,
|
163
|
+
node.expressions.every(exp => isConstant(exp, false));
|
147
164
|
|
148
165
|
case "ArrayExpression": {
|
149
|
-
if (
|
166
|
+
if (!inBooleanPosition) {
|
150
167
|
return node.elements.every(element => isConstant(element, false));
|
151
168
|
}
|
152
169
|
return true;
|
@@ -196,6 +213,8 @@ module.exports = {
|
|
196
213
|
|
197
214
|
case "SequenceExpression":
|
198
215
|
return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
|
216
|
+
case "SpreadElement":
|
217
|
+
return isConstant(node.argument, inBooleanPosition);
|
199
218
|
|
200
219
|
// no default
|
201
220
|
}
|
@@ -11,6 +11,21 @@
|
|
11
11
|
|
12
12
|
const astUtils = require("./utils/ast-utils");
|
13
13
|
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Helpers
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Determines if the given code path is a code path with lexical `this` binding.
|
20
|
+
* That is, if `this` within the code path refers to `this` of surrounding code path.
|
21
|
+
* @param {CodePath} codePath Code path.
|
22
|
+
* @param {ASTNode} node Node that started the code path.
|
23
|
+
* @returns {boolean} `true` if it is a code path with lexical `this` binding.
|
24
|
+
*/
|
25
|
+
function isCodePathWithLexicalThis(codePath, node) {
|
26
|
+
return codePath.origin === "function" && node.type === "ArrowFunctionExpression";
|
27
|
+
}
|
28
|
+
|
14
29
|
//------------------------------------------------------------------------------
|
15
30
|
// Rule Definition
|
16
31
|
//------------------------------------------------------------------------------
|
@@ -72,71 +87,53 @@ module.exports = {
|
|
72
87
|
return current;
|
73
88
|
};
|
74
89
|
|
75
|
-
|
76
|
-
* Pushs new checking context into the stack.
|
77
|
-
*
|
78
|
-
* The checking context is not initialized yet.
|
79
|
-
* Because most functions don't have `this` keyword.
|
80
|
-
* When `this` keyword was found, the checking context is initialized.
|
81
|
-
* @param {ASTNode} node A function node that was entered.
|
82
|
-
* @returns {void}
|
83
|
-
*/
|
84
|
-
function enterFunction(node) {
|
85
|
-
|
86
|
-
// `this` can be invalid only under strict mode.
|
87
|
-
stack.push({
|
88
|
-
init: !context.getScope().isStrict,
|
89
|
-
node,
|
90
|
-
valid: true
|
91
|
-
});
|
92
|
-
}
|
90
|
+
return {
|
93
91
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
function exitFunction() {
|
99
|
-
stack.pop();
|
100
|
-
}
|
92
|
+
onCodePathStart(codePath, node) {
|
93
|
+
if (isCodePathWithLexicalThis(codePath, node)) {
|
94
|
+
return;
|
95
|
+
}
|
101
96
|
|
102
|
-
|
97
|
+
if (codePath.origin === "program") {
|
98
|
+
const scope = context.getScope();
|
99
|
+
const features = context.parserOptions.ecmaFeatures || {};
|
100
|
+
|
101
|
+
stack.push({
|
102
|
+
init: true,
|
103
|
+
node,
|
104
|
+
valid: !(
|
105
|
+
scope.isStrict ||
|
106
|
+
node.sourceType === "module" ||
|
107
|
+
(features.globalReturn && scope.childScopes[0].isStrict)
|
108
|
+
)
|
109
|
+
});
|
103
110
|
|
104
|
-
|
105
|
-
|
106
|
-
* Modules is always strict mode.
|
107
|
-
*/
|
108
|
-
Program(node) {
|
109
|
-
const scope = context.getScope(),
|
110
|
-
features = context.parserOptions.ecmaFeatures || {};
|
111
|
+
return;
|
112
|
+
}
|
111
113
|
|
114
|
+
/*
|
115
|
+
* `init: false` means that `valid` isn't determined yet.
|
116
|
+
* Most functions don't use `this`, and the calculation for `valid`
|
117
|
+
* is relatively costly, so we'll calculate it lazily when the first
|
118
|
+
* `this` within the function is traversed. A special case are non-strict
|
119
|
+
* functions, because `this` refers to the global object and therefore is
|
120
|
+
* always valid, so we can set `init: true` right away.
|
121
|
+
*/
|
112
122
|
stack.push({
|
113
|
-
init:
|
123
|
+
init: !context.getScope().isStrict,
|
114
124
|
node,
|
115
|
-
valid:
|
116
|
-
scope.isStrict ||
|
117
|
-
node.sourceType === "module" ||
|
118
|
-
(features.globalReturn && scope.childScopes[0].isStrict)
|
119
|
-
)
|
125
|
+
valid: true
|
120
126
|
});
|
121
127
|
},
|
122
128
|
|
123
|
-
|
129
|
+
onCodePathEnd(codePath, node) {
|
130
|
+
if (isCodePathWithLexicalThis(codePath, node)) {
|
131
|
+
return;
|
132
|
+
}
|
133
|
+
|
124
134
|
stack.pop();
|
125
135
|
},
|
126
136
|
|
127
|
-
FunctionDeclaration: enterFunction,
|
128
|
-
"FunctionDeclaration:exit": exitFunction,
|
129
|
-
FunctionExpression: enterFunction,
|
130
|
-
"FunctionExpression:exit": exitFunction,
|
131
|
-
|
132
|
-
// Field initializers are implicit functions.
|
133
|
-
"PropertyDefinition > *.value": enterFunction,
|
134
|
-
"PropertyDefinition > *.value:exit": exitFunction,
|
135
|
-
|
136
|
-
// Class static blocks are implicit functions.
|
137
|
-
StaticBlock: enterFunction,
|
138
|
-
"StaticBlock:exit": exitFunction,
|
139
|
-
|
140
137
|
// Reports if `this` of the current context is invalid.
|
141
138
|
ThisExpression(node) {
|
142
139
|
const current = stack.getCurrent();
|
@@ -5,6 +5,12 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
8
14
|
//------------------------------------------------------------------------------
|
9
15
|
// Rule Definition
|
10
16
|
//------------------------------------------------------------------------------
|
@@ -44,12 +50,12 @@ module.exports = {
|
|
44
50
|
const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports);
|
45
51
|
|
46
52
|
/**
|
47
|
-
* Checks and reports given exported
|
48
|
-
* @param {ASTNode} node exported `Identifier` node to check.
|
53
|
+
* Checks and reports given exported name.
|
54
|
+
* @param {ASTNode} node exported `Identifier` or string `Literal` node to check.
|
49
55
|
* @returns {void}
|
50
56
|
*/
|
51
57
|
function checkExportedName(node) {
|
52
|
-
const name = node
|
58
|
+
const name = astUtils.getModuleExportName(node);
|
53
59
|
|
54
60
|
if (restrictedNames.has(name)) {
|
55
61
|
context.report({
|
@@ -4,6 +4,12 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const astUtils = require("./utils/ast-utils");
|
12
|
+
|
7
13
|
//------------------------------------------------------------------------------
|
8
14
|
// Rule Definition
|
9
15
|
//------------------------------------------------------------------------------
|
@@ -63,6 +69,9 @@ const arrayOfStringsOrObjectPatterns = {
|
|
63
69
|
message: {
|
64
70
|
type: "string",
|
65
71
|
minLength: 1
|
72
|
+
},
|
73
|
+
caseSensitive: {
|
74
|
+
type: "boolean"
|
66
75
|
}
|
67
76
|
},
|
68
77
|
additionalProperties: false,
|
@@ -142,10 +151,18 @@ module.exports = {
|
|
142
151
|
}, {});
|
143
152
|
|
144
153
|
// Handle patterns too, either as strings or groups
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
154
|
+
let restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
|
155
|
+
|
156
|
+
// standardize to array of objects if we have an array of strings
|
157
|
+
if (restrictedPatterns.length > 0 && typeof restrictedPatterns[0] === "string") {
|
158
|
+
restrictedPatterns = [{ group: restrictedPatterns }];
|
159
|
+
}
|
160
|
+
|
161
|
+
// relative paths are supported for this rule
|
162
|
+
const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive }) => ({
|
163
|
+
matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group),
|
164
|
+
customMessage: message
|
165
|
+
}));
|
149
166
|
|
150
167
|
// if no imports are restricted we don't need to check
|
151
168
|
if (Object.keys(restrictedPaths).length === 0 && restrictedPatternGroups.length === 0) {
|
@@ -269,12 +286,12 @@ module.exports = {
|
|
269
286
|
} else if (specifier.type === "ImportNamespaceSpecifier") {
|
270
287
|
name = "*";
|
271
288
|
} else if (specifier.imported) {
|
272
|
-
name = specifier.imported
|
289
|
+
name = astUtils.getModuleExportName(specifier.imported);
|
273
290
|
} else if (specifier.local) {
|
274
|
-
name = specifier.local
|
291
|
+
name = astUtils.getModuleExportName(specifier.local);
|
275
292
|
}
|
276
293
|
|
277
|
-
if (name) {
|
294
|
+
if (typeof name === "string") {
|
278
295
|
if (importNames.has(name)) {
|
279
296
|
importNames.get(name).push(specifierData);
|
280
297
|
} else {
|
@@ -132,8 +132,10 @@ module.exports = {
|
|
132
132
|
return;
|
133
133
|
}
|
134
134
|
|
135
|
-
if (
|
136
|
-
|
135
|
+
if (
|
136
|
+
node.imported.range[0] !== node.local.range[0] &&
|
137
|
+
astUtils.getModuleExportName(node.imported) === node.local.name
|
138
|
+
) {
|
137
139
|
reportError(node, node.imported, "Import");
|
138
140
|
}
|
139
141
|
}
|
@@ -148,8 +150,10 @@ module.exports = {
|
|
148
150
|
return;
|
149
151
|
}
|
150
152
|
|
151
|
-
if (
|
152
|
-
|
153
|
+
if (
|
154
|
+
node.local.range[0] !== node.exported.range[0] &&
|
155
|
+
astUtils.getModuleExportName(node.local) === astUtils.getModuleExportName(node.exported)
|
156
|
+
) {
|
153
157
|
reportError(node, node.local, "Export");
|
154
158
|
}
|
155
159
|
|
package/lib/rules/quotes.js
CHANGED
@@ -223,9 +223,20 @@ module.exports = {
|
|
223
223
|
// ModuleSpecifier.
|
224
224
|
case "ImportDeclaration":
|
225
225
|
case "ExportNamedDeclaration":
|
226
|
-
case "ExportAllDeclaration":
|
227
226
|
return parent.source === node;
|
228
227
|
|
228
|
+
// ModuleExportName or ModuleSpecifier.
|
229
|
+
case "ExportAllDeclaration":
|
230
|
+
return parent.exported === node || parent.source === node;
|
231
|
+
|
232
|
+
// ModuleExportName.
|
233
|
+
case "ImportSpecifier":
|
234
|
+
return parent.imported === node;
|
235
|
+
|
236
|
+
// ModuleExportName.
|
237
|
+
case "ExportSpecifier":
|
238
|
+
return parent.local === node || parent.exported === node;
|
239
|
+
|
229
240
|
// Others don't allow.
|
230
241
|
default:
|
231
242
|
return false;
|
@@ -769,6 +769,25 @@ function getSwitchCaseColonToken(node, sourceCode) {
|
|
769
769
|
return sourceCode.getFirstToken(node, 1);
|
770
770
|
}
|
771
771
|
|
772
|
+
/**
|
773
|
+
* Gets ESM module export name represented by the given node.
|
774
|
+
* @param {ASTNode} node `Identifier` or string `Literal` node in a position
|
775
|
+
* that represents a module export name:
|
776
|
+
* - `ImportSpecifier#imported`
|
777
|
+
* - `ExportSpecifier#local` (if it is a re-export from another module)
|
778
|
+
* - `ExportSpecifier#exported`
|
779
|
+
* - `ExportAllDeclaration#exported`
|
780
|
+
* @returns {string} The module export name.
|
781
|
+
*/
|
782
|
+
function getModuleExportName(node) {
|
783
|
+
if (node.type === "Identifier") {
|
784
|
+
return node.name;
|
785
|
+
}
|
786
|
+
|
787
|
+
// string literal
|
788
|
+
return node.value;
|
789
|
+
}
|
790
|
+
|
772
791
|
//------------------------------------------------------------------------------
|
773
792
|
// Public Interface
|
774
793
|
//------------------------------------------------------------------------------
|
@@ -1898,5 +1917,6 @@ module.exports = {
|
|
1898
1917
|
equalLiteralValue,
|
1899
1918
|
isSameReference,
|
1900
1919
|
isLogicalAssignmentOperator,
|
1901
|
-
getSwitchCaseColonToken
|
1920
|
+
getSwitchCaseColonToken,
|
1921
|
+
getModuleExportName
|
1902
1922
|
};
|
@@ -6,7 +6,7 @@ module.exports = function(it) {
|
|
6
6
|
return `
|
7
7
|
ESLint couldn't find a configuration file. To set up a configuration file for this project, please run:
|
8
8
|
|
9
|
-
|
9
|
+
npm init @eslint/config
|
10
10
|
|
11
11
|
ESLint looked for configuration files in ${directoryPath} and its ancestors. If it found none, it then looked in your home directory.
|
12
12
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.7.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -54,11 +54,10 @@
|
|
54
54
|
"cross-spawn": "^7.0.2",
|
55
55
|
"debug": "^4.3.2",
|
56
56
|
"doctrine": "^3.0.0",
|
57
|
-
"enquirer": "^2.3.5",
|
58
57
|
"escape-string-regexp": "^4.0.0",
|
59
58
|
"eslint-scope": "^7.1.0",
|
60
59
|
"eslint-utils": "^3.0.0",
|
61
|
-
"eslint-visitor-keys": "^3.
|
60
|
+
"eslint-visitor-keys": "^3.2.0",
|
62
61
|
"espree": "^9.3.0",
|
63
62
|
"esquery": "^1.4.0",
|
64
63
|
"esutils": "^2.0.2",
|
@@ -67,7 +66,7 @@
|
|
67
66
|
"functional-red-black-tree": "^1.0.1",
|
68
67
|
"glob-parent": "^6.0.1",
|
69
68
|
"globals": "^13.6.0",
|
70
|
-
"ignore": "^
|
69
|
+
"ignore": "^5.2.0",
|
71
70
|
"import-fresh": "^3.0.0",
|
72
71
|
"imurmurhash": "^0.1.4",
|
73
72
|
"is-glob": "^4.0.0",
|
@@ -78,9 +77,7 @@
|
|
78
77
|
"minimatch": "^3.0.4",
|
79
78
|
"natural-compare": "^1.4.0",
|
80
79
|
"optionator": "^0.9.1",
|
81
|
-
"progress": "^2.0.0",
|
82
80
|
"regexpp": "^3.2.0",
|
83
|
-
"semver": "^7.2.1",
|
84
81
|
"strip-ansi": "^6.0.1",
|
85
82
|
"strip-json-comments": "^3.1.0",
|
86
83
|
"text-table": "^0.2.0",
|
@@ -125,10 +122,12 @@
|
|
125
122
|
"node-polyfill-webpack-plugin": "^1.0.3",
|
126
123
|
"npm-license": "^0.3.3",
|
127
124
|
"nyc": "^15.0.1",
|
125
|
+
"progress": "^2.0.3",
|
128
126
|
"proxyquire": "^2.0.1",
|
129
127
|
"puppeteer": "^9.1.1",
|
130
128
|
"recast": "^0.20.4",
|
131
129
|
"regenerator-runtime": "^0.13.2",
|
130
|
+
"semver": "^7.3.5",
|
132
131
|
"shelljs": "^0.8.2",
|
133
132
|
"sinon": "^11.0.0",
|
134
133
|
"temp": "^0.9.0",
|