import { parse } from "npm:parse5";
export default async function discover(source) {
let found = [];
let raw = await fetch(source, {
redirect: "follow",
follow: 10,
});
for (let [k, v] of raw.headers.entries()) {
if (k.toLowerCase() === "link") {
let raw = v.split(",");
for (let h of v.split(",")) {
let [l, r] = h.split(";");
let rel = r.replace("rel", "").replace("=", "").replace(/\"|\'/g, "").trim().toLowerCase();
if (rel === "webmention") found.push(cleanHeader(source, l));
}
}
}
let html = await raw.text();
let doc = parse(html);
let links = [];
(function walk(nodes) {
for (let n of nodes) {
if (n.childNodes) walk(n.childNodes);
if (
n.tagName === "link" && n.attrs?.find(a => a.name === "rel" && a.value.split(" ").includes("webmention"))
&& n.attrs?.find(a => a.name === "href")
) {
let raw = n.attrs.find(a => a.name === "href").value;
if (raw.length)
found.push(cleanTag(source, raw));
}
if (
n.tagName === "a" && n.attrs?.find(a => a.name === "rel" && a.value === "webmention")
&& n.attrs?.find(a => a.name === "href")
) {
let raw = n.attrs.find(a => a.name === "href").value;
if (raw.length)
found.push(cleanTag(source, raw));
}
}
})(doc.childNodes);
return found.length ? found[0] : false;
}
function cleanHeader(src, h) {
let exp = /<([^>]*)>/;
let matches = h.match(exp);
let raw = matches ? matches[1] : false;
if (raw.startsWith("/"))
return (new URL(src)).origin + raw;
if (raw.startsWith("http") === false) {
let bits = raw.split("/");
bits.shift();
return src + "/" + bits.join("/");
}
return raw;
}
function cleanTag(src, raw) {
if (raw.startsWith("/"))
return (new URL(src)).origin + raw;
if (raw.startsWith("http") === false) {
let bits = raw.split("/");
bits.shift();
return src + "/" + bits.join("/");
}
return raw;
}