fix(notes): show raw-text fallback when markdown render fails
All checks were successful
CI / verify (push) Successful in 1m2s
All checks were successful
CI / verify (push) Successful in 1m2s
A throwing markdown-it plugin propagated uncaught and left the note silently blank. Wrap the central render in try/catch and degrade to the note's escaped raw text with a gentle notice, so content stays readable.
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
|||||||
} from "@/utils/decodeBase64ToUTF8"
|
} from "@/utils/decodeBase64ToUTF8"
|
||||||
import { html5Media } from "@/utils/markdown/markdown-html5-media"
|
import { html5Media } from "@/utils/markdown/markdown-html5-media"
|
||||||
import { markdownItTablerIcons } from "@/utils/markdown/markdown-it-tabler-icons"
|
import { markdownItTablerIcons } from "@/utils/markdown/markdown-it-tabler-icons"
|
||||||
|
import { renderFallback } from "@/utils/markdown/renderFallback"
|
||||||
|
|
||||||
const TIKZ_BUNDLE_URL =
|
const TIKZ_BUNDLE_URL =
|
||||||
"https://cdn.jsdelivr.net/gh/artisticat1/obsidian-tikzjax@0.5.2/tikzjax.js"
|
"https://cdn.jsdelivr.net/gh/artisticat1/obsidian-tikzjax@0.5.2/tikzjax.js"
|
||||||
@@ -399,7 +400,14 @@ const renderMarkdown = (content: string, env?: Record<string, unknown>) => {
|
|||||||
// unhighlighted because nothing else invalidates the computed.
|
// unhighlighted because nothing else invalidates the computed.
|
||||||
if (content.includes("```")) void shikijiReady.value
|
if (content.includes("```")) void shikijiReady.value
|
||||||
slugger.reset()
|
slugger.reset()
|
||||||
return env ? md.render(content, env) : md.render(content)
|
try {
|
||||||
|
return env ? md.render(content, env) : md.render(content)
|
||||||
|
} catch (error) {
|
||||||
|
// Never let a plugin failure blank the note or dump a raw error —
|
||||||
|
// degrade to the note's raw text.
|
||||||
|
console.error("markdown render failed", error)
|
||||||
|
return renderFallback(content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const renderCodeFile = async ({
|
export const renderCodeFile = async ({
|
||||||
|
|||||||
26
src/utils/markdown/renderFallback.spec.ts
Normal file
26
src/utils/markdown/renderFallback.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
import { renderFallback } from "./renderFallback"
|
||||||
|
|
||||||
|
describe("renderFallback", () => {
|
||||||
|
it("shows the raw content inside a pre with a gentle notice", () => {
|
||||||
|
const html = renderFallback("# hello")
|
||||||
|
|
||||||
|
expect(html).toContain("note-render-fallback")
|
||||||
|
expect(html).toContain("couldn't be fully rendered")
|
||||||
|
expect(html).toContain("<pre># hello</pre>")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("escapes HTML so raw content can't inject markup into v-html", () => {
|
||||||
|
const html = renderFallback('<img src=x onerror="alert(1)"> & "q"')
|
||||||
|
|
||||||
|
expect(html).toContain(
|
||||||
|
"<img src=x onerror="alert(1)"> & "q""
|
||||||
|
)
|
||||||
|
expect(html).not.toContain("<img src=x")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("escapes ampersands before other entities", () => {
|
||||||
|
expect(renderFallback("<")).toContain("<pre>&lt;</pre>")
|
||||||
|
})
|
||||||
|
})
|
||||||
14
src/utils/markdown/renderFallback.ts
Normal file
14
src/utils/markdown/renderFallback.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
const escapeHtml = (value: string): string =>
|
||||||
|
value
|
||||||
|
.replaceAll("&", "&")
|
||||||
|
.replaceAll("<", "<")
|
||||||
|
.replaceAll(">", ">")
|
||||||
|
.replaceAll('"', """)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calm degradation for a note that failed to render: never a raw error dump
|
||||||
|
* or a silent blank — show the note's raw text (escaped) with a gentle notice,
|
||||||
|
* so the content is still readable.
|
||||||
|
*/
|
||||||
|
export const renderFallback = (content: string): string =>
|
||||||
|
`<div class="note-render-fallback"><p><em>This note couldn't be fully rendered — showing its raw text.</em></p><pre>${escapeHtml(content)}</pre></div>`
|
||||||
Reference in New Issue
Block a user