# core/adapters/diagram.adapter.ts

> 58 lines of code and 16 definitions.

Tree: GovLab Docs
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-adapters-diagram-adapter-ts
Source text: https://banes-lab.com/source/docs/core/adapters/diagram.adapter.ts.txt

Listed in [core/adapters](https://banes-lab.com/api/source/docs/core/adapters.md), before [core/adapters/markdown.adapter.ts](https://banes-lab.com/source/docs/core/adapters/markdown.adapter.ts.md).

## Definitions

- `messageOf` (lexical_declaration, line 44)
- `createMermaidParser` (lexical_declaration, line 48, exported)
- `loadParser` (lexical_declaration, line 30)
- `installGlobals` (lexical_declaration, line 15)
- `firstLine` (lexical_declaration, line 39)
- `parse` (method_definition, line 54, exported)
- `GLOBAL_KEYS` (lexical_declaration, line 5)
- `BLANK_PAGE` (lexical_declaration, line 6)
- `LINE_BREAK` (lexical_declaration, line 7)
- `loaded` (lexical_declaration, line 9)
- `noop` (lexical_declaration, line 11)
- `view` (lexical_declaration, line 16)
- `{ default: mermaid }` (lexical_declaration, line 32)
- `{ default: elkLayouts }` (lexical_declaration, line 33)
- `lineBreak` (lexical_declaration, line 40)
- `mermaid` (lexical_declaration, line 51, exported)

## Contained in

- [core/adapters](https://banes-lab.com/anatomy/docs/folder-docs-core-adapters.md)

## Used by

- [core/validators/diagram.validator.ts](https://banes-lab.com/source/docs/core/validators/diagram.validator.ts.md)

## Linked from

- [core/adapters](https://banes-lab.com/anatomy/docs/folder-docs-core-adapters.md)
- [core/validators](https://banes-lab.com/anatomy/docs/folder-docs-core-validators.md)

## Source

```typescript
import { JSDOM } from "jsdom";
import type { Mermaid } from "mermaid";
import type { MermaidParser } from "#types/diagram.types";

const GLOBAL_KEYS: readonly string[] = ["DOMParser", "Node", "SVGElement", "HTMLElement", "getComputedStyle"];
const BLANK_PAGE = "<!DOCTYPE html><html><body></body></html>";
const LINE_BREAK = "\n";

const loaded: { mermaid?: Promise<Mermaid> } = {};

const noop = function noop(): null {
    return null;
};

const installGlobals = function installGlobals(dom: JSDOM): void {
    const view = dom.window;
    Reflect.set(globalThis, "window", view);
    Reflect.set(globalThis, "document", Reflect.get(view, "document"));
    for (const key of GLOBAL_KEYS) {
        Reflect.set(globalThis, key, Reflect.get(view, key));
    }
    if (!Reflect.has(globalThis, "navigator")) {
        Object.defineProperty(globalThis, "navigator", { configurable: true, value: Reflect.get(view, "navigator") });
    }
    if (!Reflect.has(view, "matchMedia")) {
        Reflect.set(view, "matchMedia", () => ({ addListener: noop, matches: false, removeListener: noop }));
    }
};

const loadParser = async function loadParser(): Promise<Mermaid> {
    installGlobals(new JSDOM(BLANK_PAGE, { pretendToBeVisual: true }));
    const { default: mermaid } = await import("mermaid");
    const { default: elkLayouts } = await import("@mermaid-js/layout-elk");
    mermaid.registerLayoutLoaders(elkLayouts);
    mermaid.initialize({ securityLevel: "strict", startOnLoad: false });
    return mermaid;
};

const firstLine = function firstLine(message: string): string {
    const lineBreak = message.indexOf(LINE_BREAK);
    return lineBreak === -1 ? message.trim() : message.slice(0, lineBreak).trim();
};

const messageOf = function messageOf(error: unknown): string {
    return error instanceof Error ? error.message : String(error);
};

export const createMermaidParser = async function createMermaidParser(): Promise<MermaidParser> {
    try {
        loaded.mermaid ??= loadParser();
        const mermaid = await loaded.mermaid;
        return {
            available: true,
            async parse(code: string): Promise<string | null> {
                try {
                    await mermaid.parse(code);
                    return null;
                } catch (error) {
                    return firstLine(messageOf(error));
                }
            },
        };
    } catch (error) {
        return { available: false, reason: messageOf(error) };
    }
};
```
