From d6f8217db9433de0d3aca1d64a81455d08dba47b Mon Sep 17 00:00:00 2001 From: Okiki Ojo Date: Sat, 21 Feb 2026 01:29:35 -0500 Subject: [PATCH] fix(cache): limit regex cache size to prevent unbounded growth Bounded the regex cache at 128 entries to avoid excessive memory usage from adversarially varied indent widths. This change improves performance by reusing compiled regex patterns for common indent widths. Signed-off-by: Okiki Ojo --- mod.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mod.ts b/mod.ts index bd5a35d..7185382 100644 --- a/mod.ts +++ b/mod.ts @@ -1044,7 +1044,13 @@ const TRAILING_ALL = /(?:(?:\r\n|\r|\n)[ \t]*)+$/; * Why: compiling `new RegExp(...)` on every `.string()`/tag call adds * avoidable overhead on hot paths. The pattern is deterministic for a * given indent width, so we compile once and reuse. + * + * Bounded at 128 entries. Real-world indent widths cluster around 2–8, + * so the cap is rarely reached. Without a bound, adversarially varied + * indent widths (e.g. server-rendered user-supplied code blocks) could + * grow the cache without limit. */ +const STRIP_REGEX_CACHE_MAX = 128; const STRIP_REGEX_CACHE = new Map(); /** @@ -1060,6 +1066,10 @@ function getStripIndentRegex(indentCount: number): RegExp { let re = STRIP_REGEX_CACHE.get(indentCount); if (!re) { re = new RegExp(`(\\r\\n|\\r|\\n)[ \\t]{0,${indentCount}}`, "g"); + if (STRIP_REGEX_CACHE.size >= STRIP_REGEX_CACHE_MAX) { + const oldest = STRIP_REGEX_CACHE.keys().next().value; + if (oldest !== undefined) STRIP_REGEX_CACHE.delete(oldest); + } STRIP_REGEX_CACHE.set(indentCount, re); } return re; -- 2.51.2