# configuration/constants/graph.constants.ts

> 155 lines of code and 52 definitions.

Tree: Site tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/tree#file-configuration-constants-graph-constants-ts
Source text: https://banes-lab.com/source/tree/configuration/constants/graph.constants.ts.txt

Listed in [configuration/constants](https://banes-lab.com/api/source/tree/configuration/constants.md), after [configuration/constants/grammar.fragment.constants.ts](https://banes-lab.com/source/tree/configuration/constants/grammar.fragment.constants.ts.md) and before [configuration/constants/learning.constants.ts](https://banes-lab.com/source/tree/configuration/constants/learning.constants.ts.md).

## Definitions

- `pair` (lexical_declaration, line 57)
- `chunkKeyOf` (lexical_declaration, line 139, exported)
- `withOf` (lexical_declaration, line 61)
- `isListingRef` (lexical_declaration, line 149, exported)
- `LINKS_TO_RELATION` (lexical_declaration, line 25, exported)
- `LINKED_FROM_RELATION` (lexical_declaration, line 26)
- `EVIDENCE_RELATION_ID` (lexical_declaration, line 27, exported)
- `EVIDENCE_FOR_RELATION` (lexical_declaration, line 28, exported)
- `USES_RELATION` (lexical_declaration, line 29, exported)
- `USED_BY_RELATION` (lexical_declaration, line 30)
- `CALLS_RELATION_ID` (lexical_declaration, line 31, exported)
- `CALLED_BY_RELATION_ID` (lexical_declaration, line 32)
- `CONTAINS_RELATION` (lexical_declaration, line 33, exported)
- `CONTAINED_IN_RELATION` (lexical_declaration, line 34, exported)
- `BUILDS_ON_RELATION` (lexical_declaration, line 35, exported)
- `PREREQUISITE_OF_RELATION` (lexical_declaration, line 36)
- `DERIVATION_RELATION` (lexical_declaration, line 37)
- `CONCEPT_RELATION` (lexical_declaration, line 38, exported)
- `DETECTED_BY_RELATION` (lexical_declaration, line 39, exported)
- `REFERENCES_RELATION` (lexical_declaration, line 40, exported)
- `REFERENCED_FROM_RELATION` (lexical_declaration, line 41)
- `ENFORCED_BY_RELATION` (lexical_declaration, line 42, exported)
- `ENFORCES_RELATION` (lexical_declaration, line 43)
- `GOVERNED_BY_RELATION` (lexical_declaration, line 44, exported)
- `GOVERNS_RELATION` (lexical_declaration, line 45)
- `CONCERN_RELATION` (lexical_declaration, line 46, exported)
- `CONCERN_LAYER_RELATION` (lexical_declaration, line 47, exported)
- `MATH_TYPE_RELATION` (lexical_declaration, line 48)
- `TERM_OF_RELATION` (lexical_declaration, line 49)
- `REQUIRED_BY_RELATION` (lexical_declaration, line 50)
- `REINFORCED_BY_RELATION` (lexical_declaration, line 51)
- `ENABLED_BY_RELATION` (lexical_declaration, line 52)
- `NEGATED_BY_RELATION` (lexical_declaration, line 53)
- `OF_SUFFIX` (lexical_declaration, line 55)
- `RELATIONS` (lexical_declaration, line 65, exported)
- `RELATION_PAIRS` (lexical_declaration, line 119, exported)
- `TOOLTIP_RELATIONS` (lexical_declaration, line 121, exported)
- `ROLLED_UP_RELATIONS` (lexical_declaration, line 125, exported)
- `LEAF_RELATIONS` (lexical_declaration, line 129, exported)
- `CHAPTER_COLLECTION` (lexical_declaration, line 131)
- `PATH_MARK` (lexical_declaration, line 132)
- `FRAGMENT_MARK` (lexical_declaration, line 133)
- `SNAKE_MARK` (lexical_declaration, line 134)
- `KEBAB_MARK` (lexical_declaration, line 135)
- `LISTING_PAGES` (lexical_declaration, line 137)
- `collection` (lexical_declaration, line 140, exported)
- `path` (lexical_declaration, line 144, exported)
- `ends` (lexical_declaration, line 145, exported)
- `relationId` (lexical_declaration, line 153, exported)
- `kebab` (lexical_declaration, line 154, exported)
- `lower` (lexical_declaration, line 156, exported)
- `reverseOf` (lexical_declaration, line 168, exported)

## Source

```typescript
import {
    AXIS_RELATION,
    CATEGORY_RELATION,
    COMPOSED_BY_RELATION,
    COMPOSES_RELATION,
    CONFLICTS_WITH_RELATION,
    CONTRACTS_RELATION,
    CONTRACT_RELATION,
    DERIVED_BY_RELATION,
    DETECTS_RELATION,
    ENABLES_RELATION,
    FACE_SEPARATOR,
    GROUNDED_BY_RELATION,
    GROUNDS_RELATION,
    PRINCIPLE_RELATION,
    REINFORCES_RELATION,
    REQUIRES_RELATION,
    STAGE_RELATION,
    TENSIONS_WITH_RELATION,
    TERM_RELATION,
} from "@govlab/constants";
import type { RelationPair, RelationRecord } from "#types/graph.types";
import { ONTOLOGY_PAGE } from "#core/ids/page.ids";

export const LINKS_TO_RELATION = "links-to";
const LINKED_FROM_RELATION = "linked-from";
export const EVIDENCE_RELATION_ID = "evidence";
export const EVIDENCE_FOR_RELATION = "evidence-for";
export const USES_RELATION = "uses";
const USED_BY_RELATION = "used-by";
export const CALLS_RELATION_ID = "calls";
const CALLED_BY_RELATION_ID = "called-by";
export const CONTAINS_RELATION = "contains";
export const CONTAINED_IN_RELATION = "contained-in";
export const BUILDS_ON_RELATION = "builds-on";
const PREREQUISITE_OF_RELATION = "prerequisite-of";
const DERIVATION_RELATION = "derivation";
export const CONCEPT_RELATION = "concept";
export const DETECTED_BY_RELATION = "detected-by";
export const REFERENCES_RELATION = "references";
const REFERENCED_FROM_RELATION = "referenced-from";
export const ENFORCED_BY_RELATION = "enforced-by";
const ENFORCES_RELATION = "enforces";
export const GOVERNED_BY_RELATION = "governed-by";
const GOVERNS_RELATION = "governs";
export const CONCERN_RELATION = "concern";
export const CONCERN_LAYER_RELATION = "concern-layer";
const MATH_TYPE_RELATION = "math-type";
const TERM_OF_RELATION = "term-of";
const REQUIRED_BY_RELATION = "required-by";
const REINFORCED_BY_RELATION = "reinforced-by";
const ENABLED_BY_RELATION = "enabled-by";
const NEGATED_BY_RELATION = "negated-by";

const OF_SUFFIX = "-of";

const pair = function pair(forward: string, reverse: string): RelationRecord {
    return { forward, leaf: null, reverse, rollsUp: false, tooltip: false };
};

const withOf = function withOf(forward: string): RelationRecord {
    return pair(forward, forward + OF_SUFFIX);
};

export const RELATIONS: readonly RelationRecord[] = [
    {
        ...pair(LINKS_TO_RELATION, LINKED_FROM_RELATION),
        leaf: { forward: "links", reverse: "linkedBy" },
        tooltip: true,
    },
    {
        ...pair(EVIDENCE_RELATION_ID, EVIDENCE_FOR_RELATION),
        leaf: { forward: "evidence", reverse: "grounds" },
        rollsUp: true,
        tooltip: true,
    },
    { ...pair(USES_RELATION, USED_BY_RELATION), leaf: { forward: "uses", reverse: "usedBy" } },
    pair(CALLS_RELATION_ID, CALLED_BY_RELATION_ID),
    pair(CONTAINS_RELATION, CONTAINED_IN_RELATION),
    pair(BUILDS_ON_RELATION, PREREQUISITE_OF_RELATION),
    pair(REQUIRES_RELATION, REQUIRED_BY_RELATION),
    pair(REINFORCES_RELATION, REINFORCED_BY_RELATION),
    pair(ENABLES_RELATION, ENABLED_BY_RELATION),
    pair(CONFLICTS_WITH_RELATION, NEGATED_BY_RELATION),
    pair(TENSIONS_WITH_RELATION, TENSIONS_WITH_RELATION),
    pair(COMPOSES_RELATION, COMPOSED_BY_RELATION),
    pair(GROUNDS_RELATION, GROUNDED_BY_RELATION),
    pair(DERIVATION_RELATION, DERIVED_BY_RELATION),
    pair(PRINCIPLE_RELATION, CONTRACTS_RELATION),
    { ...pair(DETECTED_BY_RELATION, DETECTS_RELATION), tooltip: true },
    { ...pair(ENFORCED_BY_RELATION, ENFORCES_RELATION), tooltip: true },
    { ...pair(REFERENCES_RELATION, REFERENCED_FROM_RELATION), rollsUp: true },
    { ...pair(GOVERNED_BY_RELATION, GOVERNS_RELATION), rollsUp: true },
    { ...withOf(CONCERN_RELATION), rollsUp: true },
    { ...withOf(CONCERN_LAYER_RELATION), rollsUp: true },
    pair(TERM_RELATION, TERM_OF_RELATION),
    pair("subsumes", "subsumed-by"),
    pair("transitions-to", "transitions-from"),
    pair("kinds", "allowed-by"),
    pair(CATEGORY_RELATION, "members"),
    withOf(AXIS_RELATION),
    withOf(STAGE_RELATION),
    withOf(MATH_TYPE_RELATION),
    withOf(CONTRACT_RELATION),
    withOf("domain"),
    withOf("force"),
    withOf("layer"),
    withOf("primary-math-type"),
    withOf(CONCEPT_RELATION),
    withOf("dimension"),
    withOf("invariant"),
    withOf("lens"),
    withOf("universal-axis"),
    withOf("techniques"),
    withOf("math-domains"),
    withOf("sequence"),
];

export const RELATION_PAIRS: readonly RelationPair[] = RELATIONS.map(({ forward, reverse }) => ({ forward, reverse }));

export const TOOLTIP_RELATIONS: ReadonlySet<string> = new Set(
    RELATIONS.filter((relation) => relation.tooltip).flatMap((relation) => [relation.forward, relation.reverse]),
);

export const ROLLED_UP_RELATIONS: ReadonlySet<string> = new Set(
    RELATIONS.filter((relation) => relation.rollsUp).map((relation) => relation.reverse),
);

export const LEAF_RELATIONS: readonly RelationRecord[] = RELATIONS.filter((relation) => relation.leaf !== null);

const CHAPTER_COLLECTION = "chapter";
const PATH_MARK = "/";
const FRAGMENT_MARK = "#";
const SNAKE_MARK = "_";
const KEBAB_MARK = "-";

const LISTING_PAGES: ReadonlySet<string> = new Set([ONTOLOGY_PAGE]);

export const chunkKeyOf = function chunkKeyOf(ref: string): string {
    const collection = ref.slice(0, ref.indexOf(FACE_SEPARATOR));
    if (collection !== CHAPTER_COLLECTION) {
        return collection;
    }
    const path = ref.slice(collection.length + FACE_SEPARATOR.length + PATH_MARK.length);
    const ends = [path.indexOf(PATH_MARK), path.indexOf(FRAGMENT_MARK)].filter((at) => at !== -1);
    return collection + KEBAB_MARK + path.slice(0, ends.length === 0 ? path.length : Math.min(...ends));
};

export const isListingRef = function isListingRef(ref: string): boolean {
    return [...LISTING_PAGES].some((page) => chunkKeyOf(ref) === CHAPTER_COLLECTION + KEBAB_MARK + page);
};

export const relationId = function relationId(spelling: string): string {
    let kebab = "";
    for (const character of spelling) {
        const lower = character.toLowerCase();
        if (character === SNAKE_MARK) {
            kebab += KEBAB_MARK;
        } else if (lower === character) {
            kebab += character;
        } else {
            kebab += KEBAB_MARK + lower;
        }
    }
    return kebab;
};

export const reverseOf = function reverseOf(relation: string): string | null {
    return RELATION_PAIRS.find((entry) => entry.forward === relation)?.reverse ?? null;
};
```
