From b6db719758fe3e3cd167dcd2e290c5582a462b5f Mon Sep 17 00:00:00 2001 From: Algorithm5838 <108630393+Algorithm5838@users.noreply.github.com> Date: Sun, 12 Apr 2026 00:02:17 +0300 Subject: [PATCH] perf: build mention regex once in factory closure (#23551) --- src/lib/utils/marked/mention-extension.ts | 37 +++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/lib/utils/marked/mention-extension.ts b/src/lib/utils/marked/mention-extension.ts index 4e3865fd89..b56edfbee3 100644 --- a/src/lib/utils/marked/mention-extension.ts +++ b/src/lib/utils/marked/mention-extension.ts @@ -18,24 +18,6 @@ function mentionStart(src: string) { return src.indexOf('<'); } -function mentionTokenizer(this: any, src: string, options: MentionOptions = {}) { - const trigger = options.triggerChar ?? '@'; - // Build dynamic regex for `<@id>`, `<@id|label>`, `<@id|>` - // Added forward slash (/) to the character class for IDs - const re = new RegExp(`^<\\${trigger}([\\w.\\-:/]+)(?:\\|([^>]*))?>`); - const m = re.exec(src); - if (!m) return; - - const [, id, label] = m; - return { - type: 'mention', - raw: m[0], - triggerChar: trigger, - id, - label: label && label.length > 0 ? label : id - }; -} - function mentionRenderer(token: any, options: MentionOptions = {}) { const trigger = options.triggerChar ?? '@'; const cls = options.className ?? 'mention'; @@ -55,15 +37,30 @@ function mentionRenderer(token: any, options: MentionOptions = {}) { } export function mentionExtension(opts: MentionOptions = {}) { + // Compile the regex once when the extension is created, not on every tokenizer call. + // mentionStart fires on every '<' in the document, making the tokenizer a hot path. + const trigger = opts.triggerChar ?? '@'; + const re = new RegExp(`^<\\${trigger}([\\w.\\-:/]+)(?:\\|([^>]*))?>`); + const snapshot: MentionOptions = { triggerChar: trigger, className: opts.className, extraAttrs: opts.extraAttrs }; + return { name: 'mention', level: 'inline' as const, start: mentionStart, tokenizer(src: string) { - return mentionTokenizer.call(this, src, opts); + const m = re.exec(src); + if (!m) return; + const [, id, label] = m; + return { + type: 'mention', + raw: m[0], + triggerChar: trigger, + id, + label: label && label.length > 0 ? label : id + }; }, renderer(token: any) { - return mentionRenderer(token, opts); + return mentionRenderer(token, snapshot); } }; }