Skip to content

Commit

Permalink
fix setAtPath in "merge" mode was sometimes converting strings to obj…
Browse files Browse the repository at this point in the history
…ects
  • Loading branch information
jmeistrich committed Aug 25, 2024
1 parent d6b75fb commit d3ff0b2
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
31 changes: 20 additions & 11 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function setAtPath<T extends object>(
} else if (o[p] === undefined && value === undefined && i === path.length - 1) {
// If setting undefined and the key is undefined, no need to initialize or set it
return obj;
} else if (o[p] === undefined || o[p] === null) {
} else if (i < path.length - 1 && (o[p] === undefined || o[p] === null)) {
const child = initializePathType(pathTypes[i]);
if (isMap(o)) {
o.set(p, child);
Expand Down Expand Up @@ -219,21 +219,30 @@ export function deepMerge<T>(target: T, ...sources: any[]): T {
return sources[sources.length - 1];
}

const result: T = (isArray(target) ? [...target] : { ...target }) as T;
let result: T = (isArray(target) ? [...target] : { ...target }) as T;

for (let i = 0; i < sources.length; i++) {
const obj2 = sources[i];
for (const key in obj2) {
if (hasOwnProperty.call(obj2, key)) {
if (obj2[key] instanceof Object && !isObservable(obj2[key]) && Object.keys(obj2[key]).length > 0) {
(result as any)[key] = deepMerge(
(result as any)[key] || (isArray((obj2 as any)[key]) ? [] : {}),
(obj2 as any)[key],
);
} else {
(result as any)[key] = obj2[key];
if (isObject(obj2) || isArray(obj2)) {
const objTarget = obj2 as Record<string, any>;
for (const key in objTarget) {
if (hasOwnProperty.call(objTarget, key)) {
if (
objTarget[key] instanceof Object &&
!isObservable(objTarget[key]) &&
Object.keys(objTarget[key]).length > 0
) {
(result as any)[key] = deepMerge(
(result as any)[key] || (isArray((objTarget as any)[key]) ? [] : {}),
(objTarget as any)[key],
);
} else {
(result as any)[key] = objTarget[key];
}
}
}
} else {
result = obj2;
}
}

Expand Down
45 changes: 45 additions & 0 deletions tests/tests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3351,6 +3351,51 @@ describe('setAtPath', () => {
expect(Object.keys(res)).toEqual([]);
expect(res).toEqual({});
});
test('Set on empty object', () => {
const value = {};

const res = setAtPath(value, ['key', 'status'], ['object', 'object'], 'Completed');

expect(res).toEqual({ key: { status: 'Completed' } });
});
test('Set with merge on empty object', () => {
const value = {};

const res = setAtPath(value, ['key', 'status'], ['object', 'object'], 'Completed', 'merge');

expect(res).toEqual({ key: { status: 'Completed' } });
});
test('Set with merge on array', () => {
const value = {
arr: [{ id: 1 }, { id: 2 }, { id: 3 }],
};

const res = setAtPath(value, ['arr', '1', 'id'], ['object', 'object', 'object'], 22, 'merge');

expect(res).toEqual({ arr: [{ id: 1 }, { id: 22 }, { id: 3 }] });
});
test('Set on object with existing key', () => {
const value = {
key: {
sessionId: 'zz',
},
};

const res = setAtPath(value, ['key', 'status'], ['object', 'object'], 'Completed');

expect(res).toEqual({ key: { sessionId: 'zz', status: 'Completed' } });
});
test('Set with merge on object with existing key', () => {
const value = {
key: {
sessionId: 'zz',
},
};

const res = setAtPath(value, ['key', 'status'], ['object', 'object'], 'Completed', 'merge');

expect(res).toEqual({ key: { sessionId: 'zz', status: 'Completed' } });
});
});
describe('new computed', () => {
test('new computed basic', () => {
Expand Down

0 comments on commit d3ff0b2

Please sign in to comment.