# core/converters/reference.field.converter.ts

> 76 lines of code and 20 definitions.

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

Listed in [core/converters](https://banes-lab.com/api/source/build-scripts/core/converters.md), after [core/converters/reference.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/reference.converter.ts.md) and before [core/converters/report.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/report.converter.ts.md).

## Definitions

- `kebabOf` (lexical_declaration, line 34)
- `relationsOf` (lexical_declaration, line 68, exported)
- `isEdgeRef` (lexical_declaration, line 26)
- `isEdgeList` (lexical_declaration, line 30)
- `fieldsOf` (lexical_declaration, line 42)
- `summaryOf` (lexical_declaration, line 46)
- `hyphenatedOf` (lexical_declaration, line 57, exported)
- `titleOf` (lexical_declaration, line 61, exported)
- `recordOf` (lexical_declaration, line 85, exported)
- `nameOf` (lexical_declaration, line 80, exported)
- `HYPHEN` (lexical_declaration, line 5)
- `UNDERSCORE` (lexical_declaration, line 6)
- `SPACE` (lexical_declaration, line 7)
- `UPPER` (lexical_declaration, line 8)
- `SKIPPED_FIELDS` (lexical_declaration, line 9)
- `SUMMARY_FIELDS` (lexical_declaration, line 10)
- `out` (lexical_declaration, line 35)
- `held` (lexical_declaration, line 47)
- `value` (lexical_declaration, line 49)
- `name` (lexical_declaration, line 81, exported)

## Contained in

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

## Used by

- [core/converters/ontology.reference.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/ontology.reference.converter.ts.md)

## Linked from

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

## Source

```typescript
import type { ReferenceRecord, ReferenceRelation } from "@banes-lab/web/types/reference.types.js";
import type { EdgeRef } from "@banes-lab/web/types/link.types.js";
import { isRecord } from "#core/selectors/base.selector";

const HYPHEN = "-";
const UNDERSCORE = "_";
const SPACE = " ";
const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const SKIPPED_FIELDS: ReadonlySet<string> = new Set(["anchor", "id"]);
const SUMMARY_FIELDS: readonly string[] = [
    "question",
    "statement",
    "practice",
    "expression",
    "viewpoint",
    "studies",
    "decisionTest",
    "predicateExpression",
    "mathNature",
    "nature",
    "predicateFamily",
    "role",
    "principle",
];

const isEdgeRef = function isEdgeRef(value: unknown): value is EdgeRef {
    return isRecord(value) && typeof value["label"] === "string" && "ref" in value;
};

const isEdgeList = function isEdgeList(value: unknown): value is readonly EdgeRef[] {
    return Array.isArray(value) && value.length > 0 && value.every(isEdgeRef);
};

const kebabOf = function kebabOf(name: string): string {
    let out = "";
    for (const char of name) {
        out += UPPER.includes(char) ? HYPHEN + char.toLowerCase() : char;
    }
    return out;
};

const fieldsOf = function fieldsOf(view: object): readonly (readonly [string, unknown])[] {
    return Object.entries(view);
};

const summaryOf = function summaryOf(view: object): string | null {
    const held = new Map(fieldsOf(view));
    for (const field of SUMMARY_FIELDS) {
        const value = held.get(field);
        if (typeof value === "string" && value.length > 0) {
            return value;
        }
    }
    return null;
};

export const hyphenatedOf = function hyphenatedOf(id: string): string {
    return id.split(UNDERSCORE).join(HYPHEN);
};

export const titleOf = function titleOf(id: string): string {
    return id
        .split(HYPHEN)
        .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
        .join(SPACE);
};

export const relationsOf = function relationsOf(view: object): readonly ReferenceRelation[] {
    return fieldsOf(view).flatMap(([field, value]) => {
        if (SKIPPED_FIELDS.has(field)) {
            return [];
        }
        if (isEdgeRef(value)) {
            return [{ edges: [value], relation: kebabOf(field) }];
        }
        return isEdgeList(value) ? [{ edges: value, relation: kebabOf(field) }] : [];
    });
};

export const nameOf = function nameOf(view: object, id: string): string {
    const name = new Map(fieldsOf(view)).get("name");
    return typeof name === "string" && name.length > 0 ? name : titleOf(id);
};

export const recordOf = function recordOf(view: object, kind: string, name: string): ReferenceRecord {
    return { code: null, kind, layer: null, name, relations: relationsOf(view), summary: summaryOf(view) };
};
```
