From 9e8e0e8acb0c4a9e57dee636a797c405bc8d647a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Wed, 16 Oct 2024 20:37:36 +0200 Subject: [PATCH] feat: add ESLint v9 compatibility layer --- .eslintrc.js | 23 ++++++++++++++++ lib/eslint-compat.js | 24 +++++++++++++++++ lib/rules/arrow-parens.js | 23 +++++++--------- lib/rules/block-scoped-var.js | 17 +++++------- lib/rules/no-instanceof-array.js | 13 ++++----- lib/rules/no-instanceof-wrapper.js | 13 ++++----- lib/rules/no-this-in-static.js | 11 +++----- lib/rules/no-use-ignored-vars.js | 10 +++---- lib/rules/no-useless-rest-spread.js | 19 ++++++------- lib/rules/prefer-for-of.js | 41 ++++++++++++++++------------- 10 files changed, 111 insertions(+), 83 deletions(-) create mode 100644 lib/eslint-compat.js diff --git a/.eslintrc.js b/.eslintrc.js index 94dcb46..ede7308 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,6 +7,29 @@ module.exports = { "plugin:@eslint-community/mysticatea/es2015", "plugin:@eslint-community/mysticatea/+eslint-plugin", ], + rules: { + "no-restricted-properties": [ + "error", + { + object: "context", + property: "getDeclaredVariables", + message: + "If you are using it in a test case, use test/test-lib/eslint-compat.mjs#getDeclaredVariables instead. Other than that, the API should also be compatible with ESLint v9.", + }, + { + object: "context", + property: "getSourceCode", + message: + "If you are using it in a test case, use test/test-lib/eslint-compat.mjs#getSourceCode instead. Other than that, the API should also be compatible with ESLint v9.", + }, + { + object: "context", + property: "getScope", + message: + "If you are using it in a test case, use test/test-lib/eslint-compat.mjs#getScope instead. Other than that, the API should also be compatible with ESLint v9.", + }, + ], + }, overrides: [ { files: ["lib/utils.js", "scripts/*.js"], diff --git a/lib/eslint-compat.js b/lib/eslint-compat.js new file mode 100644 index 0000000..aadd34b --- /dev/null +++ b/lib/eslint-compat.js @@ -0,0 +1,24 @@ +/* eslint-disable no-restricted-properties */ + +"use strict" + +function getDeclaredVariables(context, node) { + return ( + getSourceCode(context).getDeclaredVariables?.(node) ?? + context.getDeclaredVariables(node) + ) +} + +function getSourceCode(context) { + return context.sourceCode ?? context.getSourceCode() +} + +function getScope(context, node) { + return getSourceCode(context).getScope?.(node) ?? context.getScope() +} + +module.exports = { + getDeclaredVariables, + getSourceCode, + getScope, +} diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js index 9a18682..5888adf 100644 --- a/lib/rules/arrow-parens.js +++ b/lib/rules/arrow-parens.js @@ -1,12 +1,9 @@ -/** - * @author Toru Nagashima - * @copyright 2015 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" +const { getSourceCode } = require("../eslint-compat") + /** - * Checks whether or not a given token is `(`. + * Checks whether a given token is `(`. * @param {Token} token - A token to check. * @returns {boolean} `true` when the token is `(`. */ @@ -15,7 +12,7 @@ function isOpenParen(token) { } /** - * Checks whether or not given two tokens are at a same line. + * Checks whether given two tokens are at a same line. * @param {Token} a - A left token. * @param {Token} b - A right token. * @returns {boolean} `true` when the tokens are at a same line. @@ -43,12 +40,11 @@ module.exports = { type: "suggestion", }, create(context) { + const sourceCode = getSourceCode(context) return { ArrowFunctionExpression(node) { - const first = context - .getSourceCode() - .getFirstToken(node, node.async ? 1 : 0) - const before = context.getSourceCode().getTokenBefore(first) + const first = sourceCode.getFirstToken(node, node.async ? 1 : 0) + const before = sourceCode.getTokenBefore(first) if (isOpenParen(first)) { if ( @@ -63,9 +59,8 @@ module.exports = { fix(fixer) { const id = node.params[0] const begin = first.range[0] - const end = context - .getSourceCode() - .getTokenAfter(id).range[1] + const end = + sourceCode.getTokenAfter(id).range[1] return fixer.replaceTextRange( [begin, end], diff --git a/lib/rules/block-scoped-var.js b/lib/rules/block-scoped-var.js index ee25e82..db2a5ba 100644 --- a/lib/rules/block-scoped-var.js +++ b/lib/rules/block-scoped-var.js @@ -1,10 +1,7 @@ -/** - * @author Toru Nagashima - * @copyright 2015 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" +const { getDeclaredVariables } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ @@ -15,7 +12,7 @@ const containerNodeType = /^(?:For(?:In|Of)?Statement|(?:Arrow)?Function(?:Declaration|Expression))$/u /** - * Checks whether or not a given definition should be skipped. + * Checks whether a given definition should be skipped. * @param {escope.Variable.DefEntry} def - A definition to check. * @param {escope.Variable.DefEntry[]} defs - A definition list which includes `def`. * @param {escope.Variable} variable - A variable which is defined by the definition. @@ -180,7 +177,7 @@ class PseudoScope { } /** - * Turns an used flag on. + * Turns a used flag on. * @returns {void} */ markAsUsed() { @@ -213,12 +210,12 @@ module.exports = { }, create(context) { /** - * Finds and reports references which are outside of valid scopes. + * Finds and reports references which are outside valid scopes. * @param {ASTNode} node - A node to get variables. * @returns {void} */ function checkForVariables(node) { - const variables = context.getDeclaredVariables(node) + const variables = getDeclaredVariables(context, node) for (const variable of variables) { const defs = variable.defs const lastDef = defs[defs.length - 1] @@ -235,7 +232,7 @@ module.exports = { continue } - // Check whether or not any reading reference exists. + // Check whether any reading reference exists. // And while it does, warn references which does not belong to any // scope. let hasReadRef = false diff --git a/lib/rules/no-instanceof-array.js b/lib/rules/no-instanceof-array.js index ea74699..135909f 100644 --- a/lib/rules/no-instanceof-array.js +++ b/lib/rules/no-instanceof-array.js @@ -1,10 +1,7 @@ -/** - * @author Toru Nagashima - * @copyright 2016 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" +const { getScope, getSourceCode } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -26,7 +23,7 @@ module.exports = { }, create(context) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) /** * Checks whether the given node is RHS of instanceof. @@ -43,8 +40,8 @@ module.exports = { } return { - "Program:exit"() { - const globalScope = context.getScope() + "Program:exit"(globalNode) { + const globalScope = getScope(context, globalNode) const variable = globalScope.set.get("Array") // Skip if undefined or shadowed diff --git a/lib/rules/no-instanceof-wrapper.js b/lib/rules/no-instanceof-wrapper.js index c343ca9..6d9aee5 100644 --- a/lib/rules/no-instanceof-wrapper.js +++ b/lib/rules/no-instanceof-wrapper.js @@ -1,10 +1,7 @@ -/** - * @author Toru Nagashima - * @copyright 2016 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" +const { getScope, getSourceCode } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -26,7 +23,7 @@ module.exports = { }, create(context) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) const targetTypes = [ "Boolean", "Number", @@ -51,8 +48,8 @@ module.exports = { } return { - "Program:exit"() { - const globalScope = context.getScope() + "Program:exit"(globalNode) { + const globalScope = getScope(context, globalNode) for (const ctorName of targetTypes) { const typeName = ctorName.toLowerCase() diff --git a/lib/rules/no-this-in-static.js b/lib/rules/no-this-in-static.js index ab84bdb..b27ef2b 100644 --- a/lib/rules/no-this-in-static.js +++ b/lib/rules/no-this-in-static.js @@ -1,10 +1,7 @@ -/** - * @author Toru Nagashima - * @copyright 2016 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" +const { getSourceCode } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -25,7 +22,7 @@ module.exports = { }, create(context) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) let funcInfo = null /** @@ -65,7 +62,7 @@ module.exports = { } /** - * Reports the `this`/`super` node if this is inside of a static method. + * Reports the `this`/`super` node if this is inside a static method. * * @param {ASTNode} node - The node to report. * @returns {void} diff --git a/lib/rules/no-use-ignored-vars.js b/lib/rules/no-use-ignored-vars.js index daa677a..1e43e99 100644 --- a/lib/rules/no-use-ignored-vars.js +++ b/lib/rules/no-use-ignored-vars.js @@ -1,9 +1,7 @@ -/** - * @fileoverview Rule to disallow a use of ignored variables. - * @author Toru Nagashima - */ "use strict" +const { getScope } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ @@ -84,8 +82,8 @@ module.exports = { } return { - "Program:exit"() { - const queue = [context.getScope()] + "Program:exit"(node) { + const queue = [getScope(context, node)] let scope = null while ((scope = queue.pop()) != null) { diff --git a/lib/rules/no-useless-rest-spread.js b/lib/rules/no-useless-rest-spread.js index 5c3f615..fa18c09 100644 --- a/lib/rules/no-useless-rest-spread.js +++ b/lib/rules/no-useless-rest-spread.js @@ -1,9 +1,7 @@ -/** - * @fileoverview Rule to disallow unnecessary spread operators. - * @author Toru Nagashima - */ "use strict" +const { getSourceCode } = require("../eslint-compat") + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ @@ -109,7 +107,7 @@ module.exports = { }, create(context) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) /** * Verify the given SpreadElement or RestElement. @@ -133,12 +131,11 @@ module.exports = { const isRestParameter = nodeType === "RestElement" && argumentType !== parentType const type1 = nodeType === "RestElement" ? "rest" : "spread" - const type2 = - /* eslint-disable @eslint-community/mysticatea/prettier */ - isRestParameter ? "parameter" : - isArray ? "element" : - /* otherwise */ "property" - /* eslint-enable @eslint-community/mysticatea/prettier */ + const type2 = isRestParameter + ? "parameter" + : isArray + ? "element" + : /* otherwise */ "property" context.report({ node, diff --git a/lib/rules/prefer-for-of.js b/lib/rules/prefer-for-of.js index e0921d9..721983a 100644 --- a/lib/rules/prefer-for-of.js +++ b/lib/rules/prefer-for-of.js @@ -1,8 +1,3 @@ -/** - * @author Toru Nagashima - * @copyright 2016 Toru Nagashima. All rights reserved. - * See LICENSE file in root directory for full license. - */ "use strict" //------------------------------------------------------------------------------ @@ -10,6 +5,11 @@ //------------------------------------------------------------------------------ const assert = require("assert") +const { + getDeclaredVariables, + getScope, + getSourceCode, +} = require("../eslint-compat") //------------------------------------------------------------------------------ // Helpers @@ -92,7 +92,7 @@ function isSimpleReference(node) { function isCalledRecursively(context, node) { return ( node.id != null && - context.getDeclaredVariables(node)[0].references.length > 0 + getDeclaredVariables(context, node)[0].references.length > 0 ) } @@ -203,7 +203,7 @@ function getArrayTextOfForStatement(sourceCode, node) { /** * Checks whether the given node is in an assignee or not. - * @param {ASTNode} startNode The ndoe to check. + * @param {ASTNode} startNode The node to check. * @returns {boolean} `true` if the node is in an assignee. */ function isAssignee(startNode) { @@ -234,13 +234,13 @@ function isAssignee(startNode) { * @param {RuleContext} context - The rule context object. * @param {ASTNode} node - The `for` loop node which is a simple array * traversing. - * @returns {boolean} `true` if the the all references of the index variable are + * @returns {boolean} `true` if all references of the index variable are * used to get array elements. */ function isIndexVarOnlyUsedToGetArrayElements(context, node) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) const arrayText = getArrayTextOfForStatement(sourceCode, node) - const indexVar = context.getDeclaredVariables(node.init)[0] + const indexVar = getDeclaredVariables(context, node.init)[0] return indexVar.references.every((reference) => { const id = reference.identifier @@ -262,14 +262,17 @@ function isIndexVarOnlyUsedToGetArrayElements(context, node) { * @param {RuleContext} context - The rule context object. * @param {ASTNode} node - The `for` loop node which is a simple array * traversing. - * @returns {boolean} `true` if the the all references of the index variable are + * @returns {boolean} `true` if all references of the index variable are * used to get array elements. */ function isLengthVarOnlyUsedToTest(context, node) { if (node.init.declarations.length !== 2) { return true } - const lengthVar = context.getDeclaredVariables(node.init.declarations[1])[0] + const lengthVar = getDeclaredVariables( + context, + node.init.declarations[1] + )[0] return lengthVar.references.every( (reference) => @@ -280,12 +283,12 @@ function isLengthVarOnlyUsedToTest(context, node) { /** * Gets the variable object of the given name. * - * @param {RuleContext} context - The rule context to get variables. + * @param {Scope.Scope} startScope - The rule context to get variables. * @param {string} name - The variable name to get. * @returns {escope.Variable|null} The found variable. */ -function getVariableByName(context, name) { - let scope = context.getScope() +function getVariableByName(startScope, name) { + let scope = startScope while (scope != null) { const variable = scope.set.get(name) @@ -334,7 +337,7 @@ function getContextVariable(context, contextNode) { } assert(node.type === "Identifier") - const scope = context.getScope().upper + const scope = getScope(context, contextNode).upper return scope.set.get(node.name) || null } @@ -425,7 +428,7 @@ function applyFixes(originalText, fixes) { * @returns {Fix|null} The created fix object. */ function fixArrayForEach(context, callbackInfo, fixer) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) const funcNode = callbackInfo.node const callNode = funcNode.parent const calleeNode = callNode.callee @@ -474,7 +477,7 @@ function fixArrayForEach(context, callbackInfo, fixer) { * @returns {Fix|null} The created fix object. */ function fixForStatement(context, node, fixer) { - const sourceCode = context.getSourceCode() + const sourceCode = getSourceCode(context) const element = getElementVariableDeclaration(sourceCode, node) // Cannot fix if element name is unknown. @@ -593,7 +596,7 @@ module.exports = { if (thisFuncInfo.canReplaceAllThis) { if (thisFuncInfo.contextVar != null) { const variable = getVariableByName( - context, + getScope(context, node), thisFuncInfo.contextVar.name )