# core/resolvers/pattern.resolver.ts

> 66 lines of code and 12 definitions.

Tree: Project Scripts
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/scripts#file-scripts-core-resolvers-pattern-resolver-ts
Source text: https://banes-lab.com/source/scripts/core/resolvers/pattern.resolver.ts.txt

Listed in [core/resolvers](https://banes-lab.com/api/source/scripts/core/resolvers.md), before [core/resolvers/specifier.resolver.ts](https://banes-lab.com/source/scripts/core/resolvers/specifier.resolver.ts.md).

## Definitions

- `expandPattern` (lexical_declaration, line 58, exported)
- `entriesIn` (lexical_declaration, line 36)
- `expandDeep` (lexical_declaration, line 48)
- `expandMatch` (lexical_declaration, line 40)
- `segmentMatches` (lexical_declaration, line 20, exported)
- `stepScan` (lexical_declaration, line 6)
- `patternChar` (lexical_declaration, line 7)
- `at` (lexical_declaration, line 21, exported)
- `next` (lexical_declaration, line 23, exported)
- `tail` (lexical_declaration, line 29, exported)
- `isDir` (lexical_declaration, line 41)
- `rest]` (lexical_declaration, line 62, exported)

## Contained in

- [core/resolvers](https://banes-lab.com/anatomy/scripts/folder-scripts-core-resolvers.md)

## Linked from

- [core/resolvers](https://banes-lab.com/anatomy/scripts/folder-scripts-core-resolvers.md)

## Source

```typescript
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));
};
```
