# core/converters/structure.converter.ts

> 60 lines of code and 16 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-converters-structure-converter-ts
Source text: https://banes-lab.com/source/build-scripts/core/converters/structure.converter.ts.txt

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

## Definitions

- `total` (lexical_declaration, line 48, exported)
- `sumStats` (lexical_declaration, line 45, exported)
- `tallyOf` (lexical_declaration, line 35, exported)
- `fileLayerOf` (lexical_declaration, line 23, exported)
- `folderLayerOf` (lexical_declaration, line 27, exported)
- `NAME_SEPARATOR` (lexical_declaration, line 5)
- `MIN_SLOT_SEGMENTS` (lexical_declaration, line 6)
- `ROLE_CONCERN` (lexical_declaration, line 7)
- `slotsOf` (lexical_declaration, line 9, exported)
- `segments` (lexical_declaration, line 13, exported)
- `concern` (lexical_declaration, line 14, exported)
- `subject` (lexical_declaration, line 15, exported)
- `middle` (lexical_declaration, line 19, exported)
- `tag` (lexical_declaration, line 31, exported)
- `flows` (lexical_declaration, line 46, exported)
- `findings` (lexical_declaration, line 47, exported)

## Contained in

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

## Used by

- [core/converters/anatomy.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/anatomy.converter.ts.md)
- [core/converters/metric.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/metric.converter.ts.md)

## Linked from

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

## Source

```typescript
import type { AnatomySlots, AnatomyStats } from "@banes-lab/web/types/anatomy.types.js";
import { isConcern, isNameExempt, layerFor, tagForFolder } from "@ssot/govlab/shared/manifests/taxonomy.manifest.ts";
import type { DiskFolder } from "#types/structure.types";

const NAME_SEPARATOR = ".";
const MIN_SLOT_SEGMENTS = 3;
const ROLE_CONCERN = "concern";

export const slotsOf = function slotsOf(name: string, root?: string): AnatomySlots | null {
    if (isNameExempt(name, root)) {
        return null;
    }
    const segments = name.split(NAME_SEPARATOR);
    const concern = segments.at(-2) ?? "";
    const subject = segments[0] ?? "";
    if (segments.length < MIN_SLOT_SEGMENTS || !isConcern(concern, root) || subject === "") {
        return null;
    }
    const middle = segments.slice(1, -2);
    return { concern, subject, variant: middle.length === 0 ? null : middle.join(NAME_SEPARATOR) };
};

export const fileLayerOf = function fileLayerOf(slots: AnatomySlots | null, root?: string): string | null {
    return slots === null ? null : (layerFor(slots.concern, root) ?? null);
};

export const folderLayerOf = function folderLayerOf(folder: DiskFolder): string | null {
    if (folder.role !== ROLE_CONCERN) {
        return null;
    }
    const tag = tagForFolder(folder.name, folder.governedBy);
    return tag === undefined ? null : (layerFor(tag, folder.governedBy) ?? null);
};

export const tallyOf = function tallyOf(parts: readonly Readonly<Record<string, number>>[]): Record<string, number> {
    const total: Record<string, number> = {};
    for (const part of parts) {
        for (const [key, count] of Object.entries(part)) {
            total[key] = (total[key] ?? 0) + count;
        }
    }
    return total;
};

export const sumStats = function sumStats(parts: readonly AnatomyStats[]): AnatomyStats {
    const flows = tallyOf(parts.map((part) => part.flows));
    const findings = tallyOf(parts.map((part) => part.findings));
    const total = function total(pick: (part: AnatomyStats) => number): number {
        return parts.reduce((sum, part) => sum + pick(part), 0);
    };
    return {
        bytes: total((part) => part.bytes),
        callable: total((part) => part.callable),
        definitions: total((part) => part.definitions),
        edges: total((part) => part.edges),
        exported: total((part) => part.exported),
        files: total((part) => part.files),
        findings,
        flows,
        lines: {
            blank: total((part) => part.lines.blank),
            code: total((part) => part.lines.code),
            total: total((part) => part.lines.total),
        },
    };
};
```
