mirror of
https://git.proxmox.com/git/pve-eslint
synced 2025-10-19 12:35:33 +00:00
2418 lines
99 KiB
JavaScript
2418 lines
99 KiB
JavaScript
/**
|
|
* @fileoverview Tests for ConfigArrayFactory class.
|
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
*/
|
|
"use strict";
|
|
|
|
const os = require("os");
|
|
const path = require("path");
|
|
const { assert } = require("chai");
|
|
const { spy } = require("sinon");
|
|
const { ConfigArray } = require("../../../lib/cli-engine/config-array");
|
|
const { OverrideTester } = require("../../../lib/cli-engine/config-array");
|
|
const { createContext } = require("../../../lib/cli-engine/config-array-factory");
|
|
const { defineConfigArrayFactoryWithInMemoryFileSystem } = require("../../_utils");
|
|
|
|
const tempDir = path.join(os.tmpdir(), "eslint/config-array-factory");
|
|
|
|
// For VSCode intellisense.
|
|
/** @typedef {InstanceType<ReturnType<defineConfigArrayFactoryWithInMemoryFileSystem>["ConfigArrayFactory"]>} ConfigArrayFactory */
|
|
|
|
/**
|
|
* Assert a config array element.
|
|
* @param {Object} actual The actual value.
|
|
* @param {Object} providedExpected The expected value.
|
|
* @returns {void}
|
|
*/
|
|
function assertConfigArrayElement(actual, providedExpected) {
|
|
const expected = {
|
|
name: "",
|
|
filePath: "",
|
|
criteria: null,
|
|
env: void 0,
|
|
globals: void 0,
|
|
ignorePattern: void 0,
|
|
noInlineConfig: void 0,
|
|
parser: void 0,
|
|
parserOptions: void 0,
|
|
plugins: void 0,
|
|
processor: void 0,
|
|
reportUnusedDisableDirectives: void 0,
|
|
root: void 0,
|
|
rules: void 0,
|
|
settings: void 0,
|
|
type: "config",
|
|
...providedExpected
|
|
};
|
|
|
|
assert.deepStrictEqual(actual, expected);
|
|
}
|
|
|
|
/**
|
|
* Assert a config array element.
|
|
* @param {Object} actual The actual value.
|
|
* @param {Object} providedExpected The expected value.
|
|
* @returns {void}
|
|
*/
|
|
function assertConfig(actual, providedExpected) {
|
|
const expected = {
|
|
env: {},
|
|
globals: {},
|
|
ignorePatterns: [],
|
|
noInlineConfig: void 0,
|
|
parser: null,
|
|
parserOptions: {},
|
|
plugins: [],
|
|
reportUnusedDisableDirectives: void 0,
|
|
rules: {},
|
|
settings: {},
|
|
...providedExpected
|
|
};
|
|
|
|
assert.deepStrictEqual(actual, expected);
|
|
}
|
|
|
|
/**
|
|
* Assert a plugin definition.
|
|
* @param {Object} actual The actual value.
|
|
* @param {Object} providedExpected The expected value.
|
|
* @returns {void}
|
|
*/
|
|
function assertPluginDefinition(actual, providedExpected) {
|
|
const expected = {
|
|
configs: {},
|
|
environments: {},
|
|
processors: {},
|
|
rules: {},
|
|
...providedExpected
|
|
};
|
|
|
|
assert.deepStrictEqual(actual, expected);
|
|
}
|
|
|
|
describe("ConfigArrayFactory", () => {
|
|
describe("'create(configData, options)' method should normalize the config data.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir
|
|
});
|
|
|
|
/** @type {ConfigArrayFactory} */
|
|
let factory;
|
|
|
|
beforeEach(() => {
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
it("should return an empty config array if 'configData' is null.", () => {
|
|
assert.strictEqual(factory.create(null).length, 0);
|
|
});
|
|
|
|
it("should throw an error if the config data had invalid properties,", () => {
|
|
assert.throws(() => {
|
|
factory.create({ files: true });
|
|
}, /Unexpected top-level property "files"/u);
|
|
});
|
|
|
|
it("should call '_normalizeConfigData(configData, ctx)' with given arguments.", () => {
|
|
const configData = {};
|
|
const basePath = tempDir;
|
|
const filePath = __filename;
|
|
const name = "example";
|
|
const normalizeConfigData = spy(factory, "_normalizeConfigData");
|
|
|
|
factory.create(configData, { basePath, filePath, name });
|
|
|
|
assert.strictEqual(normalizeConfigData.callCount, 1);
|
|
assert.deepStrictEqual(normalizeConfigData.args[0], [
|
|
configData,
|
|
createContext({ cwd: tempDir }, void 0, name, filePath, basePath)
|
|
]);
|
|
});
|
|
|
|
it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
|
|
const elements = [{}, {}];
|
|
|
|
factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
|
|
|
|
const configArray = factory.create({});
|
|
|
|
assert.strictEqual(configArray.length, 2);
|
|
assert.strictEqual(configArray[0], elements[0]);
|
|
assert.strictEqual(configArray[1], elements[1]);
|
|
});
|
|
});
|
|
|
|
describe("'loadFile(filePath, options)' method should load a config file.", () => {
|
|
const basicFiles = {
|
|
"js/.eslintrc.js": "exports.settings = { name: 'js/.eslintrc.js' }",
|
|
"cjs/.eslintrc.cjs": "exports.settings = { name: 'cjs/.eslintrc.cjs' }",
|
|
"json/.eslintrc.json": "{ \"settings\": { \"name\": \"json/.eslintrc.json\" } }",
|
|
"legacy-json/.eslintrc": "{ \"settings\": { \"name\": \"legacy-json/.eslintrc\" } }",
|
|
"legacy-yml/.eslintrc": "settings:\n name: legacy-yml/.eslintrc",
|
|
"package-json/package.json": "{ \"eslintConfig\": { \"settings\": { \"name\": \"package-json/package.json\" } } }",
|
|
"yml/.eslintrc.yml": "settings:\n name: yml/.eslintrc.yml",
|
|
"yaml/.eslintrc.yaml": "settings:\n name: yaml/.eslintrc.yaml"
|
|
};
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
...basicFiles,
|
|
"invalid-property.json": "{ \"files\": \"*.js\" }",
|
|
"package-json-no-config/package.json": "{ \"name\": \"foo\" }"
|
|
}
|
|
});
|
|
|
|
/** @type {ConfigArrayFactory} */
|
|
let factory;
|
|
|
|
beforeEach(() => {
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
it("should throw an error if 'filePath' is null.", () => {
|
|
assert.throws(() => factory.loadFile(null));
|
|
});
|
|
|
|
it("should throw an error if 'filePath' doesn't exist.", () => {
|
|
assert.throws(() => {
|
|
factory.loadFile("non-exist");
|
|
}, /Cannot read config file:.*non-exist/su);
|
|
});
|
|
|
|
it("should throw an error if 'filePath' was 'package.json' and it doesn't have 'eslintConfig' field.", () => {
|
|
assert.throws(() => {
|
|
factory.loadFile("package-json-no-config/package.json");
|
|
}, /Cannot read config file:.*package.json/su);
|
|
});
|
|
|
|
it("should throw an error if the config data had invalid properties,", () => {
|
|
assert.throws(() => {
|
|
factory.loadFile("invalid-property.json");
|
|
}, /Unexpected top-level property "files"/u);
|
|
});
|
|
|
|
for (const filePath of Object.keys(basicFiles)) {
|
|
it(`should load '${filePath}' then return a config array what contains that file content.`, () => { // eslint-disable-line no-loop-func
|
|
const configArray = factory.loadFile(filePath);
|
|
|
|
assert.strictEqual(configArray.length, 1);
|
|
assertConfigArrayElement(configArray[0], {
|
|
filePath: path.resolve(tempDir, filePath),
|
|
name: path.relative(tempDir, path.resolve(tempDir, filePath)),
|
|
settings: { name: filePath }
|
|
});
|
|
});
|
|
}
|
|
|
|
it("should call '_normalizeConfigData(configData, ctx)' with the loaded config data and given options.", () => {
|
|
const basePath = tempDir;
|
|
const filePath = "js/.eslintrc.js";
|
|
const name = "example";
|
|
const normalizeConfigData = spy(factory, "_normalizeConfigData");
|
|
|
|
factory.loadFile(filePath, { basePath, name });
|
|
|
|
assert.strictEqual(normalizeConfigData.callCount, 1);
|
|
assert.deepStrictEqual(normalizeConfigData.args[0], [
|
|
{ settings: { name: filePath } },
|
|
createContext({ cwd: tempDir }, void 0, name, filePath, basePath)
|
|
]);
|
|
});
|
|
|
|
it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
|
|
const elements = [{}, {}];
|
|
|
|
factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
|
|
|
|
const configArray = factory.loadFile("js/.eslintrc.js");
|
|
|
|
assert.strictEqual(configArray.length, 2);
|
|
assert.strictEqual(configArray[0], elements[0]);
|
|
assert.strictEqual(configArray[1], elements[1]);
|
|
});
|
|
});
|
|
|
|
describe("'loadInDirectory(directoryPath, options)' method should load the config file of a directory.", () => {
|
|
const basicFiles = {
|
|
"js/.eslintrc.js": "exports.settings = { name: 'js/.eslintrc.js' }",
|
|
"cjs/.eslintrc.cjs": "exports.settings = { name: 'cjs/.eslintrc.cjs' }",
|
|
"json/.eslintrc.json": "{ \"settings\": { \"name\": \"json/.eslintrc.json\" } }",
|
|
"legacy-json/.eslintrc": "{ \"settings\": { \"name\": \"legacy-json/.eslintrc\" } }",
|
|
"legacy-yml/.eslintrc": "settings:\n name: legacy-yml/.eslintrc",
|
|
"package-json/package.json": "{ \"eslintConfig\": { \"settings\": { \"name\": \"package-json/package.json\" } } }",
|
|
"yml/.eslintrc.yml": "settings:\n name: yml/.eslintrc.yml",
|
|
"yaml/.eslintrc.yaml": "settings:\n name: yaml/.eslintrc.yaml"
|
|
};
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
...basicFiles,
|
|
"invalid-property/.eslintrc.json": "{ \"files\": \"*.js\" }",
|
|
"package-json-no-config/package.json": "{ \"name\": \"foo\" }"
|
|
}
|
|
});
|
|
|
|
/** @type {ConfigArrayFactory} */
|
|
let factory;
|
|
|
|
beforeEach(() => {
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
it("should throw an error if 'directoryPath' is null.", () => {
|
|
assert.throws(() => factory.loadInDirectory(null));
|
|
});
|
|
|
|
it("should return an empty config array if the config file of 'directoryPath' doesn't exist.", () => {
|
|
assert.strictEqual(factory.loadInDirectory("non-exist").length, 0);
|
|
});
|
|
|
|
it("should return an empty config array if the config file of 'directoryPath' was package.json and it didn't have 'eslintConfig' field.", () => {
|
|
assert.strictEqual(factory.loadInDirectory("package-json-no-config").length, 0);
|
|
});
|
|
|
|
it("should throw an error if the config data had invalid properties,", () => {
|
|
assert.throws(() => {
|
|
factory.loadInDirectory("invalid-property");
|
|
}, /Unexpected top-level property "files"/u);
|
|
});
|
|
|
|
for (const filePath of Object.keys(basicFiles)) {
|
|
const directoryPath = filePath.split("/")[0];
|
|
|
|
it(`should load '${directoryPath}' then return a config array what contains the config file of that directory.`, () => { // eslint-disable-line no-loop-func
|
|
const configArray = factory.loadInDirectory(directoryPath);
|
|
|
|
assert.strictEqual(configArray.length, 1);
|
|
assertConfigArrayElement(configArray[0], {
|
|
filePath: path.resolve(tempDir, filePath),
|
|
name: path.relative(tempDir, path.resolve(tempDir, filePath)),
|
|
settings: { name: filePath }
|
|
});
|
|
});
|
|
}
|
|
|
|
it("should call '_normalizeConfigData(configData, ctx)' with the loaded config data and given options.", () => {
|
|
const basePath = tempDir;
|
|
const directoryPath = "js";
|
|
const name = "example";
|
|
const normalizeConfigData = spy(factory, "_normalizeConfigData");
|
|
|
|
factory.loadInDirectory(directoryPath, { basePath, name });
|
|
|
|
assert.strictEqual(normalizeConfigData.callCount, 1);
|
|
assert.deepStrictEqual(normalizeConfigData.args[0], [
|
|
{ settings: { name: `${directoryPath}/.eslintrc.js` } },
|
|
createContext({ cwd: tempDir }, void 0, name, path.join(directoryPath, ".eslintrc.js"), basePath)
|
|
]);
|
|
});
|
|
|
|
it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
|
|
const elements = [{}, {}];
|
|
|
|
factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
|
|
|
|
const configArray = factory.loadInDirectory("js");
|
|
|
|
assert.strictEqual(configArray.length, 2);
|
|
assert.strictEqual(configArray[0], elements[0]);
|
|
assert.strictEqual(configArray[1], elements[1]);
|
|
});
|
|
});
|
|
|
|
/*
|
|
* All of `create`, `loadFile`, and `loadInDirectory` call this method.
|
|
* So this section tests the common part of the three.
|
|
*/
|
|
describe("'_normalizeConfigData(configData, ctx)' method should normalize the config data.", () => {
|
|
|
|
/** @type {ConfigArrayFactory} */
|
|
let factory = null;
|
|
|
|
/**
|
|
* Call `_normalizeConfigData` method with given arguments.
|
|
* @param {ConfigData} configData The config data to normalize.
|
|
* @param {Object} [options] The options.
|
|
* @param {string} [options.filePath] The path to the config file of the config data.
|
|
* @param {string} [options.name] The name of the config file of the config data.
|
|
* @returns {ConfigArray} The created config array.
|
|
*/
|
|
function create(configData, { filePath, name } = {}) {
|
|
const ctx = createContext({ cwd: tempDir }, void 0, name, filePath, void 0);
|
|
|
|
return new ConfigArray(...factory._normalizeConfigData(configData, ctx)); // eslint-disable-line no-underscore-dangle
|
|
}
|
|
|
|
describe("misc", () => {
|
|
before(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir
|
|
});
|
|
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
describe("if the config data was empty, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({});
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the default values in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], {});
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'env' property, the returned value", () => {
|
|
const env = { node: true };
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ env });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'env' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { env });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'globals' property, the returned value", () => {
|
|
const globals = { window: "readonly" };
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ globals });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'globals' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { globals });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'parser' property, the returned value", () => {
|
|
const parser = "espree";
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ parser });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'parser' value in the element.", () => {
|
|
assert.strictEqual(configArray[0].parser.id, parser);
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'parserOptions' property, the returned value", () => {
|
|
const parserOptions = { ecmaVersion: 2015 };
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ parserOptions });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'parserOptions' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { parserOptions });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'plugins' property, the returned value", () => {
|
|
const plugins = [];
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ plugins });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'plugins' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { plugins: {} });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'root' property, the returned value", () => {
|
|
const root = true;
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ root });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'root' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { root });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'rules' property, the returned value", () => {
|
|
const rules = { eqeqeq: "error" };
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ rules });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'rules' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { rules });
|
|
});
|
|
});
|
|
|
|
describe("if the config data had 'settings' property, the returned value", () => {
|
|
const settings = { foo: 777 };
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ settings });
|
|
});
|
|
|
|
it("should have an element.", () => {
|
|
assert.strictEqual(configArray.length, 1);
|
|
});
|
|
|
|
it("should have the 'settings' value in the element.", () => {
|
|
assertConfigArrayElement(configArray[0], { settings });
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("'parser' details", () => {
|
|
before(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/xxx-parser/index.js": "exports.name = 'xxx-parser';",
|
|
"subdir/node_modules/xxx-parser/index.js": "exports.name = 'subdir/xxx-parser';",
|
|
"parser.js": "exports.name = './parser.js';"
|
|
}
|
|
});
|
|
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
describe("if the 'parser' property was a valid package, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ parser: "xxx-parser" })[0];
|
|
});
|
|
|
|
it("should have the package ID at 'parser.id' property.", () => {
|
|
assert.strictEqual(element.parser.id, "xxx-parser");
|
|
});
|
|
|
|
it("should have the package object at 'parser.definition' property.", () => {
|
|
assert.deepStrictEqual(element.parser.definition, { name: "xxx-parser" });
|
|
});
|
|
|
|
it("should have the path to the package at 'parser.filePath' property.", () => {
|
|
assert.strictEqual(element.parser.filePath, path.join(tempDir, "node_modules/xxx-parser/index.js"));
|
|
});
|
|
});
|
|
|
|
describe("if the 'parser' property was an invalid package, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ parser: "invalid-parser" })[0];
|
|
});
|
|
|
|
it("should have the package ID at 'parser.id' property.", () => {
|
|
assert.strictEqual(element.parser.id, "invalid-parser");
|
|
});
|
|
|
|
it("should have the loading error at 'parser.error' property.", () => {
|
|
assert.match(element.parser.error.message, /Cannot find module 'invalid-parser'/u);
|
|
});
|
|
});
|
|
|
|
describe("if the 'parser' property was a valid relative path, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ parser: "./parser" })[0];
|
|
});
|
|
|
|
it("should have the given path at 'parser.id' property.", () => {
|
|
assert.strictEqual(element.parser.id, "./parser");
|
|
});
|
|
|
|
it("should have the file's object at 'parser.definition' property.", () => {
|
|
assert.deepStrictEqual(element.parser.definition, { name: "./parser.js" });
|
|
});
|
|
|
|
it("should have the absolute path to the file at 'parser.filePath' property.", () => {
|
|
assert.strictEqual(element.parser.filePath, path.join(tempDir, "./parser.js"));
|
|
});
|
|
});
|
|
|
|
describe("if the 'parser' property was an invalid relative path, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ parser: "./invalid-parser" })[0];
|
|
});
|
|
|
|
it("should have the given path at 'parser.id' property.", () => {
|
|
assert.strictEqual(element.parser.id, "./invalid-parser");
|
|
});
|
|
|
|
it("should have the loading error at 'parser.error' property.", () => {
|
|
assert.match(element.parser.error.message, /Cannot find module '.\/invalid-parser'/u);
|
|
});
|
|
});
|
|
|
|
describe("if 'parser' property was given and 'filePath' option was given, the parser", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create(
|
|
{ parser: "xxx-parser" },
|
|
{ filePath: path.join(tempDir, "subdir/.eslintrc") }
|
|
)[0];
|
|
});
|
|
|
|
it("should be resolved relative to the 'filePath' option.", () => {
|
|
assert.strictEqual(
|
|
element.parser.filePath,
|
|
|
|
// rather than "xxx-parser" at the project root.
|
|
path.join(tempDir, "subdir/node_modules/xxx-parser/index.js")
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("'plugins' details", () => {
|
|
before(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/eslint-plugin-ext/index.js": "exports.processors = { '.abc': {}, '.xyz': {}, other: {} };",
|
|
"node_modules/eslint-plugin-subdir/index.js": "",
|
|
"node_modules/eslint-plugin-xxx/index.js": "exports.configs = { name: 'eslint-plugin-xxx' };",
|
|
"subdir/node_modules/eslint-plugin-subdir/index.js": "",
|
|
"parser.js": ""
|
|
}
|
|
});
|
|
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
it("should throw an error if a 'plugins' value is a file path.", () => {
|
|
assert.throws(() => {
|
|
create({ plugins: ["./path/to/plugin"] });
|
|
}, /Plugins array cannot includes file paths/u);
|
|
});
|
|
|
|
describe("if the 'plugins' property was a valid package, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ plugins: ["xxx"] })[0];
|
|
});
|
|
|
|
it("should have 'plugins[id]' property.", () => {
|
|
assert.notStrictEqual(element.plugins.xxx, void 0);
|
|
});
|
|
|
|
it("should have the package ID at 'plugins[id].id' property.", () => {
|
|
assert.strictEqual(element.plugins.xxx.id, "xxx");
|
|
});
|
|
|
|
it("should have the package object at 'plugins[id].definition' property.", () => {
|
|
assertPluginDefinition(
|
|
element.plugins.xxx.definition,
|
|
{ configs: { name: "eslint-plugin-xxx" } }
|
|
);
|
|
});
|
|
|
|
it("should have the path to the package at 'plugins[id].filePath' property.", () => {
|
|
assert.strictEqual(element.plugins.xxx.filePath, path.join(tempDir, "node_modules/eslint-plugin-xxx/index.js"));
|
|
});
|
|
});
|
|
|
|
describe("if the 'plugins' property was an invalid package, the first config array element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = create({ plugins: ["invalid"] })[0];
|
|
});
|
|
|
|
it("should have 'plugins[id]' property.", () => {
|
|
assert.notStrictEqual(element.plugins.invalid, void 0);
|
|
});
|
|
|
|
it("should have the package ID at 'plugins[id].id' property.", () => {
|
|
assert.strictEqual(element.plugins.invalid.id, "invalid");
|
|
});
|
|
|
|
it("should have the loading error at 'plugins[id].error' property.", () => {
|
|
assert.match(element.plugins.invalid.error.message, /Cannot find module 'eslint-plugin-invalid'/u);
|
|
});
|
|
});
|
|
|
|
describe("even if 'plugins' property was given and 'filePath' option was given,", () => {
|
|
it("should load the plugin from 'subdir'.", () => {
|
|
const configArray = create(
|
|
{ plugins: ["subdir"] },
|
|
{ filePath: path.resolve(tempDir, "subdir/a.js") }
|
|
);
|
|
|
|
assert.strictEqual(
|
|
configArray[0].plugins.subdir.filePath,
|
|
path.resolve(tempDir, "subdir/node_modules/eslint-plugin-subdir/index.js")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("if 'plugins' property was given and the plugin has two file extension processors, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({ plugins: ["ext"] });
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
describe("the first element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = configArray[0];
|
|
});
|
|
|
|
it("should be named '#processors[\"ext/.abc\"]'.", () => {
|
|
assert.strictEqual(element.name, "#processors[\"ext/.abc\"]");
|
|
});
|
|
|
|
it("should not have 'plugins' property.", () => {
|
|
assert.strictEqual(element.plugins, void 0);
|
|
});
|
|
|
|
it("should have 'processor' property.", () => {
|
|
assert.strictEqual(element.processor, "ext/.abc");
|
|
});
|
|
|
|
it("should have 'criteria' property which matches '.abc'.", () => {
|
|
assert.strictEqual(element.criteria.test(path.join(tempDir, "1234.abc")), true);
|
|
assert.strictEqual(element.criteria.test(path.join(tempDir, "1234.xyz")), false);
|
|
});
|
|
});
|
|
|
|
describe("the second element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = configArray[1];
|
|
});
|
|
|
|
it("should be named '#processors[\"ext/.xyz\"]'.", () => {
|
|
assert.strictEqual(element.name, "#processors[\"ext/.xyz\"]");
|
|
});
|
|
|
|
it("should not have 'plugins' property.", () => {
|
|
assert.strictEqual(element.plugins, void 0);
|
|
});
|
|
|
|
it("should have 'processor' property.", () => {
|
|
assert.strictEqual(element.processor, "ext/.xyz");
|
|
});
|
|
|
|
it("should have 'criteria' property which matches '.xyz'.", () => {
|
|
assert.strictEqual(element.criteria.test(path.join(tempDir, "1234.abc")), false);
|
|
assert.strictEqual(element.criteria.test(path.join(tempDir, "1234.xyz")), true);
|
|
});
|
|
});
|
|
|
|
describe("the third element", () => {
|
|
let element;
|
|
|
|
beforeEach(() => {
|
|
element = configArray[2];
|
|
});
|
|
|
|
it("should have 'plugins' property.", () => {
|
|
assert.strictEqual(element.plugins.ext.id, "ext");
|
|
});
|
|
|
|
it("should not have 'processor' property.", () => {
|
|
assert.strictEqual(element.processor, void 0);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("'extends' details", () => {
|
|
before(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/eslint-config-foo/index.js": "exports.env = { browser: true }",
|
|
"node_modules/eslint-config-one/index.js": "module.exports = { extends: 'two', env: { browser: true } }",
|
|
"node_modules/eslint-config-two/index.js": "module.exports = { env: { node: true } }",
|
|
"node_modules/eslint-config-override/index.js": `
|
|
module.exports = {
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{ files: '*.xxx', rules: { override: 1 } },
|
|
{ files: '*.yyy', rules: { override: 2 } }
|
|
]
|
|
}
|
|
`,
|
|
"node_modules/eslint-plugin-foo/index.js": "exports.configs = { bar: { env: { es6: true } } }",
|
|
"node_modules/eslint-plugin-invalid-config/index.js": "exports.configs = { foo: {} }",
|
|
"node_modules/eslint-plugin-error/index.js": "throw new Error('xxx error')",
|
|
"base.js": "module.exports = { rules: { semi: [2, 'always'] } };"
|
|
}
|
|
});
|
|
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
it("should throw an error when extends config module is not found", () => {
|
|
assert.throws(() => {
|
|
create({
|
|
extends: "not-exist",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "not-exist" to extend from./u);
|
|
});
|
|
|
|
it("should throw an error when an eslint config is not found", () => {
|
|
assert.throws(() => {
|
|
create({
|
|
extends: "eslint:foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "eslint:foo" to extend from./u);
|
|
});
|
|
|
|
it("should throw an error when a plugin threw while loading.", () => {
|
|
assert.throws(() => {
|
|
create({
|
|
extends: "plugin:error/foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /xxx error/u);
|
|
});
|
|
|
|
it("should throw an error when a plugin extend is a file path.", () => {
|
|
assert.throws(() => {
|
|
create({
|
|
extends: "plugin:./path/to/foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /'extends' cannot use a file path for plugins/u);
|
|
});
|
|
|
|
it("should throw an error when an eslint config is not found", () => {
|
|
assert.throws(() => {
|
|
create({
|
|
extends: "eslint:foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "eslint:foo" to extend from./u);
|
|
});
|
|
|
|
describe("if 'extends' property was 'eslint:all', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "eslint:all", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have two elements.", () => {
|
|
assert.strictEqual(configArray.length, 2);
|
|
});
|
|
|
|
it("should have the config data of 'eslint:all' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » eslint:all",
|
|
filePath: require.resolve("../../../conf/eslint-all.js"),
|
|
...require("../../../conf/eslint-all.js")
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was 'eslint:recommended', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "eslint:recommended", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have two elements.", () => {
|
|
assert.strictEqual(configArray.length, 2);
|
|
});
|
|
|
|
it("should have the config data of 'eslint:recommended' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » eslint:recommended",
|
|
filePath: require.resolve("../../../conf/eslint-recommended.js"),
|
|
...require("../../../conf/eslint-recommended.js")
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was 'foo', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "foo", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have two elements.", () => {
|
|
assert.strictEqual(configArray.length, 2);
|
|
});
|
|
|
|
it("should have the config data of 'eslint-config-foo' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » eslint-config-foo",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-foo/index.js"),
|
|
env: { browser: true }
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was 'plugin:foo/bar', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "plugin:foo/bar", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have two elements.", () => {
|
|
assert.strictEqual(configArray.length, 2);
|
|
});
|
|
|
|
it("should have the config data of 'plugin:foo/bar' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » plugin:foo/bar",
|
|
filePath: path.join(tempDir, "node_modules/eslint-plugin-foo/index.js"),
|
|
env: { es6: true }
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was './base', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "./base", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have two elements.", () => {
|
|
assert.strictEqual(configArray.length, 2);
|
|
});
|
|
|
|
it("should have the config data of './base' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » ./base",
|
|
filePath: path.join(tempDir, "base.js"),
|
|
rules: { semi: [2, "always"] }
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was 'one' and the 'one' extends 'two', the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "one", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
it("should have the config data of 'eslint-config-two' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » eslint-config-one » eslint-config-two",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-two/index.js"),
|
|
env: { node: true }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'eslint-config-one' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc » eslint-config-one",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-one/index.js"),
|
|
env: { browser: true }
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if 'extends' property was 'override' and the 'override' has 'overrides' property, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create(
|
|
{ extends: "override", rules: { eqeqeq: 1 } },
|
|
{ name: ".eslintrc" }
|
|
);
|
|
});
|
|
|
|
it("should have four elements.", () => {
|
|
assert.strictEqual(configArray.length, 4);
|
|
});
|
|
|
|
it("should have the config data of 'eslint-config-override' at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
name: ".eslintrc » eslint-config-override",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-override/index.js"),
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the 'overrides[0]' config data of 'eslint-config-override' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: ".eslintrc » eslint-config-override#overrides[0]",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-override/index.js"),
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the 'overrides[1]' config data of 'eslint-config-override' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: ".eslintrc » eslint-config-override#overrides[1]",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-override/index.js"),
|
|
criteria: OverrideTester.create(["*.yyy"], [], tempDir),
|
|
rules: { override: 2 }
|
|
});
|
|
});
|
|
|
|
it("should have the given config data at the fourth element.", () => {
|
|
assertConfigArrayElement(configArray[3], {
|
|
name: ".eslintrc",
|
|
rules: { eqeqeq: 1 }
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("'overrides' details", () => {
|
|
before(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/eslint-config-foo/index.js": `
|
|
module.exports = {
|
|
rules: { eqeqeq: "error" }
|
|
}
|
|
`,
|
|
"node_modules/eslint-config-has-overrides/index.js": `
|
|
module.exports = {
|
|
rules: { eqeqeq: "error" },
|
|
overrides: [
|
|
{
|
|
files: ["**/foo/**/*.js"],
|
|
rules: { eqeqeq: "off" }
|
|
}
|
|
]
|
|
}
|
|
`,
|
|
"node_modules/eslint-config-root/index.js": `
|
|
module.exports = {
|
|
root: true,
|
|
rules: { eqeqeq: "error" }
|
|
}
|
|
`
|
|
}
|
|
});
|
|
|
|
factory = new ConfigArrayFactory();
|
|
});
|
|
|
|
describe("if 'overrides' property was given, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{ files: "*.xxx", rules: { override: 1 } },
|
|
{ files: "*.yyy", rules: { override: 2 } }
|
|
]
|
|
});
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
it("should have the given config data at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0]' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: "#overrides[0]",
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[1]' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: "#overrides[1]",
|
|
criteria: OverrideTester.create(["*.yyy"], [], tempDir),
|
|
rules: { override: 2 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if a config in 'overrides' property had 'extends' property, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{
|
|
files: "*.xxx",
|
|
extends: "foo",
|
|
rules: { override: 1 }
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
it("should have the given config data at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0] » eslint-config-foo' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: "#overrides[0] » eslint-config-foo",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-foo/index.js"),
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { eqeqeq: "error" }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0]' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: "#overrides[0]",
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if a config in 'overrides' property had 'extends' property and the shareable config has 'overrides' property, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{
|
|
files: "*.xxx",
|
|
extends: "has-overrides",
|
|
rules: { override: 1 }
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it("should have four elements.", () => {
|
|
assert.strictEqual(configArray.length, 4);
|
|
});
|
|
|
|
it("should have the given config data at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0] » eslint-config-has-overrides' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: "#overrides[0] » eslint-config-has-overrides",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-has-overrides/index.js"),
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { eqeqeq: "error" }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0] » eslint-config-has-overrides#overrides[0]' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: "#overrides[0] » eslint-config-has-overrides#overrides[0]",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-has-overrides/index.js"),
|
|
criteria: OverrideTester.and(
|
|
OverrideTester.create(["*.xxx"], [], tempDir),
|
|
OverrideTester.create(["**/foo/**/*.js"], [], tempDir)
|
|
),
|
|
rules: { eqeqeq: "off" }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0]' at the fourth element.", () => {
|
|
assertConfigArrayElement(configArray[3], {
|
|
name: "#overrides[0]",
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if a config in 'overrides' property had 'overrides' property, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{
|
|
files: "*.xxx",
|
|
rules: { override: 1 },
|
|
overrides: [
|
|
{
|
|
files: "*.yyy",
|
|
rules: { override: 2 }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
it("should have the given config data at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0]' at the second element.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: "#overrides[0]",
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0].overrides[0]' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: "#overrides[0]#overrides[0]",
|
|
criteria: OverrideTester.and(
|
|
OverrideTester.create(["*.xxx"], [], tempDir),
|
|
OverrideTester.create(["*.yyy"], [], tempDir)
|
|
),
|
|
rules: { override: 2 }
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("if a config in 'overrides' property had 'root' property, the returned value", () => {
|
|
let configArray;
|
|
|
|
beforeEach(() => {
|
|
configArray = create({
|
|
rules: { regular: 1 },
|
|
overrides: [
|
|
{
|
|
files: "*.xxx",
|
|
extends: "root",
|
|
rules: { override: 1 }
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
it("should have three elements.", () => {
|
|
assert.strictEqual(configArray.length, 3);
|
|
});
|
|
|
|
it("should have the given config data at the first element.", () => {
|
|
assertConfigArrayElement(configArray[0], {
|
|
rules: { regular: 1 }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0] » eslint-config-root' at the second element; it doesn't have 'root' property.", () => {
|
|
assertConfigArrayElement(configArray[1], {
|
|
name: "#overrides[0] » eslint-config-root",
|
|
filePath: path.join(tempDir, "node_modules/eslint-config-root/index.js"),
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { eqeqeq: "error" }
|
|
});
|
|
});
|
|
|
|
it("should have the config data of 'overrides[0]' at the third element.", () => {
|
|
assertConfigArrayElement(configArray[2], {
|
|
name: "#overrides[0]",
|
|
criteria: OverrideTester.create(["*.xxx"], [], tempDir),
|
|
rules: { override: 1 }
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("additional plugin pool", () => {
|
|
beforeEach(() => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir
|
|
});
|
|
|
|
factory = new ConfigArrayFactory({
|
|
additionalPluginPool: new Map([
|
|
["abc", { configs: { name: "abc" } }],
|
|
["eslint-plugin-def", { configs: { name: "def" } }]
|
|
])
|
|
});
|
|
});
|
|
|
|
it("should use the matched plugin in the additional plugin pool; short to short", () => {
|
|
const configArray = create({ plugins: ["abc"] });
|
|
|
|
assert.strictEqual(configArray[0].plugins.abc.id, "abc");
|
|
assertPluginDefinition(
|
|
configArray[0].plugins.abc.definition,
|
|
{ configs: { name: "abc" } }
|
|
);
|
|
});
|
|
|
|
it("should use the matched plugin in the additional plugin pool; long to short", () => {
|
|
const configArray = create({ plugins: ["eslint-plugin-abc"] });
|
|
|
|
assert.strictEqual(configArray[0].plugins.abc.id, "abc");
|
|
assertPluginDefinition(
|
|
configArray[0].plugins.abc.definition,
|
|
{ configs: { name: "abc" } }
|
|
);
|
|
});
|
|
|
|
it("should use the matched plugin in the additional plugin pool; short to long", () => {
|
|
const configArray = create({ plugins: ["def"] });
|
|
|
|
assert.strictEqual(configArray[0].plugins.def.id, "def");
|
|
assertPluginDefinition(
|
|
configArray[0].plugins.def.definition,
|
|
{ configs: { name: "def" } }
|
|
);
|
|
});
|
|
|
|
it("should use the matched plugin in the additional plugin pool; long to long", () => {
|
|
const configArray = create({ plugins: ["eslint-plugin-def"] });
|
|
|
|
assert.strictEqual(configArray[0].plugins.def.id, "def");
|
|
assertPluginDefinition(
|
|
configArray[0].plugins.def.definition,
|
|
{ configs: { name: "def" } }
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
// This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
|
|
describe("'extends' property should handle the content of extended configs properly.", () => {
|
|
const files = {
|
|
"node_modules/eslint-config-foo/index.js": "exports.env = { browser: true }",
|
|
"node_modules/eslint-config-one/index.js": "module.exports = { extends: 'two', env: { browser: true } }",
|
|
"node_modules/eslint-config-two/index.js": "module.exports = { env: { node: true } }",
|
|
"node_modules/eslint-plugin-invalid-parser/index.js": "exports.configs = { foo: { parser: 'nonexistent-parser' } }",
|
|
"node_modules/eslint-plugin-invalid-config/index.js": "exports.configs = { foo: {} }",
|
|
"js/.eslintrc.js": "module.exports = { rules: { semi: [2, 'always'] } };",
|
|
"cjs/.eslintrc.cjs": "module.exports = { rules: { semi: [2, 'always'] } };",
|
|
"json/.eslintrc.json": "{ \"rules\": { \"quotes\": [2, \"double\"] } }",
|
|
"package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }",
|
|
"yaml/.eslintrc.yaml": "env:\n browser: true"
|
|
};
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({ files });
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
/**
|
|
* Apply `extends` property.
|
|
* @param {Object} configData The config that has `extends` property.
|
|
* @param {string} [filePath] The path to the config data.
|
|
* @returns {Object} The applied config data.
|
|
*/
|
|
function applyExtends(configData, filePath = "whatever") {
|
|
return factory
|
|
.create(configData, { filePath })
|
|
.extractConfig(filePath)
|
|
.toCompatibleObjectAsConfigFileContent();
|
|
}
|
|
|
|
it("should apply extension 'foo' when specified from root directory config", () => {
|
|
const config = applyExtends({
|
|
extends: "foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
|
|
assertConfig(config, {
|
|
env: { browser: true },
|
|
rules: { eqeqeq: [2] }
|
|
});
|
|
});
|
|
|
|
it("should apply all rules when extends config includes 'eslint:all'", () => {
|
|
const config = applyExtends({
|
|
extends: "eslint:all"
|
|
});
|
|
|
|
assert.strictEqual(config.rules.eqeqeq[0], "error");
|
|
assert.strictEqual(config.rules.curly[0], "error");
|
|
});
|
|
|
|
it("should throw an error when extends config module is not found", () => {
|
|
assert.throws(() => {
|
|
applyExtends({
|
|
extends: "not-exist",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "not-exist" to extend from./u);
|
|
});
|
|
|
|
it("should throw an error when an eslint config is not found", () => {
|
|
assert.throws(() => {
|
|
applyExtends({
|
|
extends: "eslint:foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "eslint:foo" to extend from./u);
|
|
});
|
|
|
|
it("should throw an error when a parser in a plugin config is not found", () => {
|
|
assert.throws(() => {
|
|
applyExtends({
|
|
extends: "plugin:invalid-parser/foo",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load parser 'nonexistent-parser' declared in 'whatever » plugin:invalid-parser\/foo'/u);
|
|
});
|
|
|
|
it("should fall back to default parser when a parser called 'espree' is not found", () => {
|
|
const config = applyExtends({ parser: "espree" });
|
|
|
|
assertConfig(config, {
|
|
parser: require.resolve("espree")
|
|
});
|
|
});
|
|
|
|
it("should throw an error when a plugin config is not found", () => {
|
|
assert.throws(() => {
|
|
applyExtends({
|
|
extends: "plugin:invalid-config/bar",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
}, /Failed to load config "plugin:invalid-config\/bar" to extend from./u);
|
|
});
|
|
|
|
it("should throw an error with a message template when a plugin referenced for a plugin config is not found", () => {
|
|
try {
|
|
applyExtends({
|
|
extends: "plugin:nonexistent-plugin/baz",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
} catch (err) {
|
|
assert.strictEqual(err.messageTemplate, "plugin-missing");
|
|
assert.deepStrictEqual(err.messageData, {
|
|
pluginName: "eslint-plugin-nonexistent-plugin",
|
|
resolvePluginsRelativeTo: process.cwd(),
|
|
importerName: "whatever"
|
|
});
|
|
return;
|
|
}
|
|
assert.fail("Expected to throw an error");
|
|
});
|
|
|
|
it("should throw an error with a message template when a plugin in the plugins list is not found", () => {
|
|
try {
|
|
applyExtends({
|
|
plugins: ["nonexistent-plugin"]
|
|
});
|
|
} catch (err) {
|
|
assert.strictEqual(err.messageTemplate, "plugin-missing");
|
|
assert.deepStrictEqual(err.messageData, {
|
|
pluginName: "eslint-plugin-nonexistent-plugin",
|
|
resolvePluginsRelativeTo: process.cwd(),
|
|
importerName: "whatever"
|
|
});
|
|
return;
|
|
}
|
|
assert.fail("Expected to throw an error");
|
|
});
|
|
|
|
it("should apply extensions recursively when specified from package", () => {
|
|
const config = applyExtends({
|
|
extends: "one",
|
|
rules: { eqeqeq: 2 }
|
|
});
|
|
|
|
assertConfig(config, {
|
|
env: { browser: true, node: true },
|
|
rules: { eqeqeq: [2] }
|
|
});
|
|
});
|
|
|
|
it("should apply extensions when specified from a JavaScript file", () => {
|
|
const config = applyExtends({
|
|
extends: ".eslintrc.js",
|
|
rules: { eqeqeq: 2 }
|
|
}, "js/foo.js");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: [2, "always"],
|
|
eqeqeq: [2]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should apply extensions when specified from a YAML file", () => {
|
|
const config = applyExtends({
|
|
extends: ".eslintrc.yaml",
|
|
rules: { eqeqeq: 2 }
|
|
}, "yaml/foo.js");
|
|
|
|
assertConfig(config, {
|
|
env: { browser: true },
|
|
rules: {
|
|
eqeqeq: [2]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should apply extensions when specified from a JSON file", () => {
|
|
const config = applyExtends({
|
|
extends: ".eslintrc.json",
|
|
rules: { eqeqeq: 2 }
|
|
}, "json/foo.js");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
eqeqeq: [2],
|
|
quotes: [2, "double"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should apply extensions when specified from a package.json file in a sibling directory", () => {
|
|
const config = applyExtends({
|
|
extends: "../package-json/package.json",
|
|
rules: { eqeqeq: 2 }
|
|
}, "json/foo.js");
|
|
|
|
assertConfig(config, {
|
|
env: { es6: true },
|
|
rules: {
|
|
eqeqeq: [2]
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
|
|
describe("loading config files should work properly.", () => {
|
|
|
|
/**
|
|
* Load a given config file.
|
|
* @param {ConfigArrayFactory} factory The factory to load.
|
|
* @param {string} filePath The path to a config file.
|
|
* @returns {Object} The applied config data.
|
|
*/
|
|
function load(factory, filePath) {
|
|
return factory
|
|
.loadFile(filePath)
|
|
.extractConfig(filePath)
|
|
.toCompatibleObjectAsConfigFileContent();
|
|
}
|
|
|
|
it("should throw error if file doesn't exist", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem();
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
assert.throws(() => {
|
|
load(factory, "legacy/nofile.js");
|
|
});
|
|
|
|
assert.throws(() => {
|
|
load(factory, "legacy/package.json");
|
|
});
|
|
});
|
|
|
|
it("should load information from a legacy file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"legacy/.eslintrc": "{ rules: { eqeqeq: 2 } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "legacy/.eslintrc");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
eqeqeq: [2]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from a JavaScript file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"js/.eslintrc.js": "module.exports = { rules: { semi: [2, 'always'] } };"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "js/.eslintrc.js");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: [2, "always"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from a JavaScript file with a .cjs extension", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"cjs/.eslintrc.cjs": "module.exports = { rules: { semi: [2, 'always'] } };"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "cjs/.eslintrc.cjs");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: [2, "always"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should throw error when loading invalid JavaScript file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"js/.eslintrc.broken.js": "module.exports = { rules: { semi: [2, 'always'] }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
assert.throws(() => {
|
|
load(factory, "js/.eslintrc.broken.js");
|
|
}, /Cannot read config file/u);
|
|
});
|
|
|
|
it("should interpret parser module name when present in a JavaScript file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"node_modules/foo/index.js": "",
|
|
"js/node_modules/foo/index.js": "",
|
|
"js/.eslintrc.parser.js": `module.exports = {
|
|
parser: 'foo',
|
|
rules: { semi: [2, 'always'] }
|
|
};`
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "js/.eslintrc.parser.js");
|
|
|
|
assertConfig(config, {
|
|
parser: path.resolve("js/node_modules/foo/index.js"),
|
|
rules: {
|
|
semi: [2, "always"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should interpret parser path when present in a JavaScript file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"js/.eslintrc.parser2.js": `module.exports = {
|
|
parser: './not-a-config.js',
|
|
rules: { semi: [2, 'always'] }
|
|
};`,
|
|
"js/not-a-config.js": ""
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "js/.eslintrc.parser2.js");
|
|
|
|
assertConfig(config, {
|
|
parser: path.resolve("js/not-a-config.js"),
|
|
rules: {
|
|
semi: [2, "always"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should interpret parser module name or path when parser is set to default parser in a JavaScript file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"js/.eslintrc.parser3.js": `module.exports = {
|
|
parser: 'espree',
|
|
rules: { semi: [2, 'always'] }
|
|
};`
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "js/.eslintrc.parser3.js");
|
|
|
|
assertConfig(config, {
|
|
parser: require.resolve("espree"),
|
|
rules: {
|
|
semi: [2, "always"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from a JSON file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"json/.eslintrc.json": "{ \"rules\": { \"quotes\": [2, \"double\"] } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "json/.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
quotes: [2, "double"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load fresh information from a JSON file", () => {
|
|
const { fs, ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem();
|
|
const factory = new ConfigArrayFactory();
|
|
const initialConfig = {
|
|
rules: {
|
|
quotes: [2, "double"]
|
|
}
|
|
};
|
|
const updatedConfig = {
|
|
rules: {
|
|
quotes: [0]
|
|
}
|
|
};
|
|
let config;
|
|
|
|
fs.writeFileSync("fresh-test.json", JSON.stringify(initialConfig));
|
|
config = load(factory, "fresh-test.json");
|
|
assertConfig(config, initialConfig);
|
|
|
|
fs.writeFileSync("fresh-test.json", JSON.stringify(updatedConfig));
|
|
config = load(factory, "fresh-test.json");
|
|
assertConfig(config, updatedConfig);
|
|
});
|
|
|
|
it("should load information from a package.json file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "package-json/package.json");
|
|
|
|
assertConfig(config, {
|
|
env: { es6: true }
|
|
});
|
|
});
|
|
|
|
it("should throw error when loading invalid package.json file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"broken-package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
assert.throws(() => {
|
|
try {
|
|
load(factory, "broken-package-json/package.json");
|
|
} catch (error) {
|
|
assert.strictEqual(error.messageTemplate, "failed-to-read-json");
|
|
throw error;
|
|
}
|
|
}, /Cannot read config file/u);
|
|
});
|
|
|
|
it("should load fresh information from a package.json file", () => {
|
|
const { fs, ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem();
|
|
const factory = new ConfigArrayFactory();
|
|
const initialConfig = {
|
|
eslintConfig: {
|
|
rules: {
|
|
quotes: [2, "double"]
|
|
}
|
|
}
|
|
};
|
|
const updatedConfig = {
|
|
eslintConfig: {
|
|
rules: {
|
|
quotes: [0]
|
|
}
|
|
}
|
|
};
|
|
let config;
|
|
|
|
fs.writeFileSync("package.json", JSON.stringify(initialConfig));
|
|
config = load(factory, "package.json");
|
|
assertConfig(config, initialConfig.eslintConfig);
|
|
|
|
fs.writeFileSync("package.json", JSON.stringify(updatedConfig));
|
|
config = load(factory, "package.json");
|
|
assertConfig(config, updatedConfig.eslintConfig);
|
|
});
|
|
|
|
it("should load fresh information from a .eslintrc.js file", () => {
|
|
const { fs, ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem();
|
|
const factory = new ConfigArrayFactory();
|
|
const initialConfig = {
|
|
rules: {
|
|
quotes: [2, "double"]
|
|
}
|
|
};
|
|
const updatedConfig = {
|
|
rules: {
|
|
quotes: [0]
|
|
}
|
|
};
|
|
let config;
|
|
|
|
fs.writeFileSync(".eslintrc.js", `module.exports = ${JSON.stringify(initialConfig)}`);
|
|
config = load(factory, ".eslintrc.js");
|
|
assertConfig(config, initialConfig);
|
|
|
|
fs.writeFileSync(".eslintrc.js", `module.exports = ${JSON.stringify(updatedConfig)}`);
|
|
config = load(factory, ".eslintrc.js");
|
|
assertConfig(config, updatedConfig);
|
|
});
|
|
|
|
it("should load information from a YAML file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"yaml/.eslintrc.yaml": "env:\n browser: true"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "yaml/.eslintrc.yaml");
|
|
|
|
assertConfig(config, {
|
|
env: { browser: true }
|
|
});
|
|
});
|
|
|
|
it("should load information from an empty YAML file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"yaml/.eslintrc.empty.yaml": "{}"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "yaml/.eslintrc.empty.yaml");
|
|
|
|
assertConfig(config, {});
|
|
});
|
|
|
|
it("should load information from a YML file", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"yml/.eslintrc.yml": "env:\n node: true"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "yml/.eslintrc.yml");
|
|
|
|
assertConfig(config, {
|
|
env: { node: true }
|
|
});
|
|
});
|
|
|
|
it("should load information from a YML file and apply extensions", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"extends/.eslintrc.yml": "extends: ../package-json/package.json\nrules:\n booya: 2",
|
|
"package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "extends/.eslintrc.yml");
|
|
|
|
assertConfig(config, {
|
|
env: { es6: true },
|
|
rules: { booya: [2] }
|
|
});
|
|
});
|
|
|
|
it("should load information from `extends` chain.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"extends-chain": {
|
|
"node_modules/eslint-config-a": {
|
|
"node_modules/eslint-config-b": {
|
|
"node_modules/eslint-config-c": {
|
|
"index.js": "module.exports = { rules: { c: 2 } };"
|
|
},
|
|
"index.js": "module.exports = { extends: 'c', rules: { b: 2 } };"
|
|
},
|
|
"index.js": "module.exports = { extends: 'b', rules: { a: 2 } };"
|
|
},
|
|
".eslintrc.json": "{ \"extends\": \"a\" }"
|
|
}
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "extends-chain/.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
a: [2], // from node_modules/eslint-config-a
|
|
b: [2], // from node_modules/eslint-config-a/node_modules/eslint-config-b
|
|
c: [2] // from node_modules/eslint-config-a/node_modules/eslint-config-b/node_modules/eslint-config-c
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from `extends` chain with relative path.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"extends-chain-2": {
|
|
"node_modules/eslint-config-a/index.js": "module.exports = { extends: './relative.js', rules: { a: 2 } };",
|
|
"node_modules/eslint-config-a/relative.js": "module.exports = { rules: { relative: 2 } };",
|
|
".eslintrc.json": "{ \"extends\": \"a\" }"
|
|
}
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "extends-chain-2/.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
a: [2], // from node_modules/eslint-config-a/index.js
|
|
relative: [2] // from node_modules/eslint-config-a/relative.js
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from `extends` chain in .eslintrc with relative path.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"extends-chain-2": {
|
|
"node_modules/eslint-config-a/index.js": "module.exports = { extends: './relative.js', rules: { a: 2 } };",
|
|
"node_modules/eslint-config-a/relative.js": "module.exports = { rules: { relative: 2 } };",
|
|
"relative.eslintrc.json": "{ \"extends\": \"./node_modules/eslint-config-a/index.js\" }"
|
|
}
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "extends-chain-2/relative.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
a: [2], // from node_modules/eslint-config-a/index.js
|
|
relative: [2] // from node_modules/eslint-config-a/relative.js
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load information from `parser` in .eslintrc with relative path.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"extends-chain-2": {
|
|
"parser.eslintrc.json": "{ \"parser\": \"./parser.js\" }",
|
|
"parser.js": ""
|
|
}
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "extends-chain-2/parser.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
parser: path.resolve("extends-chain-2/parser.js")
|
|
});
|
|
});
|
|
|
|
describe("Plugins", () => {
|
|
it("should load information from a YML file and load plugins", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"node_modules/eslint-plugin-test/index.js": `
|
|
module.exports = {
|
|
environments: {
|
|
bar: { globals: { bar: true } }
|
|
}
|
|
}
|
|
`,
|
|
"plugins/.eslintrc.yml": `
|
|
plugins:
|
|
- test
|
|
rules:
|
|
test/foo: 2
|
|
env:
|
|
test/bar: true
|
|
`
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "plugins/.eslintrc.yml");
|
|
|
|
assertConfig(config, {
|
|
env: { "test/bar": true },
|
|
plugins: ["test"],
|
|
rules: {
|
|
"test/foo": [2]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should load two separate configs from a plugin", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"node_modules/eslint-plugin-test/index.js": `
|
|
module.exports = {
|
|
configs: {
|
|
foo: { rules: { semi: 2, quotes: 1 } },
|
|
bar: { rules: { quotes: 2, yoda: 2 } }
|
|
}
|
|
}
|
|
`,
|
|
"plugins/.eslintrc.yml": `
|
|
extends:
|
|
- plugin:test/foo
|
|
- plugin:test/bar
|
|
`
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "plugins/.eslintrc.yml");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: [2],
|
|
quotes: [2],
|
|
yoda: [2]
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("even if config files have Unicode BOM,", () => {
|
|
it("should read the JSON config file correctly.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"bom/.eslintrc.json": "\uFEFF{ \"rules\": { \"semi\": \"error\" } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "bom/.eslintrc.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: ["error"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should read the YAML config file correctly.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"bom/.eslintrc.yaml": "\uFEFFrules:\n semi: error"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "bom/.eslintrc.yaml");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: ["error"]
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should read the config in package.json correctly.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"bom/package.json": "\uFEFF{ \"eslintConfig\": { \"rules\": { \"semi\": \"error\" } } }"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
const config = load(factory, "bom/package.json");
|
|
|
|
assertConfig(config, {
|
|
rules: {
|
|
semi: ["error"]
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
it("throws an error including the config file name if the config file is invalid", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
files: {
|
|
"invalid/invalid-top-level-property.yml": "invalidProperty: 3"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
try {
|
|
load(factory, "invalid/invalid-top-level-property.yml");
|
|
} catch (err) {
|
|
assert.include(err.message, `ESLint configuration in ${`invalid${path.sep}invalid-top-level-property.yml`} is invalid`);
|
|
return;
|
|
}
|
|
assert.fail();
|
|
});
|
|
});
|
|
|
|
// This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
|
|
describe("'extends' property should resolve the location of configs properly.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/eslint-config-foo/index.js": "",
|
|
"node_modules/eslint-config-foo/bar.js": "",
|
|
"node_modules/eslint-config-eslint-configfoo/index.js": "",
|
|
"node_modules/@foo/eslint-config/index.js": "",
|
|
"node_modules/@foo/eslint-config-bar/index.js": "",
|
|
"node_modules/eslint-plugin-foo/index.js": "exports.configs = { bar: {} }",
|
|
"node_modules/@foo/eslint-plugin/index.js": "exports.configs = { bar: {} }",
|
|
"node_modules/@foo/eslint-plugin-bar/index.js": "exports.configs = { baz: {} }",
|
|
"foo/bar/.eslintrc": "",
|
|
".eslintrc": ""
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
/**
|
|
* Resolve `extends` module.
|
|
* @param {string} request The module name to resolve.
|
|
* @param {string} [relativeTo] The importer path to resolve.
|
|
* @returns {string} The resolved path.
|
|
*/
|
|
function resolve(request, relativeTo) {
|
|
return factory.create(
|
|
{ extends: request },
|
|
{ filePath: relativeTo }
|
|
)[0];
|
|
}
|
|
|
|
describe("Relative to CWD", () => {
|
|
for (const { input, expected } of [
|
|
{ input: ".eslintrc", expected: path.resolve(tempDir, ".eslintrc") },
|
|
{ input: "eslint-config-foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
|
|
{ input: "eslint-config-foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
|
|
{ input: "foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
|
|
{ input: "foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
|
|
{ input: "eslint-configfoo", expected: path.resolve(tempDir, "node_modules/eslint-config-eslint-configfoo/index.js") },
|
|
{ input: "@foo/eslint-config", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
|
|
{ input: "@foo", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
|
|
{ input: "@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config-bar/index.js") },
|
|
{ input: "plugin:foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-plugin-foo/index.js") },
|
|
{ input: "plugin:@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin/index.js") },
|
|
{ input: "plugin:@foo/bar/baz", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin-bar/index.js") }
|
|
]) {
|
|
it(`should return ${expected} when passed ${input}`, () => {
|
|
const result = resolve(input);
|
|
|
|
assert.strictEqual(result.filePath, expected);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe("Relative to config file", () => {
|
|
const relativePath = path.resolve(tempDir, "./foo/bar/.eslintrc");
|
|
|
|
for (const { input, expected } of [
|
|
{ input: ".eslintrc", expected: path.join(path.dirname(relativePath), ".eslintrc") },
|
|
{ input: "eslint-config-foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
|
|
{ input: "eslint-config-foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
|
|
{ input: "foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
|
|
{ input: "foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
|
|
{ input: "eslint-configfoo", expected: path.resolve(tempDir, "node_modules/eslint-config-eslint-configfoo/index.js") },
|
|
{ input: "@foo/eslint-config", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
|
|
{ input: "@foo", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
|
|
{ input: "@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config-bar/index.js") },
|
|
{ input: "plugin:foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-plugin-foo/index.js") },
|
|
{ input: "plugin:@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin/index.js") },
|
|
{ input: "plugin:@foo/bar/baz", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin-bar/index.js") }
|
|
]) {
|
|
it(`should return ${expected} when passed ${input}`, () => {
|
|
const result = resolve(input, relativePath);
|
|
|
|
assert.strictEqual(result.filePath, expected);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// This group moved from 'tests/lib/config/plugins.js' when refactoring to keep the cumulated test cases.
|
|
describe("'plugins' property should load a correct plugin.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/@scope/eslint-plugin-example/index.js": "exports.configs = { name: '@scope/eslint-plugin-example' };",
|
|
"node_modules/eslint-plugin-example/index.js": "exports.configs = { name: 'eslint-plugin-example' };",
|
|
"node_modules/eslint-plugin-throws-on-load/index.js": "throw new Error('error thrown while loading this module')"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
/**
|
|
* Load a plugin.
|
|
* @param {string} request A request to load a plugin.
|
|
* @param {ConfigArrayFactory} [configArrayFactory] The factory to use
|
|
* @returns {Map<string,Object>} The loaded plugins.
|
|
*/
|
|
function load(request, configArrayFactory = factory) {
|
|
const config = configArrayFactory.create({ plugins: [request] });
|
|
|
|
return new Map(
|
|
Object
|
|
.entries(config[0].plugins)
|
|
.map(([id, entry]) => {
|
|
if (entry.error) {
|
|
throw entry.error;
|
|
}
|
|
return [id, entry.definition];
|
|
})
|
|
);
|
|
}
|
|
|
|
it("should load a plugin when referenced by short name", () => {
|
|
const loadedPlugins = load("example");
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("example"),
|
|
{ configs: { name: "eslint-plugin-example" } }
|
|
);
|
|
});
|
|
|
|
it("should load a plugin when referenced by short name, even when using a custom loadPluginsRelativeTo value", () => {
|
|
const { ConfigArrayFactory: FactoryWithPluginsInSubdir } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"subdir/node_modules/eslint-plugin-example/index.js": "exports.configs = { name: 'eslint-plugin-example' };"
|
|
}
|
|
});
|
|
|
|
const factoryWithCustomPluginPath = new FactoryWithPluginsInSubdir({ resolvePluginsRelativeTo: "subdir" });
|
|
|
|
const loadedPlugins = load("example", factoryWithCustomPluginPath);
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("example"),
|
|
{ configs: { name: "eslint-plugin-example" } }
|
|
);
|
|
});
|
|
|
|
it("should load a plugin when referenced by long name", () => {
|
|
const loadedPlugins = load("eslint-plugin-example");
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("example"),
|
|
{ configs: { name: "eslint-plugin-example" } }
|
|
);
|
|
});
|
|
|
|
it("should throw an error when a plugin has whitespace", () => {
|
|
assert.throws(() => {
|
|
load("whitespace ");
|
|
}, /Whitespace found in plugin name 'whitespace '/u);
|
|
assert.throws(() => {
|
|
load("whitespace\t");
|
|
}, /Whitespace found in plugin name/u);
|
|
assert.throws(() => {
|
|
load("whitespace\n");
|
|
}, /Whitespace found in plugin name/u);
|
|
assert.throws(() => {
|
|
load("whitespace\r");
|
|
}, /Whitespace found in plugin name/u);
|
|
});
|
|
|
|
it("should throw an error when a plugin doesn't exist", () => {
|
|
assert.throws(() => {
|
|
load("nonexistentplugin");
|
|
}, /Failed to load plugin/u);
|
|
});
|
|
|
|
it("should rethrow an error that a plugin throws on load", () => {
|
|
assert.throws(() => {
|
|
load("throws-on-load");
|
|
}, /error thrown while loading this module/u);
|
|
});
|
|
|
|
it("should load a scoped plugin when referenced by short name", () => {
|
|
const loadedPlugins = load("@scope/example");
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("@scope/example"),
|
|
{ configs: { name: "@scope/eslint-plugin-example" } }
|
|
);
|
|
});
|
|
|
|
it("should load a scoped plugin when referenced by long name", () => {
|
|
const loadedPlugins = load("@scope/eslint-plugin-example");
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("@scope/example"),
|
|
{ configs: { name: "@scope/eslint-plugin-example" } }
|
|
);
|
|
});
|
|
|
|
describe("when referencing a scope plugin and omitting @scope/", () => {
|
|
it("should load a scoped plugin when referenced by short name, but should not get the plugin if '@scope/' is omitted", () => {
|
|
const loadedPlugins = load("@scope/example");
|
|
|
|
assert.strictEqual(loadedPlugins.get("example"), void 0);
|
|
});
|
|
|
|
it("should load a scoped plugin when referenced by long name, but should not get the plugin if '@scope/' is omitted", () => {
|
|
const loadedPlugins = load("@scope/eslint-plugin-example");
|
|
|
|
assert.strictEqual(loadedPlugins.get("example"), void 0);
|
|
});
|
|
});
|
|
});
|
|
|
|
// This group moved from 'tests/lib/config/plugins.js' when refactoring to keep the cumulated test cases.
|
|
describe("'plugins' property should load some correct plugins.", () => {
|
|
const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({
|
|
cwd: () => tempDir,
|
|
files: {
|
|
"node_modules/eslint-plugin-example1/index.js": "exports.configs = { name: 'eslint-plugin-example1' };",
|
|
"node_modules/eslint-plugin-example2/index.js": "exports.configs = { name: 'eslint-plugin-example2' };"
|
|
}
|
|
});
|
|
const factory = new ConfigArrayFactory();
|
|
|
|
/**
|
|
* Load a plugin.
|
|
* @param {string[]} request A request to load a plugin.
|
|
* @returns {Map<string,Object>} The loaded plugins.
|
|
*/
|
|
function loadAll(request) {
|
|
const config = factory.create({ plugins: request });
|
|
|
|
return new Map(
|
|
Object
|
|
.entries(config[0].plugins)
|
|
.map(([id, entry]) => {
|
|
if (entry.error) {
|
|
throw entry.error;
|
|
}
|
|
return [id, entry.definition];
|
|
})
|
|
);
|
|
}
|
|
|
|
it("should load plugins when passed multiple plugins", () => {
|
|
const loadedPlugins = loadAll(["example1", "example2"]);
|
|
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("example1"),
|
|
{ configs: { name: "eslint-plugin-example1" } }
|
|
);
|
|
assertPluginDefinition(
|
|
loadedPlugins.get("example2"),
|
|
{ configs: { name: "eslint-plugin-example2" } }
|
|
);
|
|
});
|
|
});
|
|
});
|