From e8905ff7406167203df0328cfbc0e29145d35442 Mon Sep 17 00:00:00 2001 From: Alexander Gavryushenko Date: Mon, 14 Jul 2025 16:50:53 +0300 Subject: [PATCH] Performance of calculateCellHeights --- src/calculateCellHeight.ts | 29 +++++++++++++++++++++++++---- test/calculateRowHeights.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/calculateCellHeight.ts b/src/calculateCellHeight.ts index d55ed0a..5451092 100644 --- a/src/calculateCellHeight.ts +++ b/src/calculateCellHeight.ts @@ -1,10 +1,31 @@ -import { - wrapCell, -} from './wrapCell'; +import stripAnsi from "strip-ansi"; /** * Calculates height of cell content in regard to its width and word wrapping. */ export const calculateCellHeight = (value: string, columnWidth: number, useWrapWord = false): number => { - return wrapCell(value, columnWidth, useWrapWord).length; + if (value.length === 0) { + return 1; + } + const strippedValue = stripAnsi(value); + const size = Math.max(1, columnWidth); + + const pattern = useWrapWord ? + new RegExp(`(.{0,${size - 1}}(?:(?:.\\s|[\\\\\\/_\\.,;-]|.$))|.{0,${size}}\\s?)`, 'g') : + new RegExp(`(.{0,${size}}\\s*)`, 'g'); + + let count = 0; + let match; + + while ((match = pattern.exec(strippedValue)) !== null) { + if (match[0] || match.index === strippedValue.length && strippedValue.endsWith('\n')) { + count++; + } + + if (match.index === pattern.lastIndex) { + pattern.lastIndex++; + } + } + + return count || 1; }; diff --git a/test/calculateRowHeights.ts b/test/calculateRowHeights.ts index 3fd15d1..b31bdf6 100644 --- a/test/calculateRowHeights.ts +++ b/test/calculateRowHeights.ts @@ -1,5 +1,8 @@ /* eslint-disable max-nested-callbacks */ +import { + performance, +} from 'perf_hooks'; import { expect, } from 'chai'; @@ -72,4 +75,30 @@ describe('calculateRowHeights', () => { }); }); }); + context('performance', () => { + it('processes 1000 rows with 100 newlines each in under 100 ms', () => { + const data = Array.from({length: 1_000}, () => { + return ['!', '?\n'.repeat(100)]; + }); + + const config = makeTableConfig(data, { + columns: { + 0: { + width: 10, + wrapWord: false, + }, + }, + }); + + const startTime = performance.now(); + const rowHeights = calculateRowHeights(data, config); + const endTime = performance.now(); + + const executionTime = endTime - startTime; + + expect(executionTime).to.be.lessThan(50); + expect(rowHeights).to.have.length(1_000); + expect(rowHeights[0]).to.equal(101); + }); + }); });