diff --git a/packages/cli-kit/src/public/common/array.test.ts b/packages/cli-kit/src/public/common/array.test.ts index 720becbac0b..7b8f2884a19 100644 --- a/packages/cli-kit/src/public/common/array.test.ts +++ b/packages/cli-kit/src/public/common/array.test.ts @@ -1,4 +1,4 @@ -import {difference, uniq, uniqBy} from './array.js' +import {difference, takeRandomFromArray, uniq, uniqBy} from './array.js' import {describe, test, expect} from 'vitest' describe('uniqBy', () => { @@ -62,3 +62,38 @@ describe('difference', () => { expect(got).toEqual([1]) }) }) + +describe('takeRandomFromArray', () => { + test('returns an element from the array', () => { + // Given + const array = ['apple', 'banana', 'cherry'] + + // When + const got = takeRandomFromArray(array) + + // Then + expect(array).toContain(got) + }) + + test('returns the only element from a single-element array', () => { + // Given + const array = ['apple'] + + // When + const got = takeRandomFromArray(array) + + // Then + expect(got).toBe('apple') + }) + + test('returns undefined for an empty array', () => { + // Given + const array: string[] = [] + + // When + const got = takeRandomFromArray(array) + + // Then + expect(got).toBeUndefined() + }) +}) diff --git a/packages/cli-kit/src/public/common/array.ts b/packages/cli-kit/src/public/common/array.ts index 8b22c0b7b93..dff0a38eb02 100644 --- a/packages/cli-kit/src/public/common/array.ts +++ b/packages/cli-kit/src/public/common/array.ts @@ -9,7 +9,22 @@ import type {List, ValueIteratee} from 'lodash' * @returns A random element from the array. */ export function takeRandomFromArray(array: T[]): T { - return array[Math.floor(Math.random() * array.length)]! + const length = array.length + if (length === 0) { + return array[0]! + } + + const arrayBuffer = new Uint32Array(1) + const maxUint32 = 4294967296 + const maxMultiple = maxUint32 - (maxUint32 % length) + + let randomValue: number + do { + globalThis.crypto.getRandomValues(arrayBuffer) + randomValue = arrayBuffer[0]! + } while (randomValue >= maxMultiple) + + return array[randomValue % length]! } /**