mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
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:
1 parent
506f7de440
commit
a7847960c2
14 files changed
+252
-48
No files matched your search
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user