From b075568b34b45454d655ab1fc91f164a6b59f1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Mon, 11 Dec 2023 11:04:11 +0800 Subject: [PATCH] feat: eslint v9.0.0 compatibility (fixes #143) (#144) refs: https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/ --- lib/rules/callback-return.js | 2 +- lib/rules/exports-style.js | 16 ++++++++-------- lib/rules/file-extension-in-import.js | 2 +- lib/rules/global-require.js | 11 ++++++++--- lib/rules/handle-callback-err.js | 3 ++- lib/rules/no-deprecated-api.js | 7 +++++-- lib/rules/no-exports-assign.js | 5 ++++- lib/rules/no-extraneous-import.js | 2 +- lib/rules/no-extraneous-require.js | 2 +- lib/rules/no-hide-core-modules.js | 5 +++-- lib/rules/no-missing-import.js | 2 +- lib/rules/no-missing-require.js | 2 +- lib/rules/no-path-concat.js | 6 ++++-- lib/rules/no-unpublished-bin.js | 2 +- lib/rules/no-unpublished-import.js | 2 +- lib/rules/no-unpublished-require.js | 2 +- lib/rules/no-unsupported-features.js | 15 ++++++++++----- lib/rules/no-unsupported-features/es-syntax.js | 4 +++- lib/rules/prefer-promises/dns.js | 5 +++-- lib/rules/prefer-promises/fs.js | 5 +++-- lib/rules/shebang.js | 4 ++-- lib/util/check-prefer-global.js | 10 ++++++++-- lib/util/check-unsupported-builtins.js | 4 +++- lib/util/get-configured-node-version.js | 2 +- lib/util/get-typescript-extension-map.js | 16 ++++++---------- lib/util/is-typescript.js | 4 +++- lib/util/visit-import.js | 4 +++- lib/util/visit-require.js | 11 ++++++++--- package.json | 6 +++--- 29 files changed, 99 insertions(+), 62 deletions(-) diff --git a/lib/rules/callback-return.js b/lib/rules/callback-return.js index 30f33f74..1b661532 100644 --- a/lib/rules/callback-return.js +++ b/lib/rules/callback-return.js @@ -26,7 +26,7 @@ module.exports = { create(context) { const callbacks = context.options[0] || ["callback", "cb", "next"] - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 /** * Find the closest parent matching a list of types. diff --git a/lib/rules/exports-style.js b/lib/rules/exports-style.js index c9b87c38..2ddd6ebc 100644 --- a/lib/rules/exports-style.js +++ b/lib/rules/exports-style.js @@ -258,7 +258,7 @@ module.exports = { const batchAssignAllowed = Boolean( context.options[1] != null && context.options[1].allowBatchAssign ) - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 /** * Gets the location info of reports. @@ -286,8 +286,7 @@ module.exports = { * * @returns {void} */ - function enforceModuleExports() { - const globalScope = context.getScope() + function enforceModuleExports(globalScope) { const exportsNodes = getExportsNodes(globalScope) const assignList = batchAssignAllowed ? createAssignmentList(getModuleExportsNodes(globalScope)) @@ -317,8 +316,7 @@ module.exports = { * * @returns {void} */ - function enforceExports() { - const globalScope = context.getScope() + function enforceExports(globalScope) { const exportsNodes = getExportsNodes(globalScope) const moduleExportsNodes = getModuleExportsNodes(globalScope) const assignList = batchAssignAllowed @@ -370,13 +368,15 @@ module.exports = { } return { - "Program:exit"() { + "Program:exit"(node) { + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + switch (mode) { case "module.exports": - enforceModuleExports() + enforceModuleExports(scope) break case "exports": - enforceExports() + enforceExports(scope) break // no default diff --git a/lib/rules/file-extension-in-import.js b/lib/rules/file-extension-in-import.js index a6666f67..80804029 100644 --- a/lib/rules/file-extension-in-import.js +++ b/lib/rules/file-extension-in-import.js @@ -57,7 +57,7 @@ module.exports = { type: "suggestion", }, create(context) { - if (context.getFilename().startsWith("<")) { + if ((context.filename ?? context.getFilename()).startsWith("<")) { return {} } const defaultStyle = context.options[0] || "always" diff --git a/lib/rules/global-require.js b/lib/rules/global-require.js index 70584771..d993e595 100644 --- a/lib/rules/global-require.js +++ b/lib/rules/global-require.js @@ -64,16 +64,21 @@ module.exports = { }, create(context) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + return { CallExpression(node) { - const currentScope = context.getScope() + const currentScope = + sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 if ( node.callee.name === "require" && !isShadowed(currentScope, node.callee) ) { - const isGoodRequire = context - .getAncestors() + const isGoodRequire = ( + sourceCode.getAncestors?.(node) ?? + context.getAncestors() + ) // TODO: remove context.getAncestors() when dropping support for ESLint < v9 .every( parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1 diff --git a/lib/rules/handle-callback-err.js b/lib/rules/handle-callback-err.js index 6abdba7a..7973a51c 100644 --- a/lib/rules/handle-callback-err.js +++ b/lib/rules/handle-callback-err.js @@ -24,6 +24,7 @@ module.exports = { }, create(context) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 const errorArgument = context.options[0] || "err" /** @@ -69,7 +70,7 @@ module.exports = { * @returns {void} */ function checkForError(node) { - const scope = context.getScope() + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 const parameters = getParameters(scope) const firstParameter = parameters[0] diff --git a/lib/rules/no-deprecated-api.js b/lib/rules/no-deprecated-api.js index 3962be6f..54367a71 100644 --- a/lib/rules/no-deprecated-api.js +++ b/lib/rules/no-deprecated-api.js @@ -756,9 +756,12 @@ module.exports = { }) } + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 return { - "Program:exit"() { - const tracker = new ReferenceTracker(context.getScope(), { + "Program:exit"(node) { + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + + const tracker = new ReferenceTracker(scope, { mode: "legacy", }) diff --git a/lib/rules/no-exports-assign.js b/lib/rules/no-exports-assign.js index 29bc9c42..12128011 100644 --- a/lib/rules/no-exports-assign.js +++ b/lib/rules/no-exports-assign.js @@ -50,9 +50,12 @@ module.exports = { type: "problem", }, create(context) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + return { AssignmentExpression(node) { - const scope = context.getScope() + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + if ( !isExports(node.left, scope) || // module.exports = exports = {} diff --git a/lib/rules/no-extraneous-import.js b/lib/rules/no-extraneous-import.js index c84c9df3..3514b204 100644 --- a/lib/rules/no-extraneous-import.js +++ b/lib/rules/no-extraneous-import.js @@ -34,7 +34,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/rules/no-extraneous-require.js b/lib/rules/no-extraneous-require.js index 7d3321bd..20d6d52f 100644 --- a/lib/rules/no-extraneous-require.js +++ b/lib/rules/no-extraneous-require.js @@ -36,7 +36,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/rules/no-hide-core-modules.js b/lib/rules/no-hide-core-modules.js index a854a479..6c66b1e7 100644 --- a/lib/rules/no-hide-core-modules.js +++ b/lib/rules/no-hide-core-modules.js @@ -85,10 +85,11 @@ module.exports = { }, }, create(context) { - if (context.getFilename() === "") { + const filename = context.filename ?? context.getFilename() + if (filename === "") { return {} } - const filePath = path.resolve(context.getFilename()) + const filePath = path.resolve(filename) const dirPath = path.dirname(filePath) const packageJson = getPackageJson(filePath) const deps = new Set( diff --git a/lib/rules/no-missing-import.js b/lib/rules/no-missing-import.js index 00e4d2b2..521ca57b 100644 --- a/lib/rules/no-missing-import.js +++ b/lib/rules/no-missing-import.js @@ -36,7 +36,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/rules/no-missing-require.js b/lib/rules/no-missing-require.js index 1125767c..032e41de 100644 --- a/lib/rules/no-missing-require.js +++ b/lib/rules/no-missing-require.js @@ -38,7 +38,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/rules/no-path-concat.js b/lib/rules/no-path-concat.js index f0557336..0c1756be 100644 --- a/lib/rules/no-path-concat.js +++ b/lib/rules/no-path-concat.js @@ -179,8 +179,10 @@ module.exports = { create(context) { return { - "Program:exit"() { - const globalScope = context.getScope() + "Program:exit"(node) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const globalScope = + sourceCode.getScope?.(node) ?? context.getScope() const tracker = new ReferenceTracker(globalScope) const sepNodes = new Set() diff --git a/lib/rules/no-unpublished-bin.js b/lib/rules/no-unpublished-bin.js index dd62181f..213cb9cc 100644 --- a/lib/rules/no-unpublished-bin.js +++ b/lib/rules/no-unpublished-bin.js @@ -56,7 +56,7 @@ module.exports = { return { Program(node) { // Check file path. - let rawFilePath = context.getFilename() + let rawFilePath = context.filename ?? context.getFilename() if (rawFilePath === "") { return } diff --git a/lib/rules/no-unpublished-import.js b/lib/rules/no-unpublished-import.js index 7fd34bfa..1049d3a7 100644 --- a/lib/rules/no-unpublished-import.js +++ b/lib/rules/no-unpublished-import.js @@ -35,7 +35,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() const options = context.options[0] || {} const ignoreTypeImport = options.ignoreTypeImport === void 0 diff --git a/lib/rules/no-unpublished-require.js b/lib/rules/no-unpublished-require.js index 7e804765..efd63145 100644 --- a/lib/rules/no-unpublished-require.js +++ b/lib/rules/no-unpublished-require.js @@ -36,7 +36,7 @@ module.exports = { messages, }, create(context) { - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/rules/no-unsupported-features.js b/lib/rules/no-unsupported-features.js index 874f4ac0..810945ef 100644 --- a/lib/rules/no-unsupported-features.js +++ b/lib/rules/no-unsupported-features.js @@ -1085,10 +1085,10 @@ module.exports = { }, }, create(context) { - const sourceCode = context.getSourceCode() + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 const supportInfo = parseOptions( context.options[0], - getDefaultVersion(context.getFilename()) + getDefaultVersion(context.filename ?? context.getFilename()) ) /** @@ -1098,7 +1098,8 @@ module.exports = { * @returns {void} */ function* getReferences(names) { - const globalScope = context.getScope() + const globalScope = + sourceCode.getScope?.(sourceCode.ast) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 for (const name of names) { const variable = globalScope.set.get(name) @@ -1159,6 +1160,8 @@ module.exports = { * @returns {void} */ function report(node, key) { + const globalScope = + sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 const version = supportInfo.version const feature = supportInfo.features[key] if (feature.supported) { @@ -1175,7 +1178,7 @@ module.exports = { version, }, }) - } else if (!normalizeScope(context.getScope(), node).isStrict) { + } else if (!normalizeScope(globalScope, node).isStrict) { context.report({ node, messageId: "unsupported", @@ -1331,7 +1334,9 @@ module.exports = { }, FunctionDeclaration(node) { - const scope = context.getScope().upper + const scope = ( + sourceCode.getScope?.(node) ?? context.getScope() + ).upper //TODO: remove context.getScope() when dropping support for ESLint < v9 if (!TOPLEVEL_SCOPE_TYPE.test(scope.type)) { report(node, "blockScopedFunctions") } diff --git a/lib/rules/no-unsupported-features/es-syntax.js b/lib/rules/no-unsupported-features/es-syntax.js index f6a0a2db..cee0c4b5 100644 --- a/lib/rules/no-unsupported-features/es-syntax.js +++ b/lib/rules/no-unsupported-features/es-syntax.js @@ -443,7 +443,9 @@ function normalizeScope(initialScope, node) { function defineVisitor(context, options) { const testInfoPrototype = { get isStrict() { - return normalizeScope(context.getScope(), this.node).isStrict + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = sourceCode.getScope?.(this.node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + return normalizeScope(scope, this.node).isStrict }, } diff --git a/lib/rules/prefer-promises/dns.js b/lib/rules/prefer-promises/dns.js index 10bfd687..4062a5a5 100644 --- a/lib/rules/prefer-promises/dns.js +++ b/lib/rules/prefer-promises/dns.js @@ -52,8 +52,9 @@ module.exports = { create(context) { return { - "Program:exit"() { - const scope = context.getScope() + "Program:exit"(node) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 const tracker = new ReferenceTracker(scope, { mode: "legacy" }) const references = [ ...tracker.iterateCjsReferences(trackMap), diff --git a/lib/rules/prefer-promises/fs.js b/lib/rules/prefer-promises/fs.js index c7a85f2b..f0404348 100644 --- a/lib/rules/prefer-promises/fs.js +++ b/lib/rules/prefer-promises/fs.js @@ -53,8 +53,9 @@ module.exports = { create(context) { return { - "Program:exit"() { - const scope = context.getScope() + "Program:exit"(node) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 const tracker = new ReferenceTracker(scope, { mode: "legacy" }) const references = [ ...tracker.iterateCjsReferences(trackMap), diff --git a/lib/rules/shebang.js b/lib/rules/shebang.js index 01f228bb..179f347c 100644 --- a/lib/rules/shebang.js +++ b/lib/rules/shebang.js @@ -94,8 +94,8 @@ module.exports = { }, }, create(context) { - const sourceCode = context.getSourceCode() - let filePath = context.getFilename() + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + let filePath = context.filename ?? context.getFilename() if (filePath === "") { return {} } diff --git a/lib/util/check-prefer-global.js b/lib/util/check-prefer-global.js index 7eaf442a..96aa58a0 100644 --- a/lib/util/check-prefer-global.js +++ b/lib/util/check-prefer-global.js @@ -31,7 +31,10 @@ class Verifier { */ verifyToPreferGlobals() { const { context, trackMap } = this - const tracker = new ReferenceTracker(context.getScope(), { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = + sourceCode.getScope?.(sourceCode.ast) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + const tracker = new ReferenceTracker(scope, { mode: "legacy", }) @@ -51,7 +54,10 @@ class Verifier { */ verifyToPreferModules() { const { context, trackMap } = this - const tracker = new ReferenceTracker(context.getScope()) + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = + sourceCode.getScope?.(sourceCode.ast) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + const tracker = new ReferenceTracker(scope) for (const { node } of tracker.iterateGlobalReferences( trackMap.globals diff --git a/lib/util/check-unsupported-builtins.js b/lib/util/check-unsupported-builtins.js index 32a14e8e..ffd6b1d7 100644 --- a/lib/util/check-unsupported-builtins.js +++ b/lib/util/check-unsupported-builtins.js @@ -85,7 +85,9 @@ module.exports.checkUnsupportedBuiltins = function checkUnsupportedBuiltins( trackMap ) { const options = parseOptions(context) - const tracker = new ReferenceTracker(context.getScope(), { mode: "legacy" }) + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const scope = sourceCode.getScope?.(sourceCode.ast) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + const tracker = new ReferenceTracker(scope, { mode: "legacy" }) const references = [ ...tracker.iterateCjsReferences(trackMap.modules || {}), ...tracker.iterateEsmReferences(trackMap.modules || {}), diff --git a/lib/util/get-configured-node-version.js b/lib/util/get-configured-node-version.js index ed235fa7..b9e0750d 100644 --- a/lib/util/get-configured-node-version.js +++ b/lib/util/get-configured-node-version.js @@ -47,7 +47,7 @@ module.exports = function getConfiguredNodeVersion(context) { const version = get(context.options && context.options[0]) || get(context.settings && (context.settings.n || context.settings.node)) - const filePath = context.getFilename() + const filePath = context.filename ?? context.getFilename() return ( getSemverRange(version) || diff --git a/lib/util/get-typescript-extension-map.js b/lib/util/get-typescript-extension-map.js index ccdb2feb..034d6fab 100644 --- a/lib/util/get-typescript-extension-map.js +++ b/lib/util/get-typescript-extension-map.js @@ -112,19 +112,15 @@ function getFromTSConfigFromFile(filename) { * @returns {string[]} A list of extensions. */ module.exports = function getTypescriptExtensionMap(context) { + const filename = + context.physicalFilename ?? + context.getPhysicalFilename?.() ?? + context.filename ?? + context.getFilename?.() // TODO: remove context.get(PhysicalFilename|Filename) when dropping eslint < v10 return ( get(context.options?.[0]) || get(context.settings?.n ?? context.settings?.node) || - getFromTSConfigFromFile( - // eslint ^8 - context.physicalFilename ?? - // eslint ^7.28 (deprecated ^8) - context.getPhysicalFilename?.() ?? - // eslint ^8 (if physicalFilename undefined) - context.filename ?? - // eslint ^7 (deprecated ^8) - context.getFilename?.() - ) || + getFromTSConfigFromFile(filename) || PRESERVE_MAPPING ) } diff --git a/lib/util/is-typescript.js b/lib/util/is-typescript.js index 479397cc..19d23347 100644 --- a/lib/util/is-typescript.js +++ b/lib/util/is-typescript.js @@ -11,6 +11,8 @@ const typescriptExtensions = [".ts", ".tsx", ".cts", ".mts"] * @returns {boolean} */ module.exports = function isTypescript(context) { - const sourceFileExt = path.extname(context.getPhysicalFilename()) + const sourceFileExt = path.extname( + context.physicalFilename ?? context.getPhysicalFilename() + ) return typescriptExtensions.includes(sourceFileExt) } diff --git a/lib/util/visit-import.js b/lib/util/visit-import.js index 2402651f..f44149be 100644 --- a/lib/util/visit-import.js +++ b/lib/util/visit-import.js @@ -30,7 +30,9 @@ module.exports = function visitImport( callback ) { const targets = [] - const basedir = path.dirname(path.resolve(context.getFilename())) + const basedir = path.dirname( + path.resolve(context.filename ?? context.getFilename()) + ) const paths = getResolvePaths(context, optionIndex) const extensions = getTryExtensions(context, optionIndex) const options = { basedir, paths, extensions } diff --git a/lib/util/visit-require.js b/lib/util/visit-require.js index fcdeb0b3..c7692b9c 100644 --- a/lib/util/visit-require.js +++ b/lib/util/visit-require.js @@ -33,14 +33,19 @@ module.exports = function visitRequire( callback ) { const targets = [] - const basedir = path.dirname(path.resolve(context.getFilename())) + const basedir = path.dirname( + path.resolve(context.filename ?? context.getFilename()) + ) const paths = getResolvePaths(context) const extensions = getTryExtensions(context) const options = { basedir, paths, extensions } return { - "Program:exit"() { - const tracker = new ReferenceTracker(context.getScope()) + "Program:exit"(node) { + const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 + const tracker = new ReferenceTracker( + sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 + ) const references = tracker.iterateGlobalReferences({ require: { [CALL]: true, diff --git a/package.json b/package.json index f0ecff97..641e25ea 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.1.0", + "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", "ignore": "^5.2.4", "is-builtin-module": "^3.2.1", @@ -27,10 +27,10 @@ }, "devDependencies": { "@eslint/js": "^8.43.0", - "@types/eslint": "^8.44.2", + "@types/eslint": "^8.44.6", "@typescript-eslint/parser": "^5.60.0", "esbuild": "^0.18.7", - "eslint": "^8.43.0", + "eslint": "^8.53.0", "eslint-config-prettier": "^8.8.0", "eslint-doc-generator": "^1.4.3", "eslint-plugin-eslint-plugin": "^5.1.0",