From a6dfa70c1d46e16645658189534b9a8d81b5ace4 Mon Sep 17 00:00:00 2001
From: Jamie Magee <jamie.magee@gmail.com>
Date: Wed, 26 Apr 2023 22:06:22 -0700
Subject: [PATCH] chore: migrate to `structuredClone` (#20885)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 lib/config/massage.ts                         |  5 ++---
 lib/config/presets/index.ts                   |  3 +--
 lib/config/utils.ts                           |  6 ++---
 lib/logger/utils.ts                           | 10 +++++----
 .../aws-machine-image/index.spec.ts           |  6 ++---
 lib/modules/datasource/aws-rds/index.spec.ts  |  4 ++--
 lib/modules/datasource/docker/index.spec.ts   | 22 +++++++++----------
 .../datasource/jenkins-plugins/index.ts       |  2 +-
 .../datasource/kubernetes-api/index.spec.ts   |  2 +-
 .../manager/gradle/parser/common.spec.ts      |  2 +-
 lib/modules/manager/gradle/parser/common.ts   |  3 +--
 .../update/locked-dependency/index.spec.ts    |  3 +--
 lib/modules/platform/github/index.spec.ts     |  4 ++--
 lib/util/clone.ts                             |  5 +++++
 .../memory-cache-strategy.spec.ts             | 11 +++++-----
 .../package-cache-strategy.spec.ts            |  3 +--
 lib/util/host-rules.ts                        |  5 ++---
 lib/util/http/github.spec.ts                  |  2 +-
 lib/workers/repository/init/index.ts          |  8 +++++--
 .../repository/onboarding/branch/config.ts    |  5 ++---
 lib/workers/repository/package-files.ts       |  3 +--
 lib/workers/repository/process/fetch.ts       |  3 +--
 lib/workers/repository/process/index.ts       |  3 +--
 .../process/lookup/filter-checks.spec.ts      |  3 +--
 .../repository/process/lookup/index.ts        |  3 +--
 .../update/pr/changelog/release-notes.spec.ts |  5 ++---
 26 files changed, 63 insertions(+), 68 deletions(-)

diff --git a/lib/config/massage.ts b/lib/config/massage.ts
index 094237c11b..5130edd2bd 100644
--- a/lib/config/massage.ts
+++ b/lib/config/massage.ts
@@ -1,5 +1,4 @@
 import is from '@sindresorhus/is';
-import { clone } from '../util/clone';
 import { getOptions } from './options';
 import type { PackageRule, RenovateConfig, UpdateType } from './types';
 
@@ -17,7 +16,7 @@ export function massageConfig(config: RenovateConfig): RenovateConfig {
       }
     });
   }
-  const massagedConfig = clone(config);
+  const massagedConfig = structuredClone(config);
   for (const [key, val] of Object.entries(config)) {
     if (allowedStrings.includes(key) && is.string(val)) {
       massagedConfig[key] = [val];
@@ -56,7 +55,7 @@ export function massageConfig(config: RenovateConfig): RenovateConfig {
         PackageRule
       ][]) {
         if (updateTypes.includes(key)) {
-          let newRule = clone(rule);
+          let newRule = structuredClone(rule);
           Object.keys(newRule).forEach((newKey) => {
             if (!(newKey.startsWith(`match`) || newKey.startsWith('exclude'))) {
               delete newRule[newKey];
diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts
index 24459e102c..32d17ea821 100644
--- a/lib/config/presets/index.ts
+++ b/lib/config/presets/index.ts
@@ -6,7 +6,6 @@ import {
 import { logger } from '../../logger';
 import { ExternalHostError } from '../../types/errors/external-host-error';
 import * as memCache from '../../util/cache/memory';
-import { clone } from '../../util/clone';
 import { regEx } from '../../util/regex';
 import * as massage from '../massage';
 import * as migration from '../migration';
@@ -274,7 +273,7 @@ export async function resolveConfigPresets(
   _ignorePresets?: string[],
   existingPresets: string[] = []
 ): Promise<AllConfig> {
-  let ignorePresets = clone(_ignorePresets);
+  let ignorePresets = structuredClone(_ignorePresets);
   if (!ignorePresets || ignorePresets.length === 0) {
     ignorePresets = inputConfig.ignorePresets ?? [];
   }
diff --git a/lib/config/utils.ts b/lib/config/utils.ts
index 4c891e21c1..106d9e168f 100644
--- a/lib/config/utils.ts
+++ b/lib/config/utils.ts
@@ -1,5 +1,4 @@
 import { logger } from '../logger';
-import { clone } from '../util/clone';
 import * as options from './options';
 import type { RenovateConfig } from './types';
 
@@ -11,9 +10,8 @@ export function mergeChildConfig<
   if (!child) {
     return parent as never;
   }
-  const parentConfig = clone(parent);
-  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
-  const childConfig = clone(child!);
+  const parentConfig = structuredClone(parent);
+  const childConfig = structuredClone(child);
   const config: Record<string, any> = { ...parentConfig, ...childConfig };
   for (const option of options.getOptions()) {
     if (
diff --git a/lib/logger/utils.ts b/lib/logger/utils.ts
index d169768678..4d0297cedb 100644
--- a/lib/logger/utils.ts
+++ b/lib/logger/utils.ts
@@ -3,7 +3,6 @@ import is from '@sindresorhus/is';
 import bunyan from 'bunyan';
 import fs from 'fs-extra';
 import { RequestError as HttpError } from 'got';
-import { clone } from '../util/clone';
 import { redactedFields, sanitize } from '../util/sanitize';
 import type { BunyanRecord, BunyanStream } from './types';
 
@@ -65,7 +64,7 @@ export default function prepareError(err: Error): Record<string, unknown> {
   // handle got error
   if (err instanceof HttpError) {
     const options: Record<string, unknown> = {
-      headers: clone(err.options.headers),
+      headers: structuredClone(err.options.headers),
       url: err.options.url?.toString(),
       hostType: err.options.context.hostType,
     };
@@ -82,8 +81,11 @@ export default function prepareError(err: Error): Record<string, unknown> {
         statusCode: err.response?.statusCode,
         statusMessage: err.response?.statusMessage,
         body:
-          err.name === 'TimeoutError' ? undefined : clone(err.response.body),
-        headers: clone(err.response.headers),
+          // istanbul ignore if: not easily testable
+          err.name === 'TimeoutError'
+            ? undefined
+            : structuredClone(err.response.body),
+        headers: structuredClone(err.response.headers),
         httpVersion: err.response.httpVersion,
         retryCount: err.response.retryCount,
       };
diff --git a/lib/modules/datasource/aws-machine-image/index.spec.ts b/lib/modules/datasource/aws-machine-image/index.spec.ts
index ff8f7aef30..6349da52d9 100644
--- a/lib/modules/datasource/aws-machine-image/index.spec.ts
+++ b/lib/modules/datasource/aws-machine-image/index.spec.ts
@@ -347,7 +347,7 @@ describe('modules/datasource/aws-machine-image/index', () => {
         packageName:
           '[{"Name":"owner-id","Values":["602401143452"]},{"Name":"name","Values":["with one matching image to return that image"]}]',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           {
             isDeprecated: false,
@@ -366,7 +366,7 @@ describe('modules/datasource/aws-machine-image/index', () => {
         packageName:
           '[{"Name":"owner-id","Values":["602401143452"]},{"Name":"name","Values":["with one deprecated matching image to return that image"]}]',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           {
             isDeprecated: true,
@@ -385,7 +385,7 @@ describe('modules/datasource/aws-machine-image/index', () => {
         packageName:
           '[{"Name":"owner-id","Values":["602401143452"]},{"Name":"name","Values":["with 3 matching image to return the newest image"]}]',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           {
             isDeprecated: false,
diff --git a/lib/modules/datasource/aws-rds/index.spec.ts b/lib/modules/datasource/aws-rds/index.spec.ts
index d0eda95cfa..7d46e5493c 100644
--- a/lib/modules/datasource/aws-rds/index.spec.ts
+++ b/lib/modules/datasource/aws-rds/index.spec.ts
@@ -119,7 +119,7 @@ describe('modules/datasource/aws-rds/index', () => {
         datasource: AwsRdsDataSource.id,
         packageName: '[{"Name":"engine","Values":["mysql"]}]',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           {
             isDeprecated: true,
@@ -138,7 +138,7 @@ describe('modules/datasource/aws-rds/index', () => {
         datasource: AwsRdsDataSource.id,
         packageName: '[{"Name":"engine","Values":["mysql"]}]',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           {
             isDeprecated: false,
diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts
index 17ce2dee16..fe3979b58e 100644
--- a/lib/modules/datasource/docker/index.spec.ts
+++ b/lib/modules/datasource/docker/index.spec.ts
@@ -1830,7 +1830,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [
           {
@@ -1881,7 +1881,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [
           {
@@ -1935,7 +1935,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
         sourceUrl: 'https://github.com/renovatebot/renovate',
@@ -1962,7 +1962,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
       });
@@ -1986,7 +1986,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
       });
@@ -2007,7 +2007,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
       });
@@ -2048,7 +2048,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [
           {
@@ -2093,7 +2093,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [
           {
@@ -2123,7 +2123,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
       });
@@ -2173,7 +2173,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'registry.company.com/node',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://registry.company.com',
         releases: [],
       });
@@ -2229,7 +2229,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         packageName: 'ghcr.io/visualon/drone-git',
       });
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         registryUrl: 'https://ghcr.io',
         sourceUrl: 'https://github.com/visualon/drone-git',
         releases: [{ version: '1.0.0' }],
diff --git a/lib/modules/datasource/jenkins-plugins/index.ts b/lib/modules/datasource/jenkins-plugins/index.ts
index aef686da9b..d8f717c28d 100644
--- a/lib/modules/datasource/jenkins-plugins/index.ts
+++ b/lib/modules/datasource/jenkins-plugins/index.ts
@@ -33,7 +33,7 @@ export class JenkinsPluginsDatasource extends Datasource {
       return null;
     }
 
-    const result = clone(plugin);
+    const result = structuredClone(plugin);
     const versions = await this.getJenkinsPluginVersions();
     const releases = versions[packageName];
     result.releases = releases ? clone(releases) : [];
diff --git a/lib/modules/datasource/kubernetes-api/index.spec.ts b/lib/modules/datasource/kubernetes-api/index.spec.ts
index d4b2a954e4..7b453fc2d8 100644
--- a/lib/modules/datasource/kubernetes-api/index.spec.ts
+++ b/lib/modules/datasource/kubernetes-api/index.spec.ts
@@ -16,7 +16,7 @@ describe('modules/datasource/kubernetes-api/index', () => {
         packageName: 'CSIStorageCapacity',
       });
       expect(res).not.toBeNull();
-      expect(res).toStrictEqual({
+      expect(res).toEqual({
         releases: [
           { version: 'storage.k8s.io/v1beta1' },
           { version: 'storage.k8s.io/v1' },
diff --git a/lib/modules/manager/gradle/parser/common.spec.ts b/lib/modules/manager/gradle/parser/common.spec.ts
index 9b2c2339de..8c377a1345 100644
--- a/lib/modules/manager/gradle/parser/common.spec.ts
+++ b/lib/modules/manager/gradle/parser/common.spec.ts
@@ -59,7 +59,7 @@ describe('modules/manager/gradle/parser/common', () => {
   it('prependNestingDepth', () => {
     ctx.tmpNestingDepth = ctx.varTokens = [token];
     prependNestingDepth(ctx);
-    expect(ctx.varTokens).toStrictEqual([token, token]);
+    expect(ctx.varTokens).toEqual([token, token]);
 
     coalesceVariable(ctx);
     expect(ctx).toMatchObject({
diff --git a/lib/modules/manager/gradle/parser/common.ts b/lib/modules/manager/gradle/parser/common.ts
index 6f5c17790d..e72d582ea0 100644
--- a/lib/modules/manager/gradle/parser/common.ts
+++ b/lib/modules/manager/gradle/parser/common.ts
@@ -1,5 +1,4 @@
 import { lexer, parser, query as q } from 'good-enough-parser';
-import { clone } from '../../../../util/clone';
 import { regEx } from '../../../../util/regex';
 import type {
   Ctx,
@@ -52,7 +51,7 @@ export function reduceNestingDepth(ctx: Ctx): Ctx {
 }
 
 export function prependNestingDepth(ctx: Ctx): Ctx {
-  ctx.varTokens = [...clone(ctx.tmpNestingDepth), ...ctx.varTokens];
+  ctx.varTokens = [...structuredClone(ctx.tmpNestingDepth), ...ctx.varTokens];
   return ctx;
 }
 
diff --git a/lib/modules/manager/npm/update/locked-dependency/index.spec.ts b/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
index 857621abaa..930836f4ff 100644
--- a/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
+++ b/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
@@ -1,7 +1,6 @@
 import { updateLockedDependency } from '../..';
 import { Fixtures } from '../../../../../../test/fixtures';
 import * as httpMock from '../../../../../../test/http-mock';
-import { clone } from '../../../../../util/clone';
 import type { UpdateLockedConfig } from '../../../types';
 
 const packageFileContent = Fixtures.get('package.json', './package-lock');
@@ -114,7 +113,7 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
     });
 
     it('fails to remediate if parent dep cannot support', async () => {
-      const acceptsModified = clone(acceptsJson);
+      const acceptsModified = structuredClone(acceptsJson);
       acceptsModified.versions['2.0.0'] = {};
       httpMock
         .scope('https://registry.npmjs.org')
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 91d35bc717..b787c71f2e 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -208,7 +208,7 @@ describe('modules/platform/github/index', () => {
         });
 
       const repos = await github.getRepos();
-      expect(repos).toStrictEqual(['a/b', 'c/d']);
+      expect(repos).toEqual(['a/b', 'c/d']);
     });
 
     it('should return an array of repos when using GitHub App Installation Token', async () => {
@@ -236,7 +236,7 @@ describe('modules/platform/github/index', () => {
         });
 
       const repos = await github.getRepos();
-      expect(repos).toStrictEqual(['a/b', 'c/d']);
+      expect(repos).toEqual(['a/b', 'c/d']);
     });
   });
 
diff --git a/lib/util/clone.ts b/lib/util/clone.ts
index 67813c0242..422add0b37 100644
--- a/lib/util/clone.ts
+++ b/lib/util/clone.ts
@@ -1,5 +1,10 @@
 import { quickStringify } from './stringify';
 
+/**
+ * Creates a deep clone of an object.
+ * @deprecated Use {@link structuredClone} instead.
+ * @param input The object to clone.
+ */
 export function clone<T>(input: T | null = null): T {
   const stringifiedInput = quickStringify(input);
   return stringifiedInput ? JSON.parse(stringifiedInput) : null;
diff --git a/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts b/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts
index 88849193a1..71ab720310 100644
--- a/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts
+++ b/lib/util/github/graphql/cache-strategies/memory-cache-strategy.spec.ts
@@ -1,6 +1,5 @@
 import { DateTime, Settings } from 'luxon';
 import * as memCache from '../../../cache/memory';
-import { clone } from '../../../clone';
 import type { GithubDatasourceItem, GithubGraphqlCacheRecord } from '../types';
 import { GithubGraphqlMemoryCacheStrategy } from './memory-cache-strategy';
 
@@ -45,7 +44,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => {
       items,
       createdAt: isoTs('2022-10-01 15:30'),
     };
-    memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));
+    memCache.set('github-graphql-cache:foo:bar', structuredClone(cacheRecord));
 
     // At this moment, cache is valid
     let now = '2022-10-31 15:29:59';
@@ -85,7 +84,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => {
       items: oldItems,
       createdAt: isoTs('2022-10-30 12:00'),
     };
-    memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));
+    memCache.set('github-graphql-cache:foo:bar', structuredClone(cacheRecord));
 
     const now = '2022-10-31 15:30';
     mockTime(now);
@@ -121,7 +120,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => {
       items: oldItems,
       createdAt: isoTs('2022-10-30 12:00'),
     };
-    memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));
+    memCache.set('github-graphql-cache:foo:bar', structuredClone(cacheRecord));
 
     const now = '2022-10-31 15:30';
     mockTime(now);
@@ -147,7 +146,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => {
       items: oldItems,
       createdAt: isoTs('2022-12-31 12:00'),
     };
-    memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));
+    memCache.set('github-graphql-cache:foo:bar', structuredClone(cacheRecord));
 
     const now = '2022-12-31 23:59';
     mockTime(now);
@@ -191,7 +190,7 @@ describe('util/github/graphql/cache-strategies/memory-cache-strategy', () => {
       items,
       createdAt: isoTs('2022-10-30 12:00'),
     };
-    memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));
+    memCache.set('github-graphql-cache:foo:bar', structuredClone(cacheRecord));
 
     const now = '2022-10-31 15:30';
     mockTime(now);
diff --git a/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts b/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts
index 80c02add16..b288f2eeb6 100644
--- a/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts
+++ b/lib/util/github/graphql/cache-strategies/package-cache-strategy.spec.ts
@@ -1,6 +1,5 @@
 import { DateTime, Settings } from 'luxon';
 import * as packageCache from '../../../cache/package';
-import { clone } from '../../../clone';
 import type { GithubDatasourceItem, GithubGraphqlCacheRecord } from '../types';
 import { GithubGraphqlPackageCacheStrategy } from './package-cache-strategy';
 
@@ -31,7 +30,7 @@ describe('util/github/graphql/cache-strategies/package-cache-strategy', () => {
       items: oldItems,
       createdAt: isoTs('2022-10-15 12:00'),
     };
-    cacheGet.mockResolvedValueOnce(clone(cacheRecord));
+    cacheGet.mockResolvedValueOnce(structuredClone(cacheRecord));
 
     const now = '2022-10-30 12:00';
     mockTime(now);
diff --git a/lib/util/host-rules.ts b/lib/util/host-rules.ts
index 0f5e721945..9ee45b797c 100644
--- a/lib/util/host-rules.ts
+++ b/lib/util/host-rules.ts
@@ -2,7 +2,6 @@ import is from '@sindresorhus/is';
 import merge from 'deepmerge';
 import { logger } from '../logger';
 import type { HostRule, HostRuleSearchResult } from '../types';
-import { clone } from './clone';
 import * as sanitize from './sanitize';
 import { toBase64 } from './string';
 import { parseUrl, validateUrl } from './url';
@@ -16,7 +15,7 @@ interface LegacyHostRule {
 }
 
 function migrateRule(rule: LegacyHostRule & HostRule): HostRule {
-  const cloned: LegacyHostRule & HostRule = clone(rule);
+  const cloned: LegacyHostRule & HostRule = structuredClone(rule);
   delete cloned.hostName;
   delete cloned.domainName;
   delete cloned.baseUrl;
@@ -187,7 +186,7 @@ export function findAll({ hostType }: { hostType: string }): HostRule[] {
  * @returns a deep copy of all known host rules without any filtering
  */
 export function getAll(): HostRule[] {
-  return clone(hostRules);
+  return structuredClone(hostRules);
 }
 
 export function clear(): void {
diff --git a/lib/util/http/github.spec.ts b/lib/util/http/github.spec.ts
index f2383c4b71..fe85535129 100644
--- a/lib/util/http/github.spec.ts
+++ b/lib/util/http/github.spec.ts
@@ -621,7 +621,7 @@ describe('util/http/github', () => {
         .reply(200, { data: { repository } });
 
       const res = await githubApi.requestGraphql(graphqlQuery);
-      expect(res?.data).toStrictEqual({ repository });
+      expect(res?.data).toEqual({ repository });
     });
 
     it('queryRepoField', async () => {
diff --git a/lib/workers/repository/init/index.ts b/lib/workers/repository/init/index.ts
index 89296f134f..10eb930580 100644
--- a/lib/workers/repository/init/index.ts
+++ b/lib/workers/repository/init/index.ts
@@ -3,7 +3,6 @@ import { applySecretsToConfig } from '../../../config/secrets';
 import type { RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
 import { platform } from '../../../modules/platform';
-import { clone } from '../../../util/clone';
 import { cloneSubmodules, setUserRepoConfig } from '../../../util/git';
 import { getAll } from '../../../util/host-rules';
 import { checkIfConfigured } from '../configured';
@@ -14,7 +13,12 @@ import { getRepoConfig } from './config';
 import { detectVulnerabilityAlerts } from './vulnerability';
 
 function initializeConfig(config: RenovateConfig): RenovateConfig {
-  return { ...clone(config), errors: [], warnings: [], branchList: [] };
+  return {
+    ...structuredClone(config),
+    errors: [],
+    warnings: [],
+    branchList: [],
+  };
 }
 
 function warnOnUnsupportedOptions(config: RenovateConfig): void {
diff --git a/lib/workers/repository/onboarding/branch/config.ts b/lib/workers/repository/onboarding/branch/config.ts
index 8350dba61b..fdceac6ba7 100644
--- a/lib/workers/repository/onboarding/branch/config.ts
+++ b/lib/workers/repository/onboarding/branch/config.ts
@@ -6,13 +6,12 @@ import type {
   RenovateSharedConfig,
 } from '../../../../config/types';
 import { logger } from '../../../../logger';
-import { clone } from '../../../../util/clone';
 import { EditorConfig, JSONWriter } from '../../../../util/json-writer';
 
 async function getOnboardingConfig(
   config: RenovateConfig
-): Promise<RenovateSharedConfig> {
-  let onboardingConfig = clone(config.onboardingConfig);
+): Promise<RenovateSharedConfig | undefined> {
+  let onboardingConfig = structuredClone(config.onboardingConfig);
 
   let orgPreset: string | undefined;
 
diff --git a/lib/workers/repository/package-files.ts b/lib/workers/repository/package-files.ts
index 02887c20c9..b33bec994c 100644
--- a/lib/workers/repository/package-files.ts
+++ b/lib/workers/repository/package-files.ts
@@ -1,7 +1,6 @@
 import is from '@sindresorhus/is';
 import { logger } from '../../logger';
 import type { PackageFile } from '../../modules/manager/types';
-import { clone } from '../../util/clone';
 
 export class PackageFiles {
   private static data = new Map<string, Record<string, PackageFile[]> | null>();
@@ -45,7 +44,7 @@ export class PackageFiles {
     let removed = false;
     let truncated = false;
 
-    const data = new Map(clone(Array.from(this.data)));
+    const data = new Map(structuredClone(Array.from(this.data)));
 
     // filter all deps with skip reason
     for (const managers of [...data.values()].filter(is.truthy)) {
diff --git a/lib/workers/repository/process/fetch.ts b/lib/workers/repository/process/fetch.ts
index 92ae3315d1..9f9c2ec29d 100644
--- a/lib/workers/repository/process/fetch.ts
+++ b/lib/workers/repository/process/fetch.ts
@@ -14,7 +14,6 @@ import type {
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import * as memCache from '../../../util/cache/memory';
 import type { LookupStats } from '../../../util/cache/memory/types';
-import { clone } from '../../../util/clone';
 import { applyPackageRules } from '../../../util/package-rules';
 import * as p from '../../../util/promises';
 import { PackageFiles } from '../package-files';
@@ -38,7 +37,7 @@ async function fetchDepUpdates(
   packageFileConfig: RenovateConfig & PackageFile,
   indep: PackageDependency
 ): Promise<PackageDependency> {
-  const dep = clone(indep);
+  const dep = structuredClone(indep);
   dep.updates = [];
   if (is.string(dep.depName)) {
     dep.depName = dep.depName.trim();
diff --git a/lib/workers/repository/process/index.ts b/lib/workers/repository/process/index.ts
index 62596fd29d..0593f539bc 100644
--- a/lib/workers/repository/process/index.ts
+++ b/lib/workers/repository/process/index.ts
@@ -8,7 +8,6 @@ import type { PackageFile } from '../../../modules/manager/types';
 import { platform } from '../../../modules/platform';
 import { scm } from '../../../modules/platform/scm';
 import { getCache } from '../../../util/cache/repository';
-import { clone } from '../../../util/clone';
 import { getBranchList } from '../../../util/git';
 import { configRegexPredicate } from '../../../util/regex';
 import { addSplit } from '../../../util/split';
@@ -23,7 +22,7 @@ async function getBaseBranchConfig(
 ): Promise<RenovateConfig> {
   logger.debug(`baseBranch: ${baseBranch}`);
 
-  let baseBranchConfig: RenovateConfig = clone(config);
+  let baseBranchConfig: RenovateConfig = structuredClone(config);
 
   if (
     config.useBaseBranchConfig === 'merge' &&
diff --git a/lib/workers/repository/process/lookup/filter-checks.spec.ts b/lib/workers/repository/process/lookup/filter-checks.spec.ts
index 8c210db87d..9e950ed707 100644
--- a/lib/workers/repository/process/lookup/filter-checks.spec.ts
+++ b/lib/workers/repository/process/lookup/filter-checks.spec.ts
@@ -1,7 +1,6 @@
 import { getConfig, mocked } from '../../../../../test/util';
 import type { Release } from '../../../../modules/datasource';
 import * as allVersioning from '../../../../modules/versioning';
-import { clone } from '../../../../util/clone';
 import * as _dateUtil from '../../../../util/date';
 import * as _mergeConfidence from '../../../../util/merge-confidence';
 import { toMs } from '../../../../util/pretty-time';
@@ -43,7 +42,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {
   beforeEach(() => {
     config = getConfig();
     config.currentVersion = '1.0.0';
-    sortedReleases = clone(releases);
+    sortedReleases = structuredClone(releases);
     jest.resetAllMocks();
     dateUtil.getElapsedMs.mockReturnValueOnce(toMs('3 days') ?? 0);
     dateUtil.getElapsedMs.mockReturnValueOnce(toMs('5 days') ?? 0);
diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts
index 1434370d15..0b087ede0e 100644
--- a/lib/workers/repository/process/lookup/index.ts
+++ b/lib/workers/repository/process/lookup/index.ts
@@ -16,7 +16,6 @@ import {
 import { getRangeStrategy } from '../../../../modules/manager';
 import * as allVersioning from '../../../../modules/versioning';
 import { ExternalHostError } from '../../../../types/errors/external-host-error';
-import { clone } from '../../../../util/clone';
 import { applyPackageRules } from '../../../../util/package-rules';
 import { regEx } from '../../../../util/regex';
 import { getBucket } from './bucket';
@@ -81,7 +80,7 @@ export async function lookupUpdates(
         return res;
       }
 
-      dependency = clone(await getPkgReleases(config));
+      dependency = structuredClone(await getPkgReleases(config));
       if (!dependency) {
         // If dependency lookup fails then warn and return
         const warning: ValidationMessage = {
diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
index ae031163b8..978bef659f 100644
--- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
@@ -2,7 +2,6 @@ import { DateTime } from 'luxon';
 import { Fixtures } from '../../../../../../test/fixtures';
 import * as httpMock from '../../../../../../test/http-mock';
 import { mocked, partial } from '../../../../../../test/util';
-import { clone } from '../../../../../util/clone';
 import * as githubGraphql from '../../../../../util/github/graphql';
 import * as _hostRules from '../../../../../util/host-rules';
 import { toBase64 } from '../../../../../util/string';
@@ -1136,7 +1135,7 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
 
     it('handles github sourceDirectory', async () => {
       const sourceDirectory = 'packages/foo';
-      const subdirTree = clone(githubTreeResponse);
+      const subdirTree = structuredClone(githubTreeResponse);
       for (const file of subdirTree.tree) {
         file.path = `${sourceDirectory}/${file.path}`;
       }
@@ -1307,7 +1306,7 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
 
       it('handles gitlab sourceDirectory', async () => {
         const sourceDirectory = 'packages/foo';
-        const response = clone(gitlabTreeResponse).map((file) => ({
+        const response = structuredClone(gitlabTreeResponse).map((file) => ({
           ...file,
           path: `${sourceDirectory}/${file.path}`,
         }));
-- 
GitLab