From c6932e195869fd8a3e8ffd0f644e314f19704fc9 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Sun, 9 Aug 2026 10:50:55 +0530 Subject: [PATCH 1/2] perf: optimize reference link masking --- src/Lexer.ts | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Lexer.ts b/src/Lexer.ts index 64cbe8101c..46380b50a7 100644 --- a/src/Lexer.ts +++ b/src/Lexer.ts @@ -1,7 +1,7 @@ import { _Tokenizer } from './Tokenizer.ts'; import { _defaults } from './defaults.ts'; import { other, block, inline } from './rules.ts'; -import type { Token, TokensList, Tokens } from './Tokens.ts'; +import type { Links, Token, TokensList, Tokens } from './Tokens.ts'; import type { MarkedOptions } from './MarkedOptions.ts'; /** @@ -19,7 +19,7 @@ export class _Lexer { public inlineQueue: { src: string, tokens: Token[] }[]; private tokenizer: _Tokenizer; - + private linksForInline: Links | null = null; constructor(options?: MarkedOptions) { // TokenList cannot be created in one go this.tokens = [] as unknown as TokensList; @@ -90,9 +90,16 @@ export class _Lexer { this.blockTokens(src, this.tokens); - for (let i = 0; i < this.inlineQueue.length; i++) { - const next = this.inlineQueue[i]; - this.inlineTokens(next.src, next.tokens); + if (Object.keys(this.tokens.links).length > 0) { + this.linksForInline = this.tokens.links; + } + try { + for (let i = 0; i < this.inlineQueue.length; i++) { + const next = this.inlineQueue[i]; + this.inlineTokens(next.src, next.tokens); + } + } finally { + this.linksForInline = null; } this.inlineQueue = []; @@ -307,12 +314,20 @@ export class _Lexer { // Mask out reflinks if (this.tokens.links) { - const links = Object.keys(this.tokens.links); - if (links.length > 0) { + const linksForInline = this.linksForInline; + if (linksForInline) { maskedSrc = maskedSrc.replace(this.tokenizer.rules.inline.reflinkSearch, match0 => - links.includes(match0.slice(match0.lastIndexOf('[') + 1, -1)) + Object.hasOwn(linksForInline, match0.slice(match0.lastIndexOf('[') + 1, -1)) ? '[' + 'a'.repeat(match0.length - 2) + ']' : match0); + } else { + const links = Object.keys(this.tokens.links); + if (links.length > 0) { + maskedSrc = maskedSrc.replace(this.tokenizer.rules.inline.reflinkSearch, match0 => + links.includes(match0.slice(match0.lastIndexOf('[') + 1, -1)) + ? '[' + 'a'.repeat(match0.length - 2) + ']' + : match0); + } } } From 171e3df610c9baba89bf61f4f848330a2f8bf969 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Mon, 10 Aug 2026 13:22:00 +0530 Subject: [PATCH 2/2] simplify reference link lookup --- src/Lexer.ts | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/src/Lexer.ts b/src/Lexer.ts index 46380b50a7..f33dc4926c 100644 --- a/src/Lexer.ts +++ b/src/Lexer.ts @@ -1,7 +1,7 @@ import { _Tokenizer } from './Tokenizer.ts'; import { _defaults } from './defaults.ts'; import { other, block, inline } from './rules.ts'; -import type { Links, Token, TokensList, Tokens } from './Tokens.ts'; +import type { Token, TokensList, Tokens } from './Tokens.ts'; import type { MarkedOptions } from './MarkedOptions.ts'; /** @@ -19,7 +19,7 @@ export class _Lexer { public inlineQueue: { src: string, tokens: Token[] }[]; private tokenizer: _Tokenizer; - private linksForInline: Links | null = null; + constructor(options?: MarkedOptions) { // TokenList cannot be created in one go this.tokens = [] as unknown as TokensList; @@ -90,16 +90,9 @@ export class _Lexer { this.blockTokens(src, this.tokens); - if (Object.keys(this.tokens.links).length > 0) { - this.linksForInline = this.tokens.links; - } - try { - for (let i = 0; i < this.inlineQueue.length; i++) { - const next = this.inlineQueue[i]; - this.inlineTokens(next.src, next.tokens); - } - } finally { - this.linksForInline = null; + for (let i = 0; i < this.inlineQueue.length; i++) { + const next = this.inlineQueue[i]; + this.inlineTokens(next.src, next.tokens); } this.inlineQueue = []; @@ -313,23 +306,10 @@ export class _Lexer { let maskedSrc = src; // Mask out reflinks - if (this.tokens.links) { - const linksForInline = this.linksForInline; - if (linksForInline) { - maskedSrc = maskedSrc.replace(this.tokenizer.rules.inline.reflinkSearch, match0 => - Object.hasOwn(linksForInline, match0.slice(match0.lastIndexOf('[') + 1, -1)) - ? '[' + 'a'.repeat(match0.length - 2) + ']' - : match0); - } else { - const links = Object.keys(this.tokens.links); - if (links.length > 0) { - maskedSrc = maskedSrc.replace(this.tokenizer.rules.inline.reflinkSearch, match0 => - links.includes(match0.slice(match0.lastIndexOf('[') + 1, -1)) - ? '[' + 'a'.repeat(match0.length - 2) + ']' - : match0); - } - } - } + maskedSrc = maskedSrc.replace(this.tokenizer.rules.inline.reflinkSearch, match0 => + Object.hasOwn(this.tokens.links, match0.slice(match0.lastIndexOf('[') + 1, -1)) + ? '[' + 'a'.repeat(match0.length - 2) + ']' + : match0); // Mask out escaped characters. // Every mask must keep the length it replaces: emStrong and del line