Skip to content

Commit

Permalink
feat!: Switch Linter to flat config by default (#17851)
Browse files Browse the repository at this point in the history
* feat!: Switch Linter to flat config by default

Refs #13481

* Fix failing tests

* Fix fuzzer

* Ensure verify() defaults to flat config
  • Loading branch information
nzakas committed Dec 24, 2023
1 parent 3826cdf commit 2916c63
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 91 deletions.
2 changes: 1 addition & 1 deletion lib/cli-engine/cli-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ class CLIEngine {
});
const lintResultCache =
options.cache ? new LintResultCache(cacheFilePath, options.cacheStrategy) : null;
const linter = new Linter({ cwd: options.cwd });
const linter = new Linter({ cwd: options.cwd, configType: "eslintrc" });

/** @type {ConfigArray[]} */
const lastConfigArrays = [configArrayFactory.getConfigArrayForFile()];
Expand Down
48 changes: 24 additions & 24 deletions lib/linter/linter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1172,9 +1172,9 @@ class Linter {
* Initialize the Linter.
* @param {Object} [config] the config object
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
* @param {"flat"|"eslintrc"} [config.configType="eslintrc"] the type of config used.
* @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
*/
constructor({ cwd, configType } = {}) {
constructor({ cwd, configType = "flat" } = {}) {
internalSlotsMap.set(this, {
cwd: normalizeCwd(cwd),
lastConfigArray: null,
Expand Down Expand Up @@ -1368,29 +1368,29 @@ class Linter {
? { filename: filenameOrOptions }
: filenameOrOptions || {};

if (config) {
if (configType === "flat") {

/*
* Because of how Webpack packages up the files, we can't
* compare directly to `FlatConfigArray` using `instanceof`
* because it's not the same `FlatConfigArray` as in the tests.
* So, we work around it by assuming an array is, in fact, a
* `FlatConfigArray` if it has a `getConfig()` method.
*/
let configArray = config;

if (!Array.isArray(config) || typeof config.getConfig !== "function") {
configArray = new FlatConfigArray(config, { basePath: cwd });
configArray.normalizeSync();
}
const configToUse = config ?? {};

return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
}
if (configType !== "eslintrc") {

/*
* Because of how Webpack packages up the files, we can't
* compare directly to `FlatConfigArray` using `instanceof`
* because it's not the same `FlatConfigArray` as in the tests.
* So, we work around it by assuming an array is, in fact, a
* `FlatConfigArray` if it has a `getConfig()` method.
*/
let configArray = configToUse;

if (typeof config.extractConfig === "function") {
return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, config, options));
if (!Array.isArray(configToUse) || typeof configToUse.getConfig !== "function") {
configArray = new FlatConfigArray(configToUse, { basePath: cwd });
configArray.normalizeSync();
}

return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
}

if (typeof configToUse.extractConfig === "function") {
return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, configToUse, options));
}

/*
Expand All @@ -1403,9 +1403,9 @@ class Linter {
* So we cannot apply multiple processors.
*/
if (options.preprocess || options.postprocess) {
return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, config, options));
return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, configToUse, options));
}
return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, config, options));
return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, configToUse, options));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/rule-tester/rule-tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ class RuleTester {
* @type {Object}
*/
this.rules = {};
this.linter = new Linter();
this.linter = new Linter({ configType: "eslintrc" });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/linter/code-path-analysis/code-path-analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const STANDARD_ESQUERY_OPTION = { visitorKeys: vk.KEYS, fallback: Traverser.getK

const expectedPattern = /\/\*expected\s+((?:.|[\r\n])+?)\s*\*\//gu;
const lineEndingPattern = /\r?\n/gu;
const linter = new Linter();
const linter = new Linter({ configType: "eslintrc" });

/**
* Extracts the content of `/*expected` comments from a given source code.
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/linter/code-path-analysis/code-path.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

const assert = require("assert"),
{ Linter } = require("../../../../lib/linter");
const linter = new Linter();
const linter = new Linter({ configType: "eslintrc" });

//------------------------------------------------------------------------------
// Helpers
Expand Down
67 changes: 28 additions & 39 deletions tests/lib/linter/linter.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe("Linter", () => {
let linter;

beforeEach(() => {
linter = new Linter();
linter = new Linter({ configType: "eslintrc" });
});

afterEach(() => {
Expand Down Expand Up @@ -1397,7 +1397,7 @@ describe("Linter", () => {

describe("when evaluating code with invalid comments to enable rules", () => {
it("should report a violation when the config is not a valid rule configuration", () => {
const messages = linter.verify("/*eslint no-alert:true*/ alert('test');", {});
const messages = linter.verify("/*eslint no-alert:true*/ alert('test');");
const suppressedMessages = linter.getSuppressedMessages();

assert.deepStrictEqual(
Expand All @@ -1420,7 +1420,7 @@ describe("Linter", () => {
});

it("should report a violation when the config violates a rule's schema", () => {
const messages = linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/", {});
const messages = linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/");
const suppressedMessages = linter.getSuppressedMessages();

assert.deepStrictEqual(
Expand Down Expand Up @@ -3509,7 +3509,7 @@ var a = "test2";

it("should get cwd correctly in the context", () => {
const cwd = "cwd";
const linterWithOption = new Linter({ cwd });
const linterWithOption = new Linter({ cwd, configType: "eslintrc" });
let spy;

linterWithOption.defineRule("checker", {
Expand All @@ -3528,7 +3528,7 @@ var a = "test2";

it("should assign process.cwd() to it if cwd is undefined", () => {
let spy;
const linterWithOption = new Linter({ });
const linterWithOption = new Linter({ configType: "eslintrc" });

linterWithOption.defineRule("checker", {
create(context) {
Expand Down Expand Up @@ -6573,8 +6573,8 @@ var a = "test2";
let linter2 = null;

beforeEach(() => {
linter1 = new Linter();
linter2 = new Linter();
linter1 = new Linter({ configType: "eslintrc" });
linter2 = new Linter({ configType: "eslintrc" });
});

describe("rules", () => {
Expand Down Expand Up @@ -10320,7 +10320,7 @@ describe("Linter with FlatConfigArray", () => {

describe("when evaluating code with invalid comments to enable rules", () => {
it("should report a violation when the config is not a valid rule configuration", () => {
const messages = linter.verify("/*eslint no-alert:true*/ alert('test');", {});
const messages = linter.verify("/*eslint no-alert:true*/ alert('test');");
const suppressedMessages = linter.getSuppressedMessages();

assert.deepStrictEqual(
Expand All @@ -10343,7 +10343,7 @@ describe("Linter with FlatConfigArray", () => {
});

it("should report a violation when a rule is configured using a string severity that contains uppercase letters", () => {
const messages = linter.verify("/*eslint no-alert: \"Error\"*/ alert('test');", {});
const messages = linter.verify("/*eslint no-alert: \"Error\"*/ alert('test');");
const suppressedMessages = linter.getSuppressedMessages();

assert.deepStrictEqual(
Expand All @@ -10366,7 +10366,7 @@ describe("Linter with FlatConfigArray", () => {
});

it("should report a violation when the config violates a rule's schema", () => {
const messages = linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/", {});
const messages = linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/");
const suppressedMessages = linter.getSuppressedMessages();

assert.deepStrictEqual(
Expand Down Expand Up @@ -10395,7 +10395,7 @@ describe("Linter with FlatConfigArray", () => {
"foo(); // <-- expected no-undef error here"
].join("\n");

const messages = linter.verify(code, {});
const messages = linter.verify(code);
const suppressedMessages = linter.getSuppressedMessages();

// different engines have different JSON parsing error messages
Expand Down Expand Up @@ -14508,7 +14508,7 @@ var a = "test2";
const code = BROKEN_TEST_CODE;

it("should report a violation with a useful parse error prefix", () => {
const messages = linter.verify(code, {});
const messages = linter.verify(code);
const suppressedMessages = linter.getSuppressedMessages();

assert.strictEqual(messages.length, 1);
Expand Down Expand Up @@ -14554,6 +14554,21 @@ var a = "test2";
});

});

it("should default to flat config mode when a config isn't passed", () => {

// eslint-env should not be honored
const messages = linter.verify("/*eslint no-undef:error*//*eslint-env browser*/\nwindow;");
const suppressedMessages = linter.getSuppressedMessages();

assert.strictEqual(messages.length, 1);
assert.strictEqual(messages[0].ruleId, "no-undef");
assert.strictEqual(messages[0].severity, 2);
assert.strictEqual(messages[0].line, 2);
assert.strictEqual(messages[0].column, 1);

assert.strictEqual(suppressedMessages.length, 0);
});
});

describe("getSourceCode()", () => {
Expand Down Expand Up @@ -14858,32 +14873,6 @@ var a = "test2";
});
});

describe("Mutability", () => {
let linter1 = null;
let linter2 = null;

beforeEach(() => {
linter1 = new Linter();
linter2 = new Linter();
});

describe("rules", () => {
it("with no changes, same rules are loaded", () => {
assert.sameDeepMembers(Array.from(linter1.getRules().keys()), Array.from(linter2.getRules().keys()));
});

it("loading rule in one doesn't change the other", () => {
linter1.defineRule("mock-rule", {
create: () => ({})
});

assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present");
assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present");
});
});
});


describe("processors", () => {
let receivedFilenames = [];
let receivedPhysicalFilenames = [];
Expand Down Expand Up @@ -15465,7 +15454,7 @@ var a = "test2";
});

it("should not crash when invalid parentheses syntax is encountered", () => {
linter.verify("left = (aSize.width/2) - ()", {});
linter.verify("left = (aSize.width/2) - ()");
});

it("should not crash when let is used inside of switch case", () => {
Expand Down
27 changes: 8 additions & 19 deletions tests/lib/linter/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,19 @@ describe("rules", () => {

const linter = new Linter();

const problems = linter.verify("foo", { rules: { "test-rule": "error" } });

assert.lengthOf(problems, 1);
assert.strictEqual(problems[0].message, "Definition for rule 'test-rule' was not found.");
assert.strictEqual(problems[0].line, 1);
assert.strictEqual(problems[0].column, 1);
assert.strictEqual(problems[0].endLine, 1);
assert.strictEqual(problems[0].endColumn, 2);
assert.throws(() => {
linter.verify("foo", { rules: { "test-rule": "error" } });
}, TypeError, "Could not find \"test-rule\" in plugin \"@\".");

});


it("should report a linting error that lists replacements if a rule is known to have been replaced", () => {
const linter = new Linter();
const problems = linter.verify("foo", { rules: { "no-arrow-condition": "error" } });

assert.lengthOf(problems, 1);
assert.strictEqual(
problems[0].message,
"Rule 'no-arrow-condition' was removed and replaced by: no-confusing-arrow, no-constant-condition"
);
assert.strictEqual(problems[0].line, 1);
assert.strictEqual(problems[0].column, 1);
assert.strictEqual(problems[0].endLine, 1);
assert.strictEqual(problems[0].endColumn, 2);

assert.throws(() => {
linter.verify("foo", { rules: { "no-arrow-condition": "error" } });
}, TypeError, "Key \"rules\": Key \"no-arrow-condition\": Rule \"no-arrow-condition\" was removed and replaced by \"no-confusing-arrow,no-constant-condition\".");
});
});

Expand Down
2 changes: 1 addition & 1 deletion tests/lib/rules/utils/ast-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ESPREE_CONFIG = {
range: true,
loc: true
};
const linter = new Linter();
const linter = new Linter({ configType: "eslintrc" });

describe("ast-utils", () => {
let callCounts;
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/shared/config-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const assert = require("chai").assert,
// Helpers
//------------------------------------------------------------------------------

const linter = new Linter();
const linter = new Linter({ configType: "eslintrc" });

const mockRule = {
meta: {
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/source-code/source-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const DEFAULT_CONFIG = {
range: true,
loc: true
};
const linter = new Linter();
const linter = new Linter({ configType: "eslintrc" });
const flatLinter = new Linter({ configType: "flat" });
const AST = espree.parse("let foo = bar;", DEFAULT_CONFIG),
TEST_CODE = "var answer = 6 * 7;",
Expand Down
2 changes: 1 addition & 1 deletion tests/tools/eslint-fuzzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("eslint-fuzzer", function() {
*/
this.timeout(15000); // eslint-disable-line no-invalid-this -- Mocha timeout

const linter = new eslint.Linter();
const linter = new eslint.Linter({ configType: "eslintrc" });
const coreRules = linter.getRules();
const fixableRuleNames = Array.from(coreRules)
.filter(rulePair => rulePair[1].meta && rulePair[1].meta.fixable)
Expand Down
2 changes: 1 addition & 1 deletion tools/fuzzer-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
const ProgressBar = require("progress");
const fuzz = require("./eslint-fuzzer");
const eslint = require("..");
const linter = new eslint.Linter();
const linter = new eslint.Linter({ configType: "eslintrc" });

//------------------------------------------------------------------------------
// Helpers
Expand Down

0 comments on commit 2916c63

Please sign in to comment.