diff --git a/packages/utils/src/colors.ts b/packages/utils/src/colors.ts index be258195c2e3..f486002473bc 100644 --- a/packages/utils/src/colors.ts +++ b/packages/utils/src/colors.ts @@ -74,10 +74,14 @@ export function createColors(isTTY = false): Colors { || 'CI' in process.env) const replaceClose = (string: string, close: string, replace: string, index: number): string => { - const start = string.substring(0, index) + replace - const end = string.substring(index + close.length) - const nextIndex = end.indexOf(close) - return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end + let result = '' + let cursor = 0 + do { + result += string.substring(cursor, index) + replace + cursor = index + close.length + index = string.indexOf(close, cursor) + } while (~index) + return result + string.substring(cursor) } const formatter = (open: string, close: string, replace = open) => { diff --git a/test/core/test/utils.spec.ts b/test/core/test/utils.spec.ts index 359e34126103..3e9344f52b17 100644 --- a/test/core/test/utils.spec.ts +++ b/test/core/test/utils.spec.ts @@ -1,5 +1,5 @@ import { beforeAll, describe, expect, test } from 'vitest' -import { assertTypes, deepClone, objDisplay, objectAttr, toArray } from '@vitest/utils' +import { assertTypes, createColors, deepClone, objDisplay, objectAttr, toArray } from '@vitest/utils' import { deepMerge, resetModules } from '../../../packages/vitest/src/utils' import { deepMergeSnapshot } from '../../../packages/snapshot/src/port/utils' import type { EncodedSourceMap } from '../../../packages/vite-node/src/types' @@ -285,3 +285,13 @@ describe('objDisplay', () => { expect(objDisplay(value)).toEqual(expected) }) }) + +describe(createColors, () => { + test('no maximum call stack error', () => { + process.env.FORCE_COLOR = '1' + delete process.env.GITHUB_ACTIONS + const c = createColors() + expect(c.isColorSupported).toBe(true) + expect(c.blue(c.blue('x').repeat(10000))).toBeTruthy() + }) +})