# shared/analyzers/check.analyzer.ts

> 44 lines of code and 15 definitions.

Tree: Governance tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/governance#file-governance-shared-analyzers-check-analyzer-ts
Source text: https://banes-lab.com/source/governance/shared/analyzers/check.analyzer.ts.txt

Listed in [shared/analyzers](https://banes-lab.com/api/source/governance/shared/analyzers.md), before [shared/analyzers/composition.analyzer.ts](https://banes-lab.com/source/governance/shared/analyzers/composition.analyzer.ts.md).

## Definitions

- `visit` (lexical_declaration, line 43, exported)
- `stringsOf` (lexical_declaration, line 8)
- `declarationOf` (lexical_declaration, line 23)
- `isDeclaringCall` (lexical_declaration, line 33)
- `fieldOf` (lexical_declaration, line 16)
- `declarationsIn` (lexical_declaration, line 37, exported)
- `DECLARING_CALLEE` (lexical_declaration, line 4, exported)
- `Field` (type_alias_declaration, line 6)
- `values` (lexical_declaration, line 12)
- `property` (lexical_declaration, line 17)
- `[argument]` (lexical_declaration, line 24)
- `detects` (lexical_declaration, line 28)
- `enforces` (lexical_declaration, line 29)
- `source` (lexical_declaration, line 41, exported)
- `found` (lexical_declaration, line 42, exported)

## Source

```typescript
import type { ReadDeclaration } from "../../types/check.types.ts";
import ts from "typescript";

export const DECLARING_CALLEE = "defineCheck";

type Field = keyof ReadDeclaration;

const stringsOf = function stringsOf(node: ts.Expression): readonly string[] | null {
    if (!ts.isArrayLiteralExpression(node)) {
        return null;
    }
    const values = node.elements.flatMap((element) => (ts.isStringLiteral(element) ? [element.text] : []));
    return values.length === node.elements.length ? values : null;
};

const fieldOf = function fieldOf(object: ts.ObjectLiteralExpression, field: Field): readonly string[] | null {
    const property = object.properties.find(
        (member) => ts.isPropertyAssignment(member) && ts.isIdentifier(member.name) && member.name.text === field,
    );
    return property !== undefined && ts.isPropertyAssignment(property) ? stringsOf(property.initializer) : null;
};

const declarationOf = function declarationOf(node: ts.CallExpression): ReadDeclaration | null {
    const [argument] = node.arguments;
    if (argument === undefined || !ts.isObjectLiteralExpression(argument)) {
        return null;
    }
    const detects = fieldOf(argument, "detects");
    const enforces = fieldOf(argument, "enforces");
    return detects === null || enforces === null ? null : { detects, enforces };
};

const isDeclaringCall = function isDeclaringCall(node: ts.Node): node is ts.CallExpression {
    return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === DECLARING_CALLEE;
};

export const declarationsIn = function declarationsIn(
    fileName: string,
    text: string,
): readonly (ReadDeclaration | null)[] {
    const source = ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
    const found: (ReadDeclaration | null)[] = [];
    const visit = (node: ts.Node): void => {
        if (isDeclaringCall(node)) {
            found.push(declarationOf(node));
        }
        ts.forEachChild(node, visit);
    };
    visit(source);
    return found;
};
```
