-
Notifications
You must be signed in to change notification settings - Fork 795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add deep-merge util #1503
Conversation
Signed-off-by: Naseem <[email protected]>
Codecov Report
@@ Coverage Diff @@
## master #1503 +/- ##
==========================================
+ Coverage 92.69% 93.18% +0.48%
==========================================
Files 152 156 +4
Lines 4409 4857 +448
Branches 846 987 +141
==========================================
+ Hits 4087 4526 +439
- Misses 322 331 +9
|
Thanks for comments @vmarchaud, ready for re-review. |
Signed-off-by: Naseem <[email protected]>
9092761
to
55f6cba
Compare
Signed-off-by: Naseem <[email protected]>
Signed-off-by: Naseem <[email protected]>
55f6cba
to
ce389d1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this implementation come from somewhere that we might need to include the original license, or was it written from scratch?
export function deepMerge( | ||
target: Record<string, any>, | ||
source: Record<string, any> | ||
) { | ||
const merged = target; | ||
for (const prop in source) { | ||
if (typeof source[prop] === 'object' && source[prop] !== null) { | ||
merged[prop] = deepMerge(target[prop], source[prop]); | ||
} else { | ||
merged[prop] = source[prop]; | ||
} | ||
} | ||
return merged; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function does no sort of cycle checking, which could cause an infinite CPU loop. This needs at the very least to be documented, but it might be nice to actually do some cycle checking. You don't need to do anything fancy like a Floyd's algorithm, but a simple maxDepth
optional parameter that defaults to 10 or something and decrements each time you recurse might be a good sanity check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, TIL
maxDepth param added... Can you provide a scenario where this could happen btw?
whats happened to previous version of this function I think it had more cases and code.
|
The code comments state that arrays should be replaced, not merged. In this case, I would expect |
Right, the comments are misleading, @obecny is correct. |
Was based off what I saw in a blog post, not sure which, I found this and this which both have the custom function this is based off of, it may have been one of these. It was changed quite a bit though. Shall I attribute them? |
…ride primtive target props Signed-off-by: Naseem <[email protected]>
Signed-off-by: Naseem <[email protected]>
…g own properties only Signed-off-by: Naseem <[email protected]>
00b6fdb
to
6570984
Compare
for (const [prop, value] of Object.entries(source)) { | ||
if (bothPropsAreArrays(target, source, prop)) { | ||
merged[prop] = []; | ||
merged[prop] = value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you set it first as an array and then override it with value ? If the last line
merged[prop] = value;
should win then this condition is not needed as it is exactly the same action as else
so you could simplify it to
if (bothPropsAreObjects(target, source, prop)) {
} else {
}
unless this is a bug and should be fixed differently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this one, as it stands the merged[prop]
at that time holds the target array as a value, but we want it to hold the source object's value however (as this util will replace arrays entirely). i.e. we want to replace its array value entirely, that's why i reset it first, unless there is a function to replace arrays I am unaware of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but you are assigning to merged[prop]
2 different values - one after another so it doesn't make sense to overrride it first with array ([]
) and then with value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes thanks. the initialization does seem unnecessary. I thought [4]
merged into [1,2,3]
would result in [4,2,3]
without the initialization but does not seem to be the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, PTAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok so now just last concern, you have here 3 conditions
if (bothPropsAreArrays(target, source, prop)) {
} else if (bothPropsAreObjects(target, source, prop)) {
else
Condition 1 and 3 returns the same, so as I mentioned at the beginning you can simplify it to
if (bothPropsAreObjects(target, source, prop)) {
} else {
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah right, so I tried that, in in fact both props being arrays does satisfy bothPropsAreObjects, in that case we do get the [4] merged into [1,2,3] resulting in [4,2,3] .
The alternative would be to have the function be bothPropsAreObjectsButNotArrays
or something less verbose that depicts that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you prefer a bothPripsAreObjectsButNotArrays
approach or the order-being-important 3 case approach as is now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a ok then that makes sense now if arrays are being detected also as an objects, I would leave it as it is then, just add comment that the first condition is needed t prevent array being parsed as objects, thx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just refactored the if statement to make it apparent without comment, PTAL
Signed-off-by: Naseem <[email protected]>
Signed-off-by: Naseem <[email protected]>
Signed-off-by: Naseem <[email protected]>
…es both props being objects but requires different logic Signed-off-by: Naseem <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Signed-off-by: Naseem <[email protected]>
Which problem is this PR solving?
Short description of the changes