Provide a transformation function that maps absolute references to resources into relative references based on the location of a page. This makes it possible to use the same links across multiple pages in the hierarchy that works when loaded as files from the filesystem.
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import * as posix from "node:path/posix";
|
|
import { Node, Element } from "antihtml";
|
|
|
|
function shallowCopyElement(element: Element) {
|
|
const copy = new Element(element.name);
|
|
copy.attributes = new Map(element.attributes);
|
|
copy.childNodes = element.childNodes;
|
|
return copy;
|
|
}
|
|
|
|
/**
|
|
Resolves absolute href attributes in a and link elements the Node tree into relative references from the given directory.
|
|
|
|
@param node Node tree to transform
|
|
@param dir Absolute path to directory to resolve references from.
|
|
@returns new node tree with href attributes transformed, or the original node if no transformations took place.
|
|
*/
|
|
export function resolveRefs(node: Node, dir: string) {
|
|
if (!(node instanceof Element)) {
|
|
return node;
|
|
}
|
|
let resolvedNode = node;
|
|
const name = node.name;
|
|
if (
|
|
(name === "link" || name === "a")
|
|
&& node.attributes.has("href")
|
|
) {
|
|
const original = node.attributes.get("href")!
|
|
/* node:coverage ignore next 3 */
|
|
if (!original.startsWith("/")) {
|
|
console.log(`Warning: found relative href to ${original}`);
|
|
} else {
|
|
const ref = posix.relative(dir, original);
|
|
resolvedNode = shallowCopyElement(node);
|
|
resolvedNode.attributes.set("href", ref);
|
|
}
|
|
}
|
|
const resolvedChildren: Node[] = [];
|
|
let modifiedChildren = false;
|
|
for (const child of resolvedNode.childNodes) {
|
|
const resolvedChild = resolveRefs(child, dir);
|
|
if (child !== resolvedChild) {
|
|
modifiedChildren = true;
|
|
}
|
|
resolvedChildren.push(resolvedChild);
|
|
}
|
|
if (modifiedChildren) {
|
|
resolvedNode = shallowCopyElement(node);
|
|
resolvedNode.childNodes = resolvedChildren;
|
|
}
|
|
return resolvedNode;
|
|
}
|