@kubb/ast
Spec-agnostic AST layer for Kubb
Defines the node tree, visitor pattern, factory functions, and type guards used across every Kubb code generation plugin.
Imports
@kubb/ast | Runtime: node definitions, guards, visitor, macro engine, constants |
ast.factory (via @kubb/ast) | Node constructors (createSchema, createFile, and friends), the ts.factory analogue |
kubb/kit | Re-exports the ast and factory namespaces, the way most Kubb code reaches the AST without a direct dependency |
@kubb/ast is an internal library. Inside the Kubb ecosystem the whole surface travels on the ast namespace from kubb/kit, so plugins and generators reach it there instead of depending on this package directly. The examples below import from @kubb/ast for clarity; through kubb/kit the same calls read as ast.transform, ast.factory.createSchema, and so on.
Node tree
InputNode
├── schemas: SchemaNode[]
└── operations: OperationNode[]
├── parameters: ParameterNode[] → SchemaNode
├── requestBody?: SchemaNode
└── responses: ResponseNode[] → SchemaNode?
SchemaNode (discriminated union)
object → properties: PropertyNode[] → SchemaNode
array | tuple → items: SchemaNode[]
union | intersection → members: SchemaNode[]
enum | ref | string | number | integer | bigint
boolean | null | any | unknown | void
date | datetime | time | uuid | email | url | blob
Usage
Factory
Constructors are available as ast.factory from @kubb/ast, mirroring ts.factory.createX.
import { ast } from '@kubb/ast'
const { createInput, createSchema, createProperty } = ast.factory
const root = createInput({
schemas: [
createSchema({
name: 'Pet',
type: 'object',
properties: [
createProperty({
name: 'id',
schema: createSchema({ type: 'integer' }),
required: true,
}),
createProperty({
name: 'name',
schema: createSchema({ type: 'string' }),
required: true,
}),
],
}),
],
})
Visitor
import { collectSync, transform } from '@kubb/ast'
const updated = transform(root, {
schema(node) {
return { ...node, description: 'generated' }
},
})
const types = collectSync<string>(root, {
schema(node) {
return node.type
},
})
Guards
import { narrowSchema } from '@kubb/ast'
import type { Node } from '@kubb/ast'
function process(node: Node) {
if (node.kind === 'Schema') {
const obj = narrowSchema(node, 'object')
obj?.properties?.forEach((p) => console.log(p.name))
}
}
Refs
import { resolveRefName } from '@kubb/ast'
resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' })
Adding a node
Adding a node touches three files.
- Define the node type and its
createFoo function in its own src/nodes/*.ts file, and add the kind to NodeKind in src/nodes/base.ts.
- Add the type to the
Node union and re-export createFoo in src/nodes/index.ts, and export the type from src/types.ts.
- When the node has children or a visitor callback, add it to
VISITOR_KEYS and VISITOR_KEY_BY_KIND in src/visitor.ts.
Supporting Kubb
Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:
License
MIT