core/normalizers/link.normalizer.ts

core/normalizers/link.normalizer.ts is a file in Bane's Lab Content. 42 lines of code and 15 definitions.

import { FENCE_MARK, FOLDER_SEPARATOR, LINK_CLOSE, LINK_MIDDLE } from "#configuration/constants/chapter.constants";
import { ANCHOR_MARK } from "#configuration/constants/readme.constants";
import { LINE_END } from "#configuration/constants/inventory.constants";
import type { LinkResolver } from "#types/chapter.types";
import { SITE_URL } from "@banes-lab/web/core/assets/link.assets.ts";

const ROOT_LINK = LINK_MIDDLE + FOLDER_SEPARATOR;

const targetOf = function targetOf(target: string, resolve: LinkResolver): string {
    const hash = target.indexOf(ANCHOR_MARK);
    const path = hash === -1 ? target : target.slice(0, hash);
    const fragment = hash === -1 ? "" : target.slice(hash);
    const [page = "", tab = null] = path.split(FOLDER_SEPARATOR).filter((segment) => segment.length > 0);
    const file = resolve(page, tab);
    return file === null ? SITE_URL + target : file + fragment;
};

const relinkLine = function relinkLine(line: string, resolve: LinkResolver): string {
    let out = "";
    let index = 0;
    while (index < line.length) {
        const open = line.indexOf(ROOT_LINK, index);
        const close = open === -1 ? -1 : line.indexOf(LINK_CLOSE, open);
        if (close === -1) {
            return out + line.slice(index);
        }
        const start = open + LINK_MIDDLE.length;
        out += line.slice(index, start) + targetOf(line.slice(start, close), resolve);
        index = close;
    }
    return out;
};

export const relinked = function relinked(markdown: string, resolve: LinkResolver): string {
    let fenced = false;
    return markdown
        .split(LINE_END)
        .map((line) => {
            if (line.startsWith(FENCE_MARK)) {
                fenced = !fenced;
                return line;
            }
            return fenced ? line : relinkLine(line, resolve);
        })
        .join(LINE_END);
};