# core/loaders/definition.loader.ts

> 147 lines of code and 40 definitions.

Tree: Site tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/tree#file-core-loaders-definition-loader-ts
Source text: https://banes-lab.com/assets/sources/source.1835cfda7bde0b9bf17cdc629fea7f1d949317f6bb275dc83b57ac4f53681a19.generated.txt

## Definitions

- `index` (lexical_declaration, line 42)
- `bySuffix` (lexical_declaration, line 96)
- `existing` (lexical_declaration, line 82)
- `definitionsNamed` (lexical_declaration, line 63, exported)
- `listDefinitions` (lexical_declaration, line 67, exported)
- `treeFrom` (lexical_declaration, line 103)
- `collect` (lexical_declaration, line 23)
- `resolveSpecifier` (lexical_declaration, line 137, exported)
- `resolvePath` (lexical_declaration, line 116, exported)
- `resolveFolder` (lexical_declaration, line 128, exported)
- `RELATIVE_HERE` (lexical_declaration, line 12)
- `RELATIVE_UP` (lexical_declaration, line 13)
- `Index` (interface_declaration, line 15)
- `held` (lexical_declaration, line 21)
- `entry` (lexical_declaration, line 33)
- `names` (lexical_declaration, line 44)
- `files` (lexical_declaration, line 45)
- `folders` (lexical_declaration, line 46)
- `bare` (lexical_declaration, line 55)
- `trimmed` (lexical_declaration, line 56)
- `unrooted` (lexical_declaration, line 57)
- `step` (lexical_declaration, line 71)
- `normalise` (lexical_declaration, line 78)
- `{ files }` (lexical_declaration, line 83)
- `typed` (lexical_declaration, line 87)
- `endsWithTail` (lexical_declaration, line 91)
- `matches` (lexical_declaration, line 97)
- `definitionsNamedFrom` (lexical_declaration, line 107, exported)
- `all` (lexical_declaration, line 111, exported)
- `candidate` (lexical_declaration, line 129, exported)
- `own` (lexical_declaration, line 133, exported)
- `tree` (lexical_declaration, line 138, exported)
- `tail` (lexical_declaration, line 140, exported)
- `base` (lexical_declaration, line 150, exported)
- `local` (lexical_declaration, line 151, exported)
- `inFile` (lexical_declaration, line 155)
- `citedDefinition` (lexical_declaration, line 159, exported)
- `found` (lexical_declaration, line 163, exported)
- `site` (lexical_declaration, line 164, exported)
- `[only]` (lexical_declaration, line 165, exported)

## Uses

- [core/converters/folder.converter.ts](https://banes-lab.com/source/tree/core/converters/folder.converter.ts.md)

## Used by

- [domain/loaders/search.loader.ts](https://banes-lab.com/source/tree/domain/loaders/search.loader.ts.md)
- [presentation/components/source.component.ts](https://banes-lab.com/source/tree/presentation/components/source.component.ts.md)

## Source

```typescript
import type { AnatomyFolder, DefinitionLocation } from "#types/anatomy.types";
import {
    EXTENSION_SEPARATOR,
    PATH_SEPARATOR,
    SELF_IMPORT_MARK,
    TYPESCRIPT_EXTENSION,
} from "#configuration/constants/anatomy.constants";
import { localPath, qualifiedPath, treeOf } from "#core/converters/folder.converter";
import { ANATOMY_TREES } from "#core/registries/anatomy.registry";
import { TREE_TAB } from "#core/ids/anatomy.ids";

const RELATIVE_HERE = ".";
const RELATIVE_UP = "..";

interface Index {
    readonly files: ReadonlySet<string>;
    readonly folders: ReadonlySet<string>;
    readonly names: ReadonlyMap<string, readonly DefinitionLocation[]>;
}

let held: Index | null = null;

const collect = function collect(
    folder: AnatomyFolder,
    names: Map<string, DefinitionLocation[]>,
    files: Set<string>,
    folders: Set<string>,
): void {
    folders.add(folder.path);
    for (const file of folder.files) {
        files.add(file.path);
        for (const definition of file.definitions) {
            const entry = { file: file.path, line: definition.line, name: definition.name };
            names.set(definition.name, [...(names.get(definition.name) ?? []), entry]);
        }
    }
    for (const child of folder.folders) {
        collect(child, names, files, folders);
    }
};

const index = function index(): Index {
    if (held === null) {
        const names = new Map<string, DefinitionLocation[]>();
        const files = new Set<string>();
        const folders = new Set<string>();
        for (const tree of ANATOMY_TREES) {
            collect(tree.snapshot.tree, names, files, folders);
        }
        held = { files, folders, names };
    }
    return held;
};

const bare = function bare(text: string): string {
    const trimmed = text.trim();
    const unrooted = trimmed.startsWith(RELATIVE_HERE + PATH_SEPARATOR)
        ? trimmed.slice(RELATIVE_HERE.length + PATH_SEPARATOR.length)
        : trimmed;
    return unrooted.endsWith(PATH_SEPARATOR) ? unrooted.slice(0, -PATH_SEPARATOR.length) : unrooted;
};

export const definitionsNamed = function definitionsNamed(name: string): readonly DefinitionLocation[] {
    return index().names.get(name) ?? [];
};

export const listDefinitions = function listDefinitions(): readonly DefinitionLocation[] {
    return [...index().names.values()].flat();
};

const step = function step(out: string[], segment: string): string[] {
    if (segment === RELATIVE_UP) {
        return out.slice(0, -1);
    }
    return segment === RELATIVE_HERE || segment.length === 0 ? out : [...out, segment];
};

const normalise = function normalise(segments: readonly string[]): string {
    return segments.reduce<string[]>(step, []).join(PATH_SEPARATOR);
};

const existing = function existing(candidate: string): string | null {
    const { files } = index();
    if (files.has(candidate)) {
        return candidate;
    }
    const typed = candidate + EXTENSION_SEPARATOR + TYPESCRIPT_EXTENSION;
    return files.has(typed) ? typed : null;
};

const endsWithTail = function endsWithTail(path: string, tail: string): boolean {
    const local = localPath(path);
    return local.endsWith(PATH_SEPARATOR + tail) || local === tail;
};

const bySuffix = function bySuffix(tail: string, tree: string | null = null): string | null {
    const matches = [...index().files].filter(
        (path) => (tree === null || treeOf(path) === tree) && endsWithTail(path, tail),
    );
    return matches.length === 1 ? (matches[0] ?? null) : null;
};

const treeFrom = function treeFrom(from: string | null): string {
    return from === null ? TREE_TAB : treeOf(from);
};

export const definitionsNamedFrom = function definitionsNamedFrom(
    name: string,
    from: string,
): readonly DefinitionLocation[] {
    const all = definitionsNamed(name);
    const own = all.filter((location) => treeOf(location.file) === treeOf(from));
    return own.length > 0 ? own : all;
};

export const resolvePath = function resolvePath(text: string, from: string | null = null): string | null {
    const candidate = bare(text);
    if (candidate.length === 0) {
        return null;
    }
    const own = qualifiedPath(treeFrom(from), candidate);
    if (index().files.has(own)) {
        return own;
    }
    return (from === null ? null : bySuffix(candidate, treeFrom(from))) ?? bySuffix(candidate);
};

export const resolveFolder = function resolveFolder(text: string, from: string | null = null): string | null {
    const candidate = bare(text);
    if (candidate.length === 0) {
        return null;
    }
    const own = qualifiedPath(treeFrom(from), candidate);
    return index().folders.has(own) ? own : null;
};

export const resolveSpecifier = function resolveSpecifier(specifier: string, fromPath: string): string | null {
    const tree = treeOf(fromPath);
    if (specifier.startsWith(SELF_IMPORT_MARK)) {
        const tail = specifier.slice(SELF_IMPORT_MARK.length);
        return (
            existing(qualifiedPath(tree, tail)) ??
            bySuffix(tail + EXTENSION_SEPARATOR + TYPESCRIPT_EXTENSION, tree) ??
            bySuffix(tail, tree)
        );
    }
    if (!specifier.startsWith(RELATIVE_HERE)) {
        return null;
    }
    const base = localPath(fromPath).split(PATH_SEPARATOR).slice(0, -1);
    const local = normalise([...base, ...specifier.split(PATH_SEPARATOR)]);
    return existing(qualifiedPath(tree, local));
};

const inFile = function inFile(location: DefinitionLocation, file: string | null): boolean {
    return file === null || location.file === file || location.file.endsWith(PATH_SEPARATOR + file);
};

export const citedDefinition = function citedDefinition(
    name: string,
    file: string | null = null,
): DefinitionLocation | null {
    const found = definitionsNamed(name).filter((location) => inFile(location, file));
    const site = found.filter((location) => treeOf(location.file) === TREE_TAB);
    const [only] = found.length === 1 ? found : site;
    return (found.length === 1 || site.length === 1) && only !== undefined ? only : null;
};
```
