Parsers
A parser turns a FileNode into the source string written to disk. This page documents defineParser, the Parser interface, the built-in parsers, and how to add your own. For why parsers exist and where they sit in the pipeline, see Parsers concepts.
TIP
For TypeScript and JavaScript output use the built-in @kubb/parser-ts. It is added by default when you import defineConfig from the kubb package. Build a custom parser only when you target a different language, such as Python, Kotlin, or Rust.
defineParser
defineParser creates a parser that converts generated file ASTs to formatted source strings. Each parser declares which file extensions it handles via extNames. A minimal parser registers its extensions and concatenates each source:
import { defineParser } from 'kubb/kit'
export const parserText = defineParser(() => ({
name: 'parser-text',
extNames: ['.txt'],
parse(file) {
return file.sources
.flatMap((source) => source.nodes ?? [])
.map((node) => (node.kind === 'Text' ? node.value : ''))
.join('\n')
},
print(...nodes) {
return nodes.map(String).join('\n')
},
}))Wire it into your config:
import { defineConfig } from 'kubb/config'
import { parserTs, parserTsx } from '@kubb/parser-ts'
import { parserText } from './parserText.ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [parserTs(), parserTsx(), parserText()],
})Parser anatomy
Every value returned from defineParser matches the Parser interface from kubb/kit:
| Property | Type | Required | When called | Purpose |
|---|---|---|---|---|
name | string | Yes | Unique parser identifier. Convention is parser-<id>. | |
extNames | Array<FileNode['extname']> | undefined | Yes | File extensions this parser handles. Set to undefined to register a catch-all fallback. | |
parse | (file: FileNode) => string | Yes | By the file processor after all plugins run | Serializes the file's staged sources into the final output string. Must return synchronously. |
print | (...nodes: TNode[]) => string | Yes | By plugins, before files are staged | Renders compiler AST nodes to source text. The node type is parser-specific, for example ts.Node for parserTs. |
IMPORTANT
If two parsers register the same extension, the last one in the parsers array wins. Order matters.
When no parser matches a file's extension, the file processor joins the file's source strings directly.
Parser naming convention
Parsers share the layout of plugins and adapters:
| Surface | Pattern | Example |
|---|---|---|
| npm package | @<scope>/parser-<name> or kubb-parser-<name> | @kubb/parser-ts |
| Parser runtime name | The output language or format (lowercase) | 'typescript', 'markdown' |
| Factory export | parser<Name> (camelCase) | parserTs, parserMd |
A parser is a factory function that returns a Parser object. Call it when you pass it to parsers: in defineConfig:
import { defineParser } from 'kubb/kit'
export const parserCustom = defineParser(() => ({
name: 'custom',
extNames: ['.custom'],
parse(file) {
return file.sources.map((source) => source.name ?? '').join('\n')
},
print(...nodes) {
return nodes.map(String).join('\n')
},
}))TIP
Parsers compose by extension. parserTs (.ts, .js) and parserTsx (.tsx, .jsx) ship in the same @kubb/parser-ts package and register side by side.
Creating a custom parser
defineParser wraps a factory function and infers the parser type, mirroring definePlugin: the factory receives the caller's options, and calling the result without options passes an empty object.
import { defineParser } from 'kubb/kit'
export const parserPython = defineParser(() => ({
name: 'parser-python',
extNames: ['.py', '.pyi'],
parse(file) {
const lines: Array<string> = []
if (file.banner) {
lines.push(file.banner)
}
for (const source of file.sources) {
for (const node of source.nodes ?? []) {
if (node.kind === 'Text') {
lines.push(node.value)
}
}
}
if (file.footer) {
lines.push(file.footer)
}
return lines.join('\n')
},
print(...nodes) {
return nodes.map(String).join('\n')
},
}))Register it alongside the built-ins:
import { defineConfig } from 'kubb/config'
import { parserTs } from '@kubb/parser-ts'
import { parserPython } from './parserPython.ts'
export default defineConfig({
input: './petStore.yaml',
output: { path: './src/gen' },
parsers: [parserTs(), parserPython()],
})TIP
Set extNames: undefined to register a catch-all fallback that runs when no other parser matches. Useful for a default .txt writer or for inspecting what files the build produces.