# core/analyzers/diagram.analyzer.ts

> 76 lines of code and 23 definitions.

Tree: Site tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-core-analyzers-diagram-analyzer-ts
Source text: https://banes-lab.com/assets/sources/source.690b1be868d65e6dcd9e2e91a48cd8528aca624c3de7bb3097f0aa1de95688a5.generated.txt

## Definitions

- `visit` (lexical_declaration, line 63, exported)
- `walkOrder` (lexical_declaration, line 50, exported)
- `hexOf` (lexical_declaration, line 14)
- `diagramDigest` (lexical_declaration, line 18, exported)
- `DIGEST_ALGORITHM` (lexical_declaration, line 9)
- `HEX_RADIX` (lexical_declaration, line 10)
- `HEX_WIDTH` (lexical_declaration, line 11)
- `HEX_PAD` (lexical_declaration, line 12)
- `nodeNameOf` (lexical_declaration, line 22, exported)
- `rest` (lexical_declaration, line 27, exported)
- `cut` (lexical_declaration, line 28, exported)
- `edgeEndsOf` (lexical_declaration, line 32, exported)
- `body` (lexical_declaration, line 39, exported)
- `at` (lexical_declaration, line 40, exported)
- `from` (lexical_declaration, line 41, exported)
- `to` (lexical_declaration, line 42, exported)
- `byName` (lexical_declaration, line 54, exported)
- `name` (lexical_declaration, line 56, exported)
- `names` (lexical_declaration, line 60, exported)
- `steps` (lexical_declaration, line 61, exported)
- `seen` (lexical_declaration, line 62, exported)
- `id` (lexical_declaration, line 64, exported)
- `ends` (lexical_declaration, line 71, exported)

## Used by

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

## Source

```typescript
import {
    EDGE_PART_MARK,
    EDGE_PREFIX,
    FLOWCHART_MARK,
    NODE_COUNT_MARK,
} from "#configuration/constants/diagram.constants";
import type { WalkStep } from "#types/diagram.types";

const DIGEST_ALGORITHM = "SHA-256";
const HEX_RADIX = 16;
const HEX_WIDTH = 2;
const HEX_PAD = "0";

const hexOf = function hexOf(bytes: ArrayBuffer): string {
    return [...new Uint8Array(bytes)].map((byte) => byte.toString(HEX_RADIX).padStart(HEX_WIDTH, HEX_PAD)).join("");
};

export const diagramDigest = async function diagramDigest(source: string): Promise<string> {
    return hexOf(await crypto.subtle.digest(DIGEST_ALGORITHM, new TextEncoder().encode(source)));
};

export const nodeNameOf = function nodeNameOf(id: string): string | null {
    const at = id.indexOf(FLOWCHART_MARK);
    if (at === -1) {
        return null;
    }
    const rest = id.slice(at + FLOWCHART_MARK.length);
    const cut = rest.lastIndexOf(NODE_COUNT_MARK);
    return cut === -1 ? rest : rest.slice(0, cut);
};

export const edgeEndsOf = function edgeEndsOf(
    id: string,
    names: ReadonlySet<string>,
): readonly [string, string] | null {
    if (!id.startsWith(EDGE_PREFIX)) {
        return null;
    }
    const body = id.slice(EDGE_PREFIX.length, id.lastIndexOf(EDGE_PART_MARK));
    for (let at = body.indexOf(EDGE_PART_MARK); at !== -1; at = body.indexOf(EDGE_PART_MARK, at + 1)) {
        const from = body.slice(0, at);
        const to = body.slice(at + EDGE_PART_MARK.length);
        if (names.has(from) && names.has(to)) {
            return [from, to];
        }
    }
    return null;
};

export const walkOrder = function walkOrder(
    nodeIds: readonly string[],
    edgeIds: readonly string[],
): readonly WalkStep[] {
    const byName = new Map(
        nodeIds.flatMap((id) => {
            const name = nodeNameOf(id);
            return name === null ? [] : [[name, id] as const];
        }),
    );
    const names = new Set(byName.keys());
    const steps: WalkStep[] = [];
    const seen = new Set<string>();
    const visit = function visit(name: string): void {
        const id = byName.get(name);
        if (id !== undefined && !seen.has(id)) {
            seen.add(id);
            steps.push({ id, kind: "node" });
        }
    };
    for (const edge of edgeIds) {
        const ends = edgeEndsOf(edge, names);
        if (ends !== null) {
            visit(ends[0]);
            steps.push({ id: edge, kind: "edge" });
            visit(ends[1]);
        }
    }
    for (const name of names) {
        visit(name);
    }
    return steps;
};
```
