Skip to content

Commit a9c7d68

Browse files
committed
perf: build mention regex once in factory closure
1 parent 32934ec commit a9c7d68

1 file changed

Lines changed: 17 additions & 20 deletions

File tree

src/lib/utils/marked/mention-extension.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,6 @@ function mentionStart(src: string) {
1818
return src.indexOf('<');
1919
}
2020

21-
function mentionTokenizer(this: any, src: string, options: MentionOptions = {}) {
22-
const trigger = options.triggerChar ?? '@';
23-
// Build dynamic regex for `<@id>`, `<@id|label>`, `<@id|>`
24-
// Added forward slash (/) to the character class for IDs
25-
const re = new RegExp(`^<\\${trigger}([\\w.\\-:/]+)(?:\\|([^>]*))?>`);
26-
const m = re.exec(src);
27-
if (!m) return;
28-
29-
const [, id, label] = m;
30-
return {
31-
type: 'mention',
32-
raw: m[0],
33-
triggerChar: trigger,
34-
id,
35-
label: label && label.length > 0 ? label : id
36-
};
37-
}
38-
3921
function mentionRenderer(token: any, options: MentionOptions = {}) {
4022
const trigger = options.triggerChar ?? '@';
4123
const cls = options.className ?? 'mention';
@@ -55,15 +37,30 @@ function mentionRenderer(token: any, options: MentionOptions = {}) {
5537
}
5638

5739
export function mentionExtension(opts: MentionOptions = {}) {
40+
// Compile the regex once when the extension is created, not on every tokenizer call.
41+
// mentionStart fires on every '<' in the document, making the tokenizer a hot path.
42+
const trigger = opts.triggerChar ?? '@';
43+
const re = new RegExp(`^<\\${trigger}([\\w.\\-:/]+)(?:\\|([^>]*))?>`);
44+
const snapshot: MentionOptions = { triggerChar: trigger, className: opts.className, extraAttrs: opts.extraAttrs };
45+
5846
return {
5947
name: 'mention',
6048
level: 'inline' as const,
6149
start: mentionStart,
6250
tokenizer(src: string) {
63-
return mentionTokenizer.call(this, src, opts);
51+
const m = re.exec(src);
52+
if (!m) return;
53+
const [, id, label] = m;
54+
return {
55+
type: 'mention',
56+
raw: m[0],
57+
triggerChar: trigger,
58+
id,
59+
label: label && label.length > 0 ? label : id
60+
};
6461
},
6562
renderer(token: any) {
66-
return mentionRenderer(token, opts);
63+
return mentionRenderer(token, snapshot);
6764
}
6865
};
6966
}

0 commit comments

Comments
 (0)