# core/predicates/surface.predicate.ts

> 27 lines of code and 9 definitions.

Tree: Bane's Lab Site
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/tree#file-core-predicates-surface-predicate-ts
Source text: https://banes-lab.com/source/tree/core/predicates/surface.predicate.ts.txt

Listed in [core/predicates](https://banes-lab.com/api/source/tree/core/predicates.md), after [core/predicates/resource.predicate.ts](https://banes-lab.com/source/tree/core/predicates/resource.predicate.ts.md).

## Definitions

- `isRecord` (lexical_declaration, line 3)
- `hasText` (lexical_declaration, line 7)
- `listOf` (lexical_declaration, line 11)
- `isRecording` (lexical_declaration, line 28, exported)
- `isTextList` (lexical_declaration, line 24)
- `isFrame` (lexical_declaration, line 20)
- `isLine` (lexical_declaration, line 16)
- `held` (lexical_declaration, line 12)
- `frames` (lexical_declaration, line 32, exported)

## Contained in

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

## Used by

- [domain/loaders/surface.loader.ts](https://banes-lab.com/source/tree/domain/loaders/surface.loader.ts.md)

## Linked from

- [core/predicates](https://banes-lab.com/anatomy/tree/folder-core-predicates.md)
- [domain/loaders](https://banes-lab.com/anatomy/tree/folder-domain-loaders.md)

## Source

```typescript
import type { SurfaceFrame, SurfaceLine, SurfaceRecording } from "#types/surface.types";

const isRecord = function isRecord(value: unknown): value is Record<string, unknown> {
    return typeof value === "object" && value !== null;
};

const hasText = function hasText(value: Record<string, unknown>, keys: readonly string[]): boolean {
    return keys.every((key) => typeof value[key] === "string");
};

const listOf = function listOf(value: Record<string, unknown>, key: string): readonly unknown[] {
    const held = value[key];
    return Array.isArray(held) ? held : [];
};

const isLine = function isLine(value: unknown): value is SurfaceLine {
    return isRecord(value) && hasText(value, ["text"]) && typeof value["changed"] === "boolean";
};

const isFrame = function isFrame(value: unknown): value is SurfaceFrame {
    return isRecord(value) && hasText(value, ["command", "output", "surface"]) && listOf(value, "lines").every(isLine);
};

const isTextList = function isTextList(value: Record<string, unknown>, key: string): boolean {
    return Array.isArray(value[key]) && listOf(value, key).every((entry) => typeof entry === "string");
};

export const isRecording = function isRecording(value: unknown): value is SurfaceRecording {
    if (!isRecord(value) || !hasText(value, ["figure"]) || !isTextList(value, "opening")) {
        return false;
    }
    const frames = listOf(value, "frames");
    return frames.length > 0 && frames.every(isFrame);
};
```
