From 13d0bd371eb8eb4aa1601c8727212a62ab923d0e Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 24 Jul 2024 07:02:07 -0400 Subject: [PATCH] feat: Add and use SourceCode#getLoc/getRange (#18703) * feat: Add and use SourceCode#getLoc/getRange * Update report-translator * Update rule-fixer * Upgrade @eslint/json * Fix FixTracker tests --- lib/languages/js/source-code/source-code.js | 19 ++++ lib/linter/apply-disable-directives.js | 36 +++++--- lib/linter/linter.js | 49 ++++++---- lib/linter/report-translator.js | 20 ++-- lib/linter/rule-fixer.js | 53 ++++++++--- package.json | 2 +- tests/lib/linter/apply-disable-directives.js | 97 ++++++++++++++++++++ tests/lib/linter/rule-fixer.js | 17 +++- tests/lib/rules/utils/fix-tracker.js | 9 +- 9 files changed, 244 insertions(+), 58 deletions(-) diff --git a/lib/languages/js/source-code/source-code.js b/lib/languages/js/source-code/source-code.js index 7baf2ea26c86..f672fc883156 100644 --- a/lib/languages/js/source-code/source-code.js +++ b/lib/languages/js/source-code/source-code.js @@ -916,6 +916,25 @@ class SourceCode extends TokenStore { return ancestorsStartingAtParent.reverse(); } + + /** + * Returns the locatin of the given node or token. + * @param {ASTNode|Token} nodeOrToken The node or token to get the location of. + * @returns {SourceLocation} The location of the node or token. + */ + getLoc(nodeOrToken) { + return nodeOrToken.loc; + } + + /** + * Returns the range of the given node or token. + * @param {ASTNode|Token} nodeOrToken The node or token to get the range of. + * @returns {[number, number]} The range of the node or token. + */ + getRange(nodeOrToken) { + return nodeOrToken.range; + } + /* eslint-enable class-methods-use-this -- node is owned by SourceCode */ /** diff --git a/lib/linter/apply-disable-directives.js b/lib/linter/apply-disable-directives.js index 723bcf55015c..ba7e58906a88 100644 --- a/lib/linter/apply-disable-directives.js +++ b/lib/linter/apply-disable-directives.js @@ -61,15 +61,18 @@ function groupByParentDirective(directives) { * Creates removal details for a set of directives within the same comment. * @param {Directive[]} directives Unused directives to be removed. * @param {Token} node The backing Comment token. + * @param {SourceCode} sourceCode The source code object for the file being linted. * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. */ -function createIndividualDirectivesRemoval(directives, node) { +function createIndividualDirectivesRemoval(directives, node, sourceCode) { + + const range = sourceCode.getRange(node); /* * `node.value` starts right after `//` or `/*`. * All calculated offsets will be relative to this index. */ - const commentValueStart = node.range[0] + "//".length; + const commentValueStart = range[0] + "//".length; // Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`) const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length; @@ -165,10 +168,11 @@ function createIndividualDirectivesRemoval(directives, node) { * Creates a description of deleting an entire unused disable directive. * @param {Directive[]} directives Unused directives to be removed. * @param {Token} node The backing Comment token. + * @param {SourceCode} sourceCode The source code object for the file being linted. * @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem. */ -function createDirectiveRemoval(directives, node) { - const { range } = node; +function createDirectiveRemoval(directives, node, sourceCode) { + const range = sourceCode.getRange(node); const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`); return { @@ -186,9 +190,10 @@ function createDirectiveRemoval(directives, node) { /** * Parses details from directives to create output Problems. * @param {Iterable} allDirectives Unused directives to be removed. + * @param {SourceCode} sourceCode The source code object for the file being linted. * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. */ -function processUnusedDirectives(allDirectives) { +function processUnusedDirectives(allDirectives, sourceCode) { const directiveGroups = groupByParentDirective(allDirectives); return directiveGroups.flatMap( @@ -201,8 +206,8 @@ function processUnusedDirectives(allDirectives) { } return remainingRuleIds.size - ? createIndividualDirectivesRemoval(directives, parentDirective.node) - : [createDirectiveRemoval(directives, parentDirective.node)]; + ? createIndividualDirectivesRemoval(directives, parentDirective.node, sourceCode) + : [createDirectiveRemoval(directives, parentDirective.node, sourceCode)]; } ); } @@ -309,6 +314,7 @@ function collectUsedEnableDirectives(directives) { function applyDirectives(options) { const problems = []; const usedDisableDirectives = new Set(); + const { sourceCode } = options; for (const problem of options.problems) { let disableDirectivesForProblem = []; @@ -370,8 +376,8 @@ function applyDirectives(options) { } } - const processed = processUnusedDirectives(unusedDisableDirectivesToReport) - .concat(processUnusedDirectives(unusedEnableDirectivesToReport)); + const processed = processUnusedDirectives(unusedDisableDirectivesToReport, sourceCode) + .concat(processUnusedDirectives(unusedEnableDirectivesToReport, sourceCode)); const columnOffset = options.language.columnStart === 1 ? 0 : 1; const lineOffset = options.language.lineStart === 1 ? 0 : 1; @@ -390,11 +396,14 @@ function applyDirectives(options) { ? `Unused eslint-disable directive (no problems were reported from ${description}).` : "Unused eslint-disable directive (no problems were reported)."; } + + const loc = sourceCode.getLoc(parentDirective.node); + return { ruleId: null, message, - line: type === "disable-next-line" ? parentDirective.node.loc.start.line + lineOffset : line, - column: type === "disable-next-line" ? parentDirective.node.loc.start.column + columnOffset : column, + line: type === "disable-next-line" ? loc.start.line + lineOffset : line, + column: type === "disable-next-line" ? loc.start.column + columnOffset : column, severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2, nodeType: null, ...options.disableFixes ? {} : { fix } @@ -409,6 +418,7 @@ function applyDirectives(options) { * of reported problems, adds the suppression information to the problems. * @param {Object} options Information about directives and problems * @param {Language} options.language The language being linted. + * @param {SourceCode} options.sourceCode The source code object for the file being linted. * @param {{ * type: ("disable"|"enable"|"disable-line"|"disable-next-line"), * ruleId: (string|null), @@ -427,7 +437,7 @@ function applyDirectives(options) { * @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]} * An object with a list of reported problems, the suppressed of which contain the suppression information. */ -module.exports = ({ language, directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => { +module.exports = ({ language, sourceCode, directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => { const blockDirectives = directives .filter(directive => directive.type === "disable" || directive.type === "enable") .map(directive => Object.assign({}, directive, { unprocessedDirective: directive })) @@ -477,6 +487,7 @@ module.exports = ({ language, directives, disableFixes, problems, configuredRule const blockDirectivesResult = applyDirectives({ language, + sourceCode, problems, directives: blockDirectives, disableFixes, @@ -485,6 +496,7 @@ module.exports = ({ language, directives, disableFixes, problems, configuredRule }); const lineDirectivesResult = applyDirectives({ language, + sourceCode, problems: blockDirectivesResult.problems, directives: lineDirectives, disableFixes, diff --git a/lib/linter/linter.js b/lib/linter/linter.js index ac3c5eeaed05..e5d4d2c789c5 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -323,9 +323,10 @@ function createLintingProblem(options) { * @param {ASTNode|token} options.node The Comment node/token. * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules * @param {Language} language The language to use to adjust the location information. + * @param {SourceCode} sourceCode The SourceCode object to get comments from. * @returns {Object} Directives and problems from the comment */ -function createDisableDirectives({ type, value, justification, node }, ruleMapper, language) { +function createDisableDirectives({ type, value, justification, node }, ruleMapper, language, sourceCode) { const ruleIds = Object.keys(commentParser.parseListConfig(value)); const directiveRules = ruleIds.length ? ruleIds : [null]; const result = { @@ -336,11 +337,15 @@ function createDisableDirectives({ type, value, justification, node }, ruleMappe for (const ruleId of directiveRules) { + const loc = sourceCode.getLoc(node); + // push to directives, if the rule is defined(including null, e.g. /*eslint enable*/) if (ruleId === null || !!ruleMapper(ruleId)) { + + if (type === "disable-next-line") { const { line, column } = updateLocationInformation( - node.loc.end, + loc.end, language ); @@ -354,7 +359,7 @@ function createDisableDirectives({ type, value, justification, node }, ruleMappe }); } else { const { line, column } = updateLocationInformation( - node.loc.start, + loc.start, language ); @@ -368,7 +373,7 @@ function createDisableDirectives({ type, value, justification, node }, ruleMappe }); } } else { - result.directiveProblems.push(createLintingProblem({ ruleId, loc: node.loc, language })); + result.directiveProblems.push(createLintingProblem({ ruleId, loc, language })); } } return result; @@ -410,25 +415,27 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) return; } + const loc = sourceCode.getLoc(comment); + if (warnInlineConfig) { const kind = comment.type === "Block" ? `/*${directiveText}*/` : `//${directiveText}`; problems.push(createLintingProblem({ ruleId: null, message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`, - loc: comment.loc, + loc, severity: 1 })); return; } - if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) { + if (directiveText === "eslint-disable-line" && loc.start.line !== loc.end.line) { const message = `${directiveText} comment should not span multiple lines.`; problems.push(createLintingProblem({ ruleId: null, message, - loc: comment.loc + loc })); return; } @@ -446,7 +453,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) value: directiveValue, justification: justificationPart, node: comment - }, ruleMapper, jslang); + }, ruleMapper, jslang, sourceCode); disableDirectives.push(...directives); problems.push(...directiveProblems); @@ -467,7 +474,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) } catch (err) { problems.push(createLintingProblem({ ruleId: null, - loc: comment.loc, + loc, message: err.message })); continue; @@ -494,14 +501,14 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) const ruleValue = parseResult.config[name]; if (!rule) { - problems.push(createLintingProblem({ ruleId: name, loc: comment.loc })); + problems.push(createLintingProblem({ ruleId: name, loc })); return; } if (Object.hasOwn(configuredRules, name)) { problems.push(createLintingProblem({ message: `Rule "${name}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`, - loc: comment.loc + loc })); return; } @@ -563,7 +570,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) problems.push(createLintingProblem({ ruleId: name, message: err.message, - loc: comment.loc + loc })); // do not apply the config, if found invalid options. @@ -575,7 +582,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) } else { const problem = createLintingProblem({ ruleId: null, - loc: comment.loc, + loc, message: parseResult.error.message }); @@ -623,7 +630,7 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper, language) { }))); directivesSources.forEach(directive => { - const { directives, directiveProblems } = createDisableDirectives(directive, ruleMapper, language); + const { directives, directiveProblems } = createDisableDirectives(directive, ruleMapper, language, sourceCode); disableDirectives.push(...directives); problems.push(...directiveProblems); @@ -1473,7 +1480,7 @@ class Linter { debug("An error occurred while traversing"); debug("Filename:", options.filename); if (err.currentNode) { - const { line } = err.currentNode.loc.start; + const { line } = sourceCode.getLoc(err.currentNode).start; debug("Line:", line); err.message += `:${line}`; @@ -1491,6 +1498,7 @@ class Linter { return applyDisableDirectives({ language: jslang, + sourceCode, directives: commentDirectives.disableDirectives, disableFixes: options.disableFixes, problems: lintingProblems @@ -1770,10 +1778,14 @@ class Linter { if (options.warnInlineConfig) { if (sourceCode.getInlineConfigNodes) { sourceCode.getInlineConfigNodes().forEach(node => { + + const loc = sourceCode.getLoc(node); + const range = sourceCode.getRange(node); + inlineConfigProblems.push(createLintingProblem({ ruleId: null, - message: `'${sourceCode.text.slice(node.range[0], node.range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`, - loc: node.loc, + message: `'${sourceCode.text.slice(range[0], range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`, + loc, severity: 1, language: config.language })); @@ -1953,7 +1965,7 @@ class Linter { debug("An error occurred while traversing"); debug("Filename:", options.filename); if (err.currentNode) { - const { line } = err.currentNode.loc.start; + const { line } = sourceCode.getLoc(err.currentNode).start; debug("Line:", line); err.message += `:${line}`; @@ -1972,6 +1984,7 @@ class Linter { return applyDisableDirectives({ language: config.language, + sourceCode, directives: commentDirectives.disableDirectives, disableFixes: options.disableFixes, problems: lintingProblems diff --git a/lib/linter/report-translator.js b/lib/linter/report-translator.js index 88355ceb6bf7..0b81d783040b 100644 --- a/lib/linter/report-translator.js +++ b/lib/linter/report-translator.js @@ -10,7 +10,7 @@ //------------------------------------------------------------------------------ const assert = require("node:assert"); -const ruleFixer = require("./rule-fixer"); +const { RuleFixer } = require("./rule-fixer"); const { interpolate } = require("./interpolate"); //------------------------------------------------------------------------------ @@ -91,13 +91,10 @@ function assertValidNodeInfo(descriptor) { * from the `node` of the original descriptor, or infers the `start` from the `loc` of the original descriptor. */ function normalizeReportLoc(descriptor) { - if (descriptor.loc) { - if (descriptor.loc.start) { - return descriptor.loc; - } - return { start: descriptor.loc, end: null }; + if (descriptor.loc.start) { + return descriptor.loc; } - return descriptor.node.loc; + return { start: descriptor.loc, end: null }; } /** @@ -190,6 +187,8 @@ function normalizeFixes(descriptor, sourceCode) { return null; } + const ruleFixer = new RuleFixer({ sourceCode }); + // @type {null | Fix | Fix[] | IterableIterator} const fix = descriptor.fix(ruleFixer); @@ -335,6 +334,7 @@ module.exports = function createReportTranslator(metadata) { return (...args) => { const descriptor = normalizeMultiArgReportCall(...args); const messages = metadata.messageIds; + const { sourceCode } = metadata; assertValidNodeInfo(descriptor); @@ -367,9 +367,9 @@ module.exports = function createReportTranslator(metadata) { node: descriptor.node, message: interpolate(computedMessage, descriptor.data), messageId: descriptor.messageId, - loc: normalizeReportLoc(descriptor), - fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode), - suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, metadata.sourceCode, messages), + loc: descriptor.loc ? normalizeReportLoc(descriptor) : sourceCode.getLoc(descriptor.node), + fix: metadata.disableFixes ? null : normalizeFixes(descriptor, sourceCode), + suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, sourceCode, messages), language: metadata.language }); }; diff --git a/lib/linter/rule-fixer.js b/lib/linter/rule-fixer.js index bdd80d13b162..f9c45feb5f3e 100644 --- a/lib/linter/rule-fixer.js +++ b/lib/linter/rule-fixer.js @@ -4,6 +4,8 @@ */ "use strict"; +/* eslint class-methods-use-this: off -- Methods desired on instance */ + //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ @@ -35,8 +37,22 @@ function insertTextAt(index, text) { /** * Creates code fixing commands for rules. */ +class RuleFixer { -const ruleFixer = Object.freeze({ + /** + * The source code object representing the text to be fixed. + * @type {SourceCode} + */ + #sourceCode; + + /** + * Creates a new instance. + * @param {Object} options The options for the fixer. + * @param {SourceCode} options.sourceCode The source code object representing the text to be fixed. + */ + constructor({ sourceCode }) { + this.#sourceCode = sourceCode; + } /** * Creates a fix command that inserts text after the given node or token. @@ -46,8 +62,10 @@ const ruleFixer = Object.freeze({ * @returns {Object} The fix command. */ insertTextAfter(nodeOrToken, text) { - return this.insertTextAfterRange(nodeOrToken.range, text); - }, + const range = this.#sourceCode.getRange(nodeOrToken); + + return this.insertTextAfterRange(range, text); + } /** * Creates a fix command that inserts text after the specified range in the source text. @@ -59,7 +77,7 @@ const ruleFixer = Object.freeze({ */ insertTextAfterRange(range, text) { return insertTextAt(range[1], text); - }, + } /** * Creates a fix command that inserts text before the given node or token. @@ -69,8 +87,10 @@ const ruleFixer = Object.freeze({ * @returns {Object} The fix command. */ insertTextBefore(nodeOrToken, text) { - return this.insertTextBeforeRange(nodeOrToken.range, text); - }, + const range = this.#sourceCode.getRange(nodeOrToken); + + return this.insertTextBeforeRange(range, text); + } /** * Creates a fix command that inserts text before the specified range in the source text. @@ -82,7 +102,7 @@ const ruleFixer = Object.freeze({ */ insertTextBeforeRange(range, text) { return insertTextAt(range[0], text); - }, + } /** * Creates a fix command that replaces text at the node or token. @@ -92,8 +112,10 @@ const ruleFixer = Object.freeze({ * @returns {Object} The fix command. */ replaceText(nodeOrToken, text) { - return this.replaceTextRange(nodeOrToken.range, text); - }, + const range = this.#sourceCode.getRange(nodeOrToken); + + return this.replaceTextRange(range, text); + } /** * Creates a fix command that replaces text at the specified range in the source text. @@ -108,7 +130,7 @@ const ruleFixer = Object.freeze({ range, text }; - }, + } /** * Creates a fix command that removes the node or token from the source. @@ -117,8 +139,10 @@ const ruleFixer = Object.freeze({ * @returns {Object} The fix command. */ remove(nodeOrToken) { - return this.removeRange(nodeOrToken.range); - }, + const range = this.#sourceCode.getRange(nodeOrToken); + + return this.removeRange(range); + } /** * Creates a fix command that removes the specified range of text from the source. @@ -133,8 +157,7 @@ const ruleFixer = Object.freeze({ text: "" }; } - -}); +} -module.exports = ruleFixer; +module.exports = { RuleFixer }; diff --git a/package.json b/package.json index 5dbef3e66c9e..98b520c15a3f 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "@babel/core": "^7.4.3", "@babel/preset-env": "^7.4.3", "@eslint/core": "^0.1.0", - "@eslint/json": "^0.1.0", + "@eslint/json": "^0.2.0", "@types/estree": "^1.0.5", "@types/node": "^20.11.5", "@wdio/browser-runner": "^8.38.3", diff --git a/tests/lib/linter/apply-disable-directives.js b/tests/lib/linter/apply-disable-directives.js index 0dfec427ebe7..7c562ebeac48 100644 --- a/tests/lib/linter/apply-disable-directives.js +++ b/tests/lib/linter/apply-disable-directives.js @@ -44,6 +44,15 @@ function createParentDirective(range, value, ruleIds = []) { }; } +const sourceCode = { + getRange(node) { + return node.range; + }, + getLoc(node) { + return node.loc; + } +}; + //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ @@ -54,6 +63,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 7]), type: "disable", line: 1, column: 8, ruleId: null, justification: "justification" }], problems: [{ line: 1, column: 7, ruleId: "foo" }] }), @@ -65,6 +75,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([21, 27]), type: "disable", line: 2, column: 1, ruleId: null, justification: "justification" }], problems: [{ line: 1, column: 10, ruleId: "foo" }] }), @@ -76,6 +87,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 8, ruleId: null, justification: "justification" }], problems: [{ line: 1, column: 8, ruleId: null }] }), @@ -87,6 +99,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 8, ruleId: null, justification: "justification" }], problems: [{ line: 1, column: 10, ruleId: "foo" }] }), @@ -98,6 +111,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 8, ruleId: null, justification: "justification" }], problems: [{ line: 2, column: 3, ruleId: "foo" }] }), @@ -111,6 +125,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 8, ruleId: "foo", justification: "justification" }], problems: [{ line: 2, column: 3, ruleId: "foo" }] }), @@ -122,6 +137,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 8, ruleId: "foo", justification: "justification" }], problems: [{ line: 1, column: 8, ruleId: "foo" }] }), @@ -133,6 +149,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([26, 29]), type: "disable", @@ -151,6 +168,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([7, 31]), type: "disable", @@ -170,6 +188,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 26]), @@ -198,6 +217,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 25]), @@ -226,6 +246,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { type: "disable", line: 1, column: 1, ruleId: null, justification: "j1" }, { type: "enable", line: 1, column: 26, ruleId: null, justification: "j2" } @@ -240,6 +261,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -276,6 +298,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -312,6 +335,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -342,6 +366,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -370,6 +395,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -398,6 +424,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -426,6 +453,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { type: "disable", line: 1, column: 1, ruleId: null, justification: "j1" }, { type: "enable", line: 1, column: 22, ruleId: "foo", justification: "j2" }, @@ -457,6 +485,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([6, 27]), type: "disable-line", @@ -475,6 +504,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([7, 28]), type: "disable-line", @@ -493,6 +523,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([7, 28]), type: "disable-line", @@ -511,6 +542,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([7, 34]), type: "disable-line", @@ -531,6 +563,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([7, 34]), type: "disable-line", @@ -549,6 +582,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 27]), type: "disable-line", @@ -567,6 +601,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -595,6 +630,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([7, 34]), @@ -657,6 +693,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 31]), type: "disable-next-line", @@ -675,6 +712,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 31]), type: "disable-next-line", @@ -692,6 +730,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 31]), type: "disable-next-line", @@ -710,6 +749,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 31]), type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "j1" }, { parentDirective: createParentDirective([31, 50]), type: "enable", line: 1, column: 31, ruleId: null, justification: "j2" } @@ -726,6 +766,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: "foo", justification: "justification" }], problems: [{ line: 2, column: 1, ruleId: "foo" }] }), @@ -737,6 +778,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 31]), type: "disable-next-line", @@ -770,6 +812,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 20]), type: "disable", @@ -799,6 +842,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 20]), type: "disable", @@ -825,6 +869,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 1, ruleId: null, justification: "justification" }], problems: [{ line: 2, column: 1, ruleId: "foo" }], reportUnusedDisableDirectives: "error" @@ -837,6 +882,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 21]), type: "disable", @@ -867,6 +913,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 24]), type: "disable", @@ -904,6 +951,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -951,6 +999,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -991,6 +1040,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1045,6 +1095,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1096,6 +1147,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1147,6 +1199,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable", line: 1, column: 1, ruleId: "foo", justification: "justification" }], problems: [{ line: 1, column: 6, ruleId: "foo" }], reportUnusedDisableDirectives: "error" @@ -1159,6 +1212,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1210,6 +1264,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -1258,6 +1313,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -1305,6 +1361,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 24]), @@ -1352,6 +1409,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1419,6 +1477,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 20]), type: "enable", @@ -1448,6 +1507,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 20]), type: "enable", @@ -1474,6 +1534,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { type: "disable", line: 1, column: 1, ruleId: null, justification: "justification" }, { type: "enable", line: 3, column: 1, ruleId: null, justification: "justification" } @@ -1489,6 +1550,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 21]), type: "enable", @@ -1519,6 +1581,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 24]), @@ -1567,6 +1630,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1643,6 +1707,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1699,6 +1764,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1753,6 +1819,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1809,6 +1876,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1865,6 +1933,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { type: "disable", line: 1, column: 1, ruleId: "foo", justification: "j1" }, { type: "enable", line: 3, column: 1, ruleId: "foo", justification: "j2" } @@ -1880,6 +1949,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 21]), @@ -1938,6 +2008,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -1994,6 +2065,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -2050,6 +2122,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -2126,6 +2199,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), @@ -2196,6 +2270,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 22]), type: "disable-line", @@ -2229,6 +2304,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable-line", line: 1, column: 1, ruleId: null, justification: "justification" }], problems: [{ line: 1, column: 10, ruleId: "foo" }], reportUnusedDisableDirectives: "error" @@ -2241,6 +2317,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 27]), type: "disable-next-line", @@ -2273,6 +2350,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "justification" }], problems: [{ line: 2, column: 10, ruleId: "foo" }], reportUnusedDisableDirectives: "error" @@ -2285,6 +2363,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 20]), type: "disable", line: 1, column: 1, ruleId: null }, { parentDirective: createParentDirective([20, 43]), type: "disable-line", line: 1, column: 22, ruleId: null } @@ -2325,6 +2404,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [{ parentDirective: createParentDirective([0, 27]), type: "disable-next-line", @@ -2348,6 +2428,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2397,6 +2478,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2447,6 +2529,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2497,6 +2580,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2547,6 +2631,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2617,6 +2702,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2707,6 +2793,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2751,6 +2838,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -2798,6 +2886,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -2868,6 +2957,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -2925,6 +3015,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -2983,6 +3074,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -3041,6 +3133,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -3099,6 +3192,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -3177,6 +3271,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective: createParentDirective([0, 29], " eslint-disable foo ", ["foo"]), @@ -3275,6 +3370,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, @@ -3319,6 +3415,7 @@ describe("apply-disable-directives", () => { assert.deepStrictEqual( applyDisableDirectives({ language: jslang, + sourceCode, directives: [ { parentDirective, diff --git a/tests/lib/linter/rule-fixer.js b/tests/lib/linter/rule-fixer.js index 7cc350b6152c..403527811501 100644 --- a/tests/lib/linter/rule-fixer.js +++ b/tests/lib/linter/rule-fixer.js @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ const assert = require("chai").assert, - ruleFixer = require("../../../lib/linter/rule-fixer"); + { RuleFixer } = require("../../../lib/linter/rule-fixer"); //------------------------------------------------------------------------------ // Tests @@ -17,6 +17,21 @@ const assert = require("chai").assert, describe("RuleFixer", () => { + let ruleFixer; + + beforeEach(() => { + ruleFixer = new RuleFixer({ + sourceCode: { + getLoc(node) { + return node.loc; + }, + getRange(node) { + return node.range; + } + } + }); + }); + describe("insertTextBefore", () => { it("should return an object with the correct information when called", () => { diff --git a/tests/lib/rules/utils/fix-tracker.js b/tests/lib/rules/utils/fix-tracker.js index 0fc004f0626c..9daf12bda70c 100644 --- a/tests/lib/rules/utils/fix-tracker.js +++ b/tests/lib/rules/utils/fix-tracker.js @@ -11,7 +11,7 @@ const assert = require("chai").assert, espree = require("espree"), FixTracker = require("../../../../lib/rules/utils/fix-tracker"), - ruleFixer = require("../../../../lib/linter/rule-fixer"), + { RuleFixer } = require("../../../../lib/linter/rule-fixer"), { SourceCode } = require("../../../../lib/languages/js/source-code"), Traverser = require("../../../../lib/shared/traverser"); @@ -53,6 +53,7 @@ describe("FixTracker", () => { describe("replaceTextRange", () => { it("should expand to include an explicitly retained range", () => { const sourceCode = createSourceCode("var foo = +bar;"); + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainRange([4, 14]) .replaceTextRange([10, 11], "-"); @@ -65,6 +66,7 @@ describe("FixTracker", () => { it("ignores a retained range that's smaller than the replaced range", () => { const sourceCode = createSourceCode("abcdefghij"); + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainRange([5, 7]) .replaceTextRange([4, 8], "123"); @@ -77,6 +79,7 @@ describe("FixTracker", () => { it("allows an unspecified retained range", () => { const sourceCode = createSourceCode("abcdefghij"); + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .replaceTextRange([4, 8], "123"); @@ -90,6 +93,7 @@ describe("FixTracker", () => { describe("remove", () => { it("should expand to include an explicitly retained range", () => { const sourceCode = createSourceCode("a = b + +c"); + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainRange([4, 10]) .remove(sourceCode.ast.tokens[4]); @@ -105,6 +109,7 @@ describe("FixTracker", () => { it("handles a normal enclosing function", () => { const sourceCode = createSourceCode("f = function() { return x; }"); const xNode = sourceCode.ast.body[0].expression.right.body.body[0].argument; + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainEnclosingFunction(xNode) .replaceTextRange(xNode.range, "y"); @@ -118,6 +123,7 @@ describe("FixTracker", () => { it("handles the case when there is no enclosing function", () => { const sourceCode = createSourceCode("const a = b;"); const bNode = sourceCode.ast.body[0].declarations[0].init; + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainEnclosingFunction(bNode) .replaceTextRange(bNode.range, "c"); @@ -133,6 +139,7 @@ describe("FixTracker", () => { it("handles a change to a binary operator", () => { const sourceCode = createSourceCode("const i = j + k;"); const plusToken = sourceCode.ast.tokens[4]; + const ruleFixer = new RuleFixer({ sourceCode }); const result = new FixTracker(ruleFixer, sourceCode) .retainSurroundingTokens(plusToken) .replaceTextRange(plusToken.range, "*");