Transformers

Folder: src/parsers/transformers/

Transformers convert custom HTML-like tags into semantic HTML. They run as part of the postprocessing stage.

Role in the Pipeline

┌─────────────────┐
│ POSTPROCESSORS  │
│                 │
│ • heading-ids   │
│ • external-links│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  TRANSFORMERS   │  ◀── YOU ARE HERE
│                 │
│ • callout       │
│ • tabs          │
│ • collapsible   │
│ (Custom tags)   │
└─────────────────┘

Key Insight

Transformers are postprocessors - the TagTransformerRegistry provides a createProcessor() method that wraps the transformer as a standard Processor for the pipeline.

Transformer Files

File Purpose
registry.ts TagTransformerRegistry class - manages custom tag transformers
index.ts Module exports (re-exports from custom-tags/)

How It Works

Transformers match custom HTML-like tags and replace them with semantic HTML:

<!-- Input (in markdown) -->
<callout type="warning">This is a warning</callout>

<!-- Output (after transformation) -->
<div class="callout callout--warning">This is a warning</div>

TagTransformerRegistry

The registry manages all custom tag transformers:

import { TagTransformerRegistry, createTransformerRegistry } from '@parsers/transformers';

const registry = new TagTransformerRegistry();

// Register a transformer
registry.register({
  tag: 'callout',
  transform(content, attrs) {
    const type = attrs.type || 'info';
    return `<div class="callout callout--${type}">${content}</div>`;
  }
});

// Check if registered
registry.has('callout');  // true

// Get all registered tags
registry.getTags();  // ['callout']

// Transform all tags in HTML
const html = registry.transformAll(inputHtml);

// Create a processor for the pipeline
const processor = registry.createProcessor();
pipeline.addPostprocessor(processor);

Available Transformers

Custom tags are defined in src/custom-tags/:

Transformer Tag Purpose
Callout <callout> Info boxes, warnings, tips
Tabs <tabs>, <tab> Tabbed content
Collapsible <collapsible> Expandable sections

Callout

<callout type="info">This is informational</callout>
<callout type="warning">This is a warning</callout>
<callout type="danger">This is dangerous</callout>
<callout type="tip">This is a tip</callout>

Tabs

<tabs>
  <tab label="JavaScript">
    JavaScript content here
  </tab>
  <tab label="Python">
    Python content here
  </tab>
</tabs>

Collapsible

<collapsible title="Click to expand">
  Hidden content here
</collapsible>

Creating Custom Transformers

Transformer Interface

interface TagTransformer {
  tag: string;
  transform: (content: string, attrs: Record<string, string>) => string;
}

Example: Badge Transformer

import { globalRegistry } from '@parsers/transformers';

globalRegistry.register({
  tag: 'badge',
  transform(content, attrs) {
    const color = attrs.color || 'blue';
    return `<span class="badge badge--${color}">${content}</span>`;
  }
});

// Usage in markdown:
// <badge color="green">New</badge>
// → <span class="badge badge--green">New</span>

Example: Alert Transformer

const alertTransformer: TagTransformer = {
  tag: 'alert',
  transform(content, attrs) {
    const type = attrs.type || 'info';
    const title = attrs.title || '';
    const titleHtml = title ? `<strong>${title}</strong>` : '';
    return `<div class="alert alert--${type}">${titleHtml}${content}</div>`;
  }
};

registry.register(alertTransformer);

// Usage:
// <alert type="warning" title="Attention">Be careful!</alert>

Self-Closing Tags

Transformers support both self-closing and content tags:

<!-- Self-closing -->
<divider />

<!-- With content -->
<callout>Some content</callout>

Attribute Parsing

The registry automatically parses HTML-style attributes:

<tag attr="value" flag standalone>content</tag>

Parsed as:

{
  attr: 'value',
  flag: 'true',
  standalone: 'true'
}

Global Registry

A global registry instance is available for convenience:

import { globalRegistry } from '@parsers/transformers';

// Register globally
globalRegistry.register(myTransformer);

// Use in pipeline
pipeline.addPostprocessor(globalRegistry.createProcessor());

Factory Functions

import {
  createCalloutTransformer,
  createTabsTransformer,
  createCollapsibleTransformer,
  createCustomTagsRegistry,
} from '@parsers/transformers';

// Create individual transformers
const callout = createCalloutTransformer({ defaultType: 'info' });

// Create a registry with all custom tags pre-registered
const registry = createCustomTagsRegistry();

// Get list of all custom tags
import { getAllCustomTags } from '@parsers/transformers';
const tags = getAllCustomTags();  // ['callout', 'tabs', 'tab', 'collapsible']