eslint 8.9.0 → 8.10.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 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 the [babel-eslint](https://github.com/babel/babel-eslint) parser and [eslint-plugin-babel](https://github.com/babel/eslint-plugin-babel) to use any option available in Babel.
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
 
@@ -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://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.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
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.ignitionapp.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
@@ -616,8 +616,8 @@ class CLIEngine {
616
616
  useEslintrc: options.useEslintrc,
617
617
  builtInRules,
618
618
  loadRules,
619
- eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
620
- eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
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
- eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
219
- eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
218
+ getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
219
+ getEslintAllConfig: () => require("../../conf/eslint-all.js")
220
220
  }),
221
221
  extensions = null,
222
222
  globInputPaths = true,
@@ -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
- return allConfig;
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;
@@ -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
 
@@ -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" &&
@@ -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) && !(allowParens && astUtils.isParenthesised(sourceCode, 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",
@@ -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
- inner &&
103
- outer[0] < inner[0] &&
104
- inner[1] < outer[1] &&
105
- ((innerDef.type === "FunctionName" && innerDef.node.type === "FunctionExpression") || innerDef.node.type === "ClassExpression") &&
106
- outerScope === innerScope.upper
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
- outer &&
158
- inner[1] < outer[0] &&
267
+ outer &&
268
+ inner[1] < outer[0] &&
159
269
 
160
- // Excepts FunctionDeclaration if is {"hoist":"function"}.
161
- (options.hoist !== "functions" || !outerDef || outerDef.node.type !== "FunctionDeclaration")
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
- isDuplicatedClassNameVariable(variable) ||
179
- isAllowed(variable)
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
- (shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) &&
189
- !isOnInitializer(variable, shadowed) &&
190
- !(options.hoist !== "all" && isInTdz(variable, shadowed))
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "8.9.0",
3
+ "version": "8.10.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.0",
50
+ "@eslint/eslintrc": "^1.2.0",
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",