# core/coordinators/validation.coordinator.ts

> 60 lines of code and 10 definitions.

Tree: GovLab Quality
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-coordinators-validation-coordinator-ts
Source text: https://banes-lab.com/source/quality/core/coordinators/validation.coordinator.ts.txt

Listed in [core/coordinators](https://banes-lab.com/api/source/quality/core/coordinators.md), after [core/coordinators/quality.coordinator.ts](https://banes-lab.com/source/quality/core/coordinators/quality.coordinator.ts.md).

## Definitions

- `applies` (lexical_declaration, line 38)
- `extensionOf` (lexical_declaration, line 15)
- `validatorFindings` (lexical_declaration, line 42)
- `loadValidators` (lexical_declaration, line 55, exported)
- `safeRead` (lexical_declaration, line 20)
- `runValidators` (lexical_declaration, line 60, exported)
- `dotIdx` (lexical_declaration, line 16)
- `readInputs` (lexical_declaration, line 31)
- `content` (lexical_declaration, line 33)
- `findings` (lexical_declaration, line 61, exported)

## Contained in

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

## Uses

- [core/formatters/validation.formatter.ts](https://banes-lab.com/source/quality/core/formatters/validation.formatter.ts.md)
- [core/loaders/folder.loader.ts](https://banes-lab.com/source/quality/core/loaders/folder.loader.ts.md)
- [core/predicates/failure.predicate.ts](https://banes-lab.com/source/quality/core/predicates/failure.predicate.ts.md)
- [core/registries/validation.registry.ts](https://banes-lab.com/source/quality/core/registries/validation.registry.ts.md)

## Linked from

- [core/coordinators](https://banes-lab.com/anatomy/quality/folder-quality-core-coordinators.md)
- [core/formatters](https://banes-lab.com/anatomy/quality/folder-quality-core-formatters.md)
- [core/loaders](https://banes-lab.com/anatomy/quality/folder-quality-core-loaders.md)
- [core/predicates](https://banes-lab.com/anatomy/quality/folder-quality-core-predicates.md)
- [core/registries](https://banes-lab.com/anatomy/quality/folder-quality-core-registries.md)

## Source

```typescript
import type {
    FileInput,
    FileReader,
    ProjectValidator,
    ValidationInput,
    ValidationResult,
} from "#types/validation.types";
import type { Finding } from "#types/finding.types";
import { VALIDATOR_SUFFIX } from "#configuration/constants/validation.constants";
import { importFolder } from "#core/loaders/folder.loader";
import { isNotFound } from "#core/predicates/failure.predicate";
import { registeredValidators } from "#core/registries/validation.registry";
import { renderPanel } from "#core/formatters/validation.formatter";

const extensionOf = function extensionOf(path: string): string {
    const dotIdx = path.lastIndexOf(".");
    return dotIdx === -1 ? "" : path.slice(dotIdx + 1);
};

const safeRead = function safeRead(readFile: FileReader, path: string): string | null {
    try {
        return readFile(path);
    } catch (error) {
        if (error instanceof Error && isNotFound(error)) {
            return null;
        }
        throw error;
    }
};

const readInputs = function readInputs(readFile: FileReader, files: readonly string[]): FileInput[] {
    return files.flatMap((path) => {
        const content = safeRead(readFile, path);
        return content === null ? [] : [{ content, path }];
    });
};

const applies = function applies(validator: ProjectValidator, entry: FileInput): boolean {
    return validator.appliesTo === "*" || validator.appliesTo.includes(extensionOf(entry.path));
};

const validatorFindings = function validatorFindings(
    validators: readonly ProjectValidator[],
    inputs: readonly FileInput[],
    consumers: readonly FileInput[],
): Finding[] {
    return validators.flatMap((validator) =>
        validator.validate(
            inputs.filter((entry) => applies(validator, entry)),
            consumers.filter((entry) => applies(validator, entry)),
        ),
    );
};

export const loadValidators = async function loadValidators(): Promise<ProjectValidator[]> {
    await importFolder("govlab.quality.validators", VALIDATOR_SUFFIX);
    return registeredValidators();
};

export const runValidators = function runValidators(input: ValidationInput): ValidationResult {
    const findings = validatorFindings(
        input.validators,
        readInputs(input.readFile, input.files),
        readInputs(input.readFile, input.consumers),
    );
    return { clean: findings.length === 0, findings, panel: renderPanel(findings) };
};
```
