From f4e967bf220d6deba7cf63028def8b2f00bcc030 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Sat, 5 Sep 2026 14:16:17 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A9=B9=20fix:=20Restore=20the=20Client=20?= =?UTF-8?q?Build=20by=20Parsing=20Single-Dollar=20Math=20via=20Micromark?= =?UTF-8?q?=20(#15638)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `markdownToHtml` (#15087) imported `preprocessLaTeX` from `client/src/utils/latex.ts`, but #15181 replaced that preprocessing pass with the currency-safe `singleDollarMath` micromark construct and removed the function. The symbol exists nowhere in the repo, so `dev` fails `tsc --noEmit` with TS2305 and the Vite build with `[MISSING_EXPORT] "preprocessLaTeX" is not exported by "src/utils/latex.ts"`, which reds out the client typecheck, the build verification, and every job downstream of the client build on `dev` and on every open pull request. Register `singleDollarMath` in the extension list when `mode.latex` is set instead. That is exactly what the message renderers do — `markdownConfig.ts` adds `remarkSingleDollarMath` only when `latexParsing` is on, and that plugin does nothing but push `singleDollarMath` into `micromarkExtensions` — so clipboard HTML keeps mirroring the rendered message, which is the parity this helper is built around. `markdownToHtml` parses with `fromMarkdown` directly rather than through unified, so the extension array is the equivalent seam. Both specs already pinned the intended behavior and pass unchanged: `$E=mc^2$` becomes inline math under `latex: true`, `$5 to $10` stays currency. Their titles said "preprocesses", which no longer names a mechanism that exists; they now say "parses". --- client/src/utils/richtext.spec.ts | 4 ++-- client/src/utils/richtext.ts | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/client/src/utils/richtext.spec.ts b/client/src/utils/richtext.spec.ts index 7ca85bc184..4752094b1c 100644 --- a/client/src/utils/richtext.spec.ts +++ b/client/src/utils/richtext.spec.ts @@ -113,14 +113,14 @@ describe('markdownToHtml', () => { ); }); - it('renders single-dollar math when the renderer preprocesses LaTeX', () => { + it('renders single-dollar math when the renderer parses LaTeX', () => { expect(markdownToHtml('Energy is $E=mc^2$ inline.', { variant: 'full', latex: true })).toBe( '
Energy is E=mc^2 inline.
', ); expect(markdownToHtml('Energy is $E=mc^2$ inline.')).toBe('Energy is $E=mc^2$ inline.
'); }); - it('still leaves currency alone with LaTeX preprocessing on', () => { + it('still leaves currency alone with LaTeX parsing on', () => { expect(markdownToHtml('Costs rose from $5 to $10.', { variant: 'full', latex: true })).toBe( 'Costs rose from $5 to $10.
', ); diff --git a/client/src/utils/richtext.ts b/client/src/utils/richtext.ts index e54269740b..b4304cbd6e 100644 --- a/client/src/utils/richtext.ts +++ b/client/src/utils/richtext.ts @@ -20,7 +20,7 @@ import type { import type { Extension as MicromarkExtension } from 'micromark-util-types'; import { mcpUIResourcePlugin } from '~/components/MCPUIResource/plugin'; import { remarkApproxTilde } from './tilde'; -import { preprocessLaTeX } from './latex'; +import { singleDollarMath } from './latex'; /** * Which message renderer this copy has to match. `Markdown` (assistant turns) @@ -404,10 +404,11 @@ function serializeChildren(nodes: readonly SerializableNode[], context: Serializ * the clipboard as `text/html`. Paste targets that ignore Markdown (Teams, * Outlook, Word) strip stylesheets, so every visual cue has to be inline. * - * Parsing mirrors the message renderers: the same LaTeX preprocessing, the same - * micromark extensions with `singleDollarTextMath` off so currency such as - * `$5 to $10` stays currency, then the same `remarkApproxTilde` and - * `remark-supersub` transforms they apply to the parsed tree. + * Parsing mirrors the message renderers: the same currency-safe single-dollar + * math extension, the same `micromark-extension-math` with `singleDollarTextMath` + * off so currency such as `$5 to $10` stays currency, then the same + * `remarkApproxTilde` and `remark-supersub` transforms they apply to the parsed + * tree. */ export function markdownToHtml( markdown: string, @@ -417,10 +418,11 @@ export function markdownToHtml( if (mode.variant === 'full') { extensions.push(directive()); } + if (mode.latex) { + extensions.push(singleDollarMath); + } - const source = mode.latex ? preprocessLaTeX(markdown) : markdown; - - const tree = fromMarkdown(source, { + const tree = fromMarkdown(markdown, { extensions, mdastExtensions: [gfmFromMarkdown(), directiveFromMarkdown(), mathFromMarkdown()], });