From 9ebc218394c3f510621ca8db40bbb7f72f979520 Mon Sep 17 00:00:00 2001 From: LukeParkerDev <10430890+Hona@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:09:31 +1000 Subject: [PATCH] fix(ui): preserve code spans adjacent to tildes --- bun.lock | 6 ++++-- package.json | 2 +- .../ui/src/context/marked-code-span.test.ts | 15 +++++++++++++++ packages/ui/src/context/marked-code-span.ts | 17 +++++++++++++++++ packages/ui/src/context/marked.tsx | 2 ++ 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 packages/ui/src/context/marked-code-span.test.ts create mode 100644 packages/ui/src/context/marked-code-span.ts diff --git a/bun.lock b/bun.lock index 6af38c1f784a..4651a27880f9 100644 --- a/bun.lock +++ b/bun.lock @@ -1129,7 +1129,7 @@ "hono": "4.10.7", "hono-openapi": "1.1.2", "luxon": "3.6.1", - "marked": "17.0.1", + "marked": "17.0.6", "marked-shiki": "1.2.1", "opentui-spinner": "0.0.7", "remeda": "2.26.0", @@ -4303,7 +4303,7 @@ "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], - "marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], + "marked": ["marked@17.0.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA=="], "marked-katex-extension": ["marked-katex-extension@5.1.6", "", { "peerDependencies": { "katex": ">=0.16 <0.17", "marked": ">=4 <18" } }, "sha512-vYpLXwmlIDKILIhJtiRTgdyZRn5sEYdFBuTmbpjD7lbCIzg0/DWyK3HXIntN3Tp8zV6hvOUgpZNLWRCgWVc24A=="], @@ -6025,6 +6025,8 @@ "@opentui/core/diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], + "@opentui/core/marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], + "@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], "@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="], diff --git a/package.json b/package.json index e5526b22ffb1..0eb7c5f77616 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "hono-openapi": "1.1.2", "fuzzysort": "3.1.0", "luxon": "3.6.1", - "marked": "17.0.1", + "marked": "17.0.6", "marked-shiki": "1.2.1", "remend": "1.3.0", "@playwright/test": "1.59.1", diff --git a/packages/ui/src/context/marked-code-span.test.ts b/packages/ui/src/context/marked-code-span.test.ts new file mode 100644 index 000000000000..5721f62b73d6 --- /dev/null +++ b/packages/ui/src/context/marked-code-span.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from "bun:test" +import { Marked } from "marked" +import { markedCodeSpanBoundary } from "./marked-code-span" + +test("preserves code spans adjacent to tildes", async () => { + const marked = new Marked(markedCodeSpanBoundary) + + expect(await marked.parse("~`0.1576` to measurement-window-only `0.00092`")).toBe( + "

~0.1576 to measurement-window-only 0.00092

\n", + ) + expect(await marked.parse("`before`~`after`")).toBe( + "

before~after

\n", + ) + expect(await marked.parse("~~`deleted code`~~")).toBe("

deleted code

\n") +}) diff --git a/packages/ui/src/context/marked-code-span.ts b/packages/ui/src/context/marked-code-span.ts new file mode 100644 index 000000000000..895935c3116d --- /dev/null +++ b/packages/ui/src/context/marked-code-span.ts @@ -0,0 +1,17 @@ +import type { MarkedExtension } from "marked" + +// Keep adjacent tilde and backtick runs separate until markedjs/marked#4011 is released. +export const markedCodeSpanBoundary = { + tokenizer: { + inlineText(src) { + const match = /^(`+(?=~)|~+(?=`))/.exec(src) + if (!match) return false + return { + type: "text", + raw: match[0], + text: match[0], + escaped: this.lexer.state.inRawBlock, + } + }, + }, +} satisfies MarkedExtension diff --git a/packages/ui/src/context/marked.tsx b/packages/ui/src/context/marked.tsx index a4f264ac6720..cead61ba6090 100644 --- a/packages/ui/src/context/marked.tsx +++ b/packages/ui/src/context/marked.tsx @@ -3,6 +3,7 @@ import markedShiki from "marked-shiki" import katex from "katex" import { bundledLanguages, type BundledLanguage } from "shiki" import { createSimpleContext } from "./helper" +import { markedCodeSpanBoundary } from "./marked-code-span" import { getSharedHighlighter, registerCustomTheme, ThemeRegistrationResolved } from "@pierre/diffs" export const OpenCodeTheme = { @@ -521,6 +522,7 @@ export const { use: useMarked, provider: MarkedProvider } = createSimpleContext( name: "Marked", init: (props: { nativeParser?: NativeMarkdownParser }) => { const jsParser = marked.use( + markedCodeSpanBoundary, { renderer: { link({ href, title, text }) {