diff --git a/renderer/app.js b/renderer/app.js index 5ae6cbc..272cd2e 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -3819,14 +3819,21 @@ function setupColumnResizing() { }); } +// Single-pass escape instead of 4 chained .replace(/x/g, ...) calls. +// Hot path on large table rebuilds — every text cell runs through one of these. +const _HTML_ESC_MAP = { '&': '&', '<': '<', '>': '>', '"': '"' }; +const _HTML_ESC_RE = /[&<>"]/g; +const _ATTR_ESC_MAP = { '&': '&', '"': '"', "'": ''' }; +const _ATTR_ESC_RE = /[&"']/g; + function escapeHtml(str) { if (!str) return ''; - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + return String(str).replace(_HTML_ESC_RE, (c) => _HTML_ESC_MAP[c]); } function escapeAttr(str) { if (!str) return ''; - return String(str).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, '''); + return String(str).replace(_ATTR_ESC_RE, (c) => _ATTR_ESC_MAP[c]); } function showCopyToast(msg) {