eslint 8.10.0 → 8.13.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 +2 -2
- package/lib/cli-engine/cli-engine.js +2 -1
- package/lib/cli-engine/formatters/html.js +5 -3
- package/lib/eslint/eslint.js +4 -19
- package/lib/linter/apply-disable-directives.js +1 -1
- package/lib/rules/comma-dangle.js +24 -4
- package/lib/rules/no-constant-condition.js +30 -3
- package/lib/rules/no-eval.js +23 -18
- package/lib/rules/no-invalid-this.js +3 -3
- package/lib/rules/no-unused-vars.js +28 -1
- package/lib/rules/operator-assignment.js +7 -5
- package/lib/rules/padding-line-between-statements.js +2 -4
- package/lib/rules/valid-typeof.js +37 -1
- package/lib/shared/types.js +24 -0
- package/messages/all-files-ignored.js +1 -1
- package/messages/extend-config-missing.js +1 -1
- package/messages/failed-to-read-json.js +1 -1
- package/messages/file-not-found.js +1 -1
- package/messages/no-config-found.js +1 -1
- package/messages/plugin-invalid.js +1 -1
- package/messages/plugin-missing.js +1 -1
- package/messages/print-config-with-directory-path.js +1 -1
- package/messages/whitespace-found.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
@@ -292,9 +292,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
292
292
|
<!--sponsorsstart-->
|
293
293
|
<h3>Platinum Sponsors</h3>
|
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
|
-
<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://
|
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://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://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
|
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" 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.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
|
298
298
|
<!--sponsorsend-->
|
299
299
|
|
300
300
|
## <a name="technology-sponsors"></a>Technology Sponsors
|
@@ -56,6 +56,7 @@ const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
|
|
56
56
|
/** @typedef {import("../shared/types").Plugin} Plugin */
|
57
57
|
/** @typedef {import("../shared/types").RuleConf} RuleConf */
|
58
58
|
/** @typedef {import("../shared/types").Rule} Rule */
|
59
|
+
/** @typedef {import("../shared/types").FormatterFunction} FormatterFunction */
|
59
60
|
/** @typedef {ReturnType<CascadingConfigArrayFactory.getConfigArrayForFile>} ConfigArray */
|
60
61
|
/** @typedef {ReturnType<ConfigArray.extractConfig>} ExtractedConfig */
|
61
62
|
|
@@ -1002,7 +1003,7 @@ class CLIEngine {
|
|
1002
1003
|
* @param {string} [format] The name of the format to load or the path to a
|
1003
1004
|
* custom formatter.
|
1004
1005
|
* @throws {any} As may be thrown by requiring of formatter
|
1005
|
-
* @returns {(
|
1006
|
+
* @returns {(FormatterFunction|null)} The formatter function or null if the `format` is not a string.
|
1006
1007
|
*/
|
1007
1008
|
getFormatter(format) {
|
1008
1009
|
|
@@ -39,6 +39,8 @@ function pageTemplate(it) {
|
|
39
39
|
<head>
|
40
40
|
<meta charset="UTF-8">
|
41
41
|
<title>ESLint Report</title>
|
42
|
+
<link rel="icon" type="image/png" sizes="any" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAHaAAAB2gGFomX7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAABD1JREFUWMPFl11sk2UUx3/nbYtjxS1MF7MLMTECMgSTtSSyrQkLhAj7UBPnDSEGoxegGzMwojhXVpmTAA5iYpSoMQa8GBhFOrMFk03buei6yRAlcmOM0SEmU9d90b19jxcM1o5+sGnsc/e+z/l6ztf/HFFVMnns6QieeOCHBePGsHM+wrOtvLG2C4WRVDSSygNV7sCjlspxwDnPB44aols/DXk+mbMBmx/6OseITF1CuOtfevkPh2Uu+/jbdX8lujSScRlT5r7/QDlAfsRmfzmpnkQ/H3H13gf6bBrBn1uqK8WylgEnU8eZmk1repbfchJG1TyKyIKEwuBHFd3lD3naY3O1siiwXsVoBV2VgM1ht/QQUJk2ByqKghsQziYQ8ifKgexIXmuyzC4r67Y7R+xPAfuB/Nn3Cpva+0s7khpQVtZtd4bt51BWxtBYAiciprG7c7D4SixzU9PYalDL6110Ifb/w8W9eY7JqFeFHbO8fPGyLHwwFHJNJTSgwtVTB9oaw9BlQ+tO93vOxypoaQnfEYlI43SeCHDC4TDq9+51/h5fxr33q0ZfV9g04wat9Q943rjJgCp3952W2i8Bi6eDvdsfKj0cK/DYMRyXL4/sUJUmIHd2zYMezsvLaamp4WpcWN3BXSiHpuMwbGbZlnZ8tXY4rgosy+G7oRwQ0cAsd28YGgqfU5UjCZQDLALxDg+Hv/P5Rqvj4hwrS8izXzWb4spwc1GgENFnkpWRzxeuB+ssUHgLdb9UVdt8vpGdKQpze7n7y1U3DBChNRUuqOo9c+0+qpKKxyZqtAIYla7gY4JszAAQri93BSsMRZoyBcUC+w3Q3AyOA4sNhAOZ0q7Iq0b2vUNvK5zPgP+/H8+Zetdoa6uOikhdGurxebwvJY8Iz3V1rTMNAH+opEuQj5KTT/qA1yC+wyUjBm12OidaUtCcPNNX2h0Hx2JG69VulANZAJZJwfU7rzd/FHixuXniTdM0m4GtSQT7bTartqEh9yfImUEzkwKZmTwmo5a5JwkYBfcDL01/RkR5y8iWhtPBknB8ZxwtU9UjwOrrKCeizzc25nTGg1F/turEHoU9wMLpDvWKf8DTmNCAKnd/tqUTF4ElMXJ+A5rWDJS+41WsGWzALhJ+ErBWrLj9g+pqojHxlXJX8HGUg0BsR/x1yhxf3jm4cSzpQFLp6tmi6PEE7g1ZhtZ91ufpSZUAFa6gC+UoQslNaSmypT1U8mHKiUgEKS8KfgF4EpYunFI16tsHin+OG0LcgQK7yj7g6cSzpva2D3hKVNG0Y3mVO1BkqfSlmJrHBQ4uvM12gJHc6ETW8HZVfMRmXvyxxNC1Z/o839zyXlDuCr4nsC11J+MXueaVJWn6yPv+/pJtc9oLTNN4AeTvNGByd3rlhE2x9s5pLwDoHCy+grDzWmOZ95lUtLYj5Bma126Y8eX0/zj/ADxGyViSg4BXAAAAAElFTkSuQmCC">
|
43
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
|
42
44
|
<style>
|
43
45
|
body {
|
44
46
|
font-family:Arial, "Helvetica Neue", Helvetica, sans-serif;
|
@@ -149,7 +151,7 @@ function pageTemplate(it) {
|
|
149
151
|
</script>
|
150
152
|
</body>
|
151
153
|
</html>
|
152
|
-
`.
|
154
|
+
`.trimStart();
|
153
155
|
}
|
154
156
|
|
155
157
|
/**
|
@@ -220,7 +222,7 @@ function messageTemplate(it) {
|
|
220
222
|
<a href="${ruleUrl ? ruleUrl : ""}" target="_blank" rel="noopener noreferrer">${ruleId ? ruleId : ""}</a>
|
221
223
|
</td>
|
222
224
|
</tr>
|
223
|
-
`.
|
225
|
+
`.trimStart();
|
224
226
|
}
|
225
227
|
|
226
228
|
/**
|
@@ -278,7 +280,7 @@ function resultTemplate(it) {
|
|
278
280
|
<span>${encodeHTML(summary)}</span>
|
279
281
|
</th>
|
280
282
|
</tr>
|
281
|
-
`.
|
283
|
+
`.trimStart();
|
282
284
|
}
|
283
285
|
|
284
286
|
/**
|
package/lib/eslint/eslint.js
CHANGED
@@ -35,10 +35,11 @@ const { version } = require("../../package.json");
|
|
35
35
|
/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
|
36
36
|
/** @typedef {import("../shared/types").Plugin} Plugin */
|
37
37
|
/** @typedef {import("../shared/types").Rule} Rule */
|
38
|
+
/** @typedef {import("../shared/types").LintResult} LintResult */
|
38
39
|
|
39
40
|
/**
|
40
41
|
* The main formatter object.
|
41
|
-
* @typedef
|
42
|
+
* @typedef LoadedFormatter
|
42
43
|
* @property {function(LintResult[]): string | Promise<string>} format format function.
|
43
44
|
*/
|
44
45
|
|
@@ -74,22 +75,6 @@ const { version } = require("../../package.json");
|
|
74
75
|
* @property {Object} definition The plugin definition.
|
75
76
|
*/
|
76
77
|
|
77
|
-
/**
|
78
|
-
* A linting result.
|
79
|
-
* @typedef {Object} LintResult
|
80
|
-
* @property {string} filePath The path to the file that was linted.
|
81
|
-
* @property {LintMessage[]} messages All of the messages for the result.
|
82
|
-
* @property {SuppressedLintMessage[]} suppressedMessages All of the suppressed messages for the result.
|
83
|
-
* @property {number} errorCount Number of errors for the result.
|
84
|
-
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
85
|
-
* @property {number} warningCount Number of warnings for the result.
|
86
|
-
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
87
|
-
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
88
|
-
* @property {string} [source] The source code of the file that was linted.
|
89
|
-
* @property {string} [output] The source code of the file that was linted, with as many fixes applied as possible.
|
90
|
-
* @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
|
91
|
-
*/
|
92
|
-
|
93
78
|
/**
|
94
79
|
* Private members for the `ESLint` instance.
|
95
80
|
* @typedef {Object} ESLintPrivateMembers
|
@@ -619,7 +604,7 @@ class ESLint {
|
|
619
604
|
* - `@foo` → `@foo/eslint-formatter`
|
620
605
|
* - `@foo/bar` → `@foo/eslint-formatter-bar`
|
621
606
|
* - A file path ... Load the file.
|
622
|
-
* @returns {Promise<
|
607
|
+
* @returns {Promise<LoadedFormatter>} A promise resolving to the formatter object.
|
623
608
|
* This promise will be rejected if the given formatter was not found or not
|
624
609
|
* a function.
|
625
610
|
*/
|
@@ -639,7 +624,7 @@ class ESLint {
|
|
639
624
|
|
640
625
|
/**
|
641
626
|
* The main formatter method.
|
642
|
-
* @param {
|
627
|
+
* @param {LintResult[]} results The lint results to format.
|
643
628
|
* @returns {string | Promise<string>} The formatted lint results.
|
644
629
|
*/
|
645
630
|
format(results) {
|
@@ -66,7 +66,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|
66
66
|
const listText = commentToken.value
|
67
67
|
.slice(listStartOffset) // remove directive name and all whitespace before the list
|
68
68
|
.split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
|
69
|
-
.
|
69
|
+
.trimEnd(); // remove all whitespace after the list
|
70
70
|
|
71
71
|
/*
|
72
72
|
* We can assume that `listText` contains multiple elements.
|
@@ -243,8 +243,18 @@ module.exports = {
|
|
243
243
|
node: lastItem,
|
244
244
|
loc: trailingToken.loc,
|
245
245
|
messageId: "unexpected",
|
246
|
-
fix(fixer) {
|
247
|
-
|
246
|
+
*fix(fixer) {
|
247
|
+
yield fixer.remove(trailingToken);
|
248
|
+
|
249
|
+
/*
|
250
|
+
* Extend the range of the fix to include surrounding tokens to ensure
|
251
|
+
* that the element after which the comma is removed stays _last_.
|
252
|
+
* This intentionally makes conflicts in fix ranges with rules that may be
|
253
|
+
* adding or removing elements in the same autofix pass.
|
254
|
+
* https://github.com/eslint/eslint/issues/15660
|
255
|
+
*/
|
256
|
+
yield fixer.insertTextBefore(sourceCode.getTokenBefore(trailingToken), "");
|
257
|
+
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
|
248
258
|
}
|
249
259
|
});
|
250
260
|
}
|
@@ -282,8 +292,18 @@ module.exports = {
|
|
282
292
|
end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)
|
283
293
|
},
|
284
294
|
messageId: "missing",
|
285
|
-
fix(fixer) {
|
286
|
-
|
295
|
+
*fix(fixer) {
|
296
|
+
yield fixer.insertTextAfter(trailingToken, ",");
|
297
|
+
|
298
|
+
/*
|
299
|
+
* Extend the range of the fix to include surrounding tokens to ensure
|
300
|
+
* that the element after which the comma is inserted stays _last_.
|
301
|
+
* This intentionally makes conflicts in fix ranges with rules that may be
|
302
|
+
* adding or removing elements in the same autofix pass.
|
303
|
+
* https://github.com/eslint/eslint/issues/15660
|
304
|
+
*/
|
305
|
+
yield fixer.insertTextBefore(trailingToken, "");
|
306
|
+
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
|
287
307
|
}
|
288
308
|
});
|
289
309
|
}
|
@@ -120,12 +120,30 @@ module.exports = {
|
|
120
120
|
return false;
|
121
121
|
}
|
122
122
|
|
123
|
+
/**
|
124
|
+
* Checks if an identifier is a reference to a global variable.
|
125
|
+
* @param {ASTNode} node An identifier node to check.
|
126
|
+
* @returns {boolean} `true` if the identifier is a reference to a global variable.
|
127
|
+
*/
|
128
|
+
function isReferenceToGlobalVariable(node) {
|
129
|
+
const scope = context.getScope();
|
130
|
+
const reference = scope.references.find(ref => ref.identifier === node);
|
131
|
+
|
132
|
+
return Boolean(
|
133
|
+
reference &&
|
134
|
+
reference.resolved &&
|
135
|
+
reference.resolved.scope.type === "global" &&
|
136
|
+
reference.resolved.defs.length === 0
|
137
|
+
);
|
138
|
+
}
|
139
|
+
|
123
140
|
/**
|
124
141
|
* Checks if a node has a constant truthiness value.
|
125
142
|
* @param {ASTNode} node The AST node to check.
|
126
|
-
* @param {boolean} inBooleanPosition `
|
127
|
-
*
|
128
|
-
*
|
143
|
+
* @param {boolean} inBooleanPosition `true` if checking the test of a
|
144
|
+
* condition. `false` in all other cases. When `false`, checks if -- for
|
145
|
+
* both string and number -- if coerced to that type, the value will
|
146
|
+
* be constant.
|
129
147
|
* @returns {Bool} true when node's truthiness is constant
|
130
148
|
* @private
|
131
149
|
*/
|
@@ -215,6 +233,15 @@ module.exports = {
|
|
215
233
|
return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
|
216
234
|
case "SpreadElement":
|
217
235
|
return isConstant(node.argument, inBooleanPosition);
|
236
|
+
case "CallExpression":
|
237
|
+
if (node.callee.type === "Identifier" && node.callee.name === "Boolean") {
|
238
|
+
if (node.arguments.length === 0 || isConstant(node.arguments[0], true)) {
|
239
|
+
return isReferenceToGlobalVariable(node.callee);
|
240
|
+
}
|
241
|
+
}
|
242
|
+
return false;
|
243
|
+
case "Identifier":
|
244
|
+
return node.name === "undefined" && isReferenceToGlobalVariable(node);
|
218
245
|
|
219
246
|
// no default
|
220
247
|
}
|
package/lib/rules/no-eval.js
CHANGED
@@ -72,21 +72,25 @@ module.exports = {
|
|
72
72
|
let funcInfo = null;
|
73
73
|
|
74
74
|
/**
|
75
|
-
* Pushs a
|
75
|
+
* Pushs a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
|
76
|
+
* Top-level scopes are handled separately.
|
76
77
|
*
|
77
78
|
* This is used in order to check whether or not `this` binding is a
|
78
79
|
* reference to the global object.
|
79
|
-
* @param {ASTNode} node A node of the scope.
|
80
|
-
* FunctionDeclaration, FunctionExpression
|
80
|
+
* @param {ASTNode} node A node of the scope.
|
81
|
+
* For functions, this is one of FunctionDeclaration, FunctionExpression.
|
82
|
+
* For class static blocks, this is StaticBlock.
|
83
|
+
* For class field initializers, this can be any node that is PropertyDefinition#value.
|
81
84
|
* @returns {void}
|
82
85
|
*/
|
83
|
-
function
|
86
|
+
function enterThisScope(node) {
|
84
87
|
const strict = context.getScope().isStrict;
|
85
88
|
|
86
89
|
funcInfo = {
|
87
90
|
upper: funcInfo,
|
88
91
|
node,
|
89
92
|
strict,
|
93
|
+
isTopLevelOfScript: false,
|
90
94
|
defaultThis: false,
|
91
95
|
initialized: strict
|
92
96
|
};
|
@@ -96,7 +100,7 @@ module.exports = {
|
|
96
100
|
* Pops a variable scope from the stack.
|
97
101
|
* @returns {void}
|
98
102
|
*/
|
99
|
-
function
|
103
|
+
function exitThisScope() {
|
100
104
|
funcInfo = funcInfo.upper;
|
101
105
|
}
|
102
106
|
|
@@ -222,12 +226,14 @@ module.exports = {
|
|
222
226
|
strict =
|
223
227
|
scope.isStrict ||
|
224
228
|
node.sourceType === "module" ||
|
225
|
-
(features.globalReturn && scope.childScopes[0].isStrict)
|
229
|
+
(features.globalReturn && scope.childScopes[0].isStrict),
|
230
|
+
isTopLevelOfScript = node.sourceType !== "module" && !features.globalReturn;
|
226
231
|
|
227
232
|
funcInfo = {
|
228
233
|
upper: null,
|
229
234
|
node,
|
230
235
|
strict,
|
236
|
+
isTopLevelOfScript,
|
231
237
|
defaultThis: true,
|
232
238
|
initialized: true
|
233
239
|
};
|
@@ -236,21 +242,19 @@ module.exports = {
|
|
236
242
|
"Program:exit"() {
|
237
243
|
const globalScope = context.getScope();
|
238
244
|
|
239
|
-
|
245
|
+
exitThisScope();
|
240
246
|
reportAccessingEval(globalScope);
|
241
247
|
reportAccessingEvalViaGlobalObject(globalScope);
|
242
248
|
},
|
243
249
|
|
244
|
-
FunctionDeclaration:
|
245
|
-
"FunctionDeclaration:exit":
|
246
|
-
FunctionExpression:
|
247
|
-
"FunctionExpression:exit":
|
248
|
-
|
249
|
-
"
|
250
|
-
|
251
|
-
"
|
252
|
-
StaticBlock: enterVarScope,
|
253
|
-
"StaticBlock:exit": exitVarScope,
|
250
|
+
FunctionDeclaration: enterThisScope,
|
251
|
+
"FunctionDeclaration:exit": exitThisScope,
|
252
|
+
FunctionExpression: enterThisScope,
|
253
|
+
"FunctionExpression:exit": exitThisScope,
|
254
|
+
"PropertyDefinition > *.value": enterThisScope,
|
255
|
+
"PropertyDefinition > *.value:exit": exitThisScope,
|
256
|
+
StaticBlock: enterThisScope,
|
257
|
+
"StaticBlock:exit": exitThisScope,
|
254
258
|
|
255
259
|
ThisExpression(node) {
|
256
260
|
if (!isMember(node.parent, "eval")) {
|
@@ -269,7 +273,8 @@ module.exports = {
|
|
269
273
|
);
|
270
274
|
}
|
271
275
|
|
272
|
-
|
276
|
+
// `this` at the top level of scripts always refers to the global object
|
277
|
+
if (funcInfo.isTopLevelOfScript || (!funcInfo.strict && funcInfo.defaultThis)) {
|
273
278
|
|
274
279
|
// `this.eval` is possible built-in `eval`.
|
275
280
|
report(node.parent);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @fileoverview A rule to disallow `this` keywords
|
2
|
+
* @fileoverview A rule to disallow `this` keywords in contexts where the value of `this` is `undefined`.
|
3
3
|
* @author Toru Nagashima
|
4
4
|
*/
|
5
5
|
|
@@ -36,7 +36,7 @@ module.exports = {
|
|
36
36
|
type: "suggestion",
|
37
37
|
|
38
38
|
docs: {
|
39
|
-
description: "disallow `this`
|
39
|
+
description: "disallow use of `this` in contexts where the value of `this` is `undefined`",
|
40
40
|
recommended: false,
|
41
41
|
url: "https://eslint.org/docs/rules/no-invalid-this"
|
42
42
|
},
|
@@ -98,11 +98,11 @@ module.exports = {
|
|
98
98
|
const scope = context.getScope();
|
99
99
|
const features = context.parserOptions.ecmaFeatures || {};
|
100
100
|
|
101
|
+
// `this` at the top level of scripts always refers to the global object
|
101
102
|
stack.push({
|
102
103
|
init: true,
|
103
104
|
node,
|
104
105
|
valid: !(
|
105
|
-
scope.isStrict ||
|
106
106
|
node.sourceType === "module" ||
|
107
107
|
(features.globalReturn && scope.childScopes[0].isStrict)
|
108
108
|
)
|
@@ -67,6 +67,9 @@ module.exports = {
|
|
67
67
|
},
|
68
68
|
caughtErrorsIgnorePattern: {
|
69
69
|
type: "string"
|
70
|
+
},
|
71
|
+
destructuredArrayIgnorePattern: {
|
72
|
+
type: "string"
|
70
73
|
}
|
71
74
|
},
|
72
75
|
additionalProperties: false
|
@@ -114,6 +117,10 @@ module.exports = {
|
|
114
117
|
if (firstOption.caughtErrorsIgnorePattern) {
|
115
118
|
config.caughtErrorsIgnorePattern = new RegExp(firstOption.caughtErrorsIgnorePattern, "u");
|
116
119
|
}
|
120
|
+
|
121
|
+
if (firstOption.destructuredArrayIgnorePattern) {
|
122
|
+
config.destructuredArrayIgnorePattern = new RegExp(firstOption.destructuredArrayIgnorePattern, "u");
|
123
|
+
}
|
117
124
|
}
|
118
125
|
}
|
119
126
|
|
@@ -155,7 +162,14 @@ module.exports = {
|
|
155
162
|
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
156
163
|
*/
|
157
164
|
function getAssignedMessageData(unusedVar) {
|
158
|
-
const
|
165
|
+
const def = unusedVar.defs[0];
|
166
|
+
let additional = "";
|
167
|
+
|
168
|
+
if (config.destructuredArrayIgnorePattern && def && def.name.parent.type === "ArrayPattern") {
|
169
|
+
additional = `. Allowed unused elements of array destructuring patterns must match ${config.destructuredArrayIgnorePattern.toString()}`;
|
170
|
+
} else if (config.varsIgnorePattern) {
|
171
|
+
additional = `. Allowed unused vars must match ${config.varsIgnorePattern.toString()}`;
|
172
|
+
}
|
159
173
|
|
160
174
|
return {
|
161
175
|
varName: unusedVar.name,
|
@@ -584,6 +598,19 @@ module.exports = {
|
|
584
598
|
|
585
599
|
if (def) {
|
586
600
|
const type = def.type;
|
601
|
+
const refUsedInArrayPatterns = variable.references.some(ref => ref.identifier.parent.type === "ArrayPattern");
|
602
|
+
|
603
|
+
// skip elements of array destructuring patterns
|
604
|
+
if (
|
605
|
+
(
|
606
|
+
def.name.parent.type === "ArrayPattern" ||
|
607
|
+
refUsedInArrayPatterns
|
608
|
+
) &&
|
609
|
+
config.destructuredArrayIgnorePattern &&
|
610
|
+
config.destructuredArrayIgnorePattern.test(def.name.name)
|
611
|
+
) {
|
612
|
+
continue;
|
613
|
+
}
|
587
614
|
|
588
615
|
// skip catch variables
|
589
616
|
if (type === "CatchClause") {
|
@@ -76,8 +76,8 @@ module.exports = {
|
|
76
76
|
|
77
77
|
fixable: "code",
|
78
78
|
messages: {
|
79
|
-
replaced: "Assignment (=) can be replaced with operator assignment ({{operator}}
|
80
|
-
unexpected: "Unexpected operator assignment ({{operator}}
|
79
|
+
replaced: "Assignment (=) can be replaced with operator assignment ({{operator}}).",
|
80
|
+
unexpected: "Unexpected operator assignment ({{operator}}) shorthand."
|
81
81
|
}
|
82
82
|
},
|
83
83
|
|
@@ -109,11 +109,13 @@ module.exports = {
|
|
109
109
|
const operator = expr.operator;
|
110
110
|
|
111
111
|
if (isCommutativeOperatorWithShorthand(operator) || isNonCommutativeOperatorWithShorthand(operator)) {
|
112
|
+
const replacementOperator = `${operator}=`;
|
113
|
+
|
112
114
|
if (astUtils.isSameReference(left, expr.left, true)) {
|
113
115
|
context.report({
|
114
116
|
node,
|
115
117
|
messageId: "replaced",
|
116
|
-
data: { operator },
|
118
|
+
data: { operator: replacementOperator },
|
117
119
|
fix(fixer) {
|
118
120
|
if (canBeFixed(left) && canBeFixed(expr.left)) {
|
119
121
|
const equalsToken = getOperatorToken(node);
|
@@ -126,7 +128,7 @@ module.exports = {
|
|
126
128
|
return null;
|
127
129
|
}
|
128
130
|
|
129
|
-
return fixer.replaceText(node, `${leftText}${
|
131
|
+
return fixer.replaceText(node, `${leftText}${replacementOperator}${rightText}`);
|
130
132
|
}
|
131
133
|
return null;
|
132
134
|
}
|
@@ -141,7 +143,7 @@ module.exports = {
|
|
141
143
|
context.report({
|
142
144
|
node,
|
143
145
|
messageId: "replaced",
|
144
|
-
data: { operator }
|
146
|
+
data: { operator: replacementOperator }
|
145
147
|
});
|
146
148
|
}
|
147
149
|
}
|
@@ -450,8 +450,7 @@ module.exports = {
|
|
450
450
|
type: "array",
|
451
451
|
items: { enum: Object.keys(StatementTypes) },
|
452
452
|
minItems: 1,
|
453
|
-
uniqueItems: true
|
454
|
-
additionalItems: false
|
453
|
+
uniqueItems: true
|
455
454
|
}
|
456
455
|
]
|
457
456
|
}
|
@@ -466,8 +465,7 @@ module.exports = {
|
|
466
465
|
},
|
467
466
|
additionalProperties: false,
|
468
467
|
required: ["blankLine", "prev", "next"]
|
469
|
-
}
|
470
|
-
additionalItems: false
|
468
|
+
}
|
471
469
|
},
|
472
470
|
|
473
471
|
messages: {
|
@@ -19,6 +19,8 @@ module.exports = {
|
|
19
19
|
url: "https://eslint.org/docs/rules/valid-typeof"
|
20
20
|
},
|
21
21
|
|
22
|
+
hasSuggestions: true,
|
23
|
+
|
22
24
|
schema: [
|
23
25
|
{
|
24
26
|
type: "object",
|
@@ -33,7 +35,8 @@ module.exports = {
|
|
33
35
|
],
|
34
36
|
messages: {
|
35
37
|
invalidValue: "Invalid typeof comparison value.",
|
36
|
-
notString: "Typeof comparisons should be to string literals."
|
38
|
+
notString: "Typeof comparisons should be to string literals.",
|
39
|
+
suggestString: 'Use `"{{type}}"` instead of `{{type}}`.'
|
37
40
|
}
|
38
41
|
},
|
39
42
|
|
@@ -44,6 +47,21 @@ module.exports = {
|
|
44
47
|
|
45
48
|
const requireStringLiterals = context.options[0] && context.options[0].requireStringLiterals;
|
46
49
|
|
50
|
+
let globalScope;
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Checks whether the given node represents a reference to a global variable that is not declared in the source code.
|
54
|
+
* These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
|
55
|
+
* @param {ASTNode} node `Identifier` node to check.
|
56
|
+
* @returns {boolean} `true` if the node is a reference to a global variable.
|
57
|
+
*/
|
58
|
+
function isReferenceToGlobalVariable(node) {
|
59
|
+
const variable = globalScope.set.get(node.name);
|
60
|
+
|
61
|
+
return variable && variable.defs.length === 0 &&
|
62
|
+
variable.references.some(ref => ref.identifier === node);
|
63
|
+
}
|
64
|
+
|
47
65
|
/**
|
48
66
|
* Determines whether a node is a typeof expression.
|
49
67
|
* @param {ASTNode} node The node
|
@@ -59,6 +77,10 @@ module.exports = {
|
|
59
77
|
|
60
78
|
return {
|
61
79
|
|
80
|
+
Program() {
|
81
|
+
globalScope = context.getScope();
|
82
|
+
},
|
83
|
+
|
62
84
|
UnaryExpression(node) {
|
63
85
|
if (isTypeofExpression(node)) {
|
64
86
|
const parent = context.getAncestors().pop();
|
@@ -72,6 +94,20 @@ module.exports = {
|
|
72
94
|
if (VALID_TYPES.indexOf(value) === -1) {
|
73
95
|
context.report({ node: sibling, messageId: "invalidValue" });
|
74
96
|
}
|
97
|
+
} else if (sibling.type === "Identifier" && sibling.name === "undefined" && isReferenceToGlobalVariable(sibling)) {
|
98
|
+
context.report({
|
99
|
+
node: sibling,
|
100
|
+
messageId: requireStringLiterals ? "notString" : "invalidValue",
|
101
|
+
suggest: [
|
102
|
+
{
|
103
|
+
messageId: "suggestString",
|
104
|
+
data: { type: "undefined" },
|
105
|
+
fix(fixer) {
|
106
|
+
return fixer.replaceText(sibling, '"undefined"');
|
107
|
+
}
|
108
|
+
}
|
109
|
+
]
|
110
|
+
});
|
75
111
|
} else if (requireStringLiterals && !isTypeofExpression(sibling)) {
|
76
112
|
context.report({ node: sibling, messageId: "notString" });
|
77
113
|
}
|
package/lib/shared/types.js
CHANGED
@@ -173,3 +173,27 @@ module.exports = {};
|
|
173
173
|
* @property {string} ruleId The rule ID.
|
174
174
|
* @property {string[]} replacedBy The rule IDs that replace this deprecated rule.
|
175
175
|
*/
|
176
|
+
|
177
|
+
/**
|
178
|
+
* A linting result.
|
179
|
+
* @typedef {Object} LintResult
|
180
|
+
* @property {string} filePath The path to the file that was linted.
|
181
|
+
* @property {LintMessage[]} messages All of the messages for the result.
|
182
|
+
* @property {SuppressedLintMessage[]} suppressedMessages All of the suppressed messages for the result.
|
183
|
+
* @property {number} errorCount Number of errors for the result.
|
184
|
+
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
185
|
+
* @property {number} warningCount Number of warnings for the result.
|
186
|
+
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
187
|
+
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
188
|
+
* @property {string} [source] The source code of the file that was linted.
|
189
|
+
* @property {string} [output] The source code of the file that was linted, with as many fixes applied as possible.
|
190
|
+
* @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
|
191
|
+
*/
|
192
|
+
|
193
|
+
/**
|
194
|
+
* A formatter function.
|
195
|
+
* @callback FormatterFunction
|
196
|
+
* @param {LintResult[]} results The list of linting results.
|
197
|
+
* @param {{cwd: string, rulesMeta: Record<string, RuleMeta>}} [context] A context object.
|
198
|
+
* @returns {string | Promise<string>} Formatted text.
|
199
|
+
*/
|
@@ -12,5 +12,5 @@ If you do want to lint these files, try the following solutions:
|
|
12
12
|
|
13
13
|
* Check your .eslintignore file, or the eslintIgnore property in package.json, to ensure that the files are not configured to be ignored.
|
14
14
|
* Explicitly list the files from this glob that you'd like to lint on the command-line, rather than providing a glob as an argument.
|
15
|
-
`.
|
15
|
+
`.trimStart();
|
16
16
|
};
|
@@ -9,5 +9,5 @@ ESLint couldn't find the config "${configName}" to extend from. Please check tha
|
|
9
9
|
The config "${configName}" was referenced from the config file in "${importerName}".
|
10
10
|
|
11
11
|
If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
|
12
|
-
`.
|
12
|
+
`.trimStart();
|
13
13
|
};
|
@@ -11,5 +11,5 @@ ESLint couldn't find a configuration file. To set up a configuration file for th
|
|
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
|
|
13
13
|
If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat/help
|
14
|
-
`.
|
14
|
+
`.trimStart();
|
15
15
|
};
|
@@ -15,5 +15,5 @@ It's likely that the plugin isn't installed correctly. Try reinstalling by runni
|
|
15
15
|
The plugin "${pluginName}" was referenced from the config file in "${importerName}".
|
16
16
|
|
17
17
|
If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
|
18
|
-
`.
|
18
|
+
`.trimStart();
|
19
19
|
};
|
@@ -7,5 +7,5 @@ module.exports = function(it) {
|
|
7
7
|
ESLint couldn't find the plugin "${pluginName}". because there is whitespace in the name. Please check your configuration and remove all whitespace from the plugin name.
|
8
8
|
|
9
9
|
If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
|
10
|
-
`.
|
10
|
+
`.trimStart();
|
11
11
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.13.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -47,7 +47,7 @@
|
|
47
47
|
"homepage": "https://eslint.org",
|
48
48
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
49
49
|
"dependencies": {
|
50
|
-
"@eslint/eslintrc": "^1.2.
|
50
|
+
"@eslint/eslintrc": "^1.2.1",
|
51
51
|
"@humanwhocodes/config-array": "^0.9.2",
|
52
52
|
"ajv": "^6.10.0",
|
53
53
|
"chalk": "^4.0.0",
|