# core/converters/binding.converter.ts

> 67 lines of code and 21 definitions.

Tree: Site tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-core-converters-binding-converter-ts
Source text: https://banes-lab.com/source/tree/core/converters/binding.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/tree/core/converters.md), before [core/converters/code.converter.ts](https://banes-lab.com/source/tree/core/converters/code.converter.ts.md).

## Definitions

- `siteKey` (lexical_declaration, line 40, exported)
- `codeFilesOf` (lexical_declaration, line 14, exported)
- `siteTargetsOf` (lexical_declaration, line 44, exported)
- `SITE_JOINER` (lexical_declaration, line 7)
- `SITE_WIDTH` (lexical_declaration, line 8)
- `filesOf` (lexical_declaration, line 10)
- `root` (lexical_declaration, line 19, exported)
- `targetOf` (lexical_declaration, line 24)
- `held` (lexical_declaration, line 28)
- `exact` (lexical_declaration, line 31)
- `[only]` (lexical_declaration, line 32)
- `location` (lexical_declaration, line 33)
- `found` (lexical_declaration, line 45, exported)
- `[line, column, index]` (lexical_declaration, line 47, exported)
- `bindingSitesOf` (lexical_declaration, line 56, exported)
- `targets` (lexical_declaration, line 60, exported)
- `positions` (lexical_declaration, line 61, exported)
- `sites` (lexical_declaration, line 62, exported)
- `target` (lexical_declaration, line 64, exported)
- `key` (lexical_declaration, line 65, exported)
- `at` (lexical_declaration, line 66, exported)

## Uses

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

## Used by

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

## Source

```typescript
import type { AnatomyFile, AnatomyFolder } from "#types/anatomy.types";
import type { Binding, CodeFile, CodeTarget, SourceReferences } from "#types/code.types";
import { localPath, treeOf } from "#core/converters/folder.converter";
import type { DefinitionIndex } from "#types/definition.types";
import { PATH_SEPARATOR } from "#configuration/constants/anatomy.constants";

const SITE_JOINER = ":";
const SITE_WIDTH = 3;

const filesOf = function filesOf(folder: AnatomyFolder): readonly AnatomyFile[] {
    return [...folder.files, ...folder.folders.flatMap(filesOf)];
};

export const codeFilesOf = function codeFilesOf(
    roots: readonly AnatomyFolder[],
    rootOf: (tab: string) => string | null,
): readonly CodeFile[] {
    return roots.flatMap(filesOf).flatMap((file): readonly CodeFile[] => {
        const root = file.inherited ? null : rootOf(treeOf(file.path));
        return root === null ? [] : [{ absolute: root + PATH_SEPARATOR + localPath(file.path), path: file.path }];
    });
};

const targetOf = function targetOf(index: DefinitionIndex, binding: Binding): CodeTarget {
    if (binding.module) {
        return { kind: "file", path: binding.file };
    }
    const held = index
        .moduleDefinitionsNamedFrom(binding.name, binding.file)
        .filter((location) => location.file === binding.file);
    const exact = held.find((location) => location.line === binding.target);
    const [only] = held;
    const location = exact ?? (held.length === 1 && only !== undefined ? only : null);
    return {
        kind: "definition",
        location: location ?? { file: binding.file, line: binding.target, name: binding.name },
    };
};

export const siteKey = function siteKey(line: number, column: number): string {
    return String(line) + SITE_JOINER + String(column);
};

export const siteTargetsOf = function siteTargetsOf(references: SourceReferences): ReadonlyMap<string, CodeTarget> {
    const found = new Map<string, CodeTarget>();
    for (let at = 0; at + SITE_WIDTH <= references.sites.length; at += SITE_WIDTH) {
        const [line, column, index] = references.sites.slice(at, at + SITE_WIDTH);
        const target = index === undefined ? undefined : references.targets[index];
        if (line !== undefined && column !== undefined && target !== undefined) {
            found.set(siteKey(line, column), target);
        }
    }
    return found;
};

export const bindingSitesOf = function bindingSitesOf(
    index: DefinitionIndex,
    bindings: readonly Binding[],
): { readonly sites: readonly number[]; readonly targets: readonly CodeTarget[] } {
    const targets: CodeTarget[] = [];
    const positions = new Map<string, number>();
    const sites: number[] = [];
    for (const binding of bindings) {
        const target = targetOf(index, binding);
        const key = JSON.stringify(target);
        const at = positions.get(key) ?? targets.length;
        if (at === targets.length) {
            positions.set(key, at);
            targets.push(target);
        }
        sites.push(binding.line, binding.column, at);
    }
    return { sites, targets };
};
```
