# core/plugins/manifest.grammar.plugin.ts

> 47 lines of code and 12 definitions.

Tree: GovLab Docs
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-plugins-manifest-grammar-plugin-ts
Source text: https://banes-lab.com/source/docs/core/plugins/manifest.grammar.plugin.ts.txt

Listed in [core/plugins](https://banes-lab.com/api/source/docs/core/plugins.md), after [core/plugins/manifest.governance.plugin.ts](https://banes-lab.com/source/docs/core/plugins/manifest.governance.plugin.ts.md) and before [core/plugins/manifest.metric.plugin.ts](https://banes-lab.com/source/docs/core/plugins/manifest.metric.plugin.ts.md).

## Definitions

- `contractErrors` (lexical_declaration, line 16)
- `validate` (method_definition, line 37, exported)
- `SECTION` (lexical_declaration, line 7)
- `CONTRACTS_KEY` (lexical_declaration, line 8)
- `known` (lexical_declaration, line 9)
- `contractIds` (lexical_declaration, line 11)
- `ids` (lexical_declaration, line 23)
- `plugin` (lexical_declaration, line 27, exported)
- `contribute` (method_definition, line 28, exported)
- `contracts` (lexical_declaration, line 29, exported)
- `grammar` (lexical_declaration, line 38, exported)
- `unknownKeys` (lexical_declaration, line 45, exported)

## Contained in

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

## Uses

- [core/predicates/record.predicate.ts](https://banes-lab.com/source/docs/core/predicates/record.predicate.ts.md)
- [core/selectors/record.selector.ts](https://banes-lab.com/source/docs/core/selectors/record.selector.ts.md)

## Linked from

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

## Source

```typescript
import { MANIFEST_ERRORS, unknownContract, unknownSectionKey } from "#configuration/strings/manifest.strings";
import { isNonEmptyStringArray, recordField, stringsOf } from "#core/selectors/record.selector";
import type { ManifestPlugin } from "#types/manifest.types";
import { createAlgoGrammar } from "@govlab/context";
import { isPlainRecord } from "#core/predicates/record.predicate";

const SECTION = "algoGrammar";
const CONTRACTS_KEY = "contracts";
const known: { ids?: ReadonlySet<string> } = {};

const contractIds = function contractIds(): ReadonlySet<string> {
    known.ids ??= new Set(createAlgoGrammar().ids());
    return known.ids;
};

const contractErrors = function contractErrors(contracts: unknown): string[] {
    if (contracts === undefined) {
        return [];
    }
    if (!isNonEmptyStringArray(contracts)) {
        return [MANIFEST_ERRORS.contractsShape];
    }
    const ids = contractIds();
    return ids.size === 0 ? [] : contracts.filter((id) => !ids.has(id)).map(unknownContract);
};

export const plugin: ManifestPlugin = {
    contribute(manifest, entry) {
        const contracts = stringsOf(recordField(manifest, SECTION)?.[CONTRACTS_KEY]);
        if (contracts.length > 0) {
            entry[SECTION] = { contracts };
        }
    },
    name: "algo-grammar",
    section: {
        keys: [SECTION],
        validate(manifest) {
            const grammar = manifest[SECTION];
            if (grammar === undefined) {
                return [];
            }
            if (!isPlainRecord(grammar)) {
                return [MANIFEST_ERRORS.algoGrammarShape];
            }
            const unknownKeys = Object.keys(grammar)
                .filter((key) => key !== CONTRACTS_KEY)
                .map((key) => unknownSectionKey(SECTION, key));
            return [...unknownKeys, ...contractErrors(grammar[CONTRACTS_KEY])];
        },
    },
};
```
