Skip to content

Commit

Permalink
feat: Clone objects via wrapper (#22970)
Browse files Browse the repository at this point in the history
  • Loading branch information
zharinov authored Jun 27, 2023
1 parent 356fcea commit 53263bb
Show file tree
Hide file tree
Showing 22 changed files with 72 additions and 53 deletions.
5 changes: 3 additions & 2 deletions lib/config/massage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import is from '@sindresorhus/is';
import { clone } from '../util/clone';
import { getOptions } from './options';
import type { PackageRule, RenovateConfig, UpdateType } from './types';

Expand All @@ -16,7 +17,7 @@ export function massageConfig(config: RenovateConfig): RenovateConfig {
}
});
}
const massagedConfig = structuredClone(config);
const massagedConfig = clone(config);
for (const [key, val] of Object.entries(config)) {
if (allowedStrings.includes(key) && is.string(val)) {
massagedConfig[key] = [val];
Expand Down Expand Up @@ -55,7 +56,7 @@ export function massageConfig(config: RenovateConfig): RenovateConfig {
PackageRule
][]) {
if (updateTypes.includes(key)) {
let newRule = structuredClone(rule);
let newRule = clone(rule);
Object.keys(newRule).forEach((newKey) => {
if (!(newKey.startsWith(`match`) || newKey.startsWith('exclude'))) {
delete newRule[newKey];
Expand Down
3 changes: 2 additions & 1 deletion lib/config/presets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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';
Expand Down Expand Up @@ -273,7 +274,7 @@ export async function resolveConfigPresets(
_ignorePresets?: string[],
existingPresets: string[] = []
): Promise<AllConfig> {
let ignorePresets = structuredClone(_ignorePresets);
let ignorePresets = clone(_ignorePresets);
if (!ignorePresets || ignorePresets.length === 0) {
ignorePresets = inputConfig.ignorePresets ?? [];
}
Expand Down
5 changes: 3 additions & 2 deletions lib/config/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { logger } from '../logger';
import { clone } from '../util/clone';
import { getHighestVulnerabilitySeverity } from '../util/vulnerability/utils';
import * as options from './options';
import type { RenovateConfig } from './types';
Expand All @@ -11,8 +12,8 @@ export function mergeChildConfig<
if (!child) {
return parent as never;
}
const parentConfig = structuredClone(parent);
const childConfig = structuredClone(child);
const parentConfig = clone(parent);
const childConfig = clone(child);
const config: Record<string, any> = { ...parentConfig, ...childConfig };

// Ensure highest severity survives parent / child merge
Expand Down
2 changes: 1 addition & 1 deletion lib/logger/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export default function prepareError(err: Error): Record<string, unknown> {
statusCode: err.response?.statusCode,
statusMessage: err.response?.statusMessage,
body:
// istanbul ignore if: not easily testable
// istanbul ignore next: not easily testable
err.name === 'TimeoutError'
? undefined
: structuredClone(err.response.body),
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/datasource/jenkins-plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class JenkinsPluginsDatasource extends Datasource {
return null;
}

const result = structuredClone(plugin);
const result = clone(plugin);
const versions = await this.getJenkinsPluginVersions();
const releases = versions[packageName];
result.releases = releases ? clone(releases) : [];
Expand Down
3 changes: 2 additions & 1 deletion lib/modules/manager/bazel-module/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import parseGithubUrl from 'github-url-from-git';
import { z } from 'zod';
import { logger } from '../../../logger';
import type { SkipReason } from '../../../types';
import { clone } from '../../../util/clone';
import { regEx } from '../../../util/regex';
import { BazelDatasource } from '../../datasource/bazel';
import { GithubTagsDatasource } from '../../datasource/github-tags';
Expand Down Expand Up @@ -50,7 +51,7 @@ function isMerge(value: BazelModulePackageDep): value is MergePackageDep {
export function bazelModulePackageDepToPackageDependency(
bmpd: BazelModulePackageDep
): PackageDependency {
const copy: BazelModulePackageDep = structuredClone(bmpd);
const copy: BazelModulePackageDep = clone(bmpd);
if (isOverride(copy)) {
const partial = copy as Partial<OverridePackageDep>;
delete partial.bazelDepSkipReason;
Expand Down
3 changes: 2 additions & 1 deletion lib/modules/manager/gradle/parser/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { lexer, parser, query as q } from 'good-enough-parser';
import { clone } from '../../../../util/clone';
import { regEx } from '../../../../util/regex';
import type {
Ctx,
Expand Down Expand Up @@ -51,7 +52,7 @@ export function reduceNestingDepth(ctx: Ctx): Ctx {
}

export function prependNestingDepth(ctx: Ctx): Ctx {
ctx.varTokens = [...structuredClone(ctx.tmpNestingDepth), ...ctx.varTokens];
ctx.varTokens = [...clone(ctx.tmpNestingDepth), ...ctx.varTokens];
return ctx;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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');
Expand Down Expand Up @@ -113,7 +114,7 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
});

it('fails to remediate if parent dep cannot support', async () => {
const acceptsModified = structuredClone(acceptsJson);
const acceptsModified = clone(acceptsJson);
acceptsModified.versions['2.0.0'] = {};
httpMock
.scope('https://registry.npmjs.org')
Expand Down
13 changes: 0 additions & 13 deletions lib/util/__snapshots__/clone.spec.ts.snap

This file was deleted.

40 changes: 28 additions & 12 deletions lib/util/clone.spec.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
import { clone } from './clone';

describe('util/clone', () => {
it('returns null', () => {
const res = clone(null);
expect(res).toBeNull();
test.each`
input | expected
${undefined} | ${undefined}
${null} | ${null}
${true} | ${true}
${false} | ${false}
${0} | ${0}
${1} | ${1}
${NaN} | ${NaN}
${Infinity} | ${Infinity}
${-Infinity} | ${-Infinity}
${''} | ${''}
${'string'} | ${'string'}
${[]} | ${[]}
${[1, 2, 3]} | ${[1, 2, 3]}
${{}} | ${{}}
${{ a: 1 }} | ${{ a: 1 }}
`('returns $expected when input is $input', ({ input, expected }) => {
const res = clone(input);
expect(res).toStrictEqual(expected);
});

it('maintains same order', () => {
const obj: any = {
name: 'object',
type: 'object',
isObject: true,
b: 'foo',
a: 'bar',
c: 'baz',
};

const res = clone(obj);

expect(res).toMatchSnapshot(`{
name: 'object',
type: 'object',
isObject: true,
}`);
expect(Object.entries(res)).toMatchObject([
['b', 'foo'],
['a', 'bar'],
['c', 'baz'],
]);
});

it('assigns "[Circular]" to circular references', () => {
Expand Down
1 change: 0 additions & 1 deletion lib/util/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ 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 = unknown>(input: T): T {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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';

Expand Down Expand Up @@ -44,7 +45,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', structuredClone(cacheRecord));
memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));

// At this moment, cache is valid
let now = '2022-10-31 15:29:59';
Expand Down Expand Up @@ -84,7 +85,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', structuredClone(cacheRecord));
memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));

const now = '2022-10-31 15:30';
mockTime(now);
Expand Down Expand Up @@ -120,7 +121,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', structuredClone(cacheRecord));
memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));

const now = '2022-10-31 15:30';
mockTime(now);
Expand All @@ -146,7 +147,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', structuredClone(cacheRecord));
memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));

const now = '2022-12-31 23:59';
mockTime(now);
Expand Down Expand Up @@ -190,7 +191,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', structuredClone(cacheRecord));
memCache.set('github-graphql-cache:foo:bar', clone(cacheRecord));

const now = '2022-10-31 15:30';
mockTime(now);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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';

Expand Down Expand Up @@ -30,7 +31,7 @@ describe('util/github/graphql/cache-strategies/package-cache-strategy', () => {
items: oldItems,
createdAt: isoTs('2022-10-15 12:00'),
};
cacheGet.mockResolvedValueOnce(structuredClone(cacheRecord));
cacheGet.mockResolvedValueOnce(clone(cacheRecord));

const now = '2022-10-30 12:00';
mockTime(now);
Expand Down
5 changes: 3 additions & 2 deletions lib/util/host-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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';
Expand All @@ -17,7 +18,7 @@ export interface LegacyHostRule {
}

export function migrateRule(rule: LegacyHostRule & HostRule): HostRule {
const cloned: LegacyHostRule & HostRule = structuredClone(rule);
const cloned: LegacyHostRule & HostRule = clone(rule);
delete cloned.hostName;
delete cloned.domainName;
delete cloned.baseUrl;
Expand Down Expand Up @@ -188,7 +189,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 structuredClone(hostRules);
return clone(hostRules);
}

export function clear(): void {
Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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';
Expand All @@ -14,7 +15,7 @@ import { detectVulnerabilityAlerts } from './vulnerability';

function initializeConfig(config: RenovateConfig): RenovateConfig {
return {
...structuredClone(config),
...clone(config),
errors: [],
warnings: [],
branchList: [],
Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/onboarding/branch/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ 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 | undefined> {
let onboardingConfig = structuredClone(config.onboardingConfig);
let onboardingConfig = clone(config.onboardingConfig);

let orgPreset: string | undefined;

Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/package-files.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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>();
Expand Down Expand Up @@ -44,7 +45,7 @@ export class PackageFiles {
let removed = false;
let truncated = false;

const data = new Map(structuredClone(Array.from(this.data)));
const data = new Map(clone(Array.from(this.data)));

// filter all deps with skip reason
for (const managers of [...data.values()].filter(is.truthy)) {
Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/process/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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';
Expand All @@ -37,7 +38,7 @@ async function fetchDepUpdates(
packageFileConfig: RenovateConfig & PackageFile,
indep: PackageDependency
): Promise<PackageDependency> {
const dep = structuredClone(indep);
const dep = clone(indep);
dep.updates = [];
if (is.string(dep.depName)) {
dep.depName = dep.depName.trim();
Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/process/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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';
Expand All @@ -23,7 +24,7 @@ async function getBaseBranchConfig(
): Promise<RenovateConfig> {
logger.debug(`baseBranch: ${baseBranch}`);

let baseBranchConfig: RenovateConfig = structuredClone(config);
let baseBranchConfig: RenovateConfig = clone(config);

if (
config.useBaseBranchConfig === 'merge' &&
Expand Down
3 changes: 2 additions & 1 deletion lib/workers/repository/process/lookup/filter-checks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { 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';
Expand Down Expand Up @@ -41,7 +42,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {

beforeEach(() => {
config = { currentVersion: '1.0.0' };
sortedReleases = structuredClone(releases);
sortedReleases = clone(releases);
jest.resetAllMocks();
dateUtil.getElapsedMs.mockReturnValueOnce(toMs('3 days') ?? 0);
dateUtil.getElapsedMs.mockReturnValueOnce(toMs('5 days') ?? 0);
Expand Down
Loading

0 comments on commit 53263bb

Please sign in to comment.