Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/utils/set.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export default function set<Entity = any, Output = Entity, Value = any>(
import get from './get';

function internalSet<Entity = any, Output = Entity, Value = any>(
entity: Entity,
paths: (string | number)[],
value: Value,
removeIfUndefined: boolean,
): Output {
if (!paths.length) {
return (value as unknown) as Output;
Expand All @@ -18,7 +21,31 @@ export default function set<Entity = any, Output = Entity, Value = any>(
clone = ({ ...entity } as unknown) as Output;
}

clone[path] = set(clone[path], restPath, value);
// Delete prop if `removeIfUndefined` and value is undefined
if (removeIfUndefined && value === undefined && restPath.length === 1) {
delete clone[path][restPath[0]];
} else {
clone[path] = internalSet(clone[path], restPath, value, removeIfUndefined);
}

return clone;
}

export default function set<Entity = any, Output = Entity, Value = any>(
entity: Entity,
paths: (string | number)[],
value: Value,
removeIfUndefined: boolean = false,
): Output {
// Do nothing if `removeIfUndefined` and parent object not exist
if (
paths.length &&
removeIfUndefined &&
value === undefined &&
!get(entity, paths.slice(0, -1))
) {
return (entity as unknown) as Output;
}

return internalSet(entity, paths, value, removeIfUndefined);
}
101 changes: 74 additions & 27 deletions tests/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,83 @@ describe('utils', () => {
);
});

it('set', () => {
expect(set(null, [], 233)).toEqual(233);
expect(set({}, ['light'], 'bamboo')).toEqual({ light: 'bamboo' });
expect(set({}, ['light', 'bamboo'], 'generate')).toEqual({
light: { bamboo: 'generate' },
});
expect(
set({ other: { next: 233 } }, ['light', 'bamboo'], 'generate'),
).toEqual({
other: { next: 233 },
light: { bamboo: 'generate' },
describe('set', () => {
it('basic', () => {
expect(set(null, [], 233)).toEqual(233);
expect(set({}, ['light'], 'bamboo')).toEqual({ light: 'bamboo' });
expect(set({}, ['light', 'bamboo'], 'generate')).toEqual({
light: { bamboo: 'generate' },
});
expect(
set({ other: { next: 233 } }, ['light', 'bamboo'], 'generate'),
).toEqual({
other: { next: 233 },
light: { bamboo: 'generate' },
});

expect(set([0, 1, 2], [1, 'light', 'bamboo'], 'next')).toEqual([
0,
{ light: { bamboo: 'next' } },
2,
]);
expect(
set({ light: 'bamboo', list: [0, 1, 2] }, ['list', '1'], 233),
).toEqual({
light: 'bamboo',
list: [0, 233, 2],
});
expect(set([[[[[0]]]]], [0, 0, 0, 0, 0], 'light')).toEqual([
[[[['light']]]],
]);
expect(set([[[[[0]]]]], [0, 0, 0, 0, 0, 0], 'bamboo')).toEqual([
[[[[['bamboo']]]]],
]);
});

expect(set([0, 1, 2], [1, 'light', 'bamboo'], 'next')).toEqual([
0,
{ light: { bamboo: 'next' } },
2,
]);
expect(
set({ light: 'bamboo', list: [0, 1, 2] }, ['list', '1'], 233),
).toEqual({
light: 'bamboo',
list: [0, 233, 2],
it('remove if undefined', () => {
// Skip not exist path
expect(set({}, ['notExist'], undefined, true)).toEqual({});

// Delete value
const target = set(
{ keep: { light: 2333 } },
['keep', 'light'],
undefined,
true,
);
expect(target).toEqual({ keep: {} });
expect('light' in target.keep).toBeFalsy();

// Mid path not exist
const midTgt = set(
{ lv1: { lv2: {} } },
['lv1', 'lv2', 'lv3'],
undefined,
true,
);
expect(midTgt).toEqual({ lv1: { lv2: {} } });
expect('lv3' in midTgt.lv1.lv2).toBeFalsy();

// Long path not exist
const longNotExistTgt = set(
{ lv1: { lv2: {} } },
['lv1', 'lv2', 'lv3', 'lv4'],
undefined,
true,
);
expect(longNotExistTgt).toEqual({ lv1: { lv2: {} } });
expect('lv3' in longNotExistTgt.lv1.lv2).toBeFalsy();

// Long path remove
const longTgt = set(
{ lv1: { lv2: { lv3: { lv4: { lv: 5 } } } } },
['lv1', 'lv2', 'lv3', 'lv4'],
undefined,
true,
);
expect(longTgt).toEqual({ lv1: { lv2: { lv3: {} } } });
expect('lv4' in longTgt.lv1.lv2.lv3).toBeFalsy();
});
expect(set([[[[[0]]]]], [0, 0, 0, 0, 0], 'light')).toEqual([
[[[['light']]]],
]);
expect(set([[[[[0]]]]], [0, 0, 0, 0, 0, 0], 'bamboo')).toEqual([
[[[[['bamboo']]]]],
]);
});

describe('pickAttrs', () => {
Expand Down