# core/converters/browser.converter.ts

> 66 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-browser-converter-ts
Source text: https://banes-lab.com/source/build-scripts/core/converters/browser.converter.ts.txt

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

## Definitions

- `locationOf` (lexical_declaration, line 13)
- `exceptionRecord` (lexical_declaration, line 53, exported)
- `consoleRecord` (lexical_declaration, line 40, exported)
- `firstLine` (lexical_declaration, line 9)
- `argText` (lexical_declaration, line 20)
- `eventRecord` (lexical_declaration, line 67, exported)
- `CONSOLE_METHOD` (lexical_declaration, line 4)
- `EXCEPTION_METHOD` (lexical_declaration, line 5)
- `EVENT_METHODS` (lexical_declaration, line 7, exported)
- `{ value }` (lexical_declaration, line 24)
- `firstCallFrame` (lexical_declaration, line 34)
- `trace` (lexical_declaration, line 35)
- `[frame]` (lexical_declaration, line 36)
- `args` (lexical_declaration, line 42, exported)
- `thrown` (lexical_declaration, line 54, exported)
- `described` (lexical_declaration, line 55, exported)
- `frame` (lexical_declaration, line 56, exported)
- `method` (lexical_declaration, line 68, exported)
- `params` (lexical_declaration, line 69, exported)
- `details` (lexical_declaration, line 73, exported)

## Contained in

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

## Uses

- [core/selectors/base.selector.ts](https://banes-lab.com/source/build-scripts/core/selectors/base.selector.ts.md)
- [core/validators/catalog.validator.ts](https://banes-lab.com/source/build-scripts/core/validators/catalog.validator.ts.md)

## Linked from

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

## Source

```typescript
import { entriesAt, isRecord, numberAt, recordAt, textAt } from "#core/selectors/base.selector";
import type { ConsoleRecord } from "#types/browser.types";

const CONSOLE_METHOD = "Runtime.consoleAPICalled";
const EXCEPTION_METHOD = "Runtime.exceptionThrown";

export const EVENT_METHODS: ReadonlySet<string> = new Set([CONSOLE_METHOD, EXCEPTION_METHOD]);

const firstLine = function firstLine(text: string): string {
    return text.split("\n")[0] ?? "";
};

const locationOf = function locationOf(url: string | null, line: number | null): string {
    if (url === null || url.length === 0) {
        return "";
    }
    return line === null ? url : `${url}:${String(line + 1)}`;
};

const argText = function argText(arg: unknown): string {
    if (!isRecord(arg)) {
        return "";
    }
    const { value } = arg;
    if (typeof value === "string") {
        return value;
    }
    if (typeof value === "number" || typeof value === "boolean") {
        return String(value);
    }
    return firstLine(textAt(arg, "description") ?? "");
};

const firstCallFrame = function firstCallFrame(source: Record<string, unknown> | null): Record<string, unknown> | null {
    const trace = source === null ? null : recordAt(source, "stackTrace");
    const [frame] = trace === null ? [] : entriesAt(trace, "callFrames");
    return isRecord(frame) ? frame : null;
};

export const consoleRecord = function consoleRecord(params: Record<string, unknown> | null): ConsoleRecord {
    const frame = firstCallFrame(params);
    const args = params === null ? [] : entriesAt(params, "args");
    return {
        level: (params === null ? null : textAt(params, "type")) ?? "log",
        source: locationOf(
            frame === null ? null : textAt(frame, "url"),
            frame === null ? null : numberAt(frame, "lineNumber"),
        ),
        text: args.map(argText).join(" "),
    };
};

export const exceptionRecord = function exceptionRecord(details: Record<string, unknown>): ConsoleRecord {
    const thrown = recordAt(details, "exception");
    const described = firstLine((thrown === null ? null : textAt(thrown, "description")) ?? "");
    const frame = firstCallFrame(details);
    return {
        level: "exception",
        source: locationOf(
            textAt(details, "url") ?? (frame === null ? null : textAt(frame, "url")),
            numberAt(details, "lineNumber") ?? (frame === null ? null : numberAt(frame, "lineNumber")),
        ),
        text: described.length > 0 ? described : (textAt(details, "text") ?? ""),
    };
};

export const eventRecord = function eventRecord(parsed: Record<string, unknown>): ConsoleRecord | null {
    const method = textAt(parsed, "method");
    const params = recordAt(parsed, "params");
    if (method === CONSOLE_METHOD) {
        return consoleRecord(params);
    }
    const details = params === null ? null : recordAt(params, "exceptionDetails");
    return method === EXCEPTION_METHOD && details !== null ? exceptionRecord(details) : null;
};
```
