# core/validators/binding.validator.ts

> 24 lines of code and 3 definitions.

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

Listed in [core/validators](https://banes-lab.com/api/source/quality/core/validators.md), before [core/validators/concern.validator.ts](https://banes-lab.com/source/quality/core/validators/concern.validator.ts.md).

## Definitions

- `bindingFindings` (lexical_declaration, line 5, exported)
- `findings` (lexical_declaration, line 11, exported)
- `canonical` (lexical_declaration, line 15, exported)

## Contained in

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

## Source

```typescript
import type { BindingFinding, RuleSource } from "#types/binding.types";
import { ALGO_FACE } from "@govlab/constants";
import { canonicalOf } from "#core/parsers/binding.parser";

export const bindingFindings = function bindingFindings(
    rules: readonly RuleSource[],
    contracts: ReadonlySet<string>,
    isConcept: (concept: string) => boolean,
): BindingFinding[] {
    return rules.flatMap((rule): BindingFinding[] => {
        const findings: BindingFinding[] = [];
        if (!contracts.has(rule.id)) {
            findings.push({ detail: `${ALGO_FACE}:${rule.id}`, file: rule.file, id: rule.id, reason: "no-contract" });
        }
        const canonical = canonicalOf(rule.text);
        if (canonical === null || canonical.length === 0) {
            findings.push({ detail: "", file: rule.file, id: rule.id, reason: "no-canonical" });
            return findings;
        }
        for (const concept of canonical.filter((entry) => !isConcept(entry))) {
            findings.push({ detail: concept, file: rule.file, id: rule.id, reason: "unknown-concept" });
        }
        return findings;
    });
};
```
