fix(webapp): avoid mutating render inputs (#4716)

## Summary

Keeps render inputs and shared regular expressions immutable. Grouped
selects now compute each section's shortcut offset directly from
preceding sections, which also makes numeric shortcuts follow the
displayed item order reliably.
This commit is contained in:
Chris Arderne
2026-08-20 09:59:39 +01:00
committed by GitHub
parent 176fb6daf4
commit 7ea02716fc
3 changed files with 16 additions and 16 deletions
+10 -10
View File
@@ -221,35 +221,35 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
const [modalCopied, setModalCopied] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isWrapped, setIsWrapped] = useState(wrap);
const normalizedCode = code?.trim() ?? "";
const onCopied = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
event.stopPropagation();
navigator.clipboard.writeText(code);
navigator.clipboard.writeText(normalizedCode);
setCopied(true);
setTimeout(() => {
setCopied(false);
}, 1500);
},
[code]
[normalizedCode]
);
const onModalCopied = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
event.stopPropagation();
navigator.clipboard.writeText(code);
navigator.clipboard.writeText(normalizedCode);
setModalCopied(true);
setTimeout(() => {
setModalCopied(false);
}, 1500);
},
[code]
[normalizedCode]
);
code = code?.trim() ?? "";
const lineCount = code.split("\n").length;
const lineCount = normalizedCode.split("\n").length;
const maxLineWidth = lineCount.toString().length;
let maxHeight: string | undefined = undefined;
if (maxLines && lineCount > maxLines) {
@@ -345,7 +345,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
{shouldHighlight ? (
<HighlightCode
theme={theme}
code={code}
code={normalizedCode}
language={language}
showLineNumbers={showLineNumbers}
highlightLines={highlightLines}
@@ -373,7 +373,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
)}
dir="ltr"
>
{highlightSearchText(code, searchTerm)}
{highlightSearchText(normalizedCode, searchTerm)}
</pre>
</div>
)}
@@ -400,7 +400,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
{shouldHighlight ? (
<HighlightCode
theme={theme}
code={code}
code={normalizedCode}
language={language}
showLineNumbers={showLineNumbers}
highlightLines={highlightLines}
@@ -415,7 +415,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
className="overflow-auto px-3 py-3 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control"
>
<pre className="relative mr-2 p-2 font-mono text-base leading-relaxed" dir="ltr">
{highlightSearchText(code, searchTerm)}
{highlightSearchText(normalizedCode, searchTerm)}
</pre>
</div>
)}
@@ -187,7 +187,7 @@ export function ReportFindingLine({
* entities mono, verdict phrases bright and medium, everything else dimmed.
* Colour stays reserved for severity, so emphasis here is weight only.
*/
const QUANTITY_RE = /~?\d[\d,.]*\s?(?:%|×|\/min|ms\b|s\b|min\b|h\b)?/g;
const QUANTITY_RE = /~?\d[\d,.]*\s?(?:%|×|\/min|ms\b|s\b|min\b|h\b)?/;
const VERDICT_PHRASES = [
"not your code",
@@ -249,7 +249,6 @@ export function ReportProse({ text, entities }: { text: string; entities?: strin
segments = splitBy(
segments,
(t) => {
QUANTITY_RE.lastIndex = 0;
const m = QUANTITY_RE.exec(t);
return m && m[0].trim().length > 0 ? { start: m.index, end: m.index + m[0].length } : null;
},
@@ -413,19 +413,20 @@ function SelectGroupedRenderer<TItem>({
) => React.ReactNode;
enableItemShortcuts: boolean;
}) {
let count = 0;
return (
<>
{items.map((section, index) => {
const previousItem = items.at(index - 1);
count += previousItem ? previousItem.items.length : 0;
const startIndex = items
.slice(0, index)
.reduce((count, previousSection) => count + previousSection.items.length, 0);
return (
<Fragment key={index}>
{children(section.items as ItemFromSection<TItem>[], {
shortcutsEnabled: enableItemShortcuts,
section: {
title: section.title,
startIndex: count - 1,
startIndex,
count: section.items.length,
},
})}