# core/matchers/filename.matcher.ts

> 45 lines of code and 10 definitions.

Tree: GovLab Context
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/context#file-context-core-matchers-filename-matcher-ts
Source text: https://banes-lab.com/source/context/core/matchers/filename.matcher.ts.txt

Listed in [core/matchers](https://banes-lab.com/api/source/context/core/matchers.md), after [core/matchers/architecture.matcher.ts](https://banes-lab.com/source/context/core/matchers/architecture.matcher.ts.md) and before [core/matchers/lexicon.matcher.ts](https://banes-lab.com/source/context/core/matchers/lexicon.matcher.ts.md).

## Definitions

- `isWord` (lexical_declaration, line 20)
- `holdsOnlyWordChars` (lexical_declaration, line 11)
- `placedFileOf` (lexical_declaration, line 41, exported)
- `index` (lexical_declaration, line 12)
- `fileParts` (lexical_declaration, line 24)
- `segments` (lexical_declaration, line 25)
- `[subject = "", second = ""]` (lexical_declaration, line 32)
- `cut` (lexical_declaration, line 42, exported)
- `folder` (lexical_declaration, line 46, exported)
- `parts` (lexical_declaration, line 47, exported)

## Contained in

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

## Linked from

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

## Source

```typescript
import {
    FOLDER_SEPARATOR,
    HYPHEN,
    PLAIN_SEGMENTS,
    SEGMENT_SEPARATOR,
    VARIANT_SEGMENTS,
    WORD_CHARS,
} from "#configuration/constants/lexicon.constants";
import type { PlacedFile } from "#types/lexicon.types";

const holdsOnlyWordChars = function holdsOnlyWordChars(text: string): boolean {
    for (let index = 0; index < text.length; index += 1) {
        if (!WORD_CHARS.has(text.charAt(index))) {
            return false;
        }
    }
    return true;
};

const isWord = function isWord(text: string): boolean {
    return text.length > 0 && !text.startsWith(HYPHEN) && !text.endsWith(HYPHEN) && holdsOnlyWordChars(text);
};

const fileParts = function fileParts(file: string): Omit<PlacedFile, "folder"> | null {
    const segments = file.split(SEGMENT_SEPARATOR);
    if (segments.length !== PLAIN_SEGMENTS && segments.length !== VARIANT_SEGMENTS) {
        return null;
    }
    if (!segments.every(isWord)) {
        return null;
    }
    const [subject = "", second = ""] = segments;
    return {
        extension: segments.at(-1) ?? "",
        subject,
        tag: segments.at(-2) ?? "",
        variant: segments.length === VARIANT_SEGMENTS ? second : null,
    };
};

export const placedFileOf = function placedFileOf(path: string): PlacedFile | null {
    const cut = path.indexOf(FOLDER_SEPARATOR);
    if (cut <= 0 || cut !== path.lastIndexOf(FOLDER_SEPARATOR)) {
        return null;
    }
    const folder = path.slice(0, cut);
    const parts = fileParts(path.slice(cut + 1));
    return parts === null || !isWord(folder) || parts.subject === parts.tag ? null : { ...parts, folder };
};
```
