UNPKG

2.5 kBJavaScriptView Raw
1import lodashMerge from "lodash.merge";
2
3/**
4 * Check if a value is `null` or `undefined`
5 *
6 * @since 0.1.0
7 *
8 * @param {any|null|undefined} [item]
9 * @returns {item is null | undefined}
10 */
11export function isNil(item) {
12 return item === null || item === undefined;
13}
14
15/**
16 * Check if a value is a plain JavaScript object.
17 *
18 * @since 0.1.0
19 *
20 * @param {*} [item]
21 * @returns {boolean}
22 */
23export function isPlainObject(item) {
24 return (
25 typeof item === "object" &&
26 !isNil(item) &&
27 item.constructor === Object &&
28 Object.prototype.toString.call(item) === "[object Object]"
29 );
30}
31
32/**
33 * Deep merge source objects on to 'target'. Mutates 'target' in place.
34 *
35 * @function
36 * @since 0.1.0
37 *
38 * @type {(target: any, ...sources: any[]) => object}
39 * @param {object} target The destination object.
40 * @param {...object} [sources] The source objects.
41 * @returns {object} Returns `object`.
42 */
43export const merge = lodashMerge;
44
45/**
46 * Flatten nested objects in to a new object where the keys represent the original access
47 * path. Only goes through plain JavaScript objects and ignores arrays.
48 *
49 * @since 0.1.0
50 *
51 * @param {object} data The object to serialize
52 * @param {*} [result]
53 * @param {string} [path]
54 * @returns {Record<string, any>}
55 */
56export function flatten(data, result = {}, path = "") {
57 for (const key of Object.keys(data)) {
58 let resultPath = `${path}.${key}`;
59 if (path === "") {
60 resultPath = key;
61 }
62 const value = data[key];
63
64 if (!isPlainObject(value)) {
65 result[resultPath] = value;
66 } else {
67 flatten(value, result, resultPath);
68 }
69 }
70
71 return result;
72}
73
74/**
75 * The opposite of 'flatten'.
76 *
77 * @since 0.1.0
78 *
79 * @param {Record<string, any>} data
80 * @returns {object}
81 */
82export function unFlatten(data) {
83 const result = {};
84 for (const key of Object.keys(data)) {
85 const value = data[key];
86 const keyParts = key.split(".");
87
88 let tmpObject = result;
89 for (const part of keyParts.slice(0, keyParts.length - 1)) {
90 if (isNil(tmpObject[part]) || !isPlainObject(tmpObject[part])) {
91 tmpObject[part] = {};
92 }
93 tmpObject = tmpObject[part];
94 }
95 tmpObject[keyParts[keyParts.length - 1]] = value;
96 }
97
98 return result;
99}
100
101/**
102 *
103 * @since 0.1.0
104 *
105 * @param {string} input
106 * @returns {string}
107 */
108export function camelToSnakeCase(input) {
109 return input
110 .replace(/(.)([A-Z][a-z]+)/g, "$1_$2")
111 .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
112 .toLowerCase()
113 .trim();
114}