diff --git a/src/EleventyExtensionMap.js b/src/EleventyExtensionMap.js index 051dc7547..62d140d90 100644 --- a/src/EleventyExtensionMap.js +++ b/src/EleventyExtensionMap.js @@ -76,6 +76,8 @@ class EleventyExtensionMap { // on paths found from the file system glob search. // TODO: Method name might just need to be renamed to something more accurate. isFullTemplateFilePath(path) { + path = (path || "").toLowerCase(); + for (let extension of this.validTemplateLanguageKeys) { if (path.endsWith(`.${extension}`)) { return true; @@ -97,6 +99,8 @@ class EleventyExtensionMap { } getValidExtensionsForPath(path) { + path = (path || "").toLowerCase(); + let extensions = new Set(); for (let extension in this.extensionToKeyMap) { if (path.endsWith(`.${extension}`)) { @@ -242,8 +246,10 @@ class EleventyExtensionMap { } removeTemplateExtension(path) { + let normalizedPath = (path || "").toLowerCase(); + for (let extension in this.extensionToKeyMap) { - if (path === extension || path.endsWith("." + extension)) { + if (normalizedPath === extension || normalizedPath.endsWith("." + extension)) { return path.slice( 0, path.length - 1 - extension.length < 0 ? 0 : path.length - 1 - extension.length, diff --git a/src/UserConfig.js b/src/UserConfig.js index 4c6d58693..c6e674820 100644 --- a/src/UserConfig.js +++ b/src/UserConfig.js @@ -928,6 +928,8 @@ class UserConfig { } for (let extension of extensions) { + extension = extension.trim().toLowerCase(); + if (this.extensionConflictMap[extension]) { throw new Error( `An attempt was made to override the "${extension}" template syntax twice (via the \`addExtension\` configuration API). A maximum of one override is currently supported.`, @@ -944,6 +946,8 @@ class UserConfig { }, options, ); + extensionOptions.key = extensionOptions.key.toLowerCase(); + extensionOptions.extension = extensionOptions.extension.toLowerCase(); if (extensionOptions.key !== extensionOptions.extension) { extensionOptions.aliasKey = extensionOptions.extension; diff --git a/test/EleventyExtensionMapTest.js b/test/EleventyExtensionMapTest.js index 03f2b1ca1..b75698106 100644 --- a/test/EleventyExtensionMapTest.js +++ b/test/EleventyExtensionMapTest.js @@ -38,6 +38,38 @@ test("Keys are mapped to lower case", async (t) => { t.deepEqual(map.getGlobs("."), ["./**/*.{liquid,pug,njk}"]); }); +test("Custom addExtension keys are mapped to lower case", async (t) => { + let cfg = new TemplateConfig(); + cfg.userConfig.addExtension("vZome", { + compile: function(content) { + return () => content; + } + }); + + let map = await getExtensionMap(["vZome"], cfg); + + t.deepEqual(map.getValidGlobs("."), ["./**/*.vzome"]); + t.true(map.hasEngine("component.vZome")); + t.is(map.getKey("component.vZome"), "vzome"); + t.true(map.isFullTemplateFilePath("component.vZome")); + t.deepEqual(map.getValidExtensionsForPath("component.vZome"), ["vzome"]); + t.is(map.removeTemplateExtension("component.vZome"), "component"); +}); + +test("Custom addExtension keys detect mixed-case duplicates", (t) => { + let cfg = new TemplateConfig(); + cfg.userConfig.addExtension("vZome", {}); + + let e = t.throws(() => { + cfg.userConfig.addExtension("VZOME", {}); + }); + + t.is( + e.message, + 'An attempt was made to override the "vzome" template syntax twice (via the `addExtension` configuration API). A maximum of one override is currently supported.', + ); +}); + test("Pruned globs", async (t) => { let map = await getExtensionMap(["liquid", "njk", "png"]); t.deepEqual(map.getPassthroughCopyGlobs("."), ["./**/*.png"]); diff --git a/test/EleventyTest.js b/test/EleventyTest.js index ecae5c44f..671dd85d9 100644 --- a/test/EleventyTest.js +++ b/test/EleventyTest.js @@ -1622,6 +1622,26 @@ test("permalink on custom template lang, issue #3619", async (t) => { }`); }); +test("Mixed-case custom template extensions are discovered, issue #4224", async (t) => { + let elev = new Eleventy("./test/stubs-4224/", undefined, { + config: function(eleventyConfig) { + eleventyConfig.addTemplateFormats("vZome"); + eleventyConfig.addExtension("vZome", { + compile: function(str) { + return function() { + return `Rendered ${str.trim()}`; + }; + }, + }); + }, + }); + elev.disableLogger(); + + let results = await elev.toJSON(); + t.is(results.length, 1); + t.is(results[0].content, "Rendered mixed-case custom extension"); +}); + test("Template data throws error when tags is not an Array or String #1791", async (t) => { let elev = new Eleventy("./test/noop/", "./test/noop/_site", { config: function (eleventyConfig) { diff --git a/test/stubs-4224/index.vZome b/test/stubs-4224/index.vZome new file mode 100644 index 000000000..fef6ce908 --- /dev/null +++ b/test/stubs-4224/index.vZome @@ -0,0 +1 @@ +mixed-case custom extension