# presentation/renderers/syntax.renderer.ts

> 49 lines of code and 9 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-presentation-renderers-syntax-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.81e1d5ee2a45f09e19ecf91da1fe28006ae630fa2db2504786236555d40018d7.generated.txt

## Definitions

- `renderSyntax` (lexical_declaration, line 43, exported)
- `splitLines` (lexical_declaration, line 27)
- `renderToken` (lexical_declaration, line 16)
- `lineSpan` (lexical_declaration, line 23)
- `Piece` (interface_declaration, line 11)
- `lines` (lexical_declaration, line 28)
- `pieces` (lexical_declaration, line 30)
- `element` (lexical_declaration, line 44, exported)
- `line` (lexical_declaration, line 49, exported)

## Uses

- [core/analyzers/syntax.analyzer.ts](https://banes-lab.com/source/tree/core/analyzers/syntax.analyzer.ts.md)
- [core/factories/element.factory.ts](https://banes-lab.com/source/tree/core/factories/element.factory.ts.md)

## Used by

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

## Source

```typescript
import {
    CODE_LINE_ATTRIBUTE,
    CODE_LINE_CLASS,
    LINE_BREAK,
    SYNTAX_CLASS_PREFIX,
} from "#configuration/constants/syntax.constants";
import type { Token } from "#types/syntax.types";
import { createElement } from "#core/factories/element.factory";
import { tokenize } from "#core/analyzers/syntax.analyzer";

interface Piece {
    readonly kind: Token["kind"];
    readonly text: string;
}

const renderToken = function renderToken(token: Piece): Node {
    if (token.kind === "plain") {
        return document.createTextNode(token.text);
    }
    return createElement("span", { className: SYNTAX_CLASS_PREFIX + token.kind, text: token.text });
};

const lineSpan = function lineSpan(number: number): HTMLElement {
    return createElement("span", { attributes: { [CODE_LINE_ATTRIBUTE]: String(number) }, className: CODE_LINE_CLASS });
};

const splitLines = function splitLines(tokens: readonly Token[]): Piece[][] {
    const lines: Piece[][] = [[]];
    for (const token of tokens) {
        const pieces = token.text.split(LINE_BREAK);
        pieces.forEach((text, index) => {
            if (index > 0) {
                lines.push([]);
            }
            if (text.length > 0) {
                lines.at(-1)?.push({ kind: token.kind, text });
            }
        });
    }
    return lines;
};

export const renderSyntax = function renderSyntax(code: string, language: string): HTMLElement {
    const element = createElement("code");
    splitLines(tokenize(code, language)).forEach((pieces, index) => {
        if (index > 0) {
            element.append(document.createTextNode(LINE_BREAK));
        }
        const line = lineSpan(index + 1);
        line.append(...pieces.map(renderToken));
        element.append(line);
    });
    return element;
};
```
