Skip to content

Commit

Permalink
Fixes #3417
Browse files Browse the repository at this point in the history
  • Loading branch information
zachleat committed Sep 3, 2024
1 parent 5b7bddb commit 48886e3
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 57 deletions.
116 changes: 71 additions & 45 deletions src/Plugins/InputPathToUrl.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
import path from "node:path";
import { TemplatePath } from "@11ty/eleventy-utils";
import isValidUrl from "../Util/ValidUrl.js";
import memoize from "../Util/MemoizeFunction.js";

function normalizeInputPath(inputPath, inputDir, contentMap) {
function getValidPath(contentMap, testPath) {
let normalized = TemplatePath.addLeadingDotSlash(testPath);

// it must exist in the content map to be valid
if (contentMap[normalized]) {
return normalized;
}
}

function normalizeInputPath(targetInputPath, inputDir, sourceInputPath, contentMap) {
// inputDir is optional at the beginning of the developer supplied-path

let normalized;
// Input directory already on the input path
if (TemplatePath.join(inputPath).startsWith(TemplatePath.join(inputDir))) {
normalized = inputPath;
} else {
normalized = TemplatePath.join(inputDir, inputPath);
if (TemplatePath.join(targetInputPath).startsWith(TemplatePath.join(inputDir))) {
let absolutePath = getValidPath(contentMap, targetInputPath);
if (absolutePath) {
return absolutePath;
}
}

normalized = TemplatePath.addLeadingDotSlash(normalized);
// Relative to project input directory
let relativeToInputDir = getValidPath(contentMap, TemplatePath.join(inputDir, targetInputPath));
if (relativeToInputDir) {
return relativeToInputDir;
}

// it must exist in the content map to be valid
if (contentMap[normalized]) {
return normalized;
if (targetInputPath && !path.isAbsolute(targetInputPath)) {
// Relative to source file’s input path
let sourceInputDir = TemplatePath.getDirFromFilePath(sourceInputPath);
let relativeToSourceFile = getValidPath(
contentMap,
TemplatePath.join(sourceInputDir, targetInputPath),
);
if (relativeToSourceFile) {
return relativeToSourceFile;
}
}

// the transform may have sent in a URL so we just return it as-is
return inputPath;
return targetInputPath;
}

function parseFilePath(filepath) {
Expand Down Expand Up @@ -63,30 +83,30 @@ function FilterPlugin(eleventyConfig) {
contentMap = inputPathToUrl;
});

eleventyConfig.addFilter(
"inputPathToUrl",
memoize(function (filepath) {
if (!contentMap) {
throw new Error("Internal error: contentMap not available for `inputPathToUrl` filter.");
}

if (isValidUrl(filepath)) {
return filepath;
}

let inputDir = eleventyConfig.directories.input;
let suffix = "";
[suffix, filepath] = parseFilePath(filepath);
filepath = normalizeInputPath(filepath, inputDir, contentMap);

let urls = contentMap[filepath];
if (!urls || urls.length === 0) {
throw new Error("`inputPathToUrl` filter could not find a matching target for " + filepath);
}

return `${urls[0]}${suffix}`;
}),
);
eleventyConfig.addFilter("inputPathToUrl", function (targetFilePath) {
if (!contentMap) {
throw new Error("Internal error: contentMap not available for `inputPathToUrl` filter.");
}

if (isValidUrl(targetFilePath)) {
return targetFilePath;
}

let inputDir = eleventyConfig.directories.input;
let suffix = "";
[suffix, targetFilePath] = parseFilePath(targetFilePath);
// @ts-ignore
targetFilePath = normalizeInputPath(targetFilePath, inputDir, this.page.inputPath, contentMap);

let urls = contentMap[targetFilePath];
if (!urls || urls.length === 0) {
throw new Error(
"`inputPathToUrl` filter could not find a matching target for " + targetFilePath,
);
}

return `${urls[0]}${suffix}`;
});
}

function TransformPlugin(eleventyConfig, defaultOptions = {}) {
Expand All @@ -102,24 +122,30 @@ function TransformPlugin(eleventyConfig, defaultOptions = {}) {
contentMap = inputPathToUrl;
});

eleventyConfig.htmlTransformer.addUrlTransform(opts.extensions, function (filepathOrUrl) {
eleventyConfig.htmlTransformer.addUrlTransform(opts.extensions, function (targetFilepathOrUrl) {
if (!contentMap) {
throw new Error("Internal error: contentMap not available for the `pathToUrl` Transform.");
}
if (isValidUrl(filepathOrUrl)) {
return filepathOrUrl;
if (isValidUrl(targetFilepathOrUrl)) {
return targetFilepathOrUrl;
}

let inputDir = eleventyConfig.directories.input;

let suffix = "";
[suffix, filepathOrUrl] = parseFilePath(filepathOrUrl);
filepathOrUrl = normalizeInputPath(filepathOrUrl, inputDir, contentMap);

let urls = contentMap[filepathOrUrl];
if (!filepathOrUrl || !urls || urls.length === 0) {
[suffix, targetFilepathOrUrl] = parseFilePath(targetFilepathOrUrl);
// @ts-ignore
targetFilepathOrUrl = normalizeInputPath(
targetFilepathOrUrl,
inputDir,
this.page.inputPath,
contentMap,
);

let urls = contentMap[targetFilepathOrUrl];
if (!targetFilepathOrUrl || !urls || urls.length === 0) {
// fallback, transforms don’t error on missing paths (though the pathToUrl filter does)
return `${filepathOrUrl}${suffix}`;
return `${targetFilepathOrUrl}${suffix}`;
}

return `${urls[0]}${suffix}`;
Expand Down
52 changes: 40 additions & 12 deletions test/InputPathToUrlPluginTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ test("Using the transform (and the filter too)", async (t) => {
},
});

elev.setIsVerbose(false);
elev.disableLogger();

let results = await elev.toJSON();
// filter is already available in the default config.
t.is(
Expand All @@ -82,9 +79,6 @@ test("Using the filter", async (t) => {
configPath: false,
});

elev.setIsVerbose(false);
elev.disableLogger();

let results = await elev.toJSON();
t.is(
getContentFor(results, "/filter/index.html"),
Expand All @@ -106,9 +100,6 @@ test("Using the transform and the base plugin", async (t) => {
},
});

elev.setIsVerbose(false);
elev.disableLogger();

let results = await elev.toJSON();
t.is(
getContentFor(results, "/filter/index.html"),
Expand All @@ -130,9 +121,6 @@ test("Using the transform and the base plugin, reverse order", async (t) => {
},
});

elev.setIsVerbose(false);
elev.disableLogger();

let results = await elev.toJSON();
t.is(
getContentFor(results, "/filter/index.html"),
Expand All @@ -144,3 +132,43 @@ test("Using the transform and the base plugin, reverse order", async (t) => {
);
});


test("Issue #3417 Using the transform with relative path (dot slash)", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", "./test/stubs-virtual/_site", {
configPath: false,
config: function (eleventyConfig) {
// FilterPlugin is available in the default config.
eleventyConfig.addPlugin(TransformPlugin);

eleventyConfig.addTemplate("source/test.njk", `<a href="./target.njk">Target</a>`)
eleventyConfig.addTemplate("source/target.njk", "lol")
},
});

let results = await elev.toJSON();
// filter is already available in the default config.
t.is(
getContentFor(results, "/source/test/index.html"),
`<a href="/source/target/">Target</a>`
);
});

test("Issue #3417 Using the transform with relative path (no dot slash)", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", "./test/stubs-virtual/_site", {
configPath: false,
config: function (eleventyConfig) {
// FilterPlugin is available in the default config.
eleventyConfig.addPlugin(TransformPlugin);

eleventyConfig.addTemplate("source/test.njk", `<a href="target.njk">Target</a>`)
eleventyConfig.addTemplate("source/target.njk", "lol")
},
});

let results = await elev.toJSON();
// filter is already available in the default config.
t.is(
getContentFor(results, "/source/test/index.html"),
`<a href="/source/target/">Target</a>`
);
});

0 comments on commit 48886e3

Please sign in to comment.