core/matchers/exclusions.matcher.ts

core/matchers/exclusions.matcher.ts is a file in GovLab Quality. 62 lines of code and 21 definitions.

import { basename, isAbsolute, relative } from "node:path";
import type { PathExclusion } from "#types/exclusions.types";

const SEPARATOR = "/";
const WILDCARD = "*";
const PARENT = "..";
const CURRENT = ".";

const segmentsOf = function segmentsOf(path: string): string[] {
    return path
        .split("\\")
        .join(SEPARATOR)
        .split(SEPARATOR)
        .filter((segment) => segment.length > 0 && segment !== CURRENT);
};

const matchesSegment = function matchesSegment(text: string, marker: string): boolean {
    const parts = marker.split(WILDCARD);
    const [head = ""] = parts;
    if (parts.length === 1) {
        return text === marker;
    }
    if (!text.startsWith(head)) {
        return false;
    }
    let cursor = head.length;
    for (const part of parts.slice(1)) {
        const at = part === "" ? cursor : text.indexOf(part, cursor);
        if (at === -1) {
            return false;
        }
        cursor = at + part.length;
    }
    const tail = parts.at(-1) ?? "";
    return tail === "" || text.endsWith(tail);
};

const matchesRunAt = function matchesRunAt(path: readonly string[], marker: readonly string[], start: number): boolean {
    return marker.every((part, offset) => {
        const segment = path[start + offset];
        return segment !== undefined && matchesSegment(segment, part);
    });
};

export const isExcludedPath = function isExcludedPath(relPath: string, markers: readonly string[]): boolean {
    const path = segmentsOf(relPath);
    return markers.some((marker) => {
        const run = segmentsOf(marker);
        if (run.length === 0) {
            return false;
        }
        for (let start = 0; start + run.length <= path.length; start += 1) {
            if (matchesRunAt(path, run, start)) {
                return true;
            }
        }
        return false;
    });
};

export const pathExclusion = function pathExclusion(root: string, markers: readonly string[]): PathExclusion {
    return (target: string): boolean => {
        const rel = isAbsolute(target) ? relative(root, target) : target;
        const [first] = segmentsOf(rel);
        const outside = first === PARENT || isAbsolute(rel);
        return isExcludedPath(outside ? basename(target) : rel, markers);
    };
};