# core/coordinators/grammar.coordinator.ts

> 73 lines of code and 12 definitions.

Tree: Code Parse
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/code-parse#file-code-parse-core-coordinators-grammar-coordinator-ts
Source text: https://banes-lab.com/source/code-parse/core/coordinators/grammar.coordinator.ts.txt

Listed in [core/coordinators](https://banes-lab.com/api/source/code-parse/core/coordinators.md).

## Definitions

- `messageOf` (lexical_declaration, line 24)
- `attemptWasm` (lexical_declaration, line 39)
- `buildWasm` (lexical_declaration, line 28)
- `buildSource` (lexical_declaration, line 50)
- `buildGrammars` (lexical_declaration, line 63, exported)
- `out` (lexical_declaration, line 29)
- `fetched` (lexical_declaration, line 54)
- `grammarDir` (lexical_declaration, line 59)
- `work` (lexical_declaration, line 67, exported)
- `results` (lexical_declaration, line 70, exported)
- `map` (lexical_declaration, line 71, exported)
- `target` (lexical_declaration, line 72, exported)

## Contained in

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

## Uses

- [configuration/strings/grammar.strings.ts](https://banes-lab.com/source/code-parse/configuration/strings/grammar.strings.ts.md)
- [core/adapters/shell.adapter.ts](https://banes-lab.com/source/code-parse/core/adapters/shell.adapter.ts.md)
- [core/loaders/manifest.loader.ts](https://banes-lab.com/source/code-parse/core/loaders/manifest.loader.ts.md)
- [core/reporters/grammar.reporter.ts](https://banes-lab.com/source/code-parse/core/reporters/grammar.reporter.ts.md)
- [core/resolvers/grammar.resolver.ts](https://banes-lab.com/source/code-parse/core/resolvers/grammar.resolver.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/code-parse/folder-code-parse-configuration-strings.md)
- [core/adapters](https://banes-lab.com/anatomy/code-parse/folder-code-parse-core-adapters.md)
- [core/coordinators](https://banes-lab.com/anatomy/code-parse/folder-code-parse-core-coordinators.md)
- [core/loaders](https://banes-lab.com/anatomy/code-parse/folder-code-parse-core-loaders.md)
- [core/reporters](https://banes-lab.com/anatomy/code-parse/folder-code-parse-core-reporters.md)
- [core/resolvers](https://banes-lab.com/anatomy/code-parse/folder-code-parse-core-resolvers.md)

## Source

```typescript
import { BUILD_CLI, PARSER_SOURCE, WORK_PREFIX } from "#configuration/constants/grammar.constants";
import type { BuildResult, GrammarSource } from "#types/grammar.types";
import {
    UNKNOWN_FAILURE,
    builtLine,
    fetchFailedLine,
    noParserSource,
    noteOf,
    wasmFailedLine,
    wroteLine,
} from "#configuration/strings/grammar.strings";
import { dirname, join, relative } from "node:path";
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { fileTypesForSource, readGrammarMeta } from "#core/loaders/manifest.loader";
import { grammarPath, resolveGrammarDir } from "#core/resolvers/grammar.resolver";
import { ROOT } from "@ssot/paths";
import { extensionMapOf } from "#core/converters/grammar.converter";
import { fetchGrammarPackage } from "#core/adapters/remote.adapter";
import process from "node:process";
import { reportBuild } from "#core/reporters/grammar.reporter";
import { runCommand } from "#core/adapters/shell.adapter";
import { tmpdir } from "node:os";

const messageOf = function messageOf(error: unknown): string {
    return error instanceof Error ? error.message : UNKNOWN_FAILURE;
};

const buildWasm = function buildWasm(source: GrammarSource, grammarDir: string): void {
    const out = grammarPath(resolveGrammarDir(), source.lang);
    if (existsSync(out)) {
        return;
    }
    if (!existsSync(join(grammarDir, ...PARSER_SOURCE))) {
        throw new Error(noParserSource(source.subdir));
    }
    runCommand("npx", ["--yes", BUILD_CLI, "build", "--wasm", grammarDir, "-o", out], dirname(grammarDir));
};

const attemptWasm = function attemptWasm(source: GrammarSource, grammarDir: string, fileTypes: string[]): BuildResult {
    try {
        buildWasm(source, grammarDir);
        process.stdout.write(builtLine(source.lang, fileTypes));
        return { fileTypes, kind: "built", lang: source.lang, note: source.lang };
    } catch (error) {
        process.stderr.write(wasmFailedLine(source.lang, messageOf(error)));
        return { fileTypes, kind: "wasm-failed", lang: source.lang, note: noteOf(source.lang, messageOf(error)) };
    }
};

const buildSource = function buildSource(source: GrammarSource, work: string): BuildResult {
    if (typeof source.unsupported === "string") {
        return { fileTypes: [], kind: "skipped", lang: source.lang, note: noteOf(source.lang, source.unsupported) };
    }
    const fetched = fetchGrammarPackage(source, join(work, source.lang));
    if ("error" in fetched) {
        process.stderr.write(fetchFailedLine(source.lang, fetched.error));
        return { fileTypes: [], kind: "fetch-failed", lang: source.lang, note: noteOf(source.lang, fetched.error) };
    }
    const grammarDir = typeof source.subdir === "string" ? join(fetched.root, source.subdir) : fetched.root;
    return attemptWasm(source, grammarDir, fileTypesForSource(source, readGrammarMeta(fetched.root)));
};

export const buildGrammars = async function buildGrammars(
    sources: readonly GrammarSource[],
    writeMap: (map: Record<string, string[]>) => Promise<string>,
): Promise<boolean> {
    const work = mkdtempSync(join(tmpdir(), WORK_PREFIX));
    mkdirSync(resolveGrammarDir(), { recursive: true });
    try {
        const results = sources.map((source) => buildSource(source, work));
        const map = extensionMapOf(results);
        const target = await writeMap(map);
        process.stdout.write(wroteLine(Object.keys(map).length, relative(ROOT, target)));
        return reportBuild(results);
    } finally {
        rmSync(work, { force: true, recursive: true });
    }
};
```
