# core/validators/section.validator.ts

> 58 lines of code and 15 definitions.

Tree: GovLab Docs
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-validators-section-validator-ts
Source text: https://banes-lab.com/source/docs/core/validators/section.validator.ts.txt

Listed in [core/validators](https://banes-lab.com/api/source/docs/core/validators.md), after [core/validators/reference.validator.ts](https://banes-lab.com/source/docs/core/validators/reference.validator.ts.md).

## Definitions

- `unorderedDefects` (lexical_declaration, line 35)
- `orderedDefect` (lexical_declaration, line 26)
- `offSchema` (lexical_declaration, line 61, exported)
- `missingDefect` (lexical_declaration, line 22)
- `orderedDefects` (lexical_declaration, line 44)
- `firstMatch` (lexical_declaration, line 13)
- `namesOf` (lexical_declaration, line 18)
- `headings` (lexical_declaration, line 7)
- `HEADING_PREFIX` (lexical_declaration, line 5)
- `outOfOrder` (lexical_declaration, line 27)
- `defects` (lexical_declaration, line 48)
- `cursor` (lexical_declaration, line 49)
- `at` (lexical_declaration, line 51)
- `present` (lexical_declaration, line 62, exported)
- `required` (lexical_declaration, line 63, exported)

## Contained in

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

## Uses

- [configuration/strings/document.strings.ts](https://banes-lab.com/source/docs/configuration/strings/document.strings.ts.md)
- [core/parsers/markdown.parser.ts](https://banes-lab.com/source/docs/core/parsers/markdown.parser.ts.md)

## Used by

- [core/analyzers/document.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/document.analyzer.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/docs/folder-docs-configuration-strings.md)
- [core/analyzers](https://banes-lab.com/anatomy/docs/folder-docs-core-analyzers.md)
- [core/parsers](https://banes-lab.com/anatomy/docs/folder-docs-core-parsers.md)
- [core/validators](https://banes-lab.com/anatomy/docs/folder-docs-core-validators.md)

## Source

```typescript
import type { DocTypeSchema, MetaConcern, SchemaDefect } from "#types/document.types";
import { missingSection, sectionOutOfOrder } from "#configuration/strings/document.strings";
import { splitLines } from "#core/parsers/markdown.parser";

const HEADING_PREFIX = "## ";

const headings = function headings(source: string): string[] {
    return splitLines(source)
        .filter((line) => line.startsWith(HEADING_PREFIX))
        .map((line) => line.slice(HEADING_PREFIX.length).trim());
};

const firstMatch = function firstMatch(present: readonly string[], names: readonly string[], from: number): number {
    const at = present.slice(from).findIndex((heading) => names.includes(heading));
    return at === -1 ? -1 : at + from;
};

const namesOf = function namesOf(meta: MetaConcern): string[] {
    return [meta.concern, ...(meta.aliases ?? [])];
};

const missingDefect = function missingDefect(concern: string): SchemaDefect {
    return { code: "off-schema", concern, remediation: missingSection(concern) };
};

const orderedDefect = function orderedDefect(present: readonly string[], meta: MetaConcern): SchemaDefect {
    const outOfOrder = firstMatch(present, namesOf(meta), 0) !== -1;
    return {
        code: "off-schema",
        concern: meta.concern,
        remediation: outOfOrder ? sectionOutOfOrder(meta.concern) : missingSection(meta.concern),
    };
};

const unorderedDefects = function unorderedDefects(
    present: readonly string[],
    required: readonly MetaConcern[],
): SchemaDefect[] {
    return required
        .filter((meta) => firstMatch(present, namesOf(meta), 0) === -1)
        .map((meta) => missingDefect(meta.concern));
};

const orderedDefects = function orderedDefects(
    present: readonly string[],
    required: readonly MetaConcern[],
): SchemaDefect[] {
    const defects: SchemaDefect[] = [];
    let cursor = 0;
    for (const meta of required) {
        const at = firstMatch(present, namesOf(meta), cursor);
        if (at === -1) {
            defects.push(orderedDefect(present, meta));
        } else {
            cursor = at + 1;
        }
    }
    return defects;
};

export const offSchema = function offSchema(source: string, schema: DocTypeSchema): SchemaDefect[] {
    const present = headings(source);
    const required = schema.metaConcerns
        .toSorted((left, right) => left.order - right.order)
        .filter((meta) => meta.required);
    return schema.ordered === false ? unorderedDefects(present, required) : orderedDefects(present, required);
};
```
