just-merge is not working as expected
R35007 opened this issue · 7 comments
R35007 commented
Sample Input
const obj1 = {
"appName": "React",
"tags": ["react", 'mfe'],
"fields": {
"appName": {"type": "checkbox"},
"template": {"type": "textbox","options": [{"label": "opt1"}, {}, {"label": "opt3","value": "value3"}, {"label": "opt4","value": "value4"},{"label": "opt5","value": "value5"}]},
"projectName": {"type": "textbox"}
}
}
const obj2 = {
"appName": "React",
"tags": ["frontend"],
"fields": {
"appName": {"type": "checkbox","value": true,"label": "Confirm"},
"template": {"type": "radio","options": [{"value": "value1"},{"label": "opt2","value": "value2"}, {}, {"label": "opt4","value": "value4"}]},
"skipInstall": {"type": "checkbox","label": "Should Skip Install ?"}
}
}
Expected Output
{
"appName": "React",
"tags": ["react", "frontend", "mfe"],
"fields": {
"appName": { "type": "checkbox", "value": true, "label": "Confirm" },
"template": {
"type": "radio",
"options": [
{ "label": "opt1", "value": "value1" },
{ "label": "opt2", "value": "value2" },
{ "label": "opt3", "value": "value3" },
{ "label": "opt4", "value": "value4" },
{ "label": "opt5", "value": "value5" }
]
},
"projectName": { "type": "textbox" },
"skipInstall": { "type": "checkbox", "label": "Should Skip Install ?" }
}
}
But What I get is
{
"appName": "React",
"tags": ["frontend"],
"fields": {
"appName": { "type": "checkbox", "value": true, "label": "Confirm" },
"template": {
"type": "radio",
"options": [
{ "value": "value1" },
{ "label": "opt2", "value": "value2" },
{},
{ "label": "opt4", "value": "value4" }
]
},
"skipInstall": { "type": "checkbox", "label": "Should Skip Install ?" }
}
}
uncenter commented
I believe you want to be using just-extend
, not just-merge
. Try extend(true, obj1, obj2)
.
R35007 commented
I believe you want to be using
just-extend
, notjust-merge
. Tryextend(true, obj1, obj2)
.
Tried that as well. still not getting the expected result
uncenter commented
What is the difference between expected and what you are getting exactly?
R35007 commented
{ "appName": "React", "tags": ["frontend", "mfe"], "fields": { "appName": { "type": "checkbox", "value": true, "label": "Confirm" }, "template": { "type": "radio", "options": [ { "label": "opt1", "value": "value1" }, { "label": "opt2", "value": "value2" }, { "label": "opt3", "value": "value3" }, { "label": "opt4", "value": "value4" }, { "label": "opt5", "value": "value5" } ] }, "projectName": { "type": "textbox" }, "skipInstall": { "type": "checkbox", "label": "Should Skip Install ?" } } }
Have already share u what I get and what is expected.
the arrays are not merging. its just replacing it on index.
R35007 commented
This is what I get
{
"appName": "React",
"tags": ["frontend"],
"fields": {
"appName": { "type": "checkbox", "value": true, "label": "Confirm" },
"template": {
"type": "radio",
"options": [{ "value": "value1" }, { "label": "opt2", "value": "value2" }, {}, { "label": "opt4", "value": "value4" }]
},
"skipInstall": { "type": "checkbox", "label": "Should Skip Install ?" }
}
}
uncenter commented
Ah yeah I was also noticing that! But in your "expected" version you left a bit with that behavior so I thought that is what you wanted.
R35007 commented
const isArray = (val: unknown) => !!(val && typeof val === 'object' && Array.isArray(val));
const isPlainObject = (val: unknown) => !!(val && typeof val === 'object' && !isArray(val));
const isCollection = (val: unknown): val is Array<object> => !!(val && isArray(val) && val.length && val.every(isPlainObject));
const isMatrix = (val: unknown): val is Array<unknown[]> => !!(val && isArray(val) && val.length && val.every(isArray));
const isPrimitive = (val: unknown) => !!(val && typeof val !== 'object');
const getValuesByKey = (args: object[], keyName: string) =>
args
.map((obj) =>
Object.entries(obj)
.filter(([key]) => key === keyName)
.map(([, value]) => value)
)
.flat();
const getValuesByIndex = (args: Array<unknown[]>, index: number) => args.map((arr) => arr[index]).flat();
function mergeDeep(...args: unknown[]): object | unknown[] {
if (isCollection(args)) {
const allKeys = args.map((obj) => Object.entries(obj).map(([key]) => key)).flat();
const entries = allKeys.map((key) => {
const values = getValuesByKey(args as object[], key);
return values.every(isPrimitive) ? [key, values[values.length - 1]] : [key, mergeDeep(...values)];
});
return Object.fromEntries(entries);
}
if (isMatrix(args)) {
const maxArrayLength = args.reduce((acc, item) => (acc >= item.length ? acc : item.length), 0);
return [...Array(maxArrayLength).keys()].map((index) => mergeDeep(...getValuesByIndex(args, index))).flat();
}
return [...new Set(args)].filter(Boolean);
}
export default mergeDeep;
This is what I have comeup with. Feel free to use it for merge or expand