Parsers
This guide explains how to create custom parsers for BeDoc. Parsers read source files and extract documentation into a structured object that a formatter can render.
A parser is an action: a JavaScript file that
default-exports a class with a static meta block and a setup pipeline.
Parser structure
Section titled “Parser structure”A BeDoc parser has three parts:
- Meta — declares the language it reads and points at its contract. (required)
- Contract — an external Terms file describing the object the parser provides. (required)
- Pipeline — the steps that turn raw text into that object. (required)
Hooks are supported automatically at every named step. (optional, external)
Minimal parser
Section titled “Minimal parser”import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
export default class LuaParser { static meta = Object.freeze({ kind: "parser", input: "lua", // matched against --language lua terms: "ref://./bedoc-lua-parser.yaml", })
// `setup` configures the pipeline. Step names become hook anchor points. setup = builder => builder .do("Extract blocks", this.#extractBlocks) .do("Process functions", ACTIVITY.SPLIT, ctx => ctx, // splitter: hand each block onward ctx => ctx, // rejoiner: collect the results new ActionBuilder() .do("Extract signature", this.#extractSignature) .do("Extract description", this.#extractDescription) .do("Extract tags", this.#extractTags), ) .done(this.#finally)
// The first step receives the raw file content as `ctx`. #extractBlocks = ctx => { const blocks = [] for(const line of ctx.split(/\r?\n/)) { // …find doc blocks, push structured chunks… } return blocks }
#extractSignature = ctx => ctx #extractDescription = ctx => ctx #extractTags = ctx => ctx
// The final step returns the object promised by the contract. #finally = ctx => ({ functions: ctx })}The first pipeline step receives the file’s text as its context. Each step
returns the context passed to the next. The .done() step returns the
structured result — the shape your contract provides.
The contract
Section titled “The contract”A parser declares what it produces in an external Terms
file referenced by meta.terms (ref:// is resolved relative to the action
file). A parser’s contract uses provides::
# yaml-language-server: $schema=https://schema.gesslar.dev/bedoc/v1/bedoc-action.json$schema: https://schema.gesslar.dev/bedoc/v1/bedoc-action.jsonprovides: type: object required: - functions properties: functions: type: array items: type: object required: [name, signature] properties: name: { type: string } signature: type: object properties: name: { type: string } parameters: type: array items: { type: string } description: type: array items: { type: string }See the Contracts guide for the full structure.
Hook support
Section titled “Hook support”Every named pipeline step is a hook anchor. A user can wrap a step named
"Extract tags" with before$extractTags / after$extractTags handlers (the
hook name is the camelCase of the step name) to mutate the context as it flows
through. See the Hooks guide.
Example implementations
Section titled “Example implementations”Real parsers (LPC and Lua) live in the BeDoc repository under
examples/node_modules_test.
Best practices
Section titled “Best practices”- Keep steps small and named. Each named step is a hook point and a unit of testability.
- Honour your contract. The object you
.done()with must match what your Terms fileprovides:. - Use
ACTIVITY.SPLITfor per-item work (e.g. per-function) so it runs concurrently. - Reset state deliberately if your steps carry parsing state.
Testing your parser
Section titled “Testing your parser”Mock mode — point BeDoc at a directory of mock actions:
bedoc --mock ./mock_dir -l mylang -f markdown -i "test/*.ml" -o test/docsDirect file — use your parser file without packaging it:
bedoc --parser ./my-parser.js --format markdown -i "test/*.ml" -o test/docs# Or the short formbedoc -p ./my-parser.js -f markdown -i "test/*.ml" -o test/docsPublishing your parser
Section titled “Publishing your parser”Package your parser following BeDoc’s naming and structure conventions, and list
the action file(s) under bedoc.actions:
{ "name": "bedoc-mylang-parser", "version": "1.0.0", "type": "module", "description": "MyLang parser for BeDoc", "bedoc": { "actions": ["./bedoc-mylang-parser.js"] }}This lets BeDoc automatically discover and load your parser when it’s installed.
