





















@@ -8,7 +8,6 @@ import { resolveDiscordDirectoryUserId } from "./directory-cache.js";
8899type DiscordMentionAliasesConfig = Record<string, string>;
101011-const MARKDOWN_CODE_SEGMENT_PATTERN = /```[\s\S]*?```|`[^`\n]*`/g;
1211const MENTION_CANDIDATE_PATTERN = /(^|[\s([{"'.,;:!?])@([a-z0-9_.-]{2,32}(?:#[0-9]{4})?)/gi;
1312const DISCORD_RESERVED_MENTIONS = new Set(["everyone", "here"]);
1413const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/;
@@ -126,6 +125,72 @@ function rewritePlainTextMentions(
126125});
127126}
128127128+function countBacktickRun(text: string, index: number): number {
129+let cursor = index;
130+while (text[cursor] === "`") {
131+cursor += 1;
132+}
133+return cursor - index;
134+}
135+136+function findSameLineBacktickRun(
137+text: string,
138+startIndex: number,
139+runLength: number,
140+): number | null {
141+const delimiter = "`".repeat(runLength);
142+const newlineIndex = text.indexOf("\n", startIndex);
143+const lineEnd = newlineIndex === -1 ? text.length : newlineIndex;
144+const closeIndex = text.indexOf(delimiter, startIndex);
145+return closeIndex !== -1 && closeIndex < lineEnd ? closeIndex + runLength : null;
146+}
147+148+function findFenceEnd(text: string, startIndex: number, runLength: number): number {
149+let searchIndex = startIndex + runLength;
150+while (searchIndex < text.length) {
151+const newlineIndex = text.indexOf("\n", searchIndex);
152+if (newlineIndex === -1) {
153+return text.length;
154+}
155+let lineCursor = newlineIndex + 1;
156+while (text[lineCursor] === " " && lineCursor - newlineIndex <= 3) {
157+lineCursor += 1;
158+}
159+const closingRunLength = countBacktickRun(text, lineCursor);
160+if (closingRunLength >= runLength) {
161+return lineCursor + closingRunLength;
162+}
163+searchIndex = lineCursor + Math.max(closingRunLength, 1);
164+}
165+return text.length;
166+}
167+168+function findNextMarkdownCodeSegment(
169+text: string,
170+startIndex: number,
171+): { startIndex: number; endIndex: number } | null {
172+let searchIndex = startIndex;
173+while (searchIndex < text.length) {
174+const segmentStart = text.indexOf("`", searchIndex);
175+if (segmentStart === -1) {
176+return null;
177+}
178+const runLength = countBacktickRun(text, segmentStart);
179+const inlineEndIndex = findSameLineBacktickRun(text, segmentStart + runLength, runLength);
180+if (inlineEndIndex !== null) {
181+return { startIndex: segmentStart, endIndex: inlineEndIndex };
182+}
183+if (runLength >= 3) {
184+return {
185+startIndex: segmentStart,
186+endIndex: findFenceEnd(text, segmentStart, runLength),
187+};
188+}
189+searchIndex = segmentStart + runLength;
190+}
191+return null;
192+}
193+129194export function rewriteDiscordKnownMentions(
130195text: string,
131196params: {
@@ -138,12 +203,12 @@ export function rewriteDiscordKnownMentions(
138203}
139204let rewritten = "";
140205let offset = 0;
141-MARKDOWN_CODE_SEGMENT_PATTERN.lastIndex = 0;
142-for (const match of text.matchAll(MARKDOWN_CODE_SEGMENT_PATTERN)) {
143-const matchIndex = match.index ?? 0;
144-rewritten += rewritePlainTextMentions(text.slice(offset, matchIndex), params);
145-rewritten += match[0];
146-offset = matchIndex + match[0].length;
206+let segment = findNextMarkdownCodeSegment(text, offset);
207+while (segment) {
208+rewritten += rewritePlainTextMentions(text.slice(offset, segment.startIndex), params);
209+rewritten += text.slice(segment.startIndex, segment.endIndex);
210+offset = segment.endIndex;
211+segment = findNextMarkdownCodeSegment(text, offset);
147212}
148213rewritten += rewritePlainTextMentions(text.slice(offset), params);
149214return rewritten;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。