diff --git a/lib/config/flat-config-array.js b/lib/config/flat-config-array.js index 46d436db5cf..78b4ef44bac 100644 --- a/lib/config/flat-config-array.js +++ b/lib/config/flat-config-array.js @@ -36,6 +36,45 @@ function splitPluginIdentifier(identifier) { }; } +/** + * Returns the name of an object in the config by reading its `meta` key. + * @param {Object} object The object to check. + * @returns {string?} The name of the object if found or `null` if there + * is no name. + */ +function getObjectId(object) { + + // first check old-style name + let name = object.name; + + if (!name) { + + if (!object.meta) { + return null; + } + + name = object.meta.name; + + if (!name) { + return null; + } + } + + // now check for old-style version + let version = object.version; + + if (!version) { + version = object.meta && object.meta.version; + } + + // if there's a version then append that + if (version) { + return `${name}@${version}`; + } + + return name; +} + const originalBaseConfig = Symbol("originalBaseConfig"); //----------------------------------------------------------------------------- @@ -151,16 +190,25 @@ class FlatConfigArray extends ConfigArray { // Check parser value if (languageOptions && languageOptions.parser) { - if (typeof languageOptions.parser === "string") { - const { pluginName, objectName: localParserName } = splitPluginIdentifier(languageOptions.parser); + const { parser } = languageOptions; + + if (typeof parser === "string") { + const { pluginName, objectName: localParserName } = splitPluginIdentifier(parser); - parserName = languageOptions.parser; + parserName = parser; if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[localParserName]) { throw new TypeError(`Key "parser": Could not find "${localParserName}" in plugin "${pluginName}".`); } languageOptions.parser = plugins[pluginName].parsers[localParserName]; + } else if (typeof parser === "object") { + parserName = getObjectId(parser); + + if (!parserName) { + invalidParser = true; + } + } else { invalidParser = true; } @@ -178,6 +226,13 @@ class FlatConfigArray extends ConfigArray { } config.processor = plugins[pluginName].processors[localProcessorName]; + } else if (typeof processor === "object") { + processorName = getObjectId(processor); + + if (!processorName) { + invalidProcessor = true; + } + } else { invalidProcessor = true; } @@ -191,11 +246,11 @@ class FlatConfigArray extends ConfigArray { value: function() { if (invalidParser) { - throw new Error("Caching is not supported when parser is an object."); + throw new Error("Could not serialize parser object (missing 'meta' object)."); } if (invalidProcessor) { - throw new Error("Caching is not supported when processor is an object."); + throw new Error("Could not serialize processor object (missing 'meta' object)."); } return { diff --git a/tests/lib/config/flat-config-array.js b/tests/lib/config/flat-config-array.js index fc3e455bfe6..c06e4da7798 100644 --- a/tests/lib/config/flat-config-array.js +++ b/tests/lib/config/flat-config-array.js @@ -219,7 +219,7 @@ describe("FlatConfigArray", () => { assert.strictEqual(stringify(actual), stringify(expected)); }); - it("should throw an error when config with parser object is normalized", () => { + it("should throw an error when config with unnamed parser object is normalized", () => { const configs = new FlatConfigArray([{ languageOptions: { @@ -235,11 +235,176 @@ describe("FlatConfigArray", () => { assert.throws(() => { config.toJSON(); - }, /Caching is not supported/u); + }, /Could not serialize parser/u); }); - it("should throw an error when config with processor object is normalized", () => { + it("should throw an error when config with unnamed parser object with empty meta object is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + meta: {}, + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.throws(() => { + config.toJSON(); + }, /Could not serialize parser/u); + + }); + + it("should throw an error when config with unnamed parser object with only meta version is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + meta: { + version: "0.1.1" + }, + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.throws(() => { + config.toJSON(); + }, /Could not serialize parser/u); + + }); + + it("should not throw an error when config with named parser object is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + meta: { + name: "custom-parser" + }, + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "custom-parser", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: void 0 + }); + + }); + + it("should not throw an error when config with named and versioned parser object is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + meta: { + name: "custom-parser", + version: "0.1.0" + }, + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "custom-parser@0.1.0", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: void 0 + }); + + }); + + it("should not throw an error when config with meta-named and versioned parser object is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + meta: { + name: "custom-parser" + }, + version: "0.1.0", + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "custom-parser@0.1.0", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: void 0 + }); + + }); + + it("should not throw an error when config with named and versioned parser object outside of meta object is normalized", () => { + + const configs = new FlatConfigArray([{ + languageOptions: { + parser: { + name: "custom-parser", + version: "0.1.0", + parse() { /* empty */ } + } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "custom-parser@0.1.0", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: void 0 + }); + + }); + + it("should throw an error when config with unnamed processor object is normalized", () => { const configs = new FlatConfigArray([{ processor: { @@ -254,10 +419,146 @@ describe("FlatConfigArray", () => { assert.throws(() => { config.toJSON(); - }, /Caching is not supported/u); + }, /Could not serialize processor/u); }); + it("should throw an error when config with processor object with empty meta object is normalized", () => { + + const configs = new FlatConfigArray([{ + processor: { + meta: {}, + preprocess() { /* empty */ }, + postprocess() { /* empty */ } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.throws(() => { + config.toJSON(); + }, /Could not serialize processor/u); + + }); + + + it("should not throw an error when config with named processor object is normalized", () => { + + const configs = new FlatConfigArray([{ + processor: { + meta: { + name: "custom-processor" + }, + preprocess() { /* empty */ }, + postprocess() { /* empty */ } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "@/espree", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: "custom-processor" + }); + + }); + + it("should not throw an error when config with named processor object without meta is normalized", () => { + + const configs = new FlatConfigArray([{ + processor: { + name: "custom-processor", + preprocess() { /* empty */ }, + postprocess() { /* empty */ } + } + }]); + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "@/espree", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: "custom-processor" + }); + + }); + + it("should not throw an error when config with named and versioned processor object is normalized", () => { + + const configs = new FlatConfigArray([{ + processor: { + meta: { + name: "custom-processor", + version: "1.2.3" + }, + preprocess() { /* empty */ }, + postprocess() { /* empty */ } + } + }]); + + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "@/espree", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: "custom-processor@1.2.3" + }); + + }); + + it("should not throw an error when config with named and versioned processor object without meta is normalized", () => { + + const configs = new FlatConfigArray([{ + processor: { + name: "custom-processor", + version: "1.2.3", + preprocess() { /* empty */ }, + postprocess() { /* empty */ } + } + }]); + + + configs.normalizeSync(); + + const config = configs.getConfig("foo.js"); + + assert.deepStrictEqual(config.toJSON(), { + languageOptions: { + ecmaVersion: "latest", + parser: "@/espree", + parserOptions: {}, + sourceType: "module" + }, + plugins: ["@"], + processor: "custom-processor@1.2.3" + }); + + }); });