From 72ca3607a34631beb44855ec316a37f697b2e75b Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Tue, 23 Dec 2025 17:48:20 +0800 Subject: [PATCH] feat: Add polyfill for Array.prototype.toSpliced method (#30031) Co-authored-by: CodingOnStar --- .../components/browser-initializer.spec.ts | 78 +++++++++++++++++++ web/app/components/browser-initializer.tsx | 14 ++++ 2 files changed, 92 insertions(+) create mode 100644 web/app/components/browser-initializer.spec.ts diff --git a/web/app/components/browser-initializer.spec.ts b/web/app/components/browser-initializer.spec.ts new file mode 100644 index 0000000000..f767b80826 --- /dev/null +++ b/web/app/components/browser-initializer.spec.ts @@ -0,0 +1,78 @@ +/** + * Tests for Array.prototype.toSpliced polyfill + */ + +describe('toSpliced polyfill', () => { + let originalToSpliced: typeof Array.prototype.toSpliced + + beforeEach(() => { + // Save original method + originalToSpliced = Array.prototype.toSpliced + }) + + afterEach(() => { + // Restore original method + // eslint-disable-next-line no-extend-native + Array.prototype.toSpliced = originalToSpliced + }) + + const applyPolyfill = () => { + // @ts-expect-error - intentionally deleting for test + delete Array.prototype.toSpliced + + if (!Array.prototype.toSpliced) { + // eslint-disable-next-line no-extend-native + Array.prototype.toSpliced = function (this: T[], start: number, deleteCount?: number, ...items: T[]): T[] { + const copy = this.slice() + copy.splice(start, deleteCount ?? copy.length - start, ...items) + return copy + } + } + } + + it('should add toSpliced method when not available', () => { + applyPolyfill() + expect(typeof Array.prototype.toSpliced).toBe('function') + }) + + it('should return a new array without modifying the original', () => { + applyPolyfill() + const arr = [1, 2, 3, 4, 5] + const result = arr.toSpliced(1, 2) + + expect(result).toEqual([1, 4, 5]) + expect(arr).toEqual([1, 2, 3, 4, 5]) // original unchanged + }) + + it('should insert items at the specified position', () => { + applyPolyfill() + const arr: (number | string)[] = [1, 2, 3] + const result = arr.toSpliced(1, 0, 'a', 'b') + + expect(result).toEqual([1, 'a', 'b', 2, 3]) + }) + + it('should replace items at the specified position', () => { + applyPolyfill() + const arr: (number | string)[] = [1, 2, 3, 4, 5] + const result = arr.toSpliced(1, 2, 'a', 'b') + + expect(result).toEqual([1, 'a', 'b', 4, 5]) + }) + + it('should handle negative start index', () => { + applyPolyfill() + const arr = [1, 2, 3, 4, 5] + const result = arr.toSpliced(-2, 1) + + expect(result).toEqual([1, 2, 3, 5]) + }) + + it('should delete to end when deleteCount is omitted', () => { + applyPolyfill() + const arr = [1, 2, 3, 4, 5] + const result = arr.toSpliced(2) + + expect(result).toEqual([1, 2]) + }) +}) diff --git a/web/app/components/browser-initializer.tsx b/web/app/components/browser-initializer.tsx index fcae22c448..c2194ca8d4 100644 --- a/web/app/components/browser-initializer.tsx +++ b/web/app/components/browser-initializer.tsx @@ -1,5 +1,19 @@ 'use client' +// Polyfill for Array.prototype.toSpliced (ES2023, Chrome 110+) +if (!Array.prototype.toSpliced) { + // eslint-disable-next-line no-extend-native + Array.prototype.toSpliced = function (this: T[], start: number, deleteCount?: number, ...items: T[]): T[] { + const copy = this.slice() + // When deleteCount is undefined (omitted), delete to end; otherwise let splice handle coercion + if (deleteCount === undefined) + copy.splice(start, copy.length - start, ...items) + else + copy.splice(start, deleteCount, ...items) + return copy + } +} + class StorageMock { data: Record