Skip to main content

Parsers and generators

kurotako has exactly two kinds of component. There is no third "transformer" or "middle" stage.

Parsers​

A parser turns a schema source into a slice of the intermediate representation. It is responsible for one input technology:

  • @kurotako/parser-prisma reads a schema.prisma file (or Prisma's multi-file schema folder) and produces IR entities, fields, enums and relations.
  • @kurotako/parser-openapi reads an OpenAPI 3.0/3.1 document (local JSON/YAML or an unauthenticated HTTP(S) URL) and produces IR entities, type aliases, enums and typed maps.

A parser entry lives under sources in tako.config.ts. The config key is the namespace the parser's output is filed under:

sources: {
db: { use: prismaParser, options: { schema: './prisma/schema.prisma' } },
}

The same parser package can be instantiated several times under different keys — for example a Prisma schema for PostgreSQL under pg and another under analytics.

A parser may also implement watchPaths(), which lets tako generate --watch know which files to watch without understanding the parser's options.

Generators​

A generator consumes the merged IR — and, optionally, the artifacts of its private dependencies — and emits files:

  • @kurotako/gen-zod emits Zod schemas from the IR.
  • @kurotako/gen-angular emits TypeScript types, typed FormGroups and Validators aligned on the schema constraints. It embeds its own private copy of the Zod generator and reads its artifact; you need no zod entry.
  • @kurotako/gen-react-tanstack emits one typed React hook per entity, built on TanStack Form and validated by Zod. Like gen-angular, it embeds its own private Zod copy.
  • @kurotako/gen-typescript emits pure TypeScript type declarations from the IR, with no runtime dependency on generated code and no dependency on another generator.
  • @kurotako/gen-openapi emits one OpenAPI 3.0/3.1 document per namespace from the IR.

Generator entries live in the generators array and run in that order. A generator that needs another generator declares it as a private dependency, so this is enough:

generators: [
{ use: angularGenerator }, // runs its own private Zod copy, output in <ns>/angular/zod/
]

A generator entry can restrict its IR view to a subset of namespaces with namespaces: ['db']; by default a generator sees every namespace.

The pipeline​

sources ──parse──▶ SourceIR per namespace ──merge──▶ IR
│
┌─────────┴─────────┐
▼ ▼
gen-angular gen-openapi
(private gen-zod first) │
│ ▼
▼ files
files ──▶ writer ──▶ disk

Each step fails fast: the first error stops the run. tako validate runs the whole pipeline except the final write.

Vocabulary​

kurotako has exactly two component words — parser and generator — and uses them consistently. Packages declare a parser with defineParser and a generator with defineGenerator, both from @kurotako/config. The rationale for the pipeline shape is in docs/architecture.md.