(content: string)
| 35 | return MD_SYNTAX_RE.test(s.length > 500 ? s.slice(0, 500) : s); |
| 36 | } |
| 37 | function cachedLexer(content: string): Token[] { |
| 38 | // Fast path: plain text with no markdown syntax → single paragraph token. |
| 39 | // Skips marked.lexer's full GFM parse (~3ms on long content). Not cached — |
| 40 | // reconstruction is a single object allocation, and caching would retain |
| 41 | // 4× content in raw/text fields plus the hash key for zero benefit. |
| 42 | if (!hasMarkdownSyntax(content)) { |
| 43 | return [{ |
| 44 | type: 'paragraph', |
| 45 | raw: content, |
| 46 | text: content, |
| 47 | tokens: [{ |
| 48 | type: 'text', |
| 49 | raw: content, |
| 50 | text: content |
| 51 | }] |
| 52 | } as Token]; |
| 53 | } |
| 54 | const key = hashContent(content); |
| 55 | const hit = tokenCache.get(key); |
| 56 | if (hit) { |
| 57 | // Promote to MRU — without this the eviction is FIFO (scrolling back to |
| 58 | // an early message evicts the very item you're looking at). |
| 59 | tokenCache.delete(key); |
| 60 | tokenCache.set(key, hit); |
| 61 | return hit; |
| 62 | } |
| 63 | const tokens = marked.lexer(content); |
| 64 | if (tokenCache.size >= TOKEN_CACHE_MAX) { |
| 65 | // LRU-ish: drop oldest. Map preserves insertion order. |
| 66 | const first = tokenCache.keys().next().value; |
| 67 | if (first !== undefined) tokenCache.delete(first); |
| 68 | } |
| 69 | tokenCache.set(key, tokens); |
| 70 | return tokens; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Renders markdown content using a hybrid approach: |
no test coverage detected