Skip to content

Commit 0b46d08

Browse files
committed
feat(utils): include getters and setters utils
1 parent 3c18d14 commit 0b46d08

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

src/utils/getters-setters.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
export function splitPath(path) {
2+
return path
3+
.replace(/]/g, '')
4+
.split(/[.[]/)
5+
.map((path, index, paths) => {
6+
const def = { path };
7+
8+
if (parseInt(paths[index + 1], 10).toString() === paths[index + 1]) {
9+
def.couldBeAnArray = true;
10+
}
11+
12+
return def;
13+
});
14+
}
15+
16+
export function getValueByPath(obj, objPath) {
17+
const paths = splitPath(objPath);
18+
19+
return paths.reduce((cursor, { path }) => {
20+
if (typeof cursor === 'undefined') {
21+
return;
22+
}
23+
24+
if (!path) {
25+
return cursor;
26+
}
27+
28+
return cursor[path];
29+
}, obj);
30+
}
31+
32+
export function setValueByPath(obj, objPath, value) {
33+
const paths = splitPath(objPath);
34+
35+
if (paths.length === 1) {
36+
obj[objPath] = value;
37+
38+
return obj;
39+
}
40+
41+
const { path: lastPath } = paths[paths.length - 1];
42+
const remainingPaths = paths.slice(0, paths.length - 1);
43+
44+
const lastCursor = remainingPaths.reduce((cursor, { path, couldBeAnArray }) => {
45+
if (!path) {
46+
return cursor || (couldBeAnArray ? [] : {});
47+
}
48+
49+
if (!cursor[path]) {
50+
cursor[path] = couldBeAnArray ? [] : {};
51+
}
52+
53+
return cursor[path];
54+
}, obj);
55+
56+
lastCursor[lastPath] = value;
57+
58+
return obj || lastCursor;
59+
}

test/getters-setters.test.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { setValueByPath, getValueByPath, splitPath } from '../src/utils/getters-setters';
2+
3+
test('splitPath should split path strings into hierarchical components', () => {
4+
expect(splitPath('a.b.0.c')).toStrictEqual([
5+
{ path: 'a' },
6+
{ path: 'b', couldBeAnArray: true },
7+
{ path: '0' },
8+
{ path: 'c' },
9+
]);
10+
expect(splitPath('a.b[0].c.d')).toStrictEqual([
11+
{ path: 'a' },
12+
{ path: 'b', couldBeAnArray: true },
13+
{ path: '0' },
14+
{ path: 'c' },
15+
{ path: 'd' },
16+
]);
17+
expect(splitPath('a[0].b[2].c[3].d')).toStrictEqual([
18+
{ path: 'a', couldBeAnArray: true },
19+
{ path: '0' },
20+
{ path: 'b', couldBeAnArray: true },
21+
{ path: '2' },
22+
{ path: 'c', couldBeAnArray: true },
23+
{ path: '3' },
24+
{ path: 'd' },
25+
]);
26+
});
27+
28+
test('setValueByPath should set values inside complex objects', () => {
29+
expect(setValueByPath({}, 'a', 4)).toStrictEqual({ a: 4 });
30+
expect(setValueByPath({}, 'a.b', 5)).toStrictEqual({ a: { b: 5 } });
31+
expect(setValueByPath({}, 'a[0]', 6)).toStrictEqual({ a: [6] });
32+
expect(setValueByPath({ a: {} }, 'a[0]', 6)).toStrictEqual({ a: { '0': 6 } });
33+
expect(setValueByPath({}, 'a[0].b', 6)).toStrictEqual({ a: [{ b: 6 }] });
34+
expect(setValueByPath({}, '[1]', 'abc')).toStrictEqual({ '1': 'abc' });
35+
// eslint-disable-next-line no-sparse-arrays
36+
expect(setValueByPath(null, '[1]', 'abc')).toStrictEqual([, 'abc']);
37+
});
38+
39+
test('getValueByPath should get path value of complex objects', () => {
40+
expect(getValueByPath({}, 'a')).toBe(undefined);
41+
expect(getValueByPath({}, '[0]')).toBe(undefined);
42+
expect(getValueByPath([1, 'h'], '[1]')).toBe('h');
43+
expect(getValueByPath([{ a: 'h' }], '[0].a')).toBe('h');
44+
expect(getValueByPath({}, 'a.b')).toBe(undefined);
45+
expect(getValueByPath({ a: [6] }, 'a[0]')).toBe(6);
46+
expect(getValueByPath({ a: { '0': 6 } }, 'a[0]')).toBe(6);
47+
expect(getValueByPath({ a: [2, { b: [3, 4, 5, { c: { d: 'efg' } }] }] }, 'a[1].b.3.c')).toStrictEqual({ d: 'efg' });
48+
});

0 commit comments

Comments
 (0)