# core/registries/pattern.registry.ts

> 57 lines of code and 11 definitions.

Tree: GovLab Patterns
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/patterns#file-patterns-core-registries-pattern-registry-ts
Source text: https://banes-lab.com/source/patterns/core/registries/pattern.registry.ts.txt

Listed in [core/registries](https://banes-lab.com/api/source/patterns/core/registries.md), before [core/registries/representation.registry.ts](https://banes-lab.com/source/patterns/core/registries/representation.registry.ts.md).

## Definitions

- `buildFace` (lexical_declaration, line 28)
- `definePatternFace` (lexical_declaration, line 13, exported)
- `foldFaces` (lexical_declaration, line 49, exported)
- `FoldState` (interface_declaration, line 4)
- `REGISTRY` (lexical_declaration, line 11)
- `frozen` (lexical_declaration, line 19, exported)
- `registeredFaces` (lexical_declaration, line 24, exported)
- `definition` (lexical_declaration, line 35)
- `dependencies` (lexical_declaration, line 40)
- `port` (lexical_declaration, line 43)
- `state` (lexical_declaration, line 53, exported)

## Contained in

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

## Uses

- [configuration/strings/pattern.strings.ts](https://banes-lab.com/source/patterns/configuration/strings/pattern.strings.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/patterns/folder-patterns-configuration-strings.md)
- [core/registries](https://banes-lab.com/anatomy/patterns/folder-patterns-core-registries.md)

## Source

```typescript
import type { FaceContext, PatternFaceDefinition } from "#types/pattern.types";
import { faceCycle, faceRegistered, faceUnregistered } from "#configuration/strings/pattern.strings";

interface FoldState {
    byName: Map<string, PatternFaceDefinition>;
    built: Map<string, unknown>;
    building: Set<string>;
    context: FaceContext;
}

const REGISTRY = new Map<string, PatternFaceDefinition>();

export const definePatternFace = function definePatternFace<P>(
    definition: PatternFaceDefinition<P>,
): PatternFaceDefinition<P> {
    if (REGISTRY.has(definition.name)) {
        throw new Error(faceRegistered(definition.name));
    }
    const frozen = Object.freeze({ ...definition, dependsOn: Object.freeze([...(definition.dependsOn ?? [])]) });
    REGISTRY.set(definition.name, frozen);
    return frozen;
};

export const registeredFaces = function registeredFaces(): readonly PatternFaceDefinition[] {
    return [...REGISTRY.values()];
};

const buildFace = function buildFace(name: string, state: FoldState): unknown {
    if (state.built.has(name)) {
        return state.built.get(name);
    }
    if (state.building.has(name)) {
        throw new Error(faceCycle(name));
    }
    const definition = state.byName.get(name);
    if (!definition) {
        throw new Error(faceUnregistered(name));
    }
    state.building.add(name);
    const dependencies = Object.fromEntries(
        (definition.dependsOn ?? []).map((dependency) => [dependency, buildFace(dependency, state)]),
    );
    const port = definition.build(state.context, dependencies);
    state.building.delete(name);
    state.built.set(name, port);
    return port;
};

export const foldFaces = function foldFaces(
    definitions: readonly PatternFaceDefinition[],
    context: FaceContext,
): Map<string, unknown> {
    const state: FoldState = {
        building: new Set<string>(),
        built: new Map<string, unknown>(),
        byName: new Map(definitions.map((definition) => [definition.name, definition])),
        context,
    };
    for (const definition of definitions) {
        buildFace(definition.name, state);
    }
    return state.built;
};
```
