@renyuneyun/parse-link-header-ts
Version:
Parses a link header and returns information for each contained link.
57 lines (56 loc) • 1.55 kB
JavaScript
const PARSE_LINK_HEADER_MAXLEN = 2000;
function hasRel(link) {
if (link === null) {
return false;
}
return link.rel != null;
}
function intoRels(acc, link) {
function splitRel(rel) {
if (!(rel in acc)) {
acc[rel] = [];
}
acc[rel].push({ ...link, ...{ rel } });
}
link.rel.split(/\s+/).forEach(splitRel);
return acc;
}
function createObjects(acc, p) {
const m = p.match(/\s*(.+)\s*=\s*"?([^"]+)"?/);
if (m)
acc[m[1]] = m[2];
return acc;
}
function parseLink(link, base) {
const m = link.match(/<?([^>]*)>(.*)/);
if (m === null) {
throw new Error('Invalid link header');
}
const linkUrl = m[1];
const parts = m[2].split(';');
const parsedUrl = new URL(linkUrl, base);
const qry = {};
for (const [key, value] of parsedUrl.searchParams) {
qry[key] = value;
}
parts.shift();
let info = parts.reduce(createObjects, {});
info = { ...qry, ...info, url: linkUrl };
return info;
}
function checkHeader(linkHeader) {
if (linkHeader.length > PARSE_LINK_HEADER_MAXLEN) {
throw new Error(`Input string too long, it should be under ${PARSE_LINK_HEADER_MAXLEN} characters.`);
}
}
export default function (linkHeader, base) {
if (linkHeader === '') {
throw new Error('linkHeader is empty');
}
checkHeader(linkHeader);
return linkHeader
.split(/,\s*</)
.map((link) => parseLink(link, base))
.filter(hasRel)
.reduce(intoRels, {});
}