feat(f7.1): render augmented mermaid diff in changed-block branch (#22)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { diffArrays, diffWords } from "diff";
|
||||
import { diffMermaid } from "./mermaidDiff";
|
||||
|
||||
export type BlockType = "prose" | "code" | "mermaid";
|
||||
|
||||
@@ -204,6 +205,24 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
||||
return defaultFence(tokens, idx, options, env, self);
|
||||
};
|
||||
|
||||
/** Inner source of a ```mermaid fence (drops the fence lines), or null. */
|
||||
function mermaidFenceBody(raw: string): string | null {
|
||||
const lines = raw.split(/\r?\n/);
|
||||
const open = lines[0]?.match(/^(\s*)(`{3,}|~{3,})\s*(\w+)?/);
|
||||
if (!open || open[3]?.toLowerCase() !== "mermaid") return null;
|
||||
const body = lines.slice(1);
|
||||
if (body.length && /^(\s*)(`{3,}|~{3,})/.test(body[body.length - 1])) body.pop();
|
||||
return body.join("\n");
|
||||
}
|
||||
|
||||
/** F7.1 (#22): legend shown beneath an intra-diagram-diffed mermaid block. */
|
||||
const MERMAID_LEGEND =
|
||||
'<div class="cw-mermaid-legend">' +
|
||||
'<span class="cw-leg cw-leg-add">added</span>' +
|
||||
'<span class="cw-leg cw-leg-chg">changed</span>' +
|
||||
'<span class="cw-leg cw-leg-rem">removed</span>' +
|
||||
"</div>";
|
||||
|
||||
/** Build a markdown string with inline <ins>/<del> from a word-level prose diff. */
|
||||
function wordMergedMarkdown(beforeRaw: string, afterRaw: string): string {
|
||||
return diffWords(beforeRaw, afterRaw)
|
||||
@@ -256,8 +275,19 @@ function renderOp(op: BlockOp, render: (src: string) => string): string {
|
||||
case "changed":
|
||||
cls = "cw-changed";
|
||||
if (op.atomic) {
|
||||
inner = safe(op.block.raw); // the NEW block, whole (INV-23)
|
||||
badge = '<span class="cw-badge">changed</span>';
|
||||
const curBody = op.block.type === "mermaid" ? mermaidFenceBody(op.block.raw) : null;
|
||||
const beforeBody = op.before.type === "mermaid" ? mermaidFenceBody(op.before.raw) : null;
|
||||
const md =
|
||||
curBody !== null && beforeBody !== null
|
||||
? diffMermaid(beforeBody, curBody)
|
||||
: { kind: "fallback" as const };
|
||||
if (md.kind === "augmented") {
|
||||
// Re-render the augmented diagram as a mermaid fence; add a legend, drop the badge (INV-29).
|
||||
inner = safe("```mermaid\n" + md.source + "\n```") + MERMAID_LEGEND;
|
||||
} else {
|
||||
inner = safe(op.block.raw); // the NEW block, whole (INV-23 / INV-30 fallback)
|
||||
badge = '<span class="cw-badge">changed</span>';
|
||||
}
|
||||
} else {
|
||||
inner = safe(wordMergedMarkdown(op.before.raw, op.block.raw));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user