196 lines
4.7 KiB
JavaScript
196 lines
4.7 KiB
JavaScript
|
|
import path from "node:path";
|
|||
|
|
import { TemplatePath, isPlainObject } from "@11ty/eleventy-utils";
|
|||
|
|
|
|||
|
|
class TemplatePermalink {
|
|||
|
|
// `link` with template syntax should have already been rendered in Template.js
|
|||
|
|
constructor(link, extraSubdir) {
|
|||
|
|
let isLinkAnObject = isPlainObject(link);
|
|||
|
|
|
|||
|
|
this._isRendered = true;
|
|||
|
|
this._writeToFileSystem = true;
|
|||
|
|
|
|||
|
|
let buildLink;
|
|||
|
|
|
|||
|
|
if (isLinkAnObject) {
|
|||
|
|
if ("build" in link) {
|
|||
|
|
buildLink = link.build;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// find the first string key
|
|||
|
|
for (let key in link) {
|
|||
|
|
if (typeof key !== "string") {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
buildLink = link;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// permalink: false and permalink: build: false
|
|||
|
|
if (typeof buildLink === "boolean") {
|
|||
|
|
if (buildLink === false) {
|
|||
|
|
this._writeToFileSystem = false;
|
|||
|
|
} else {
|
|||
|
|
throw new Error(
|
|||
|
|
`\`permalink: ${
|
|||
|
|
isLinkAnObject ? "build: " : ""
|
|||
|
|
}true\` is not a supported feature in Eleventy. Did you mean \`permalink: ${
|
|||
|
|
isLinkAnObject ? "build: " : ""
|
|||
|
|
}false\`?`,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
} else if (buildLink) {
|
|||
|
|
if (typeof buildLink !== "string") {
|
|||
|
|
let stringToString = "toString" in buildLink ? `:\n\n${buildLink.toString()}` : "";
|
|||
|
|
throw new Error(
|
|||
|
|
"Expected permalink value to be a string. Received `" +
|
|||
|
|
typeof buildLink +
|
|||
|
|
"`" +
|
|||
|
|
stringToString,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
this.buildLink = buildLink;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isLinkAnObject) {
|
|||
|
|
// default if permalink is an Object but does not have a `build` prop
|
|||
|
|
if (!("build" in link)) {
|
|||
|
|
this._writeToFileSystem = false;
|
|||
|
|
this._isRendered = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.extraPaginationSubdir = extraSubdir || "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setUrlTransforms(transforms) {
|
|||
|
|
this._urlTransforms = transforms;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
get urlTransforms() {
|
|||
|
|
return this._urlTransforms || [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_addDefaultLinkFilename(link) {
|
|||
|
|
return link + (link.slice(-1) === "/" ? "index.html" : "");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
toOutputPath() {
|
|||
|
|
if (!this.buildLink) {
|
|||
|
|
// empty or false
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
let cleanLink = this._addDefaultLinkFilename(this.buildLink);
|
|||
|
|
let parsed = path.parse(cleanLink);
|
|||
|
|
|
|||
|
|
return TemplatePath.join(parsed.dir, this.extraPaginationSubdir, parsed.base);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Used in url transforms feature
|
|||
|
|
static getUrlStem(original) {
|
|||
|
|
let subject = original;
|
|||
|
|
if (original.endsWith(".html")) {
|
|||
|
|
subject = original.slice(0, -1 * ".html".length);
|
|||
|
|
}
|
|||
|
|
return TemplatePermalink.normalizePathToUrl(subject);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static normalizePathToUrl(original) {
|
|||
|
|
let compare = original || "";
|
|||
|
|
|
|||
|
|
let needleHtml = "/index.html";
|
|||
|
|
let needleBareTrailingSlash = "/index/";
|
|||
|
|
let needleBare = "/index";
|
|||
|
|
if (compare.endsWith(needleHtml)) {
|
|||
|
|
return compare.slice(0, compare.length - needleHtml.length) + "/";
|
|||
|
|
} else if (compare.endsWith(needleBareTrailingSlash)) {
|
|||
|
|
return compare.slice(0, compare.length - needleBareTrailingSlash.length) + "/";
|
|||
|
|
} else if (compare.endsWith(needleBare)) {
|
|||
|
|
return compare.slice(0, compare.length - needleBare.length) + "/";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return original;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// This method is used to generate the `page.url` variable.
|
|||
|
|
|
|||
|
|
// remove all index.html’s from links
|
|||
|
|
// index.html becomes /
|
|||
|
|
// test/index.html becomes test/
|
|||
|
|
toHref() {
|
|||
|
|
if (!this.buildLink) {
|
|||
|
|
// empty or false
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let transformedLink = this.toOutputPath();
|
|||
|
|
let original = (transformedLink.charAt(0) !== "/" ? "/" : "") + transformedLink;
|
|||
|
|
|
|||
|
|
let normalized = TemplatePermalink.normalizePathToUrl(original) || "";
|
|||
|
|
for (let transform of this.urlTransforms) {
|
|||
|
|
original =
|
|||
|
|
transform({
|
|||
|
|
url: normalized,
|
|||
|
|
urlStem: TemplatePermalink.getUrlStem(original),
|
|||
|
|
}) ?? original;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return TemplatePermalink.normalizePathToUrl(original);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
toPath(outputDir) {
|
|||
|
|
if (!this.buildLink) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let uri = this.toOutputPath();
|
|||
|
|
|
|||
|
|
if (uri === false) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return TemplatePath.addLeadingDotSlash(TemplatePath.normalize(outputDir + "/" + uri));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
toPathFromRoot() {
|
|||
|
|
if (!this.buildLink) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let uri = this.toOutputPath();
|
|||
|
|
|
|||
|
|
if (uri === false) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return TemplatePath.addLeadingDotSlash(TemplatePath.normalize(uri));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static _hasDuplicateFolder(dir, base) {
|
|||
|
|
let folders = dir.split("/");
|
|||
|
|
if (!folders[folders.length - 1]) {
|
|||
|
|
folders.pop();
|
|||
|
|
}
|
|||
|
|
return folders[folders.length - 1] === base;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static generate(dir, filenameNoExt, extraSubdir, fileExtension = "html") {
|
|||
|
|
let path;
|
|||
|
|
if (fileExtension === "html") {
|
|||
|
|
let hasDupeFolder = TemplatePermalink._hasDuplicateFolder(dir, filenameNoExt);
|
|||
|
|
|
|||
|
|
path =
|
|||
|
|
(dir ? dir + "/" : "") +
|
|||
|
|
(filenameNoExt !== "index" && !hasDupeFolder ? filenameNoExt + "/" : "") +
|
|||
|
|
"index.html";
|
|||
|
|
} else {
|
|||
|
|
path = (dir ? dir + "/" : "") + filenameNoExt + "." + fileExtension;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new TemplatePermalink(path, extraSubdir);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default TemplatePermalink;
|