eslint 8.9.0 → 8.12.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/lib/cli-engine/cli-engine.js +2 -2
- package/lib/cli-engine/file-enumerator.js +2 -2
- package/lib/cli-engine/formatters/html.js +2 -0
- package/lib/config/flat-config-array.js +7 -2
- package/lib/linter/linter.js +7 -0
- package/lib/rules/camelcase.js +2 -2
- package/lib/rules/comma-dangle.js +24 -4
- package/lib/rules/no-confusing-arrow.js +6 -2
- package/lib/rules/no-constant-condition.js +30 -3
- package/lib/rules/no-eval.js +6 -2
- package/lib/rules/no-invalid-this.js +3 -3
- package/lib/rules/no-shadow.js +127 -16
- package/lib/rules/no-unused-vars.js +28 -1
- package/lib/rules/padding-line-between-statements.js +2 -4
- package/lib/rules/valid-typeof.js +37 -1
- package/package.json +3 -2
package/README.md
CHANGED
@@ -129,7 +129,7 @@ ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2
|
|
129
129
|
|
130
130
|
ESLint's parser only officially supports the latest final ECMAScript standard. We will make changes to core rules in order to avoid crashes on stage 3 ECMAScript syntax proposals (as long as they are implemented using the correct experimental ESTree syntax). We may make changes to core rules to better work with language extensions (such as JSX, Flow, and TypeScript) on a case-by-case basis.
|
131
131
|
|
132
|
-
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use
|
132
|
+
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) and [@babel/eslint-plugin](https://www.npmjs.com/package/@babel/eslint-plugin) to use any option available in Babel.
|
133
133
|
|
134
134
|
Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/developer-guide/contributing). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
|
135
135
|
|
@@ -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
|
@@ -616,8 +616,8 @@ class CLIEngine {
|
|
616
616
|
useEslintrc: options.useEslintrc,
|
617
617
|
builtInRules,
|
618
618
|
loadRules,
|
619
|
-
|
620
|
-
|
619
|
+
getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
|
620
|
+
getEslintAllConfig: () => require("../../conf/eslint-all.js")
|
621
621
|
});
|
622
622
|
const fileEnumerator = new FileEnumerator({
|
623
623
|
configArrayFactory,
|
@@ -215,8 +215,8 @@ class FileEnumerator {
|
|
215
215
|
cwd = process.cwd(),
|
216
216
|
configArrayFactory = new CascadingConfigArrayFactory({
|
217
217
|
cwd,
|
218
|
-
|
219
|
-
|
218
|
+
getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
|
219
|
+
getEslintAllConfig: () => require("../../conf/eslint-all.js")
|
220
220
|
}),
|
221
221
|
extensions = null,
|
222
222
|
globInputPaths = true,
|
@@ -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;
|
@@ -14,7 +14,6 @@ const { flatConfigSchema } = require("./flat-config-schema");
|
|
14
14
|
const { RuleValidator } = require("./rule-validator");
|
15
15
|
const { defaultConfig } = require("./default-config");
|
16
16
|
const recommendedConfig = require("../../conf/eslint-recommended");
|
17
|
-
const allConfig = require("../../conf/eslint-all");
|
18
17
|
|
19
18
|
//-----------------------------------------------------------------------------
|
20
19
|
// Helpers
|
@@ -79,7 +78,13 @@ class FlatConfigArray extends ConfigArray {
|
|
79
78
|
}
|
80
79
|
|
81
80
|
if (config === "eslint:all") {
|
82
|
-
|
81
|
+
|
82
|
+
/*
|
83
|
+
* Load `eslint-all.js` here instead of at the top level to avoid loading all rule modules
|
84
|
+
* when it isn't necessary. `eslint-all.js` reads `meta` of rule objects to filter out deprecated ones,
|
85
|
+
* so requiring `eslint-all.js` module loads all rule modules as a consequence.
|
86
|
+
*/
|
87
|
+
return require("../../conf/eslint-all");
|
83
88
|
}
|
84
89
|
|
85
90
|
return config;
|
package/lib/linter/linter.js
CHANGED
@@ -800,14 +800,21 @@ function parse(text, languageOptions, filePath) {
|
|
800
800
|
* problem that ESLint identified just like any other.
|
801
801
|
*/
|
802
802
|
try {
|
803
|
+
debug("Parsing:", filePath);
|
803
804
|
const parseResult = (typeof parser.parseForESLint === "function")
|
804
805
|
? parser.parseForESLint(textToParse, parserOptions)
|
805
806
|
: { ast: parser.parse(textToParse, parserOptions) };
|
807
|
+
|
808
|
+
debug("Parsing successful:", filePath);
|
806
809
|
const ast = parseResult.ast;
|
807
810
|
const parserServices = parseResult.services || {};
|
808
811
|
const visitorKeys = parseResult.visitorKeys || evk.KEYS;
|
812
|
+
|
813
|
+
debug("Scope analysis:", filePath);
|
809
814
|
const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
|
810
815
|
|
816
|
+
debug("Scope analysis successful:", filePath);
|
817
|
+
|
811
818
|
return {
|
812
819
|
success: true,
|
813
820
|
|
package/lib/rules/camelcase.js
CHANGED
@@ -146,7 +146,7 @@ module.exports = {
|
|
146
146
|
|
147
147
|
/**
|
148
148
|
* Checks if a given binding identifier uses the original name as-is.
|
149
|
-
* - If it's in object destructuring, the original name is its property name.
|
149
|
+
* - If it's in object destructuring or object expression, the original name is its property name.
|
150
150
|
* - If it's in import declaration, the original name is its exported name.
|
151
151
|
* @param {ASTNode} node The `Identifier` node to check.
|
152
152
|
* @returns {boolean} `true` if the identifier uses the original name as-is.
|
@@ -161,7 +161,7 @@ module.exports = {
|
|
161
161
|
switch (parent.type) {
|
162
162
|
case "Property":
|
163
163
|
return (
|
164
|
-
parent.parent.type === "ObjectPattern" &&
|
164
|
+
(parent.parent.type === "ObjectPattern" || parent.parent.type === "ObjectExpression") &&
|
165
165
|
parent.value === valueNode &&
|
166
166
|
!parent.computed &&
|
167
167
|
parent.key.type === "Identifier" &&
|
@@ -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
|
}
|
@@ -41,7 +41,8 @@ module.exports = {
|
|
41
41
|
schema: [{
|
42
42
|
type: "object",
|
43
43
|
properties: {
|
44
|
-
allowParens: { type: "boolean", default: true }
|
44
|
+
allowParens: { type: "boolean", default: true },
|
45
|
+
onlyOneSimpleParam: { type: "boolean", default: false }
|
45
46
|
},
|
46
47
|
additionalProperties: false
|
47
48
|
}],
|
@@ -54,6 +55,7 @@ module.exports = {
|
|
54
55
|
create(context) {
|
55
56
|
const config = context.options[0] || {};
|
56
57
|
const allowParens = config.allowParens || (config.allowParens === void 0);
|
58
|
+
const onlyOneSimpleParam = config.onlyOneSimpleParam;
|
57
59
|
const sourceCode = context.getSourceCode();
|
58
60
|
|
59
61
|
|
@@ -65,7 +67,9 @@ module.exports = {
|
|
65
67
|
function checkArrowFunc(node) {
|
66
68
|
const body = node.body;
|
67
69
|
|
68
|
-
if (isConditional(body) &&
|
70
|
+
if (isConditional(body) &&
|
71
|
+
!(allowParens && astUtils.isParenthesised(sourceCode, body)) &&
|
72
|
+
!(onlyOneSimpleParam && !(node.params.length === 1 && node.params[0].type === "Identifier"))) {
|
69
73
|
context.report({
|
70
74
|
node,
|
71
75
|
messageId: "confusing",
|
@@ -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
@@ -87,6 +87,7 @@ module.exports = {
|
|
87
87
|
upper: funcInfo,
|
88
88
|
node,
|
89
89
|
strict,
|
90
|
+
isTopLevelOfScript: false,
|
90
91
|
defaultThis: false,
|
91
92
|
initialized: strict
|
92
93
|
};
|
@@ -222,12 +223,14 @@ module.exports = {
|
|
222
223
|
strict =
|
223
224
|
scope.isStrict ||
|
224
225
|
node.sourceType === "module" ||
|
225
|
-
(features.globalReturn && scope.childScopes[0].isStrict)
|
226
|
+
(features.globalReturn && scope.childScopes[0].isStrict),
|
227
|
+
isTopLevelOfScript = node.sourceType !== "module" && !features.globalReturn;
|
226
228
|
|
227
229
|
funcInfo = {
|
228
230
|
upper: null,
|
229
231
|
node,
|
230
232
|
strict,
|
233
|
+
isTopLevelOfScript,
|
231
234
|
defaultThis: true,
|
232
235
|
initialized: true
|
233
236
|
};
|
@@ -269,7 +272,8 @@ module.exports = {
|
|
269
272
|
);
|
270
273
|
}
|
271
274
|
|
272
|
-
|
275
|
+
// `this` at the top level of scripts always refers to the global object
|
276
|
+
if (funcInfo.isTopLevelOfScript || (!funcInfo.strict && funcInfo.defaultThis)) {
|
273
277
|
|
274
278
|
// `this.eval` is possible built-in `eval`.
|
275
279
|
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
|
)
|
package/lib/rules/no-shadow.js
CHANGED
@@ -11,6 +11,15 @@
|
|
11
11
|
|
12
12
|
const astUtils = require("./utils/ast-utils");
|
13
13
|
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Helpers
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
const FUNC_EXPR_NODE_TYPES = ["ArrowFunctionExpression", "FunctionExpression"];
|
19
|
+
const CALL_EXPR_NODE_TYPE = ["CallExpression"];
|
20
|
+
const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
|
21
|
+
const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u;
|
22
|
+
|
14
23
|
//------------------------------------------------------------------------------
|
15
24
|
// Rule Definition
|
16
25
|
//------------------------------------------------------------------------------
|
@@ -37,7 +46,8 @@ module.exports = {
|
|
37
46
|
items: {
|
38
47
|
type: "string"
|
39
48
|
}
|
40
|
-
}
|
49
|
+
},
|
50
|
+
ignoreOnInitialization: { type: "boolean", default: false }
|
41
51
|
},
|
42
52
|
additionalProperties: false
|
43
53
|
}
|
@@ -54,9 +64,109 @@ module.exports = {
|
|
54
64
|
const options = {
|
55
65
|
builtinGlobals: context.options[0] && context.options[0].builtinGlobals,
|
56
66
|
hoist: (context.options[0] && context.options[0].hoist) || "functions",
|
57
|
-
allow: (context.options[0] && context.options[0].allow) || []
|
67
|
+
allow: (context.options[0] && context.options[0].allow) || [],
|
68
|
+
ignoreOnInitialization: context.options[0] && context.options[0].ignoreOnInitialization
|
58
69
|
};
|
59
70
|
|
71
|
+
/**
|
72
|
+
* Checks whether or not a given location is inside of the range of a given node.
|
73
|
+
* @param {ASTNode} node An node to check.
|
74
|
+
* @param {number} location A location to check.
|
75
|
+
* @returns {boolean} `true` if the location is inside of the range of the node.
|
76
|
+
*/
|
77
|
+
function isInRange(node, location) {
|
78
|
+
return node && node.range[0] <= location && location <= node.range[1];
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Searches from the current node through its ancestry to find a matching node.
|
83
|
+
* @param {ASTNode} node a node to get.
|
84
|
+
* @param {(node: ASTNode) => boolean} match a callback that checks whether or not the node verifies its condition or not.
|
85
|
+
* @returns {ASTNode|null} the matching node.
|
86
|
+
*/
|
87
|
+
function findSelfOrAncestor(node, match) {
|
88
|
+
let currentNode = node;
|
89
|
+
|
90
|
+
while (currentNode && !match(currentNode)) {
|
91
|
+
currentNode = currentNode.parent;
|
92
|
+
}
|
93
|
+
return currentNode;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Finds function's outer scope.
|
98
|
+
* @param {Scope} scope Function's own scope.
|
99
|
+
* @returns {Scope} Function's outer scope.
|
100
|
+
*/
|
101
|
+
function getOuterScope(scope) {
|
102
|
+
const upper = scope.upper;
|
103
|
+
|
104
|
+
if (upper.type === "function-expression-name") {
|
105
|
+
return upper.upper;
|
106
|
+
}
|
107
|
+
return upper;
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Checks if a variable and a shadowedVariable have the same init pattern ancestor.
|
112
|
+
* @param {Object} variable a variable to check.
|
113
|
+
* @param {Object} shadowedVariable a shadowedVariable to check.
|
114
|
+
* @returns {boolean} Whether or not the variable and the shadowedVariable have the same init pattern ancestor.
|
115
|
+
*/
|
116
|
+
function isInitPatternNode(variable, shadowedVariable) {
|
117
|
+
const outerDef = shadowedVariable.defs[0];
|
118
|
+
|
119
|
+
if (!outerDef) {
|
120
|
+
return false;
|
121
|
+
}
|
122
|
+
|
123
|
+
const { variableScope } = variable.scope;
|
124
|
+
|
125
|
+
|
126
|
+
if (!(FUNC_EXPR_NODE_TYPES.includes(variableScope.block.type) && getOuterScope(variableScope) === shadowedVariable.scope)) {
|
127
|
+
return false;
|
128
|
+
}
|
129
|
+
|
130
|
+
const fun = variableScope.block;
|
131
|
+
const { parent } = fun;
|
132
|
+
|
133
|
+
const callExpression = findSelfOrAncestor(
|
134
|
+
parent,
|
135
|
+
node => CALL_EXPR_NODE_TYPE.includes(node.type)
|
136
|
+
);
|
137
|
+
|
138
|
+
if (!callExpression) {
|
139
|
+
return false;
|
140
|
+
}
|
141
|
+
|
142
|
+
let node = outerDef.name;
|
143
|
+
const location = callExpression.range[1];
|
144
|
+
|
145
|
+
while (node) {
|
146
|
+
if (node.type === "VariableDeclarator") {
|
147
|
+
if (isInRange(node.init, location)) {
|
148
|
+
return true;
|
149
|
+
}
|
150
|
+
if (FOR_IN_OF_TYPE.test(node.parent.parent.type) &&
|
151
|
+
isInRange(node.parent.parent.right, location)
|
152
|
+
) {
|
153
|
+
return true;
|
154
|
+
}
|
155
|
+
break;
|
156
|
+
} else if (node.type === "AssignmentPattern") {
|
157
|
+
if (isInRange(node.right, location)) {
|
158
|
+
return true;
|
159
|
+
}
|
160
|
+
} else if (SENTINEL_TYPE.test(node.type)) {
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
|
164
|
+
node = node.parent;
|
165
|
+
}
|
166
|
+
|
167
|
+
return false;
|
168
|
+
}
|
169
|
+
|
60
170
|
/**
|
61
171
|
* Check if variable name is allowed.
|
62
172
|
* @param {ASTNode} variable The variable to check.
|
@@ -99,11 +209,11 @@ module.exports = {
|
|
99
209
|
|
100
210
|
return (
|
101
211
|
outer &&
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
212
|
+
inner &&
|
213
|
+
outer[0] < inner[0] &&
|
214
|
+
inner[1] < outer[1] &&
|
215
|
+
((innerDef.type === "FunctionName" && innerDef.node.type === "FunctionExpression") || innerDef.node.type === "ClassExpression") &&
|
216
|
+
outerScope === innerScope.upper
|
107
217
|
);
|
108
218
|
}
|
109
219
|
|
@@ -154,11 +264,11 @@ module.exports = {
|
|
154
264
|
|
155
265
|
return (
|
156
266
|
inner &&
|
157
|
-
|
158
|
-
|
267
|
+
outer &&
|
268
|
+
inner[1] < outer[0] &&
|
159
269
|
|
160
|
-
|
161
|
-
|
270
|
+
// Excepts FunctionDeclaration if is {"hoist":"function"}.
|
271
|
+
(options.hoist !== "functions" || !outerDef || outerDef.node.type !== "FunctionDeclaration")
|
162
272
|
);
|
163
273
|
}
|
164
274
|
|
@@ -175,8 +285,8 @@ module.exports = {
|
|
175
285
|
|
176
286
|
// Skips "arguments" or variables of a class name in the class scope of ClassDeclaration.
|
177
287
|
if (variable.identifiers.length === 0 ||
|
178
|
-
|
179
|
-
|
288
|
+
isDuplicatedClassNameVariable(variable) ||
|
289
|
+
isAllowed(variable)
|
180
290
|
) {
|
181
291
|
continue;
|
182
292
|
}
|
@@ -185,9 +295,10 @@ module.exports = {
|
|
185
295
|
const shadowed = astUtils.getVariableByName(scope.upper, variable.name);
|
186
296
|
|
187
297
|
if (shadowed &&
|
188
|
-
|
189
|
-
|
190
|
-
|
298
|
+
(shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) &&
|
299
|
+
!isOnInitializer(variable, shadowed) &&
|
300
|
+
!(options.ignoreOnInitialization && isInitPatternNode(variable, shadowed)) &&
|
301
|
+
!(options.hoist !== "all" && isInTdz(variable, shadowed))
|
191
302
|
) {
|
192
303
|
const location = getDeclaredLocation(shadowed);
|
193
304
|
const messageId = location.global ? "noShadowGlobal" : "noShadow";
|
@@ -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") {
|
@@ -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/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.12.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.1
|
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",
|
@@ -122,6 +122,7 @@
|
|
122
122
|
"node-polyfill-webpack-plugin": "^1.0.3",
|
123
123
|
"npm-license": "^0.3.3",
|
124
124
|
"nyc": "^15.0.1",
|
125
|
+
"pirates": "^4.0.5",
|
125
126
|
"progress": "^2.0.3",
|
126
127
|
"proxyquire": "^2.0.1",
|
127
128
|
"puppeteer": "^9.1.1",
|