# tools/core/validators/writer.validator.ts

> 43 lines of code and 9 definitions.

Tree: Coordination tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-validators-writer-validator-ts
Source text: https://banes-lab.com/assets/sources/source.f5bac890f88d64a56ca16e3a409ed1a2b3ea42edbaa47721ec8cde09c0acb00f.generated.txt

## Definitions

- `reachableFrom` (lexical_declaration, line 19, exported)
- `unsanctionedWriters` (lexical_declaration, line 38, exported)
- `importsWriter` (lexical_declaration, line 11, exported)
- `WRITE_MEMBERS` (lexical_declaration, line 4)
- `WriteBreach` (interface_declaration, line 6, exported)
- `seen` (lexical_declaration, line 24, exported)
- `queue` (lexical_declaration, line 25, exported)
- `path` (lexical_declaration, line 28, exported)
- `member` (lexical_declaration, line 47, exported)

## Uses

- [tools/core/analyzers/graph.analyzer.ts](https://banes-lab.com/source/coordination/tools/core/analyzers/graph.analyzer.ts.md)
- [tools/core/predicates/source.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/source.predicate.ts.md)

## Used by

- [tools/rules/governance.rule.ts](https://banes-lab.com/source/coordination/tools/rules/governance.rule.ts.md)

## Source

```typescript
import { filesystemImports } from "../predicates/source.predicate.ts";
import { localImports } from "../analyzers/graph.analyzer.ts";

const WRITE_MEMBERS = [`writeFileSync`, `rmSync`, `mkdirSync`];

export interface WriteBreach {
    readonly path: string;
    readonly member: string;
}

export const importsWriter = function importsWriter(source: string): string | null {
    return (
        filesystemImports(source)
            .map((line) => WRITE_MEMBERS.find((member) => line.includes(member)))
            .find((member) => member !== undefined) ?? null
    );
};

export const reachableFrom = function reachableFrom(
    entries: readonly string[],
    known: ReadonlySet<string>,
    read: (path: string) => string,
): string[] {
    const seen = new Set<string>();
    const queue = [...entries];

    while (queue.length > 0) {
        const path = queue.shift() ?? "";
        if (path.length > 0 && !seen.has(path)) {
            seen.add(path);
            queue.push(...localImports(path, read(path), known));
        }
    }

    return [...seen].toSorted((left, right) => left.localeCompare(right, "en"));
};

export const unsanctionedWriters = function unsanctionedWriters(
    entries: readonly string[],
    known: ReadonlySet<string>,
    read: (path: string) => string,
    sanctioned: readonly string[],
): WriteBreach[] {
    return reachableFrom(entries, known, read)
        .filter((path) => !sanctioned.includes(path))
        .flatMap((path) => {
            const member = importsWriter(read(path));
            return member === null ? [] : [{ member, path }];
        });
};
```
