Skip to content

fix(commons): correctly handle shared references in deepMerge#5195

Open
svozza wants to merge 6 commits intomainfrom
fix/deepmerge-shared-references
Open

fix(commons): correctly handle shared references in deepMerge#5195
svozza wants to merge 6 commits intomainfrom
fix/deepmerge-shared-references

Conversation

@svozza
Copy link
Copy Markdown
Contributor

@svozza svozza commented Apr 16, 2026

Summary

deepMerge used a WeakSet to detect circular references, which incorrectly treated shared (non-circular) object references as circular — silently dropping them. This replaces the WeakSet with ancestor-chain tracking (push/pop array stack) so only true cycles in the recursion path are detected and skipped.

Changes

  • Replace WeakSet<object> with object[] ancestor array in all internal deepMerge functions
  • Push objects onto the ancestor stack before recursing, pop after returning
  • Update 3 existing tests that asserted the incorrect (broken) behavior
  • Add 11 new tests for shared references: shared arrays, shared objects in arrays, shared objects across properties, shared objects across multiple sources, diamond-shaped references, shared objects with internal circular refs, source referencing target objects, circular plain objects inside arrays, and circular ancestor arrays
  • Cross-reference against lodash _.merge test suite and add parity tests for: multi-source array-of-objects merging, indirect prototype pollution via toString.constructor.prototype, function-replaced-by-object across sources, and self-merge safety
  • Fix TypeScript type errors in tests by widening narrow target types to Record<string, unknown> where merged-in keys aren't known at compile time
  • Remove unnecessary type casts (as) in test assertions, replacing them with type annotations, toHaveProperty, toEqual, and in-operator checks.

Issue number: closes #5192


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

svozza added 2 commits April 16, 2026 18:42
…andle shared references

deepMerge used a WeakSet to detect circular references, which incorrectly
skipped shared (non-circular) object references. Replace with an ancestor
array (push/pop stack) so only true cycles are detected.
Cross-referenced against lodash _.merge test suite to close coverage
gaps: multi-source array-of-objects merging, indirect prototype pollution
via toString.constructor.prototype, function-replaced-by-object across
sources, and self-merge safety.
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation bot added size/L PRs between 100-499 LOC and removed size/L PRs between 100-499 LOC labels Apr 16, 2026
@svozza svozza requested a review from dreamorosi April 16, 2026 18:28
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation bot added size/L PRs between 100-499 LOC and removed size/L PRs between 100-499 LOC labels Apr 16, 2026
@svozza svozza force-pushed the fix/deepmerge-shared-references branch from 04ab726 to 0fa558a Compare April 16, 2026 21:13
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation bot added size/L PRs between 100-499 LOC and removed size/L PRs between 100-499 LOC labels Apr 16, 2026
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation bot added size/L PRs between 100-499 LOC and removed size/L PRs between 100-499 LOC labels Apr 16, 2026
…in deepMerge tests

Replace verbose as-casts with type annotations, use direct value checks
(toBe, toEqual, toHaveProperty, in-operator) instead of intermediate
casts and property lookups.
@svozza svozza force-pushed the fix/deepmerge-shared-references branch from 5414340 to 8e2a18f Compare April 16, 2026 22:27
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation bot added size/L PRs between 100-499 LOC and removed size/L PRs between 100-499 LOC labels Apr 16, 2026
@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L PRs between 100-499 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: deepMerge conflates duplicate references with circular references

1 participant