Skip to content

Commit

Permalink
Fixes #3327
Browse files Browse the repository at this point in the history
  • Loading branch information
zachleat committed Jun 18, 2024
1 parent 7513f21 commit 268e3f1
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 37 deletions.
11 changes: 0 additions & 11 deletions src/Template.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,6 @@ class Template extends TemplateContent {
return this.extensionMap.removeTemplateExtension(this.parsed.base);
}

get htmlIOException() {
// HTML output can’t overwrite the HTML input file.
return (
this.inputDir === this.outputDir &&
this.templateRender.isEngine("html") &&
this.baseFile === "index"
);
}

async _getRawPermalinkInstance(permalinkValue) {
let perm = new TemplatePermalink(permalinkValue, this.extraOutputSubdirectory);
perm.setUrlTransforms(this.config.urlTransforms);
Expand Down Expand Up @@ -242,7 +233,6 @@ class Template extends TemplateContent {
this.getTemplateSubfolder(),
this.baseFile,
this.extraOutputSubdirectory,
this.htmlIOException ? this.config.htmlOutputSuffix : "",
this.engine.defaultTemplateFileExtension,
);
p.setUrlTransforms(this.config.urlTransforms);
Expand All @@ -259,7 +249,6 @@ class Template extends TemplateContent {
return this._usePermalinkRoot;
}

// TODO instead of htmlIOException, do a global search to check if output path = input path and then add extra suffix
async getOutputLocations(data) {
this.bench.get("(count) getOutputLocations").incrementCount();
let link = await this._getLink(data);
Expand Down
29 changes: 22 additions & 7 deletions src/TemplateMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -745,27 +745,42 @@ class TemplateMap {
}

checkForDuplicatePermalinks() {
let inputs = {};
let permalinks = {};
let warnings = {};
for (let entry of this.map) {
for (let page of entry._pages) {
if (page.outputPath === false || page.url === false) {
// do nothing (also serverless)
} else if (!permalinks[page.outputPath]) {
permalinks[page.outputPath] = [entry.inputPath];
} else {
warnings[page.outputPath] = `Output conflict: multiple input files are writing to \`${
page.outputPath
}\`. Use distinct \`permalink\` values to resolve this conflict.
// Make sure output doesn’t overwrite input (e.g. --input=. --output=.)
// Related to https://github.com/11ty/eleventy/issues/3327
if (page.outputPath === page.inputPath) {
throw new DuplicatePermalinkOutputError(
`The template at "${page.inputPath}" attempted to overwrite itself.`,
);
} else if (inputs[page.outputPath]) {
throw new DuplicatePermalinkOutputError(
`The template at "${page.inputPath}" attempted to overwrite an existing template at "${page.outputPath}".`,
);
}
inputs[page.inputPath] = true;

if (!permalinks[page.outputPath]) {
permalinks[page.outputPath] = [entry.inputPath];
} else {
warnings[page.outputPath] = `Output conflict: multiple input files are writing to \`${
page.outputPath
}\`. Use distinct \`permalink\` values to resolve this conflict.
1. ${entry.inputPath}
${permalinks[page.outputPath]
.map(function (inputPath, index) {
return ` ${index + 2}. ${inputPath}\n`;
})
.join("")}
`;

permalinks[page.outputPath].push(entry.inputPath);
permalinks[page.outputPath].push(entry.inputPath);
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/TemplatePermalink.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class TemplatePermalink {
return folders[folders.length - 1] === base;
}

static generate(dir, filenameNoExt, extraSubdir, suffix, fileExtension = "html") {
static generate(dir, filenameNoExt, extraSubdir, fileExtension = "html") {
let path;
if (fileExtension === "html") {
let hasDupeFolder = TemplatePermalink._hasDuplicateFolder(dir, filenameNoExt);
Expand All @@ -177,10 +177,9 @@ class TemplatePermalink {
(dir ? dir + "/" : "") +
(filenameNoExt !== "index" && !hasDupeFolder ? filenameNoExt + "/" : "") +
"index" +
(suffix || "") +
".html";
} else {
path = (dir ? dir + "/" : "") + filenameNoExt + (suffix || "") + "." + fileExtension;
path = (dir ? dir + "/" : "") + filenameNoExt + "." + fileExtension;
}

return new TemplatePermalink(path, extraSubdir);
Expand Down
2 changes: 0 additions & 2 deletions src/defaultConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import TransformsUtil from "./Util/TransformsUtil.js";
* @property {string} [markdownTemplateEngine='liquid'] - Template engine to process markdown files with.
* @property {string} [htmlTemplateEngine='liquid'] - Template engine to process html files with.
* @property {boolean} [dataTemplateEngine=false] - Changed in v1.0
* @property {string} [htmlOutputSuffix='-o']
* @property {string} [jsDataFileSuffix='.11tydata'] - File suffix for jsData files.
* @property {Object} keys
* @property {string} [keys.package='pkg'] - Global data property for package.json data
Expand Down Expand Up @@ -130,7 +129,6 @@ export default function (config) {
pathPrefix: "/",
markdownTemplateEngine: "liquid",
htmlTemplateEngine: "liquid",
htmlOutputSuffix: "-o",

// Renamed from `jsDataFileSuffix` in 2.0 (and swapped to an Array)
// If you remove "" we won’t look for dir/dir.json or file.json
Expand Down
29 changes: 29 additions & 0 deletions test/EleventyTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1316,3 +1316,32 @@ test("Custom Markdown Render with permalink, Issue #2780", async (t) => {
t.is(results[0].url, `/permalink.html`);
t.is(results[0].content.trim(), `<h1>Markdown?</h1>`);
});

test("Test input/output conflicts (input overwrites output), Issue #3327", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", "./test/stubs-virtual/", {
config: eleventyConfig => {
eleventyConfig.addTemplate("test.html", `# Markdown`, { permalink: "test.html" });
}
});
elev.disableLogger();

let e = await t.throwsAsync(async () => {
await elev.toJSON();
});
t.true(e.toString().startsWith("DuplicatePermalinkOutputError:"));
});

test("Test input/output conflicts (output overwrites another input), Issue #3327", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", "./test/stubs-virtual/", {
config: eleventyConfig => {
eleventyConfig.addTemplate("test.html", `# Markdown`);
eleventyConfig.addTemplate("index.html", `# Markdown`, { permalink: "test.html" });
}
});
elev.disableLogger();

let e = await t.throwsAsync(async () => {
await elev.toJSON();
});
t.true(e.toString().startsWith("DuplicatePermalinkOutputError:"));
});
24 changes: 12 additions & 12 deletions test/TemplatePermalinkTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,17 @@ test("Permalink generate", (t) => {
});

test("Permalink generate with suffix", (t) => {
t.is(generate(".", "test", null, "-o").toOutputPath(), "test/index-o.html");
t.is(generate(".", "test", null, "-o").toHref(), "/test/index-o.html");
t.is(generate(".", "test", "1/", "-o").toOutputPath(), "test/1/index-o.html");
t.is(generate(".", "test", "1/", "-o").toHref(), "/test/1/index-o.html");
t.is(generate(".", "test", null).toOutputPath(), "test/index.html");
t.is(generate(".", "test", null).toHref(), "/test/");
t.is(generate(".", "test", "1/").toOutputPath(), "test/1/index.html");
t.is(generate(".", "test", "1/").toHref(), "/test/1/");
});

test("Permalink generate with new extension", (t) => {
t.is(generate(".", "test", null, null, "css").toOutputPath(), "test.css");
t.is(generate(".", "test", null, null, "css").toHref(), "/test.css");
t.is(generate(".", "test", "1/", null, "css").toOutputPath(), "1/test.css");
t.is(generate(".", "test", "1/", null, "css").toHref(), "/1/test.css");
t.is(generate(".", "test", null, "css").toOutputPath(), "test.css");
t.is(generate(".", "test", null, "css").toHref(), "/test.css");
t.is(generate(".", "test", "1/", "css").toOutputPath(), "1/test.css");
t.is(generate(".", "test", "1/", "css").toHref(), "/1/test.css");
});

test("Permalink generate with subfolders", (t) => {
Expand All @@ -101,15 +101,15 @@ test("Permalink generate with subfolders", (t) => {
"permalinksubfolder/test/index.html"
);
t.is(
generate("permalinksubfolder/", "test", "1/", "-o").toOutputPath(),
"permalinksubfolder/test/1/index-o.html"
generate("permalinksubfolder/", "test", "1/").toOutputPath(),
"permalinksubfolder/test/1/index.html"
);

t.is(generate("permalinksubfolder/", "index").toHref(), "/permalinksubfolder/");
t.is(generate("permalinksubfolder/", "test").toHref(), "/permalinksubfolder/test/");
t.is(
generate("permalinksubfolder/", "test", "1/", "-o").toHref(),
"/permalinksubfolder/test/1/index-o.html"
generate("permalinksubfolder/", "test", "1/").toHref(),
"/permalinksubfolder/test/1/"
);
});

Expand Down
4 changes: 2 additions & 2 deletions test/TemplateTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ test("HTML files output to the same as the input directory have a file suffix ad
test("HTML files output to the same as the input directory have a file suffix added (only if index, this _is_ index).", async (t) => {
let tmpl = await getNewTemplate("./test/stubs/index.html", "./test/stubs", "./test/stubs");
let data = await tmpl.getData();
t.is(await tmpl.getOutputPath(data), "./test/stubs/index-o.html");
t.is(await tmpl.getOutputPath(data), "./test/stubs/index.html");
});

test("HTML files output to the same as the input directory have a file suffix added (only if index, this _is_ index, subfolder).", async (t) => {
Expand All @@ -114,7 +114,7 @@ test("HTML files output to the same as the input directory have a file suffix ad
"./test/stubs"
);
let data = await tmpl.getData();
t.is(await tmpl.getOutputPath(data), "./test/stubs/subfolder/index-o.html");
t.is(await tmpl.getOutputPath(data), "./test/stubs/subfolder/index.html");
});

test("Test raw front matter from template (yaml)", async (t) => {
Expand Down

0 comments on commit 268e3f1

Please sign in to comment.