Add resolveRefs transform
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.
This commit is contained in:
parent
7aa937a7e9
commit
17f8693eae
4 changed files with 105 additions and 2 deletions
|
@ -7,7 +7,7 @@
|
|||
"scripts": {
|
||||
"prepare": "tsc",
|
||||
"build": "node --enable-source-maps build/node/cli.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "node --test --enable-source-maps --experimental-test-coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"antihtml": "^0.3.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"files": ["cli.ts"],
|
||||
"include": ["content"],
|
||||
"include": ["content", "utils"],
|
||||
"compilerOptions": {
|
||||
"outDir": "build/node",
|
||||
"rootDir": ".",
|
||||
|
|
51
utils/resolve-refs.test.tsx
Normal file
51
utils/resolve-refs.test.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { suite, test } from "node:test";
|
||||
import { resolveRefs } from "./resolve-refs.js";
|
||||
import type { Element } from "antihtml";
|
||||
|
||||
|
||||
suite("function resolveRefs", () => {
|
||||
test("root to root relative href", () => {
|
||||
const el = resolveRefs(<a href="/page.html">Link</a>, "/");
|
||||
assert.equal((el as Element).attributes.get("href"), "page.html");
|
||||
});
|
||||
|
||||
test("root to subdir relative href", () => {
|
||||
const el = resolveRefs(<a href="/dir/page.html">Link</a>, "/");
|
||||
assert.equal((el as Element).attributes.get("href"), "dir/page.html");
|
||||
});
|
||||
|
||||
test("subdir to root relative href", () => {
|
||||
const el = resolveRefs(<a href="/page.html">Link</a>, "/subdir");
|
||||
assert.equal((el as Element).attributes.get("href"), "../page.html");
|
||||
});
|
||||
|
||||
test("subdir to subdir relative href", () => {
|
||||
const el = resolveRefs(<a href="/alt/page.html">Link</a>, "/subdir");
|
||||
assert.equal((el as Element).attributes.get("href"), "../alt/page.html");
|
||||
});
|
||||
|
||||
test("nested element", () => {
|
||||
const el = resolveRefs(<div>Content with <a href="/page.html">Link</a></div>, "/");
|
||||
assert.equal((el.childNodes[1] as Element).attributes.get("href"), "page.html");
|
||||
});
|
||||
|
||||
test("returns element if no changes", () => {
|
||||
const el = <div>Content with <em>emphasis</em></div>;
|
||||
const resEl = resolveRefs(el, "/");
|
||||
assert.equal(el, resEl);
|
||||
});
|
||||
|
||||
test("returns new element if changed", () => {
|
||||
const el = <div>Content with <a href="/page.html">Link</a></div>;
|
||||
const resEl = resolveRefs(el, "/");
|
||||
assert.notEqual(el, resEl);
|
||||
});
|
||||
|
||||
test("does not modify input", () => {
|
||||
const elFn = () => <div>Content with <a href="/page.html">Link</a></div>;
|
||||
const el = elFn();
|
||||
resolveRefs(el, "/");
|
||||
assert.deepEqual(el, elFn());
|
||||
});
|
||||
});
|
52
utils/resolve-refs.ts
Normal file
52
utils/resolve-refs.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue