eslint 7.27.0 → 7.28.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/CHANGELOG.md +16 -0
- package/README.md +0 -5
- package/lib/linter/linter.js +9 -5
- package/lib/rules/arrow-body-style.js +21 -11
- package/lib/rules/no-duplicate-imports.js +214 -66
- package/lib/rules/no-implicit-coercion.js +21 -2
- package/lib/rules/no-unused-vars.js +15 -9
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
v7.28.0 - June 4, 2021
|
2
|
+
|
3
|
+
* [`1237705`](https://github.com/eslint/eslint/commit/1237705dd08c209c5e3136045ec51a4ba87a3abe) Upgrade: @eslint/eslintrc to 0.4.2 (#14672) (Milos Djermanovic)
|
4
|
+
* [`123fb86`](https://github.com/eslint/eslint/commit/123fb8648731c2c23313c544ffa1872d3024fe68) Docs: Add Feedback Needed triage description (#14670) (Nicholas C. Zakas)
|
5
|
+
* [`c545163`](https://github.com/eslint/eslint/commit/c5451635b4e89827cfc8d8d77083647c74506e42) Update: support multiline /*eslint-env*/ directives (fixes #14652) (#14660) (薛定谔的猫)
|
6
|
+
* [`8d1e75a`](https://github.com/eslint/eslint/commit/8d1e75a31b3e3d67130709a219bdd07ce6f3cf74) Upgrade: glob-parent version in package.json (#14658) (Hamza Najeeb)
|
7
|
+
* [`1f048cb`](https://github.com/eslint/eslint/commit/1f048cb0eec660d2052f1758f4b2ad7b1cb424e1) Fix: no-implicit-coercion false positive with `String()` (fixes #14623) (#14641) (Milos Djermanovic)
|
8
|
+
* [`d709abf`](https://github.com/eslint/eslint/commit/d709abfdde087325d4578b6709dc61040b8ca9d8) Chore: fix comment location in no-unused-vars (#14648) (Milos Djermanovic)
|
9
|
+
* [`e44ce0a`](https://github.com/eslint/eslint/commit/e44ce0a8acfaad513c385150c25e76e82a1b8f12) Fix: no-duplicate-imports allow unmergeable (fixes #12758, fixes #12760) (#14238) (Soufiane Boutahlil)
|
10
|
+
* [`bb66a3d`](https://github.com/eslint/eslint/commit/bb66a3d91af426dac9a7ffdbe47bdbbc0ffd4dd7) New: add `getPhysicalFilename()` method to rule context (fixes #11989) (#14616) (Nitin Kumar)
|
11
|
+
* [`2e43dac`](https://github.com/eslint/eslint/commit/2e43dacd24337a82d4184fac9b44d497675f46ef) Docs: fix `no-sequences` example (#14643) (Nitin Kumar)
|
12
|
+
* [`958ff4e`](https://github.com/eslint/eslint/commit/958ff4e8a5102f204f1484d09985e28a79790996) Docs: add note for arrow functions in no-seq rule (#14578) (Nitin Kumar)
|
13
|
+
* [`e4f111b`](https://github.com/eslint/eslint/commit/e4f111b67d114adbf76a9c9dbb18fa4f49bc91b6) Fix: arrow-body-style crash with object pattern (fixes #14633) (#14635) (Milos Djermanovic)
|
14
|
+
* [`ec28b5a`](https://github.com/eslint/eslint/commit/ec28b5a2bdc69f34ce29d670f5e84d2446774a00) Chore: upgrade eslint-plugin-eslint-plugin (#14590) (薛定谔的猫)
|
15
|
+
* [`85a2725`](https://github.com/eslint/eslint/commit/85a2725b1fade5538e727102d9701ccb503e54d4) Docs: Update README team and sponsors (ESLint Jenkins)
|
16
|
+
|
1
17
|
v7.27.0 - May 21, 2021
|
2
18
|
|
3
19
|
* [`2c0868c`](https://github.com/eslint/eslint/commit/2c0868cbeadc9f42716fa1178ebdc6b4cee6d31e) Chore: merge all html formatter files into `html.js` (#14612) (Milos Djermanovic)
|
package/README.md
CHANGED
@@ -223,11 +223,6 @@ Nicholas C. Zakas
|
|
223
223
|
Brandon Mills
|
224
224
|
</a>
|
225
225
|
</td><td align="center" valign="top" width="11%">
|
226
|
-
<a href="https://github.com/mysticatea">
|
227
|
-
<img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
|
228
|
-
Toru Nagashima
|
229
|
-
</a>
|
230
|
-
</td><td align="center" valign="top" width="11%">
|
231
226
|
<a href="https://github.com/mdjermanovic">
|
232
227
|
<img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75"><br />
|
233
228
|
Milos Djermanovic
|
package/lib/linter/linter.js
CHANGED
@@ -444,7 +444,7 @@ function normalizeEcmaVersion(ecmaVersion) {
|
|
444
444
|
return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
|
445
445
|
}
|
446
446
|
|
447
|
-
const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//
|
447
|
+
const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//gsu;
|
448
448
|
|
449
449
|
/**
|
450
450
|
* Checks whether or not there is a comment which has "eslint-env *" in a given text.
|
@@ -828,9 +828,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
828
828
|
* @param {string} filename The reported filename of the code
|
829
829
|
* @param {boolean} disableFixes If true, it doesn't make `fix` properties.
|
830
830
|
* @param {string | undefined} cwd cwd of the cli
|
831
|
+
* @param {string} physicalFilename The full path of the file on disk without any code block information
|
831
832
|
* @returns {Problem[]} An array of reported problems
|
832
833
|
*/
|
833
|
-
function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd) {
|
834
|
+
function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd, physicalFilename) {
|
834
835
|
const emitter = createEmitter();
|
835
836
|
const nodeQueue = [];
|
836
837
|
let currentNode = sourceCode.ast;
|
@@ -859,6 +860,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
|
|
859
860
|
getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
|
860
861
|
getCwd: () => cwd,
|
861
862
|
getFilename: () => filename,
|
863
|
+
getPhysicalFilename: () => physicalFilename || filename,
|
862
864
|
getScope: () => getScope(sourceCode.scopeManager, currentNode),
|
863
865
|
getSourceCode: () => sourceCode,
|
864
866
|
markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, currentNode, parserOptions, name),
|
@@ -1181,7 +1183,8 @@ class Linter {
|
|
1181
1183
|
settings,
|
1182
1184
|
options.filename,
|
1183
1185
|
options.disableFixes,
|
1184
|
-
slots.cwd
|
1186
|
+
slots.cwd,
|
1187
|
+
providedOptions.physicalFilename
|
1185
1188
|
);
|
1186
1189
|
} catch (err) {
|
1187
1190
|
err.message += `\nOccurred while linting ${options.filename}`;
|
@@ -1284,6 +1287,7 @@ class Linter {
|
|
1284
1287
|
_verifyWithProcessor(textOrSourceCode, config, options, configForRecursive) {
|
1285
1288
|
const filename = options.filename || "<input>";
|
1286
1289
|
const filenameToExpose = normalizeFilename(filename);
|
1290
|
+
const physicalFilename = options.physicalFilename || filenameToExpose;
|
1287
1291
|
const text = ensureText(textOrSourceCode);
|
1288
1292
|
const preprocess = options.preprocess || (rawText => [rawText]);
|
1289
1293
|
|
@@ -1316,7 +1320,7 @@ class Linter {
|
|
1316
1320
|
return this._verifyWithConfigArray(
|
1317
1321
|
blockText,
|
1318
1322
|
configForRecursive,
|
1319
|
-
{ ...options, filename: blockName }
|
1323
|
+
{ ...options, filename: blockName, physicalFilename }
|
1320
1324
|
);
|
1321
1325
|
}
|
1322
1326
|
|
@@ -1324,7 +1328,7 @@ class Linter {
|
|
1324
1328
|
return this._verifyWithoutProcessors(
|
1325
1329
|
blockText,
|
1326
1330
|
config,
|
1327
|
-
{ ...options, filename: blockName }
|
1331
|
+
{ ...options, filename: blockName, physicalFilename }
|
1328
1332
|
);
|
1329
1333
|
});
|
1330
1334
|
|
@@ -87,17 +87,17 @@ module.exports = {
|
|
87
87
|
}
|
88
88
|
|
89
89
|
/**
|
90
|
-
* Gets the closing parenthesis
|
91
|
-
* @param {
|
90
|
+
* Gets the closing parenthesis by the given node.
|
91
|
+
* @param {ASTNode} node first node after an opening parenthesis.
|
92
92
|
* @returns {Token} The found closing parenthesis token.
|
93
93
|
*/
|
94
|
-
function findClosingParen(
|
95
|
-
let
|
94
|
+
function findClosingParen(node) {
|
95
|
+
let nodeToCheck = node;
|
96
96
|
|
97
|
-
while (!astUtils.isParenthesised(sourceCode,
|
98
|
-
|
97
|
+
while (!astUtils.isParenthesised(sourceCode, nodeToCheck)) {
|
98
|
+
nodeToCheck = nodeToCheck.parent;
|
99
99
|
}
|
100
|
-
return sourceCode.getTokenAfter(
|
100
|
+
return sourceCode.getTokenAfter(nodeToCheck);
|
101
101
|
}
|
102
102
|
|
103
103
|
/**
|
@@ -226,12 +226,22 @@ module.exports = {
|
|
226
226
|
const arrowToken = sourceCode.getTokenBefore(arrowBody, astUtils.isArrowToken);
|
227
227
|
const [firstTokenAfterArrow, secondTokenAfterArrow] = sourceCode.getTokensAfter(arrowToken, { count: 2 });
|
228
228
|
const lastToken = sourceCode.getLastToken(node);
|
229
|
-
|
229
|
+
|
230
|
+
let parenthesisedObjectLiteral = null;
|
231
|
+
|
232
|
+
if (
|
230
233
|
astUtils.isOpeningParenToken(firstTokenAfterArrow) &&
|
231
|
-
astUtils.isOpeningBraceToken(secondTokenAfterArrow)
|
234
|
+
astUtils.isOpeningBraceToken(secondTokenAfterArrow)
|
235
|
+
) {
|
236
|
+
const braceNode = sourceCode.getNodeByRangeIndex(secondTokenAfterArrow.range[0]);
|
237
|
+
|
238
|
+
if (braceNode.type === "ObjectExpression") {
|
239
|
+
parenthesisedObjectLiteral = braceNode;
|
240
|
+
}
|
241
|
+
}
|
232
242
|
|
233
243
|
// If the value is object literal, remove parentheses which were forced by syntax.
|
234
|
-
if (
|
244
|
+
if (parenthesisedObjectLiteral) {
|
235
245
|
const openingParenToken = firstTokenAfterArrow;
|
236
246
|
const openingBraceToken = secondTokenAfterArrow;
|
237
247
|
|
@@ -247,7 +257,7 @@ module.exports = {
|
|
247
257
|
}
|
248
258
|
|
249
259
|
// Closing paren for the object doesn't have to be lastToken, e.g.: () => ({}).foo()
|
250
|
-
fixes.push(fixer.remove(findClosingParen(
|
260
|
+
fixes.push(fixer.remove(findClosingParen(parenthesisedObjectLiteral)));
|
251
261
|
fixes.push(fixer.insertTextAfter(lastToken, "}"));
|
252
262
|
|
253
263
|
} else {
|
@@ -4,92 +4,225 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Helpers
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const NAMED_TYPES = ["ImportSpecifier", "ExportSpecifier"];
|
12
|
+
const NAMESPACE_TYPES = [
|
13
|
+
"ImportNamespaceSpecifier",
|
14
|
+
"ExportNamespaceSpecifier"
|
15
|
+
];
|
16
|
+
|
7
17
|
//------------------------------------------------------------------------------
|
8
18
|
// Rule Definition
|
9
19
|
//------------------------------------------------------------------------------
|
10
20
|
|
11
21
|
/**
|
12
|
-
*
|
22
|
+
* Check if an import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier).
|
23
|
+
* @param {string} importExportType An import/export type to check.
|
24
|
+
* @param {string} type Can be "named" or "namespace"
|
25
|
+
* @returns {boolean} True if import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier) and false if it doesn't.
|
26
|
+
*/
|
27
|
+
function isImportExportSpecifier(importExportType, type) {
|
28
|
+
const arrayToCheck = type === "named" ? NAMED_TYPES : NAMESPACE_TYPES;
|
29
|
+
|
30
|
+
return arrayToCheck.includes(importExportType);
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Return the type of (import|export).
|
13
35
|
* @param {ASTNode} node A node to get.
|
14
|
-
* @returns {string}
|
36
|
+
* @returns {string} The type of the (import|export).
|
15
37
|
*/
|
16
|
-
function
|
17
|
-
if (node && node.
|
18
|
-
|
38
|
+
function getImportExportType(node) {
|
39
|
+
if (node.specifiers && node.specifiers.length > 0) {
|
40
|
+
const nodeSpecifiers = node.specifiers;
|
41
|
+
const index = nodeSpecifiers.findIndex(
|
42
|
+
({ type }) =>
|
43
|
+
isImportExportSpecifier(type, "named") ||
|
44
|
+
isImportExportSpecifier(type, "namespace")
|
45
|
+
);
|
46
|
+
const i = index > -1 ? index : 0;
|
47
|
+
|
48
|
+
return nodeSpecifiers[i].type;
|
19
49
|
}
|
50
|
+
if (node.type === "ExportAllDeclaration") {
|
51
|
+
if (node.exported) {
|
52
|
+
return "ExportNamespaceSpecifier";
|
53
|
+
}
|
54
|
+
return "ExportAll";
|
55
|
+
}
|
56
|
+
return "SideEffectImport";
|
57
|
+
}
|
20
58
|
|
21
|
-
|
59
|
+
/**
|
60
|
+
* Returns a boolean indicates if two (import|export) can be merged
|
61
|
+
* @param {ASTNode} node1 A node to check.
|
62
|
+
* @param {ASTNode} node2 A node to check.
|
63
|
+
* @returns {boolean} True if two (import|export) can be merged, false if they can't.
|
64
|
+
*/
|
65
|
+
function isImportExportCanBeMerged(node1, node2) {
|
66
|
+
const importExportType1 = getImportExportType(node1);
|
67
|
+
const importExportType2 = getImportExportType(node2);
|
68
|
+
|
69
|
+
if (
|
70
|
+
(importExportType1 === "ExportAll" &&
|
71
|
+
importExportType2 !== "ExportAll" &&
|
72
|
+
importExportType2 !== "SideEffectImport") ||
|
73
|
+
(importExportType1 !== "ExportAll" &&
|
74
|
+
importExportType1 !== "SideEffectImport" &&
|
75
|
+
importExportType2 === "ExportAll")
|
76
|
+
) {
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
if (
|
80
|
+
(isImportExportSpecifier(importExportType1, "namespace") &&
|
81
|
+
isImportExportSpecifier(importExportType2, "named")) ||
|
82
|
+
(isImportExportSpecifier(importExportType2, "namespace") &&
|
83
|
+
isImportExportSpecifier(importExportType1, "named"))
|
84
|
+
) {
|
85
|
+
return false;
|
86
|
+
}
|
87
|
+
return true;
|
22
88
|
}
|
23
89
|
|
24
90
|
/**
|
25
|
-
*
|
26
|
-
* @param {
|
27
|
-
* @param {ASTNode}
|
28
|
-
* @
|
29
|
-
* @param {string[]} array The array containing other imports or exports in the file.
|
30
|
-
* @param {string} messageId A messageId to be reported after the name of the module
|
31
|
-
*
|
32
|
-
* @returns {void} No return value
|
91
|
+
* Returns a boolean if we should report (import|export).
|
92
|
+
* @param {ASTNode} node A node to be reported or not.
|
93
|
+
* @param {[ASTNode]} previousNodes An array contains previous nodes of the module imported or exported.
|
94
|
+
* @returns {boolean} True if the (import|export) should be reported.
|
33
95
|
*/
|
34
|
-
function
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
});
|
96
|
+
function shouldReportImportExport(node, previousNodes) {
|
97
|
+
let i = 0;
|
98
|
+
|
99
|
+
while (i < previousNodes.length) {
|
100
|
+
if (isImportExportCanBeMerged(node, previousNodes[i])) {
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
i++;
|
43
104
|
}
|
105
|
+
return false;
|
44
106
|
}
|
45
107
|
|
46
108
|
/**
|
47
|
-
*
|
48
|
-
* @param {ASTNode}
|
109
|
+
* Returns array contains only nodes with declarations types equal to type.
|
110
|
+
* @param {[{node: ASTNode, declarationType: string}]} nodes An array contains objects, each object contains a node and a declaration type.
|
111
|
+
* @param {string} type Declaration type.
|
112
|
+
* @returns {[ASTNode]} An array contains only nodes with declarations types equal to type.
|
113
|
+
*/
|
114
|
+
function getNodesByDeclarationType(nodes, type) {
|
115
|
+
return nodes
|
116
|
+
.filter(({ declarationType }) => declarationType === type)
|
117
|
+
.map(({ node }) => node);
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Returns the name of the module imported or re-exported.
|
122
|
+
* @param {ASTNode} node A node to get.
|
123
|
+
* @returns {string} The name of the module, or empty string if no name.
|
49
124
|
*/
|
125
|
+
function getModule(node) {
|
126
|
+
if (node && node.source && node.source.value) {
|
127
|
+
return node.source.value.trim();
|
128
|
+
}
|
129
|
+
return "";
|
130
|
+
}
|
50
131
|
|
51
132
|
/**
|
52
|
-
*
|
133
|
+
* Checks if the (import|export) can be merged with at least one import or one export, and reports if so.
|
53
134
|
* @param {RuleContext} context The ESLint rule context object.
|
135
|
+
* @param {ASTNode} node A node to get.
|
136
|
+
* @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
|
137
|
+
* @param {string} declarationType A declaration type can be an import or export.
|
54
138
|
* @param {boolean} includeExports Whether or not to check for exports in addition to imports.
|
55
|
-
* @
|
56
|
-
* @param {string[]} exportsInFile The array containing other exports in the file.
|
57
|
-
*
|
58
|
-
* @returns {nodeCallback} A function passed to ESLint to handle the statement.
|
139
|
+
* @returns {void} No return value.
|
59
140
|
*/
|
60
|
-
function
|
61
|
-
|
62
|
-
|
141
|
+
function checkAndReport(
|
142
|
+
context,
|
143
|
+
node,
|
144
|
+
modules,
|
145
|
+
declarationType,
|
146
|
+
includeExports
|
147
|
+
) {
|
148
|
+
const module = getModule(node);
|
63
149
|
|
64
|
-
|
65
|
-
|
150
|
+
if (modules.has(module)) {
|
151
|
+
const previousNodes = modules.get(module);
|
152
|
+
const messagesIds = [];
|
153
|
+
const importNodes = getNodesByDeclarationType(previousNodes, "import");
|
154
|
+
let exportNodes;
|
66
155
|
|
156
|
+
if (includeExports) {
|
157
|
+
exportNodes = getNodesByDeclarationType(previousNodes, "export");
|
158
|
+
}
|
159
|
+
if (declarationType === "import") {
|
160
|
+
if (shouldReportImportExport(node, importNodes)) {
|
161
|
+
messagesIds.push("import");
|
162
|
+
}
|
67
163
|
if (includeExports) {
|
68
|
-
|
164
|
+
if (shouldReportImportExport(node, exportNodes)) {
|
165
|
+
messagesIds.push("importAs");
|
166
|
+
}
|
167
|
+
}
|
168
|
+
} else if (declarationType === "export") {
|
169
|
+
if (shouldReportImportExport(node, exportNodes)) {
|
170
|
+
messagesIds.push("export");
|
171
|
+
}
|
172
|
+
if (shouldReportImportExport(node, importNodes)) {
|
173
|
+
messagesIds.push("exportAs");
|
69
174
|
}
|
70
|
-
|
71
|
-
importsInFile.push(value);
|
72
175
|
}
|
73
|
-
|
176
|
+
messagesIds.forEach(messageId =>
|
177
|
+
context.report({
|
178
|
+
node,
|
179
|
+
messageId,
|
180
|
+
data: {
|
181
|
+
module
|
182
|
+
}
|
183
|
+
}));
|
184
|
+
}
|
74
185
|
}
|
75
186
|
|
76
187
|
/**
|
77
|
-
*
|
188
|
+
* @callback nodeCallback
|
189
|
+
* @param {ASTNode} node A node to handle.
|
190
|
+
*/
|
191
|
+
|
192
|
+
/**
|
193
|
+
* Returns a function handling the (imports|exports) of a given file
|
78
194
|
* @param {RuleContext} context The ESLint rule context object.
|
79
|
-
* @param {
|
80
|
-
* @param {string
|
81
|
-
*
|
195
|
+
* @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
|
196
|
+
* @param {string} declarationType A declaration type can be an import or export.
|
197
|
+
* @param {boolean} includeExports Whether or not to check for exports in addition to imports.
|
82
198
|
* @returns {nodeCallback} A function passed to ESLint to handle the statement.
|
83
199
|
*/
|
84
|
-
function
|
200
|
+
function handleImportsExports(
|
201
|
+
context,
|
202
|
+
modules,
|
203
|
+
declarationType,
|
204
|
+
includeExports
|
205
|
+
) {
|
85
206
|
return function(node) {
|
86
|
-
const
|
207
|
+
const module = getModule(node);
|
208
|
+
|
209
|
+
if (module) {
|
210
|
+
checkAndReport(
|
211
|
+
context,
|
212
|
+
node,
|
213
|
+
modules,
|
214
|
+
declarationType,
|
215
|
+
includeExports
|
216
|
+
);
|
217
|
+
const currentNode = { node, declarationType };
|
218
|
+
let nodes = [currentNode];
|
87
219
|
|
88
|
-
|
89
|
-
|
90
|
-
checkAndReport(context, node, value, importsInFile, "exportAs");
|
220
|
+
if (modules.has(module)) {
|
221
|
+
const previousNodes = modules.get(module);
|
91
222
|
|
92
|
-
|
223
|
+
nodes = [...previousNodes, currentNode];
|
224
|
+
}
|
225
|
+
modules.set(module, nodes);
|
93
226
|
}
|
94
227
|
};
|
95
228
|
}
|
@@ -105,16 +238,19 @@ module.exports = {
|
|
105
238
|
url: "https://eslint.org/docs/rules/no-duplicate-imports"
|
106
239
|
},
|
107
240
|
|
108
|
-
schema: [
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
241
|
+
schema: [
|
242
|
+
{
|
243
|
+
type: "object",
|
244
|
+
properties: {
|
245
|
+
includeExports: {
|
246
|
+
type: "boolean",
|
247
|
+
default: false
|
248
|
+
}
|
249
|
+
},
|
250
|
+
additionalProperties: false
|
251
|
+
}
|
252
|
+
],
|
253
|
+
|
118
254
|
messages: {
|
119
255
|
import: "'{{module}}' import is duplicated.",
|
120
256
|
importAs: "'{{module}}' import is duplicated as export.",
|
@@ -125,18 +261,30 @@ module.exports = {
|
|
125
261
|
|
126
262
|
create(context) {
|
127
263
|
const includeExports = (context.options[0] || {}).includeExports,
|
128
|
-
|
129
|
-
exportsInFile = [];
|
130
|
-
|
264
|
+
modules = new Map();
|
131
265
|
const handlers = {
|
132
|
-
ImportDeclaration:
|
266
|
+
ImportDeclaration: handleImportsExports(
|
267
|
+
context,
|
268
|
+
modules,
|
269
|
+
"import",
|
270
|
+
includeExports
|
271
|
+
)
|
133
272
|
};
|
134
273
|
|
135
274
|
if (includeExports) {
|
136
|
-
handlers.ExportNamedDeclaration =
|
137
|
-
|
275
|
+
handlers.ExportNamedDeclaration = handleImportsExports(
|
276
|
+
context,
|
277
|
+
modules,
|
278
|
+
"export",
|
279
|
+
includeExports
|
280
|
+
);
|
281
|
+
handlers.ExportAllDeclaration = handleImportsExports(
|
282
|
+
context,
|
283
|
+
modules,
|
284
|
+
"export",
|
285
|
+
includeExports
|
286
|
+
);
|
138
287
|
}
|
139
|
-
|
140
288
|
return handlers;
|
141
289
|
}
|
142
290
|
};
|
@@ -109,6 +109,20 @@ function getNonNumericOperand(node) {
|
|
109
109
|
return null;
|
110
110
|
}
|
111
111
|
|
112
|
+
/**
|
113
|
+
* Checks whether an expression evaluates to a string.
|
114
|
+
* @param {ASTNode} node node that represents the expression to check.
|
115
|
+
* @returns {boolean} Whether or not the expression evaluates to a string.
|
116
|
+
*/
|
117
|
+
function isStringType(node) {
|
118
|
+
return astUtils.isStringLiteral(node) ||
|
119
|
+
(
|
120
|
+
node.type === "CallExpression" &&
|
121
|
+
node.callee.type === "Identifier" &&
|
122
|
+
node.callee.name === "String"
|
123
|
+
);
|
124
|
+
}
|
125
|
+
|
112
126
|
/**
|
113
127
|
* Checks whether a node is an empty string literal or not.
|
114
128
|
* @param {ASTNode} node The node to check.
|
@@ -126,8 +140,8 @@ function isEmptyString(node) {
|
|
126
140
|
*/
|
127
141
|
function isConcatWithEmptyString(node) {
|
128
142
|
return node.operator === "+" && (
|
129
|
-
(isEmptyString(node.left) && !
|
130
|
-
(isEmptyString(node.right) && !
|
143
|
+
(isEmptyString(node.left) && !isStringType(node.right)) ||
|
144
|
+
(isEmptyString(node.right) && !isStringType(node.left))
|
131
145
|
);
|
132
146
|
}
|
133
147
|
|
@@ -332,6 +346,11 @@ module.exports = {
|
|
332
346
|
return;
|
333
347
|
}
|
334
348
|
|
349
|
+
// if the expression is already a string, then this isn't a coercion
|
350
|
+
if (isStringType(node.expressions[0])) {
|
351
|
+
return;
|
352
|
+
}
|
353
|
+
|
335
354
|
const code = sourceCode.getText(node.expressions[0]);
|
336
355
|
const recommendation = `String(${code})`;
|
337
356
|
|
@@ -449,18 +449,24 @@ module.exports = {
|
|
449
449
|
return ref.isRead() && (
|
450
450
|
|
451
451
|
// self update. e.g. `a += 1`, `a++`
|
452
|
-
(
|
453
|
-
(
|
452
|
+
(
|
453
|
+
(
|
454
454
|
parent.type === "AssignmentExpression" &&
|
455
|
-
|
456
|
-
|
455
|
+
parent.left === id &&
|
456
|
+
isUnusedExpression(parent)
|
457
457
|
) ||
|
458
|
+
(
|
459
|
+
parent.type === "UpdateExpression" &&
|
460
|
+
isUnusedExpression(parent)
|
461
|
+
)
|
462
|
+
) ||
|
463
|
+
|
464
|
+
// in RHS of an assignment for itself. e.g. `a = a + 1`
|
458
465
|
(
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
!isInsideOfStorableFunction(id, rhsNode)))
|
466
|
+
rhsNode &&
|
467
|
+
isInside(id, rhsNode) &&
|
468
|
+
!isInsideOfStorableFunction(id, rhsNode)
|
469
|
+
)
|
464
470
|
);
|
465
471
|
}
|
466
472
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.28.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -44,7 +44,7 @@
|
|
44
44
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
45
45
|
"dependencies": {
|
46
46
|
"@babel/code-frame": "7.12.11",
|
47
|
-
"@eslint/eslintrc": "^0.4.
|
47
|
+
"@eslint/eslintrc": "^0.4.2",
|
48
48
|
"ajv": "^6.10.0",
|
49
49
|
"chalk": "^4.0.0",
|
50
50
|
"cross-spawn": "^7.0.2",
|
@@ -61,7 +61,7 @@
|
|
61
61
|
"fast-deep-equal": "^3.1.3",
|
62
62
|
"file-entry-cache": "^6.0.1",
|
63
63
|
"functional-red-black-tree": "^1.0.1",
|
64
|
-
"glob-parent": "^5.
|
64
|
+
"glob-parent": "^5.1.2",
|
65
65
|
"globals": "^13.6.0",
|
66
66
|
"ignore": "^4.0.6",
|
67
67
|
"import-fresh": "^3.0.0",
|
@@ -95,7 +95,7 @@
|
|
95
95
|
"ejs": "^3.0.2",
|
96
96
|
"eslint": "file:.",
|
97
97
|
"eslint-config-eslint": "file:packages/eslint-config-eslint",
|
98
|
-
"eslint-plugin-eslint-plugin": "^
|
98
|
+
"eslint-plugin-eslint-plugin": "^3.0.3",
|
99
99
|
"eslint-plugin-internal-rules": "file:tools/internal-rules",
|
100
100
|
"eslint-plugin-jsdoc": "^25.4.3",
|
101
101
|
"eslint-plugin-node": "^11.1.0",
|