# core/formatters/link.formatter.ts

> 33 lines of code and 10 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-formatters-link-formatter-ts
Source text: https://banes-lab.com/source/build-scripts/core/formatters/link.formatter.ts.txt

Listed in [core/formatters](https://banes-lab.com/api/source/build-scripts/core/formatters.md), after [core/formatters/learning.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/learning.formatter.ts.md) and before [core/formatters/markdown.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/markdown.formatter.ts.md).

## Definitions

- `linkText` (lexical_declaration, line 8, exported)
- `placementLine` (lexical_declaration, line 30, exported)
- `relationSections` (lexical_declaration, line 26, exported)
- `linkSection` (lexical_declaration, line 17, exported)
- `headingOf` (lexical_declaration, line 21)
- `SEPARATOR` (lexical_declaration, line 6)
- `target` (lexical_declaration, line 9, exported)
- `linkList` (lexical_declaration, line 13, exported)
- `label` (lexical_declaration, line 22)
- `{ next, previous }` (lexical_declaration, line 34, exported)

## Contained in

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

## Used by

- [core/formatters/record.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/record.formatter.ts.md)
- [core/formatters/route.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/route.formatter.ts.md)
- [core/formatters/section.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/section.formatter.ts.md)
- [core/formatters/source.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/source.formatter.ts.md)

## Linked from

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

## Source

```typescript
import type { Link, Placed, Relation } from "#types/catalog.types";
import { listedInSentence } from "@banes-lab/web/strings/catalog.strings";
import { relationLabelOf } from "@banes-lab/web/strings/reference.strings";
import { section } from "#core/formatters/markdown.formatter";

const SEPARATOR = ", ";

export const linkText = function linkText(link: Link): string {
    const target = link.markdown ?? link.json ?? link.href;
    return target === null ? link.label : `[${link.label}](${target})`;
};

export const linkList = function linkList(links: readonly Link[]): string {
    return links.map(linkText).join(SEPARATOR);
};

export const linkSection = function linkSection(title: string, links: readonly Link[]): string | null {
    return section(title, links.map(linkText));
};

const headingOf = function headingOf(relation: string): string {
    const label = relationLabelOf(relation);
    return label.charAt(0).toUpperCase() + label.slice(1);
};

export const relationSections = function relationSections(relations: readonly Relation[]): readonly (string | null)[] {
    return relations.map((relation) => linkSection(headingOf(relation.relation), relation.links));
};

export const placementLine = function placementLine(placed: Placed): string | null {
    if (placed.up === null) {
        return null;
    }
    const { next, previous } = placed.siblings ?? { next: null, previous: null };
    return listedInSentence(
        linkText(placed.up),
        previous === null ? null : linkText(previous),
        next === null ? null : linkText(next),
    );
};
```
