diff --git a/src/Engines/Custom.js b/src/Engines/Custom.js index 7c9c9d712..e826e892e 100644 --- a/src/Engines/Custom.js +++ b/src/Engines/Custom.js @@ -186,9 +186,15 @@ class CustomEngine extends TemplateEngine { permalinkNeedsCompilation(str) { if (this.entry.compileOptions && "permalink" in this.entry.compileOptions) { let p = this.entry.compileOptions.permalink; - if (p === false || p === "raw") { + if (p === "raw") { return false; } + + // permalink: false is aliased to permalink: () => false + if (p === false) { + return () => false; + } + return this.entry.compileOptions.permalink; } diff --git a/src/Template.js b/src/Template.js index 514b69b7d..9be98d08d 100755 --- a/src/Template.js +++ b/src/Template.js @@ -492,6 +492,7 @@ class Template extends TemplateContent { return ret; } + // Used only by tests async renderContent(str, data, bypassMarkdown) { return super.render(str, data, bypassMarkdown); } @@ -678,11 +679,18 @@ class Template extends TemplateContent { date: data.page.date, outputPath: data.page.outputPath, url: data.page.url, + checkTemplateContent: true, set templateContent(content) { + if (content === undefined) { + this.checkTemplateContent = false; + } this._templateContent = content; }, get templateContent() { - if (this._templateContent === undefined) { + if ( + this.checkTemplateContent && + this._templateContent === undefined + ) { if (this.template.behavior.isRenderable()) { // should at least warn here throw new TemplateContentPrematureUseError( @@ -728,11 +736,18 @@ class Template extends TemplateContent { pageNumber: pageNumber, outputPath: pageData.page.outputPath, url: pageData.page.url, + checkTemplateContent: true, set templateContent(content) { + if (content === undefined) { + this.checkTemplateContent = false; + } this._templateContent = content; }, get templateContent() { - if (this._templateContent === undefined) { + if ( + this.checkTemplateContent && + this._templateContent === undefined + ) { if (this.template.behavior.isRenderable()) { throw new TemplateContentPrematureUseError( `Tried to use templateContent too early (${this.inputPath} page ${this.pageNumber})` @@ -803,13 +818,9 @@ class Template extends TemplateContent { await mkdir(templateOutputDir, { recursive: true }); } - if (Buffer.isBuffer(finalContent)) { - finalContent = finalContent.toString(); - } - - if (typeof finalContent !== "string") { + if (!Buffer.isBuffer(finalContent) && typeof finalContent !== "string") { throw new Error( - `The return value from the render function for the ${this.engine.name} template was not a string. Received ${finalContent}` + `The return value from the render function for the ${this.engine.name} template was not a String or Buffer. Received ${finalContent}` ); } @@ -854,7 +865,6 @@ class Template extends TemplateContent { return Promise.all( mapEntry._pages.map(async (page) => { let content; - // Note that behavior.render is overridden when using json or ndjson output if (mapEntry.template.behavior.isRenderable()) { // this reuses page.templateContent, it doesn’t render it @@ -907,7 +917,10 @@ class Template extends TemplateContent { return; } - return this._write(page.outputPath, content); + // compile returned undefined + if (content !== undefined) { + return this._write(page.outputPath, content); + } }) ); } diff --git a/src/TemplateContent.js b/src/TemplateContent.js index 5b4c7656b..aa8e4532e 100644 --- a/src/TemplateContent.js +++ b/src/TemplateContent.js @@ -344,6 +344,7 @@ class TemplateContent { // No string compilation: // ({ compileOptions: { permalink: "raw" }}) // These mean `permalink: false`, which is no file system writing: + // ({ compileOptions: { permalink: false }}) // ({ compileOptions: { permalink: () => false }}) // ({ compileOptions: { permalink: () => (() = > false) }}) if (permalinkCompilation === false) { diff --git a/src/TemplateMap.js b/src/TemplateMap.js index 26fe76c8c..e296e85b3 100644 --- a/src/TemplateMap.js +++ b/src/TemplateMap.js @@ -603,7 +603,10 @@ class TemplateMap { // This check skips precompiled collections if (entry) { let index = item.pageNumber || 0; - item.templateContent = entry._pages[index]._templateContent; + let content = entry._pages[index]._templateContent; + if (content !== undefined) { + item.templateContent = content; + } } } } diff --git a/test/TemplateTest-CompileOptions.js b/test/TemplateTest-CompileOptions.js index 2adf7016a..3065f29c3 100644 --- a/test/TemplateTest-CompileOptions.js +++ b/test/TemplateTest-CompileOptions.js @@ -47,7 +47,7 @@ test("Custom extension (.txt) with custom permalink compile function", async (t) }); }); -test("Custom extension with and opt-out of permalink compilation", async (t) => { +test("Custom extension with and compileOptions.permalink = false", async (t) => { let eleventyConfig = new TemplateConfig(); eleventyConfig.userConfig.extensionMap.add({ extension: "txt", @@ -73,6 +73,41 @@ test("Custom extension with and opt-out of permalink compilation", async (t) => eleventyConfig ); + let data = await tmpl.getData(); + t.is(await tmpl.render(data), "Sample content"); + t.deepEqual(await tmpl.getOutputLocations(data), { + href: false, + path: false, + rawPath: false, + }); +}); + +test("Custom extension with and opt-out of permalink compilation", async (t) => { + let eleventyConfig = new TemplateConfig(); + eleventyConfig.userConfig.extensionMap.add({ + extension: "txt", + key: "txt", + compileOptions: { + permalink: "raw", + }, + compile: function (str, inputPath) { + // plaintext + return function (data) { + return str; + }; + }, + }); + + let dataObj = new TemplateData("./test/stubs/", eleventyConfig); + let tmpl = getNewTemplate( + "./test/stubs/custom-extension.txt", + "./test/stubs/", + "dist", + dataObj, + null, + eleventyConfig + ); + let data = await tmpl.getData(); t.is(await tmpl.render(data), "Sample content"); t.deepEqual(await tmpl.getOutputLocations(data), { @@ -206,3 +241,35 @@ test("Custom extension (.txt) with custom permalink compile function that return rawPath: false, }); }); + +test("Custom extension (.txt) that returns undefined from compile", async (t) => { + let eleventyConfig = new TemplateConfig(); + eleventyConfig.userConfig.extensionMap.add({ + extension: "txt", + key: "txt", + compile: function (str, inputPath) { + t.is(str, "Sample content"); + return function (data) { + return undefined; + }; + }, + }); + + let dataObj = new TemplateData("./test/stubs/", eleventyConfig); + let tmpl = getNewTemplate( + "./test/stubs/custom-extension-no-permalink.txt", + "./test/stubs/", + "dist", + dataObj, + null, + eleventyConfig + ); + + let data = await tmpl.getData(); + t.is(await tmpl.render(data), undefined); + let pages = await tmpl.getTemplates(data); + for (let page of pages) { + page.templateContent = undefined; + t.is(page.templateContent, undefined); // shouldn’t throw an error + } +});