2022-03-22 16:17:49 -04:00
|
|
|
/**
|
2022-10-04 17:46:12 -04:00
|
|
|
* @file Provides generic functions and constants.
|
2022-03-22 16:17:49 -04:00
|
|
|
*/
|
|
|
|
|
|
2022-10-13 14:42:22 -04:00
|
|
|
/**
|
|
|
|
|
* @type {RegExp} - Match all special characters.
|
|
|
|
|
*/
|
|
|
|
|
const regexUnescaped = /[\[\]\{\}\(\)\-\*\+\?\.\,\\\^\$\|\#\s]/g;
|
|
|
|
|
|
2022-10-04 17:46:12 -04:00
|
|
|
/**
|
|
|
|
|
* Quotes regular expression characters.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} str - The input string.
|
|
|
|
|
* @return {string} Returns the quoted (escaped) string.
|
|
|
|
|
*/
|
2022-10-13 14:42:22 -04:00
|
|
|
function escapeRegExp(str) {
|
2022-10-04 17:46:12 -04:00
|
|
|
return str.replace(regexUnescaped, '\\$&');
|
|
|
|
|
}
|
2022-03-22 16:17:49 -04:00
|
|
|
|
2022-10-04 17:46:12 -04:00
|
|
|
/**
|
|
|
|
|
* Creates a new object with all nested object properties
|
|
|
|
|
* concatenated into it recursively.
|
|
|
|
|
*
|
|
|
|
|
* Nested keys are flattened into a property path:
|
|
|
|
|
*
|
|
|
|
|
* ```js
|
|
|
|
|
* {
|
|
|
|
|
* a: {
|
|
|
|
|
* b: {
|
|
|
|
|
* c: 1
|
|
|
|
|
* }
|
|
|
|
|
* },
|
|
|
|
|
* d: 1
|
|
|
|
|
* }
|
|
|
|
|
* ```
|
|
|
|
|
*
|
|
|
|
|
* ```js
|
|
|
|
|
* {
|
|
|
|
|
* "a.b.c": 1,
|
|
|
|
|
* "d": 1
|
|
|
|
|
* }
|
|
|
|
|
* ```
|
|
|
|
|
*
|
|
|
|
|
* @param {object} input - The object to flatten.
|
|
|
|
|
* @param {string} prefix - The parent key prefix.
|
|
|
|
|
* @param {object} target - The object that will receive the flattened properties.
|
|
|
|
|
* @return {object} Returns the `target` object.
|
|
|
|
|
*/
|
2022-10-13 14:42:22 -04:00
|
|
|
function flatten(input, prefix, target = {}) {
|
2022-10-04 17:46:12 -04:00
|
|
|
for (const key in input) {
|
|
|
|
|
const field = (prefix ? prefix + '.' + key : key);
|
2022-03-22 16:17:49 -04:00
|
|
|
|
2022-10-04 17:46:12 -04:00
|
|
|
if (isObjectLike(input[key])) {
|
|
|
|
|
flatten(input[key], field, target);
|
|
|
|
|
} else {
|
|
|
|
|
target[field] = input[key];
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-22 16:17:49 -04:00
|
|
|
|
2022-10-04 17:46:12 -04:00
|
|
|
return target;
|
2022-03-22 16:17:49 -04:00
|
|
|
}
|
|
|
|
|
|
2022-10-04 17:46:12 -04:00
|
|
|
/**
|
|
|
|
|
* Determines whether the passed value is an `Object`.
|
|
|
|
|
*
|
|
|
|
|
* @param {*} value - The value to be checked.
|
|
|
|
|
* @return {boolean} Returns `true` if the value is an `Object`,
|
|
|
|
|
* otherwise `false`.
|
|
|
|
|
*/
|
2022-10-13 14:42:22 -04:00
|
|
|
function isObjectLike(value) {
|
2022-10-04 17:46:12 -04:00
|
|
|
return (value != null && typeof value === 'object');
|
|
|
|
|
}
|
2022-03-22 16:17:49 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a new object with all nested object properties
|
|
|
|
|
* merged into it recursively.
|
|
|
|
|
*
|
|
|
|
|
* @param {object} target - The target object.
|
|
|
|
|
* @param {object[]} ...sources - The source object(s).
|
|
|
|
|
* @throws {TypeError} If the target and source are the same.
|
|
|
|
|
* @return {object} Returns the `target` object.
|
|
|
|
|
*/
|
2022-10-13 14:42:22 -04:00
|
|
|
function merge(target, ...sources) {
|
2022-03-22 16:17:49 -04:00
|
|
|
for (const source of sources) {
|
|
|
|
|
if (target === source) {
|
|
|
|
|
throw new TypeError(
|
|
|
|
|
'Cannot merge, target and source are the same'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const key in source) {
|
|
|
|
|
if (source[key] != null) {
|
|
|
|
|
if (isObjectLike(source[key]) && isObjectLike(target[key])) {
|
|
|
|
|
merge(target[key], source[key]);
|
|
|
|
|
continue;
|
|
|
|
|
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
|
|
|
target[key] = target[key].concat(source[key]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target[key] = source[key];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 14:42:22 -04:00
|
|
|
export {
|
|
|
|
|
escapeRegExp,
|
|
|
|
|
flatten,
|
|
|
|
|
isObjectLike,
|
|
|
|
|
merge,
|
|
|
|
|
regexUnescaped,
|
|
|
|
|
};
|