From 27b87033185c484d7f19da5c8b5cc0764f66ce45 Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Wed, 20 May 2026 00:46:00 +0000 Subject: [PATCH 1/3] [Performance] Optimize linesToColumns - Cache unstyled lengths to avoid redundant calls to `unstyled()` - Use a single pass to calculate widths and lengths - Add early return for empty input --- packages/cli-kit/src/public/common/string.ts | 25 +++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/cli-kit/src/public/common/string.ts b/packages/cli-kit/src/public/common/string.ts index 0e3e295df4d..a5eb847938a 100644 --- a/packages/cli-kit/src/public/common/string.ts +++ b/packages/cli-kit/src/public/common/string.ts @@ -251,16 +251,29 @@ export function tryParseInt(maybeInt: string | undefined): number | undefined { * @returns A string with the columns aligned. */ export function linesToColumns(lines: string[][]): string { + if (lines.length === 0 || !lines[0]) return '' + const widths: number[] = [] - for (let i = 0; lines[0] && i < lines[0].length; i++) { - const columnRows = lines.map((line) => line[i]!) - widths.push(Math.max(...columnRows.map((row) => unstyled(row).length))) + const unstyledLengths: number[][] = [] + + // Pre-calculate unstyled lengths and column widths in a single pass + for (let i = 0; i < lines.length; i++) { + const line = lines[i]! + unstyledLengths[i] = [] + for (let j = 0; j < line.length; j++) { + const cell = line[j]! + const length = unstyled(cell).length + unstyledLengths[i]![j] = length + widths[j] = Math.max(widths[j] ?? 0, length) + } } + const paddedLines = lines - .map((line) => { + .map((line, rowIndex) => { return line - .map((col, index) => { - return `${col}${' '.repeat(widths[index]! - unstyled(col).length)}` + .map((cell, colIndex) => { + const padding = ' '.repeat(widths[colIndex]! - unstyledLengths[rowIndex]![colIndex]!) + return `${cell}${padding}` }) .join(' ') .trimEnd() From e02d8fd04296432c6a57102d179e64f78a29b8e5 Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Wed, 20 May 2026 14:24:08 +0000 Subject: [PATCH 2/3] [Performance] Optimize linesToColumns - Cache unstyled lengths to avoid redundant calls to `unstyled()` - Use a single pass to calculate widths and lengths - Add early return for empty input --- .jules/bolt.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000000..8505a5a478d --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-05-20 - Optimize linesToColumns +**Learning:** Utilities that handle CLI output formatting, like `linesToColumns`, often call expensive regex-based helpers (e.g., `unstyled` for ANSI strip) multiple times for the same input. Caching these lengths in a single pass over the data significantly reduces overhead. +**Action:** Always check if string measurement utilities are called repeatedly in loops or nested maps, and use pre-calculation/caching to avoid redundant work. From 76564cdf1221a9103fbbfb99bf9546015f75c1bb Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Wed, 20 May 2026 14:59:54 +0000 Subject: [PATCH 3/3] [Performance] Optimize linesToColumns - Cache unstyled lengths to avoid redundant calls to `unstyled()` - Use a single pass to calculate widths and lengths - Add early return for empty input