diff --git a/packages/compat/src/fixup-rules.js b/packages/compat/src/fixup-rules.js index 829d54c..30710d5 100644 --- a/packages/compat/src/fixup-rules.js +++ b/packages/compat/src/fixup-rules.js @@ -32,6 +32,7 @@ const removedMethodNames = new Map([ ["getSource", "getText"], ["getSourceLines", "getLines"], ["getAllComments", "getAllComments"], + ["getDeclaredVariables", "getDeclaredVariables"], ["getNodeByRangeIndex", "getNodeByRangeIndex"], ["getCommentsBefore", "getCommentsBefore"], ["getCommentsAfter", "getCommentsAfter"], @@ -125,10 +126,6 @@ export function fixupRule(ruleDefinition) { return sourceCode.getAncestors(currentNode); }, - getDeclaredVariables() { - return sourceCode.getDeclaredVariables(currentNode); - }, - markVariableAsUsed(variable) { sourceCode.markVariableAsUsed(variable, currentNode); }, @@ -159,10 +156,14 @@ export function fixupRule(ruleDefinition) { * methods like `getScope()` need to know the current node. */ for (const [methodName, method] of Object.entries(visitor)) { - // node is the second argument for code path methods + /* + * Node is the second argument to most code path methods, + * and the third argument for onCodePathSegmentLoop. + */ if (methodName.startsWith("on")) { visitor[methodName] = (...args) => { - currentNode = args[1]; + currentNode = + args[methodName === "onCodePathSegmentLoop" ? 2 : 1]; return method.call(visitor, ...args); }; diff --git a/packages/compat/tests/fixup-rules.js b/packages/compat/tests/fixup-rules.js index 432fad8..3fc408b 100644 --- a/packages/compat/tests/fixup-rules.js +++ b/packages/compat/tests/fixup-rules.js @@ -19,11 +19,7 @@ import { Linter } from "eslint"; // Data //----------------------------------------------------------------------------- -const REPLACEMENT_METHODS = [ - "getScope", - "getAncestors", - "getDeclaredVariables", -]; +const REPLACEMENT_METHODS = ["getScope", "getAncestors"]; //----------------------------------------------------------------------------- // Tests @@ -81,8 +77,80 @@ describe("@eslint/backcompat", () => { assert.strictEqual(fixedUpRule, fixedUpRule2); }); + it("should create a rule where getDeclaredVariables() returns the same value as sourceCode.getDeclaredVariables(node)", () => { + const rule = { + create(context) { + const { sourceCode } = context; + + return { + Program(node) { + const result = context.getDeclaredVariables(node); + const expected = + sourceCode.getDeclaredVariables(node); + assert.deepStrictEqual(result, expected); + context.report(node, "Program"); + }, + + FunctionDeclaration(node) { + const result = context.getDeclaredVariables(node); + const expected = + sourceCode.getDeclaredVariables(node); + assert.deepStrictEqual(result, expected); + context.report(node, "FunctionDeclaration"); + }, + + ArrowFunctionExpression(node) { + const result = context.getDeclaredVariables(node); + const expected = + sourceCode.getDeclaredVariables(node); + assert.deepStrictEqual(result, expected); + context.report(node, "ArrowFunctionExpression"); + }, + + Identifier(node) { + const result = context.getDeclaredVariables(node); + const expected = + sourceCode.getDeclaredVariables(node); + assert.deepStrictEqual(result, expected); + context.report(node, "Identifier"); + }, + }; + }, + }; + + const config = { + plugins: { + test: { + rules: { + "test-rule": fixupRule(rule), + }, + }, + }, + rules: { + "test/test-rule": "error", + }, + }; + + const linter = new Linter(); + const code = "var foo = () => 123; function bar() { return 123; }"; + const messages = linter.verify(code, config, { + filename: "test.js", + }); + + assert.deepStrictEqual( + messages.map(message => message.message), + [ + "Program", + "Identifier", + "ArrowFunctionExpression", + "FunctionDeclaration", + "Identifier", + ], + ); + }); + REPLACEMENT_METHODS.forEach(method => { - it(`should create a rule where context.${method}() returns the same value as sourceCode.${method}(node)`, () => { + it(`should create a rule where context.${method}() returns the same value as sourceCode.${method}(node) in visitor methods`, () => { const rule = { create(context) { const { sourceCode } = context; @@ -150,6 +218,103 @@ describe("@eslint/backcompat", () => { ], ); }); + + it(`should create a rule where context.${method}() returns the same value as sourceCode.${method}(node) in code path methods`, () => { + const rule = { + create(context) { + const sourceCode = context.sourceCode; + + return { + onCodePathSegmentLoop( + fromSegment, + toSegment, + node, + ) { + const result = context[method](); + const expected = sourceCode[method](node); + assert.deepStrictEqual(result, expected); + context.report(node, "onCodePathSegmentLoop"); + }, + + onCodePathStart(codePath, node) { + const result = context[method](); + const expected = sourceCode[method](node); + assert.deepStrictEqual(result, expected); + context.report(node, "onCodePathStart"); + }, + + onCodePathEnd(codePath, node) { + const result = context[method](); + const expected = sourceCode[method](node); + assert.deepStrictEqual(result, expected); + context.report(node, "onCodePathEnd"); + }, + + onCodePathSegmentStart(segment, node) { + const result = context[method](); + const expected = sourceCode[method](node); + assert.deepStrictEqual(result, expected); + context.report(node, "onCodePathSegmentStart"); + }, + + onCodePathSegmentEnd(segment, node) { + const result = context[method](); + const expected = sourceCode[method](node); + assert.deepStrictEqual(result, expected); + context.report(node, "onCodePathSegmentEnd"); + }, + }; + }, + }; + + const config = { + plugins: { + test: { + rules: { + "test-rule": fixupRule(rule), + }, + }, + }, + rules: { + "test/test-rule": "error", + }, + }; + + const linter = new Linter(); + const code = + "var foo = () => 123; function bar() { for (const x of y) { foo(); } }"; + const messages = linter.verify(code, config, { + filename: "test.js", + }); + + assert.deepStrictEqual( + messages.map(message => message.message), + [ + "onCodePathStart", + "onCodePathSegmentStart", + "onCodePathSegmentEnd", + "onCodePathEnd", + "onCodePathStart", + "onCodePathSegmentStart", + "onCodePathSegmentEnd", + "onCodePathEnd", + "onCodePathStart", + "onCodePathSegmentStart", + "onCodePathSegmentEnd", + "onCodePathEnd", + "onCodePathSegmentLoop", + "onCodePathSegmentEnd", + "onCodePathSegmentStart", + "onCodePathSegmentEnd", + "onCodePathSegmentStart", + "onCodePathSegmentEnd", + "onCodePathSegmentStart", + "onCodePathSegmentLoop", + "onCodePathSegmentEnd", + "onCodePathSegmentStart", + ], + ); + }); }); });