core/resolvers/pattern.resolver.ts

core/resolvers/pattern.resolver.ts is a file in Project Scripts. 66 lines of code and 12 definitions.

import { DEEP_WILDCARD, PARENT_SEGMENT, SINGLE_WILDCARD, WILDCARD } from "#configuration/constants/closure.constants";
import { dirname, join } from "node:path";
import { existsSync, readdirSync, statSync } from "node:fs";
import type { ScanState } from "#types/closure.types";

const stepScan = function stepScan(name: string, pattern: string, at: ScanState): ScanState | null {
    const patternChar = at.pattern < pattern.length ? pattern.charAt(at.pattern) : undefined;
    if (patternChar === name.charAt(at.name) || patternChar === SINGLE_WILDCARD) {
        return { ...at, name: at.name + 1, pattern: at.pattern + 1 };
    }
    if (patternChar === WILDCARD) {
        return { ...at, pattern: at.pattern + 1, starName: at.name, starPattern: at.pattern };
    }
    if (at.starPattern >= 0) {
        return { ...at, name: at.starName + 1, pattern: at.starPattern + 1, starName: at.starName + 1 };
    }
    return null;
};

export const segmentMatches = function segmentMatches(name: string, pattern: string): boolean {
    let at: ScanState = { name: 0, pattern: 0, starName: -1, starPattern: -1 };
    while (at.name < name.length) {
        const next = stepScan(name, pattern, at);
        if (next === null) {
            return false;
        }
        at = next;
    }
    let tail = at.pattern;
    while (tail < pattern.length && pattern.charAt(tail) === WILDCARD) {
        tail += 1;
    }
    return tail === pattern.length;
};

const entriesIn = function entriesIn(dir: string): string[] {
    return existsSync(dir) && statSync(dir).isDirectory() ? readdirSync(dir) : [];
};

const expandMatch = function expandMatch(full: string, rest: readonly string[]): string[] {
    const isDir = statSync(full).isDirectory();
    if (rest.length === 0) {
        return isDir ? [] : [full];
    }
    return isDir ? expandPattern(full, rest) : [];
};

const expandDeep = function expandDeep(dir: string, segments: readonly string[], rest: readonly string[]): string[] {
    return [
        ...expandPattern(dir, rest),
        ...entriesIn(dir)
            .map((name) => join(dir, name))
            .filter((full) => statSync(full).isDirectory())
            .flatMap((full) => expandPattern(full, segments)),
    ];
};

export const expandPattern = function expandPattern(dir: string, segments: readonly string[]): string[] {
    if (segments.length === 0) {
        return [];
    }
    const [head = "", ...rest] = segments;
    if (head === PARENT_SEGMENT) {
        return expandPattern(dirname(dir), rest);
    }
    if (head === DEEP_WILDCARD) {
        return expandDeep(dir, segments, rest);
    }
    return entriesIn(dir)
        .filter((name) => segmentMatches(name, head))
        .flatMap((name) => expandMatch(join(dir, name), rest));
};