@veridtools/dmn-diff-highlight
v0.1.1
Published
Syntax highlighting for @veridtools/dmn-diff output — React and vanilla JS
Maintainers
Readme
@veridtools/dmn-diff-highlight
Syntax highlighting for @veridtools/dmn-diff output. Takes rendered diff text in any of the four formats — semantic, rows, JSON, XML — and returns HTML with semantic CSS classes. Ships a vanilla JS API and a React component.
React 17+ · MIT licensed · 1 runtime dependency (@veridtools/dmn-diff)
Why
@veridtools/dmn-diff produces structured, human-readable output, but it's plain text. Embedding it in a UI — a PR comment renderer, a review tool, a live diff playground — means copy-pasting raw strings into a <pre> and losing all visual structure.
dmn-diff-highlight solves this by turning any diff output into annotated HTML. Each meaningful token gets a semantic CSS class: breaking changes are dmn-dh-field-breaking, added elements are dmn-dh-added, field names are dmn-dh-fname. You control the colour; the library controls the structure.
It works on all four output formats and is format-faithful: rows input produces rows HTML, JSON input produces syntax-highlighted JSON, XML input produces line-diff HTML. No format conversion happens behind the scenes.
At a glance
- Four input formats — semantic, rows, JSON, XML; format auto-detected by default
- Format-faithful output — rows → rows HTML, JSON → syntax-highlighted JSON, XML → XML diff HTML
- Semantic CSS classes — every token gets a
dmn-dh-*class; you own the styles - React component —
<DiffHighlight>with memoized rendering - Default theme — Catppuccin-inspired dark/light theme via CSS custom properties
- Zero DOM dependency — vanilla API returns plain strings; works in Node, browsers, and SSR
Installation
pnpm add @veridtools/dmn-diff-highlight @veridtools/dmn-diff
# or
npm install @veridtools/dmn-diff-highlight @veridtools/dmn-diffQuick start — React
import { diff } from '@veridtools/dmn-diff';
import { DiffHighlight } from '@veridtools/dmn-diff-highlight/react';
import '@veridtools/dmn-diff-highlight/style.css';
const result = diff(fromXml, toXml, { fromFile: 'before.dmn', toFile: 'after.dmn' });
function MyApp() {
return <DiffHighlight result={result} />;
}Quick start — vanilla JS
import { highlightDiff, mountDiff } from '@veridtools/dmn-diff-highlight';
import '@veridtools/dmn-diff-highlight/style.css';
// From any diff text — format is auto-detected
const html = highlightDiff(diffText);
document.getElementById('output')!.innerHTML = html;
// Or use mountDiff as a shortcut
mountDiff(document.getElementById('output')!, diffText);Programmatic API
import { diff, renderRows, renderJson } from '@veridtools/dmn-diff';
import { highlightDiff, highlightResult } from '@veridtools/dmn-diff-highlight';
const result = diff(fromXml, toXml, { fromFile: 'before.dmn', toFile: 'after.dmn' });
// From a DiffResult — always renders as semantic HTML
const html = highlightResult(result);
// From any rendered text — format auto-detected
const rowsHtml = highlightDiff(renderRows(result));
const jsonHtml = highlightDiff(renderJson(result));
// Explicit format override
const xmlHtml = highlightDiff(xmlDiffText, { format: 'xml' });
// Custom CSS class on the root <pre>
const themed = highlightDiff(diffText, { className: 'dark-theme' });API reference — vanilla JS
| Function | Signature | Description |
|----------|-----------|-------------|
| highlightDiff | (text, options?) → string | Highlight raw diff text → HTML string |
| highlightResult | (result, options?) → string | Render a DiffResult as semantic HTML |
| mountDiff | (element, text, options?) → void | Set element.innerHTML directly |
| detectFormat | (text) → DiffFormat | Auto-detect format (re-exported from @veridtools/dmn-diff) |
API reference — React
import { DiffHighlight } from '@veridtools/dmn-diff-highlight/react';
// From text — format auto-detected
<DiffHighlight text={diffText} />
// Explicit format
<DiffHighlight text={rowsText} format="rows" />
<DiffHighlight text={xmlText} format="xml" />
// From DiffResult — always semantic
<DiffHighlight result={result} />
// Custom class
<DiffHighlight text={diffText} className="my-theme" />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| text | string | — | Raw diff text. Either text or result required. |
| result | DiffResult | — | Result from diff(). Either text or result required. |
| format | DiffFormat \| 'auto' | 'auto' | Format override for text prop. Ignored when result is provided. |
| className | string | — | Additional CSS class on the root <pre>. |
CSS theme
Import the default Catppuccin-inspired dark/light theme:
import '@veridtools/dmn-diff-highlight/style.css';Customize via CSS custom properties on .dmn-dh or a scoped class:
.dmn-dh {
--dmn-dh-bg: #0d1117;
--dmn-dh-fg: #e6edf3;
--dmn-dh-added: #3fb950;
--dmn-dh-removed: #f85149;
--dmn-dh-modified: #d2a8ff;
--dmn-dh-field-breaking: #f85149;
--dmn-dh-field-change: #ffa657;
--dmn-dh-arrow: #79c0ff;
/* ... any of the --dmn-dh-* properties */
}Format examples
All four formats produced by @veridtools/dmn-diff are supported:
Semantic (renderSemantic output):
before.dmn → after.dmn
⚠ 1 breaking change(s) detected
~ decision "Loan Approval" (approval) modified
@name: Loan Approval → Loan Approval Decision ⚠ BREAKINGRows (renderRows output):
- [decision] approval @name: Loan Approval [BREAKING]
+ [decision] approval @name: Loan Approval Decision [BREAKING]JSON (renderJson output):
{
"meta": { "hasChanges": true },
"changes": [{ "type": "modified", "elementType": "decision", ... }]
}XML (renderXml output):
<?xml version="1.0" encoding="UTF-8"?>
- <decision id="approval" name="Loan Approval">
+ <decision id="approval" name="Loan Approval Decision">
<decisionTable id="dt1" hitPolicy="UNIQUE">CSS class reference
Line-level
| Class | Meaning |
|-------|---------|
| dmn-dh-header | File header line (before.dmn → after.dmn) |
| dmn-dh-warn-header | Breaking change warning (⚠ 1 breaking change...) |
| dmn-dh-added | Added element or row |
| dmn-dh-removed | Removed element or row |
| dmn-dh-modified | Modified element header |
| dmn-dh-field-change | Non-breaking field change |
| dmn-dh-field-breaking | Breaking field change |
| dmn-dh-field-cosmetic | Cosmetic field change |
| dmn-dh-summary | Summary count line |
| dmn-dh-context | XML context line (unchanged) |
| dmn-dh-no-changes | No differences line |
Inline tokens
| Class | Meaning |
|-------|---------|
| dmn-dh-arrow | → arrow |
| dmn-dh-sigil | +, -, ~ prefix |
| dmn-dh-etype | Element type |
| dmn-dh-ename | Quoted element name |
| dmn-dh-eid | Element ID |
| dmn-dh-fname | Field name |
| dmn-dh-fval-from | Old field value |
| dmn-dh-fval-to | New field value |
| dmn-dh-warn | ⚠ warning symbol |
| dmn-dh-tag | [BREAKING] / (cosmetic) badge |
| dmn-dh-jkey | JSON key |
| dmn-dh-jstring | JSON string value |
| dmn-dh-jnumber | JSON number |
| dmn-dh-jbool | JSON true / false |
| dmn-dh-jnull | JSON null |
| dmn-dh-jpunct | JSON punctuation |
Contributing
See CONTRIBUTING.md.
License
MIT © 2026 Veridtools (Victor Martins Bicudo)
