From 9df37d3c43083daa9786bc43ffc59128f9abd6cb Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Mon, 18 May 2026 00:26:54 +0000 Subject: [PATCH] [Performance] Optimize getArrayContainsDuplicates with early exit Optimized the `getArrayContainsDuplicates` utility in `@shopify/cli-kit` to return early as soon as the first duplicate is found. The previous implementation always constructed a full `Set` from the entire array, which resulted in O(n) time and memory overhead even when a duplicate was present at the beginning. New behavior: - Time complexity: O(k) where k is the index of the first duplicate. - Memory complexity: O(k) for the tracking Set. --- .jules/bolt.md | 0 .../cli-kit/src/public/common/array.test.ts | 37 ++++++++++++++++++- packages/cli-kit/src/public/common/array.ts | 13 ++++++- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/cli-kit/src/public/common/array.test.ts b/packages/cli-kit/src/public/common/array.test.ts index 720becbac0b..452259e765e 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, getArrayContainsDuplicates, uniq, uniqBy} from './array.js' import {describe, test, expect} from 'vitest' describe('uniqBy', () => { @@ -62,3 +62,38 @@ describe('difference', () => { expect(got).toEqual([1]) }) }) + +describe('getArrayContainsDuplicates', () => { + test('returns true if the array contains duplicates', () => { + // Given + const array = [1, 2, 2, 3] + + // When + const got = getArrayContainsDuplicates(array) + + // Then + expect(got).toBe(true) + }) + + test('returns false if the array does not contain duplicates', () => { + // Given + const array = [1, 2, 3] + + // When + const got = getArrayContainsDuplicates(array) + + // Then + expect(got).toBe(false) + }) + + test('returns false for an empty array', () => { + // Given + const array: number[] = [] + + // When + const got = getArrayContainsDuplicates(array) + + // Then + expect(got).toBe(false) + }) +}) diff --git a/packages/cli-kit/src/public/common/array.ts b/packages/cli-kit/src/public/common/array.ts index 8b22c0b7b93..c6567c91203 100644 --- a/packages/cli-kit/src/public/common/array.ts +++ b/packages/cli-kit/src/public/common/array.ts @@ -25,11 +25,22 @@ export function getArrayRejectingUndefined(array: (T | undefined)[]): T[] { /** * Returns true if an array contains duplicates. * + * This implementation is optimized to exit early as soon as the first duplicate + * is found, avoiding unnecessary processing of the rest of the array. + * Time complexity: O(k) where k is the index of the first duplicate, O(n) otherwise. + * * @param array - The array to check against. * @returns True if the array contains duplicates. */ export function getArrayContainsDuplicates(array: T[]): boolean { - return array.length !== new Set(array).size + const seen = new Set() + for (const item of array) { + if (seen.has(item)) { + return true + } + seen.add(item) + } + return false } /**