@generative-dom/core
v0.1.0
Published
Generative DOM streaming markdown parser — core engine
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 |
