From 2c06c8dcc2ed46ed5812e2e89b42287c69322923 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Thu, 30 Apr 2026 06:06:36 +0200 Subject: [PATCH] fix: disable unsafe shiki highlighting on old webkit --- src/components/codeBlockOptions.ts | 24 +++++++++++ src/components/editorSchema.tsx | 13 +++--- src/components/editorSchema.webkit.test.ts | 49 ++++++++++++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/components/codeBlockOptions.ts create mode 100644 src/components/editorSchema.webkit.test.ts diff --git a/src/components/codeBlockOptions.ts b/src/components/codeBlockOptions.ts new file mode 100644 index 00000000..e1ad56d1 --- /dev/null +++ b/src/components/codeBlockOptions.ts @@ -0,0 +1,24 @@ +import { codeBlockOptions } from '@blocknote/code-block' +import type { CodeBlockOptions } from '@blocknote/core' + +function supportsShikiPrecompiledRegexFlags() { + try { + new RegExp('', 'd') + new RegExp('[[]]', 'v') + return true + } catch { + return false + } +} + +export function createTolariaCodeBlockOptions(): Partial { + const options: Partial = { + ...codeBlockOptions, + defaultLanguage: 'text', + } + + if (supportsShikiPrecompiledRegexFlags()) return options + + delete options.createHighlighter + return options +} diff --git a/src/components/editorSchema.tsx b/src/components/editorSchema.tsx index 1b357f65..a6cef1cf 100644 --- a/src/components/editorSchema.tsx +++ b/src/components/editorSchema.tsx @@ -1,12 +1,16 @@ /* eslint-disable react-refresh/only-export-components -- module-level schema, not a component file */ -import { createCodeBlockSpec, BlockNoteSchema, defaultInlineContentSpecs } from '@blocknote/core' -import { codeBlockOptions } from '@blocknote/code-block' +import { + createCodeBlockSpec, + BlockNoteSchema, + defaultInlineContentSpecs, +} from '@blocknote/core' import { createReactBlockSpec, createReactInlineContentSpec } from '@blocknote/react' import { resolveWikilinkColor as resolveColor } from '../utils/wikilinkColors' import { resolveEntry } from '../utils/wikilink' import { MATH_BLOCK_TYPE, MATH_INLINE_TYPE, renderMathToHtml } from '../utils/mathMarkdown' import { MERMAID_BLOCK_TYPE, mermaidFenceSource } from '../utils/mermaidMarkdown' import type { VaultEntry } from '../types' +import { createTolariaCodeBlockOptions } from './codeBlockOptions' import { NoteTitleIcon } from './NoteTitleIcon' import { MermaidDiagram } from './MermaidDiagram' @@ -153,10 +157,7 @@ const MermaidBlock = createReactBlockSpec( }, ) -const codeBlock = createCodeBlockSpec({ - ...codeBlockOptions, - defaultLanguage: 'text', -}) +const codeBlock = createCodeBlockSpec(createTolariaCodeBlockOptions()) const mathBlock = MathBlock() const mermaidBlock = MermaidBlock() diff --git a/src/components/editorSchema.webkit.test.ts b/src/components/editorSchema.webkit.test.ts new file mode 100644 index 00000000..73a07396 --- /dev/null +++ b/src/components/editorSchema.webkit.test.ts @@ -0,0 +1,49 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' + +const nativeRegExpDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'RegExp') +const NativeRegExp = RegExp + +function setRegExpConstructor(value: RegExpConstructor) { + Object.defineProperty(globalThis, 'RegExp', { + configurable: true, + writable: true, + value, + }) +} + +function restoreRegExpConstructor() { + if (nativeRegExpDescriptor) { + Object.defineProperty(globalThis, 'RegExp', nativeRegExpDescriptor) + } +} + +function installLegacyWebKitRegExp() { + const LegacyWebKitRegExp = function (pattern?: string | RegExp, flags?: string) { + if (flags?.includes('d') || flags?.includes('v')) { + throw new SyntaxError('Invalid flags supplied to RegExp constructor') + } + + return new NativeRegExp(pattern, flags) + } as RegExpConstructor + + Object.setPrototypeOf(LegacyWebKitRegExp, NativeRegExp) + LegacyWebKitRegExp.prototype = NativeRegExp.prototype + + setRegExpConstructor(LegacyWebKitRegExp) +} + +afterEach(() => { + restoreRegExpConstructor() + vi.resetModules() +}) + +describe('editor schema code block highlighting', () => { + it('omits the Shiki highlighter when WebKit lacks precompiled regex flags', async () => { + installLegacyWebKitRegExp() + vi.resetModules() + + const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions') + + expect(createTolariaCodeBlockOptions()).not.toHaveProperty('createHighlighter') + }) +})