core/matchers/markdown.matcher.ts

core/matchers/markdown.matcher.ts is a file in Bane's Lab Site. 88 lines of code and 22 definitions.

import {
    BULLET_MARKS,
    COMMENT_CLOSE,
    COMMENT_OPEN,
    FRONTMATTER_FENCE,
    HEADING_MARK,
    HEADING_MAX_LEVEL,
    ORDERED_CLOSE,
    RULE_CHARS,
    RULE_MIN_LENGTH,
    TABLE_PIPE,
    TABLE_RULE_CHARS,
} from "#configuration/constants/markdown.constants";
import { DIGITS } from "#configuration/constants/syntax.constants";
import { LINE_BREAK } from "#configuration/constants/code.constants";
import { SPACE } from "#configuration/constants/document.constants";

const charsOf = function charsOf(text: string): string[] {
    const chars: string[] = [];
    for (const char of text) {
        chars.push(char);
    }
    return chars;
};

export const isRule = function isRule(line: string): boolean {
    const chars = charsOf(line.trim()).filter((char) => char !== SPACE);
    const [first] = chars;
    return (
        chars.length >= RULE_MIN_LENGTH &&
        first !== undefined &&
        RULE_CHARS.has(first) &&
        chars.every((char) => char === first)
    );
};

export const headingLevel = function headingLevel(line: string): number {
    let level = 0;
    while (level < line.length && line.charAt(level) === HEADING_MARK) {
        level += 1;
    }
    return level > 0 && level <= HEADING_MAX_LEVEL && line.charAt(level) === SPACE ? level : 0;
};

export const bulletText = function bulletText(line: string): string | null {
    const trimmed = line.trim();
    return BULLET_MARKS.has(trimmed.charAt(0)) && trimmed.charAt(1) === SPACE ? trimmed.slice(2) : null;
};

export const orderedText = function orderedText(line: string): string | null {
    const trimmed = line.trim();
    let digits = 0;
    while (digits < trimmed.length && DIGITS.includes(trimmed.charAt(digits))) {
        digits += 1;
    }
    const closes = trimmed.charAt(digits) === ORDERED_CLOSE && trimmed.charAt(digits + 1) === SPACE;
    return digits > 0 && closes ? trimmed.slice(digits + 2) : null;
};

export const cellsOf = function cellsOf(line: string): string[] {
    const trimmed = line.trim();
    const inner = trimmed.startsWith(TABLE_PIPE) ? trimmed.slice(1) : trimmed;
    const body = inner.endsWith(TABLE_PIPE) ? inner.slice(0, -1) : inner;
    return body.split(TABLE_PIPE).map((cell) => cell.trim());
};

export const isTableRule = function isTableRule(line: string): boolean {
    const trimmed = line.trim();
    return (
        trimmed.includes(TABLE_PIPE) &&
        charsOf(trimmed).every((char) => char === TABLE_PIPE || TABLE_RULE_CHARS.has(char))
    );
};

const uncommented = function uncommented(text: string): string {
    let out = "";
    let at = 0;
    while (at < text.length) {
        const open = text.indexOf(COMMENT_OPEN, at);
        if (open === -1) {
            return out + text.slice(at);
        }
        const close = text.indexOf(COMMENT_CLOSE, open + COMMENT_OPEN.length);
        out += text.slice(at, open);
        at = close === -1 ? text.length : close + COMMENT_CLOSE.length;
    }
    return out;
};

export const bodyLines = function bodyLines(text: string): string[] {
    const lines = uncommented(text).split(LINE_BREAK);
    if (lines[0]?.trim() !== FRONTMATTER_FENCE) {
        return lines;
    }
    const close = lines.findIndex((line, index) => index > 0 && line.trim() === FRONTMATTER_FENCE);
    return close === -1 ? lines : lines.slice(close + 1);
};