Open Studio
Kit

Generators

defineGenerator declares a named generator unit that walks the AST and emits files. Covers the schema, operation, and operations methods and the GeneratorContext passed to each.

defineGenerator ​

defineGenerator declares a named generator unit consumed by a plugin. Generators walk the AST and emit files. The engine calls each method for the matching node type during the generation loop.

Each generator method returns TElement | Array<FileNode> | void. Returning a renderer element (for example JSX from kubb/jsx) requires a renderer factory on the generator.

my-generator.ts
typescript
import { ast, defineGenerator } from 'kubb/kit'

const myGenerator = defineGenerator({
  name: 'my-generator',
  operation(node, ctx) {
    return [
      ast.factory.createFile({
        baseName: `${node.operationId}.ts`,
        path: `./${node.operationId}.ts`,
        sources: [
          ast.factory.createSource({
            nodes: [ast.factory.createText(`export const op = '${node.operationId}'`)],
          }),
        ],
      }),
    ]
  },
})

Generator methods ​

MethodInputOutputWhen to use
schema()SchemaNode (per data schema)TElement | Array<FileNode> | voidGenerate types, validators, factories. Called once per schema
operation()OperationNode (per API operation)TElement | Array<FileNode> | voidGenerate hooks, clients, handlers. Called once per operation
operations()Array<OperationNode> (all operations)TElement | Array<FileNode> | voidGenerate index or barrel files. Called once after all operations

Scoping with match ​

Add a match(node, ctx) predicate to skip schema or operation for nodes a generator does not apply to. When match returns false, the engine skips that node entirely: no context work beyond what it already builds per node, and no call to schema/operation. Omitting match runs the generator for every node. match does not gate operations(), which already runs once on the full batch rather than per node.

This is useful when a plugin registers several generators for the same node type and only one should run per node, for example one hook generator per query variant in @kubb/plugin-react-query. Without match, every generator runs for every node and has to classify and bail out on its own.

scoped-generator.ts
typescript
import { ast, defineGenerator } from 'kubb/kit'

const getOnlyGenerator = defineGenerator({
  name: 'get-only-generator',
  match(node, ctx) {
    return node.kind === 'Operation' && ast.isHttpOperationNode(node) && node.method.toLowerCase() === 'get'
  },
  operation(node, ctx) {
    // node is already known to be a GET operation here
    return null
  },
})

GeneratorContext properties (the ctx argument passed to each method) ​

PropertyTypePurpose
ctx.configConfigResolved Kubb configuration
ctx.rootstringAbsolute path to the output directory for the current plugin
ctx.optionsTResolvedOptionsPer-node resolved options (after exclude/include/override filtering)
ctx.pluginPluginThe owning plugin descriptor
ctx.resolverResolverResolver for the current plugin
ctx.driverKubbDriverPlugin driver for cross-plugin access
ctx.hooksHookable<KubbHooks>Event bus for KubbHooks events
ctx.adapterAdapterThe adapter that parsed the input spec
ctx.metaInputMetaDocument metadata from the adapter. Carries title, version, baseURL, and the pre-computed circularNames and enumNames arrays.
ctx.cacheNodeCacheCache scoped to the node being generated, shared by every plugin generating from that node in the current pass. Exposes readItem, writeItem, and ensureItem
ctx.addFile()(...files: FileNode[]) => Promise<void>Add files, skipping any that already exist
ctx.upsertFile()(...files: FileNode[]) => Promise<void>Add or merge files (concatenates sources and imports)
ctx.getPlugin()(name: string) => Plugin | undefinedGet a plugin by name
ctx.requirePlugin()(name: string) => PluginGet a plugin by name or throw a descriptive error
ctx.getResolver()(name: string) => ResolverGet a resolver by plugin name
ctx.info()(message: string) => voidEmit an info message via the build event system
ctx.warn()(message: string) => voidEmit a warning via the build event system
ctx.error()(error: string | Error) => voidEmit an error via the build event system