tools: update ESLint to 8.1.0

PR-URL: https://github.com/nodejs/node/pull/40582
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Voltrex <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
Luigi Pinca authored and Node.js GitHub Bot committed 2021-10-26 17:58:17 +00:00
1 parent 506f7de440
commit a7847960c2
14 files changed
+252 -48

No files matched your search

+1 -1
View File
@@ -242,7 +242,7 @@ Toru Nagashima
</td><td align="center" valign="top" width="11%">
<a href="https://github.com/aladdin-add">
<img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
薛定谔的猫
唯然
</a>
</td></tr></tbody></table>
+10 -21
View File
@@ -570,8 +570,10 @@ class CLIEngine {
/**
* Creates a new instance of the core CLI engine.
* @param {CLIEngineOptions} providedOptions The options for this instance.
* @param {Object} [additionalData] Additional settings that are not CLIEngineOptions.
* @param {Record<string,Plugin>|null} [additionalData.preloadedPlugins] Preloaded plugins.
*/
constructor(providedOptions) {
constructor(providedOptions, { preloadedPlugins } = {}) {
const options = Object.assign(
Object.create(null),
defaultOptions,
@@ -584,6 +586,13 @@ class CLIEngine {
}
const additionalPluginPool = new Map();
if (preloadedPlugins) {
for (const [id, plugin] of Object.entries(preloadedPlugins)) {
additionalPluginPool.set(id, plugin);
}
}
const cacheFilePath = getCacheFile(
options.cacheLocation || options.cacheFile,
options.cwd
@@ -698,26 +707,6 @@ class CLIEngine {
});
}
/**
* Add a plugin by passing its configuration
* @param {string} name Name of the plugin.
* @param {Plugin} pluginObject Plugin configuration object.
* @returns {void}
*/
addPlugin(name, pluginObject) {
const {
additionalPluginPool,
configArrayFactory,
lastConfigArrays
} = internalSlotsMap.get(this);
additionalPluginPool.set(name, pluginObject);
configArrayFactory.clearCache();
lastConfigArrays.length = 1;
lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
}
/**
* Resolves the patterns passed into executeOnFiles() into glob-based patterns
* for easier handling.
+2 -15
View File
@@ -54,7 +54,7 @@ const { version } = require("../../package.json");
* @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
* @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
* @property {string} [overrideConfigFile] The configuration file to use.
* @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
* @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
* @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
* @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
* @property {string[]} [rulePaths] An array of directories to load custom rules from.
@@ -433,26 +433,13 @@ class ESLint {
*/
constructor(options = {}) {
const processedOptions = processOptions(options);
const cliEngine = new CLIEngine(processedOptions);
const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins });
const {
additionalPluginPool,
configArrayFactory,
lastConfigArrays
} = getCLIEngineInternalSlots(cliEngine);
let updated = false;
/*
* Address `plugins` to add plugin implementations.
* Operate the `additionalPluginPool` internal slot directly to avoid
* using `addPlugin(id, plugin)` method that resets cache everytime.
*/
if (options.plugins) {
for (const [id, plugin] of Object.entries(options.plugins)) {
additionalPluginPool.set(id, plugin);
updated = true;
}
}
/*
* Address `overrideConfig` to set override config.
* Operate the `configArrayFactory` internal slot directly because this
+1 -1
View File
@@ -15,7 +15,7 @@ const levn = require("levn"),
Legacy: {
ConfigOps
}
} = require("@eslint/eslintrc/universal"); // eslint-disable-line node/no-missing-require -- false positive
} = require("@eslint/eslintrc/universal");
const debug = require("debug")("eslint:config-comment-parser");
+1 -1
View File
@@ -24,7 +24,7 @@ const
ConfigValidator,
environments: BuiltInEnvironments
}
} = require("@eslint/eslintrc/universal"), // eslint-disable-line node/no-missing-require -- false positive
} = require("@eslint/eslintrc/universal"),
Traverser = require("../shared/traverser"),
{ SourceCode } = require("../source-code"),
CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
+7
View File
@@ -98,6 +98,13 @@ function getPossibleTypes(parsedSelector) {
case "adjacent":
return getPossibleTypes(parsedSelector.right);
case "class":
if (parsedSelector.name === "function") {
return ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"];
}
return null;
default:
return null;
+5 -2
View File
@@ -67,6 +67,7 @@ const { SourceCode } = require("../source-code");
/**
* A test case that is expected to pass lint.
* @typedef {Object} ValidTestCase
* @property {string} [name] Name for the test case.
* @property {string} code Code for the test case.
* @property {any[]} [options] Options for the test case.
* @property {{ [name: string]: any }} [settings] Settings for the test case.
@@ -81,6 +82,7 @@ const { SourceCode } = require("../source-code");
/**
* A test case that is expected to fail lint.
* @typedef {Object} InvalidTestCase
* @property {string} [name] Name for the test case.
* @property {string} code Code for the test case.
* @property {number | Array<TestCaseError | string | RegExp>} errors Expected errors.
* @property {string | null} [output] The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested.
@@ -124,6 +126,7 @@ let defaultConfig = { rules: {} };
* configuration
*/
const RuleTesterParameters = [
"name",
"code",
"filename",
"options",
@@ -964,7 +967,7 @@ class RuleTester {
RuleTester.describe("valid", () => {
test.valid.forEach(valid => {
RuleTester[valid.only ? "itOnly" : "it"](
sanitize(typeof valid === "object" ? valid.code : valid),
sanitize(typeof valid === "object" ? valid.name || valid.code : valid),
() => {
testValidTemplate(valid);
}
@@ -975,7 +978,7 @@ class RuleTester {
RuleTester.describe("invalid", () => {
test.invalid.forEach(invalid => {
RuleTester[invalid.only ? "itOnly" : "it"](
sanitize(invalid.code),
sanitize(invalid.name || invalid.code),
() => {
testInvalidTemplate(invalid);
}
+1
View File
@@ -221,6 +221,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
"no-unsafe-optional-chaining": () => require("./no-unsafe-optional-chaining"),
"no-unused-expressions": () => require("./no-unused-expressions"),
"no-unused-labels": () => require("./no-unused-labels"),
"no-unused-private-class-members": () => require("./no-unused-private-class-members"),
"no-unused-vars": () => require("./no-unused-vars"),
"no-use-before-define": () => require("./no-use-before-define"),
"no-useless-backreference": () => require("./no-useless-backreference"),
+14 -1
View File
@@ -109,6 +109,8 @@ module.exports = {
create(context) {
const sourceCode = context.getSourceCode();
const tokensToIgnore = new WeakSet();
/**
* Reports a given token if there are not space(s) before the token.
* @param {Token} token A token to report.
@@ -121,6 +123,7 @@ module.exports = {
if (prevToken &&
(CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
!isOpenParenOfTemplate(prevToken) &&
!tokensToIgnore.has(prevToken) &&
astUtils.isTokenOnSameLine(prevToken, token) &&
!sourceCode.isSpaceBetweenTokens(prevToken, token)
) {
@@ -147,6 +150,7 @@ module.exports = {
if (prevToken &&
(CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
!isOpenParenOfTemplate(prevToken) &&
!tokensToIgnore.has(prevToken) &&
astUtils.isTokenOnSameLine(prevToken, token) &&
sourceCode.isSpaceBetweenTokens(prevToken, token)
) {
@@ -173,6 +177,7 @@ module.exports = {
if (nextToken &&
(CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
!isCloseParenOfTemplate(nextToken) &&
!tokensToIgnore.has(nextToken) &&
astUtils.isTokenOnSameLine(token, nextToken) &&
!sourceCode.isSpaceBetweenTokens(token, nextToken)
) {
@@ -199,6 +204,7 @@ module.exports = {
if (nextToken &&
(CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
!isCloseParenOfTemplate(nextToken) &&
!tokensToIgnore.has(nextToken) &&
astUtils.isTokenOnSameLine(token, nextToken) &&
sourceCode.isSpaceBetweenTokens(token, nextToken)
) {
@@ -584,7 +590,14 @@ module.exports = {
ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
MethodDefinition: checkSpacingForProperty,
PropertyDefinition: checkSpacingForProperty,
Property: checkSpacingForProperty
Property: checkSpacingForProperty,
// To avoid conflicts with `space-infix-ops`, e.g. `a > this.b`
"BinaryExpression[operator='>']"(node) {
const operatorToken = sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken);
tokensToIgnore.add(operatorToken);
}
};
}
};
+194
View File
@@ -0,0 +1,194 @@
/**
* @fileoverview Rule to flag declared but unused private class members
* @author Tim van der Lippe
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "problem",
docs: {
description: "disallow unused private class members",
recommended: false,
url: "https://eslint.org/docs/rules/no-unused-private-class-members"
},
schema: [],
messages: {
unusedPrivateClassMember: "'{{classMemberName}}' is defined but never used."
}
},
create(context) {
const trackedClasses = [];
/**
* Check whether the current node is in a write only assignment.
* @param {ASTNode} privateIdentifierNode Node referring to a private identifier
* @returns {boolean} Whether the node is in a write only assignment
* @private
*/
function isWriteOnlyAssignment(privateIdentifierNode) {
const parentStatement = privateIdentifierNode.parent.parent;
const isAssignmentExpression = parentStatement.type === "AssignmentExpression";
if (!isAssignmentExpression &&
parentStatement.type !== "ForInStatement" &&
parentStatement.type !== "ForOfStatement" &&
parentStatement.type !== "AssignmentPattern") {
return false;
}
// It is a write-only usage, since we still allow usages on the right for reads
if (parentStatement.left !== privateIdentifierNode.parent) {
return false;
}
// For any other operator (such as '+=') we still consider it a read operation
if (isAssignmentExpression && parentStatement.operator !== "=") {
/*
* However, if the read operation is "discarded" in an empty statement, then
* we consider it write only.
*/
return parentStatement.parent.type === "ExpressionStatement";
}
return true;
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
// Collect all declared members up front and assume they are all unused
ClassBody(classBodyNode) {
const privateMembers = new Map();
trackedClasses.unshift(privateMembers);
for (const bodyMember of classBodyNode.body) {
if (bodyMember.type === "PropertyDefinition" || bodyMember.type === "MethodDefinition") {
if (bodyMember.key.type === "PrivateIdentifier") {
privateMembers.set(bodyMember.key.name, {
declaredNode: bodyMember,
isAccessor: bodyMember.type === "MethodDefinition" &&
(bodyMember.kind === "set" || bodyMember.kind === "get")
});
}
}
}
},
/*
* Process all usages of the private identifier and remove a member from
* `declaredAndUnusedPrivateMembers` if we deem it used.
*/
PrivateIdentifier(privateIdentifierNode) {
const classBody = trackedClasses.find(classProperties => classProperties.has(privateIdentifierNode.name));
// Can't happen, as it is a parser to have a missing class body, but let's code defensively here.
if (!classBody) {
return;
}
// In case any other usage was already detected, we can short circuit the logic here.
const memberDefinition = classBody.get(privateIdentifierNode.name);
if (memberDefinition.isUsed) {
return;
}
// The definition of the class member itself
if (privateIdentifierNode.parent.type === "PropertyDefinition" ||
privateIdentifierNode.parent.type === "MethodDefinition") {
return;
}
/*
* Any usage of an accessor is considered a read, as the getter/setter can have
* side-effects in its definition.
*/
if (memberDefinition.isAccessor) {
memberDefinition.isUsed = true;
return;
}
// Any assignments to this member, except for assignments that also read
if (isWriteOnlyAssignment(privateIdentifierNode)) {
return;
}
const wrappingExpressionType = privateIdentifierNode.parent.parent.type;
const parentOfWrappingExpressionType = privateIdentifierNode.parent.parent.parent.type;
// A statement which only increments (`this.#x++;`)
if (wrappingExpressionType === "UpdateExpression" &&
parentOfWrappingExpressionType === "ExpressionStatement") {
return;
}
/*
* ({ x: this.#usedInDestructuring } = bar);
*
* But should treat the following as a read:
* ({ [this.#x]: a } = foo);
*/
if (wrappingExpressionType === "Property" &&
parentOfWrappingExpressionType === "ObjectPattern" &&
privateIdentifierNode.parent.parent.value === privateIdentifierNode.parent) {
return;
}
// [...this.#unusedInRestPattern] = bar;
if (wrappingExpressionType === "RestElement") {
return;
}
// [this.#unusedInAssignmentPattern] = bar;
if (wrappingExpressionType === "ArrayPattern") {
return;
}
/*
* We can't delete the memberDefinition, as we need to keep track of which member we are marking as used.
* In the case of nested classes, we only mark the first member we encounter as used. If you were to delete
* the member, then any subsequent usage could incorrectly mark the member of an encapsulating parent class
* as used, which is incorrect.
*/
memberDefinition.isUsed = true;
},
/*
* Post-process the class members and report any remaining members.
* Since private members can only be accessed in the current class context,
* we can safely assume that all usages are within the current class body.
*/
"ClassBody:exit"() {
const unusedPrivateMembers = trackedClasses.shift();
for (const [classMemberName, { declaredNode, isUsed }] of unusedPrivateMembers.entries()) {
if (isUsed) {
continue;
}
context.report({
node: declaredNode,
loc: declaredNode.key.loc,
messageId: "unusedPrivateClassMember",
data: {
classMemberName: `#${classMemberName}`
}
});
}
}
};
}
};
+1 -1
View File
@@ -21,7 +21,7 @@ module.exports = {};
/**
* @typedef {Object} ParserOptions
* @property {EcmaFeatures} [ecmaFeatures] The optional features.
* @property {3|5|6|7|8|9|10|11|12|2015|2016|2017|2018|2019|2020|2021} [ecmaVersion] The ECMAScript version (or revision number).
* @property {3|5|6|7|8|9|10|11|12|13|2015|2016|2017|2018|2019|2020|2021|2022} [ecmaVersion] The ECMAScript version (or revision number).
* @property {"script"|"module"} [sourceType] The source code type.
*/
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@eslint/eslintrc",
"version": "1.0.2",
"version": "1.0.3",
"description": "The legacy ESLintRC config file format for ESLint",
"type": "module",
"main": "./dist/eslintrc.cjs",
@@ -19,7 +19,8 @@
"lib",
"conf",
"LICENSE",
"dist"
"dist",
"universal.js"
],
"publishConfig": {
"access": "public"
+9
View File
@@ -0,0 +1,9 @@
// Jest (and probably some other runtimes with custom implementations of
// `require`) doesn't support `exports` in `package.json`, so this file is here
// to help them load this module. Note that it is also `.js` and not `.cjs` for
// the same reason - `cjs` files requires to be loaded with an extension, but
// since Jest doesn't respect `module` outside of ESM mode it still works in
// this case (and the `require` in _this_ file does specify the extension).
// eslint-disable-next-line no-undef
module.exports = require("./dist/eslintrc-universal.cjs");
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "eslint",
"version": "8.0.0",
"version": "8.1.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
"description": "An AST-based pattern checker for JavaScript.",
"bin": {
@@ -47,7 +47,7 @@
"homepage": "https://eslint.org",
"bugs": "https://github.com/eslint/eslint/issues/",
"dependencies": {
"@eslint/eslintrc": "^1.0.2",
"@eslint/eslintrc": "^1.0.3",
"@humanwhocodes/config-array": "^0.6.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@@ -99,7 +99,7 @@
"eslint": "file:.",
"eslint-config-eslint": "file:packages/eslint-config-eslint",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-eslint-plugin": "^3.5.3",
"eslint-plugin-eslint-plugin": "^4.0.1",
"eslint-plugin-internal-rules": "file:tools/internal-rules",
"eslint-plugin-jsdoc": "^36.0.6",
"eslint-plugin-node": "^11.1.0",