@generative-dom/core
v0.4.0
Published
Generative DOM streaming markdown parser — core engine
Downloads
27
Maintainers
Readme
@generative-dom/core
Core engine for Generative DOM. Contains the streaming pipeline, plugin system, and all public types.
Installation
npm install @generative-dom/coreBasic Usage
import { GenerativeDom, injectGenerativeDomStyles } from "@generative-dom/core";
import { markdownHeading } from "@generative-dom/plugin-markdown-heading";
import { markdownBase } from "@generative-dom/plugin-markdown-base";
// Inject default styles once
injectGenerativeDomStyles();
const md = new GenerativeDom({
container: document.getElementById("output")!,
plugins: [markdownHeading(), markdownBase()],
debounceMs: 16,
});
md.push("# Hello\n\nStreaming paragraph text.");
md.end();
// Subscribe to events emitted by plugins
md.on("button-click", (payload) => console.log(payload));Pipeline
push(chunk) --> Buffer --> Tokenizer --> Parser --> Differ --> Renderer --> DOM
| |
| Scheduler (rAF + debounce) |
+--------------------------------------------------+Each stage is a pure function. The GenerativeDom class wires them together and drives the scheduler.
Key Types
GenerativeDom— main class; callpush(chunk),end(),reset(),destroy()GenerativeDomPlugin— plugin interface:matchBlock,matchInline,render,cleanup,finalizeToken— parsed token carryingtype,plugin,raw,status, and optionalchildrenBufferView— zero-copy view over the unconsumed buffer, passed tomatchBlockRenderContext— DOM construction context passed torender; usectx.createElement(), notdocumentDOMFactory— injectable abstraction overcreateElement/createTextNodeTimingProvider— injectable abstraction overrequestAnimationFrame/performance.nowGenerativeDomOptions— constructor options (see Configuration below)
Writing a Plugin
import type {
GenerativeDomPlugin,
BufferView,
Token,
RenderContext,
} from "@generative-dom/core";
export function myBlockPlugin(): GenerativeDomPlugin {
return {
name: "my-block",
priority: 150,
level: "block",
matchDescriptor: { startChars: ">", requiresSOL: true },
matchBlock(view: BufferView, isFinal?: boolean) {
const m = view.match(/^>[ \t]?(.*?)(\n|$)/);
if (!m) return null;
return {
type: "my-block",
raw: m[0],
consumed: m[0].length,
children: m[1],
};
},
render(token: Token, ctx: RenderContext) {
const el = ctx.createElement("section");
if (token.children?.length) {
ctx.renderInline(token.children, el);
}
return el;
},
};
}Key rules:
- Return
{ status: 'partial' }frommatchBlockwhen the buffer looks promising but needs more data. - Use
ctx.createElementandctx.createTextNode— neverdocumentdirectly. - Set
allowedChildren: []to disable inline parsing inside a block (e.g., code fences). - Declare
matchDescriptor.startCharsfor O(1) fast-reject before regex evaluation.
Configuration
GenerativeDomOptions fields:
| Field | Type | Default | Description |
| ---------------- | --------------------------------- | --------------- | -------------------------------------------------- |
| plugins | GenerativeDomPlugin[] | [] | Initial plugin list |
| debounceMs | number | 16 | Minimum ms between render cycles |
| highWaterMark | number | 65536 | Advisory backpressure threshold (bytes) |
| domFactory | DOMFactory | document | Override for SSR or test environments |
| timingProvider | TimingProvider | browser globals | Override for deterministic tests |
| onError | (e: GenerativeDomError) => void | console.error | Structured error reporting callback |
| width | number \| 'auto' | — | Container width override |
| height | number \| 'auto' | — | Container height override |
| debug | boolean | false | Enable getReceivedText() / getReceivedChunks() |
| log | LogConfig | — | Structured pipeline logging (see below) |
| maxLiveTokens | number | 256 | Bound on internal diff window |
Structured logging
Every pipeline phase emits typed events so you can see why a particular
matcher won, when a token was created, and how the renderer mutated the
DOM. With no log config, the logger is a NoopLogger and incurs zero
overhead.
import {
BufferLogger,
filterByPlugin,
summarizeEvents,
} from "@generative-dom/core";
const md = new GenerativeDom({
container: document.getElementById("output")!,
plugins: [markdownHeading(), markdownBase()],
log: {
level: "debug",
sink: "buffer", // collect events for later inspection
plugins: ["markdown-heading"], // optional: filter by plugin
},
});
md.push("## Title\n\nBody text.");
md.flush();
const headingEvents = filterByPlugin(md.getLogs(), "markdown-heading");
console.log(summarizeEvents(headingEvents));Four loggers are available: NoopLogger (default), ConsoleLogger
(color-coded terminal output), BufferLogger (getLogs()/clearLogs()),
and CallbackLogger (forward to your own sink). See the
Logging guide
for the full event taxonomy, configuration reference, and recipes.
