Skip to content

Commit

Permalink
refactor(utils): add merge function (#45)
Browse files Browse the repository at this point in the history
* perf(utils): extract `lodash.merge`

* test: add test case

* refactor: optimize

* chore: revert `gitignore`

* refactor: update

Co-authored-by: John <John60676@qq.com>
  • Loading branch information
Duncan-zjp and John60676 authored May 22, 2021
1 parent 6a5b074 commit 4272062
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 4 deletions.
165 changes: 165 additions & 0 deletions src/__tests__/utils-merge.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { merge } from '../core/utils/lodash';

describe('utils', () => {
beforeAll(() => {});

beforeEach(() => {});

test('no other object are passed', () => {
const obj1 = {
a: [{ b: { c: 1 } }],
};

expect(merge(obj1)).toStrictEqual(obj1);
});

test('merge should work: case 1', () => {
const obj1 = {
a: [{ b: { c: 1 } }],
};
const obj2 = {
a: [{ b: { d: 2 } }],
};
expect(merge(obj1, obj2)).toStrictEqual({ a: [{ b: { c: 1, d: 2 } }] });
});

test('merge should work: case 2', () => {
const obj1 = {
a: [{ b: { c: 1 } }],
};
const obj2 = {
a: [{ b: { d: undefined } }],
};
expect(merge(obj1, obj2)).toStrictEqual({ a: [{ b: { c: 1 } }] });
});

test('merge should work: case 3', () => {
const obj1 = {
a: [{ b: { c: 1 } }],
};
const obj2 = {
a: [{ b: { c: undefined } }],
};
expect(merge(obj1, obj2)).toStrictEqual({ a: [{ b: { c: 1 } }] });
});

test('merge should work: case 4', () => {
const obj1 = {
a: [{ b: { c: 1 } }],
};
const obj2 = {
a: { b: { c: undefined } },
};
expect(JSON.stringify(merge(obj1, obj2))).toBe(`{"a":[{"b":{"c":1}}]}`);
});

test('merge should work: case 5', () => {
const obj1 = {
a: { b: { c: 1 } },
};
const obj2 = {
a: { b: { c: undefined, d: 2 } },
};
expect(merge(obj1, obj2)).toStrictEqual({ a: { b: { c: 1, d: 2 } } });
});

test('merge should work: case 6', () => {
const obj1 = {
a: { b: { c: 1 } },
};
const obj2 = {
a: 1,
};
expect(merge(obj1, obj2)).toStrictEqual({ a: 1 });
});

test('merge should work: case 7', () => {
const obj1 = {
a: { b: { c: 1 } },
};
const obj2 = {
a: {
b: {
c: () => {
console.log(123);
},
},
},
};
expect(merge(obj1, obj2)).toStrictEqual(obj2);
});

test('merge should work: case 8', () => {
const obj1 = {
a: [{ b: { b1: 123 } }],
};
const obj2 = {
a: [{ b: [1, 2] }],
};

expect(merge(obj1, obj2)).toStrictEqual({
a: [{ b: { 0: 1, 1: 2, b1: 123 } }],
});
});

test('merge should work: case 9', () => {
const object = {
a: [{ g: 3 }, { f: 5 }],
b: 123,
};

const other = {
b: null,
};

expect(merge(object, other)).toStrictEqual({
a: [{ g: 3 }, { f: 5 }],
b: null,
});
});

test('merge should work: case 10', () => {
const object = {
a: [{ g: 3 }, { f: 5 }],
b: 123,
};

const other = {
b: undefined,
};

expect(merge(object, other)).toStrictEqual({
a: [{ g: 3 }, { f: 5 }],
b: 123,
});
});

test('multi object merge should work', () => {
const object = {
a: [{ b: 2 }, { d: 4 }],
};

const other1 = {
a: [{ c: 3 }, { e: 5 }],
};

const other2 = {
a: [{ g: 3 }, { f: 5 }],
b: 123,
};

const other3 = {
b: {
my: 'name',
},
};

expect(merge(object, other1, other2, other3)).toStrictEqual({
a: [
{ b: 2, c: 3, g: 3 },
{ d: 4, e: 5, f: 5 },
],
b: { my: 'name' },
});
});
});
1 change: 1 addition & 0 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const isString = (val: unknown): val is string =>
toTypeString(val) === '[object String]';
export const isPlainObject = (val: unknown): val is Record<string, any> =>
toTypeString(val) === '[object Object]';
export const isArray = (val: unknown): val is any[] => Array.isArray(val);

export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object';
Expand Down
5 changes: 1 addition & 4 deletions src/core/utils/lodash/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
/**
* source by `lodash`
* https://github.com/lodash/lodash.git
*/
/* istanbul ignore next */
export { default as debounce } from './debounce';
export { default as throttle } from './throttle';
export { default as merge } from './merge';
37 changes: 37 additions & 0 deletions src/core/utils/lodash/merge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { isPlainObject, isArray, isObject } from '../index';

type MergeObject = Record<string, any>;

function baseMerge(origin: MergeObject, target: MergeObject) {
for (const key in target) {
if (target[key] === undefined) {
continue;
}

if (
!isObject(target[key]) || // `target[key]` is not an object
!isObject(origin[key]) || // `target[key]` is not an object
!(key in origin) // `key` is not in the origin object
) {
origin[key] = target[key];
continue;
}

if (isPlainObject(target[key]) || isArray(target[key])) {
baseMerge(origin[key], target[key]);
}
}
}

function merge(origin: MergeObject, ...others: MergeObject[]): any {
const result = Object.assign({}, origin);
if (!others.length) return result;

for (const item of others) {
baseMerge(result, item);
}

return result;
}

export default merge;

0 comments on commit 4272062

Please sign in to comment.