Skip to content

Plugin Interface

Every Generative DOM plugin implements the GenerativeDomPlugin interface. This page documents the complete interface, the context objects plugins receive, and the match result types plugins return.

Generative DOMPlugin

ts
interface GenerativeDomPlugin {
  /** Unique plugin name, used for debugging and event namespacing. */
  name: string;

  /**
   * Priority number. Lower values are matched first.
   *
   * Recommended ranges:
   * - 0-99: custom syntax (matched first)
   * - 100-199: block-level markdown (headings, code, lists, quotes, hr)
   * - 200-299: inline markdown (bold, italic, strikethrough, code)
   * - 300+: fallback (paragraphs, plain text)
   */
  priority: number;

  /**
   * Called once when the plugin is registered with GenerativeDom.
   * Receives the plugin context for emitting events, accessing the object pool, etc.
   */
  init?(ctx: PluginContext): void;

  /**
   * Block-level detection. Given the current buffer and position,
   * return a match result if this plugin can handle it, or null to pass.
   */
  matchBlock?(buffer: string, pos: number): BlockMatch | null;

  /**
   * Inline-level detection. Given text within a block and position,
   * return a match result if this plugin can handle it, or null to pass.
   */
  matchInline?(text: string, pos: number): InlineMatch | null;

  /**
   * Render a parsed token into a DOM node.
   * Must use DOM API only -- never innerHTML.
   * Should request elements from the object pool when possible.
   * Return null for event-only plugins that produce no DOM output.
   */
  render(token: Token, ctx: RenderContext): HTMLElement | Text | null;

  /**
   * Called when elements created by this plugin are being recycled.
   * Clean up event listeners, references, etc.
   */
  cleanup?(element: HTMLElement): void;

  /**
   * Called on GenerativeDom.destroy(). Release any plugin-level resources.
   */
  destroy?(): void;
}

PluginContext

Received once during init(). Provides access to the event system, object pool, global settings, and plugin registry.

ts
interface PluginContext {
  /** Emit an event to all GenerativeDom subscribers. Namespaced as "pluginName:eventName". */
  emit(event: string, data: unknown): void;

  /** Shared DOM element object pool. */
  pool: ObjectPool;

  /** Read-only global settings (width, height, version, debounceMs). */
  settings: Readonly<GlobalSettings>;

  /**
   * Look up another registered plugin by name.
   * Returns a read-only subset (name, priority) or undefined if not found.
   * Use for coordination -- never call methods on another plugin.
   */
  getPlugin(name: string): Readonly<Pick<GenerativeDomPlugin, 'name' | 'priority'>> | undefined;

  /** Register a cleanup callback to be invoked on GenerativeDom.destroy(). */
  onDestroy(callback: () => void): void;
}

RenderContext

Received on every render() call. Provides tools for DOM construction.

ts
interface RenderContext {
  /** Render inline markdown within a block, returning a DocumentFragment. */
  renderInline(text: string): DocumentFragment;

  /** Shared DOM element object pool. */
  pool: ObjectPool;

  /** Pool-aware element creation. Always use this instead of raw document.createElement. */
  createElement(tag: string): HTMLElement;

  /** Create a safe text node. Content is always escaped. */
  createText(content: string): Text;

  /** Read-only global settings. */
  settings: Readonly<GlobalSettings>;

  /**
   * Read-only reference to the container element.
   * For measurement only -- do not append to it directly.
   */
  container: Readonly<HTMLElement>;

  /** Emit events at render time. */
  emit(event: string, data: unknown): void;
}

Registration Rules

  1. Plugins are registered in the order provided to the constructor, then sorted by priority.
  2. Duplicate name values cause the constructor to throw immediately.
  3. A plugin without a render method causes the constructor to throw.
  4. Priority ties are resolved by registration order (first registered wins).
  5. Plugins can be added after construction via md.register(plugin).
  6. Plugins cannot be removed. Call destroy() and create a new instance instead.

Error Boundaries

The core wraps every plugin method call in try/catch. A broken plugin logs an error but never crashes the Generative DOM instance:

  • matchBlock / matchInline errors return null (skip the match)
  • render errors return a text node containing [render error]
  • cleanup / destroy errors are logged and execution continues