svelte-ux
Version:
- Increment version in `package.json` and commit as `Version bump to x.y.z` - `npm run publish`
142 lines (141 loc) • 4.84 kB
JavaScript
import { get, camelCase, mergeWith } from 'lodash-es';
import { entries } from '../types/typeHelpers';
export function isLiteralObject(obj) {
return obj && typeof obj === 'object' && obj.constructor === Object;
}
export function camelCaseKeys(obj) {
return Object.keys(obj).reduce((acc, key) => ((acc[camelCase(key)] = obj[key]), acc), {});
}
// https://codereview.stackexchange.com/questions/73714/find-a-nested-property-in-an-object
// https://github.com/dominik791/obj-traverse
export function nestedFindByPredicate(obj, predicate, childrenProp) {
const getChildrenProp = propAccessor(childrenProp !== null && childrenProp !== void 0 ? childrenProp : 'children');
if (predicate(obj)) {
return obj;
}
else {
const children = getChildrenProp(obj);
if (children) {
for (let o of children) {
const match = nestedFindByPredicate(o, predicate, childrenProp);
if (match) {
return match;
}
}
}
}
}
export function propAccessor(prop) {
return typeof prop === 'function'
? prop
: typeof prop === 'string'
? (d) => get(d, prop)
: (x) => x;
}
/**
* Produce a unique Id for an object (helpful for debugging)
* See: https://stackoverflow.com/a/35306050/191902
*/
var objIdMap = new WeakMap(), objectCount = 0;
export function objectId(object) {
if (!objIdMap.has(object))
objIdMap.set(object, ++objectCount);
return objIdMap.get(object);
}
export function distinctKeys(...objs) {
const keys = [...new Set(flatten(objs.map((x) => Object.keys(x))))];
return keys;
}
// Copied from `array.ts` to remove circular dependency
function flatten(items) {
return items.reduce((prev, next) => prev.concat(next), []);
}
/**
* Recursive merge objects
* @param object The destination object
* @param source The source object
* @returns
*/
export function merge(object, source) {
return mergeWith(object, source, (objValue, srcValue) => {
if (Array.isArray(srcValue)) {
// Overwrite instead of merging by index with objValue (like standard lodash `merge` does)
return srcValue;
}
});
}
/**
* Remove properties from object based on expiration
*/
export function expireObject(object, expiry) {
const now = new Date();
if (expiry instanceof Date && expiry < now) {
// Expired
return null;
}
else if (typeof expiry === 'object') {
for (let [prop, propExpiry] of Object.entries(expiry)) {
if (propExpiry instanceof Date) {
// Check if expired
if (propExpiry < now) {
if (prop === '$default') {
// Delete all properties which do not have explicit expiry to check
for (let [objProp, value] of Object.entries(object)) {
if (!(objProp in expiry)) {
delete object[objProp];
}
}
// Remove expired `$default` property
delete object[prop];
}
else {
// Remove expired property
delete object[prop];
}
}
else {
// Keep value
}
}
else {
// Check expiry for each property in object. Skip if prop not in object (expiry only)
if (prop in object) {
expireObject(object[prop], propExpiry);
}
// Remove property if empty object (all properties removed)
if (isLiteralObject(object[prop]) && Object.keys(object[prop]).length === 0) {
delete object[prop];
}
}
}
}
return isLiteralObject(object) && Object.keys(object).length === 0 ? null : object;
}
/**
* Remove properties from an object. See also lodash `_.omit()`
*/
export function omit(obj, keys) {
if (keys.length === 0) {
return obj;
}
else {
return Object.fromEntries(Object.entries(obj).filter(([key, value]) => !keys.includes(key)));
}
}
/**
* Pick properties from an object. See also lodash `_.pick()`
*/
export function pick(obj, keys) {
if (keys.length === 0) {
return obj;
}
else {
return Object.fromEntries(keys.filter((key) => key in obj).map((key) => [key, obj[key]]));
}
}
/**
* Create new object with keys and values swapped. Last value's key is used if duplicated
*/
export function keysByValues(obj) {
return Object.fromEntries(entries(obj).map(([key, value]) => [value, key]));
}