-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobject.library.ts
More file actions
115 lines (95 loc) · 3.79 KB
/
Copy pathobject.library.ts
File metadata and controls
115 lines (95 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { ownKeys, ownEntries } from '#library/primitive.library.js';
import { isObject, isArray, isReference, isFunction, isDefined, isNullish } from '#library/assertion.library.js';
import type { Extend, Property } from '#library/type.library.js';
/** remove quotes around property names */
export const unQuoteObj = (obj: any) => {
return JSON.stringify(obj)
?.replace(/"([^"]+)":/g, '$1: ')
?.replace(/,/g, ', ')
}
/** copy enumerable properties to a new Object */
export const asObject = <T>(obj?: Record<PropertyKey, any>) => {
if (isNullish(obj) || !isObject(obj))
return obj as T;
const temp: any = isArray(obj) ? [] : {};
ownKeys(obj)
.forEach(key => temp[key] = asObject(obj[key]));
return temp as T;
}
/** deep-compare object values for equality */
export const isEqual = (obj1: any = {}, obj2: any = {}): boolean => {
const keys = new Set<PropertyKey>(); // union of unique keys from both Objects
const keys1 = isFunction(obj1.keys) ? Array.from<PropertyKey>(obj1.keys()) : ownKeys(obj1);
const keys2 = isFunction(obj2.keys) ? Array.from<PropertyKey>(obj2.keys()) : ownKeys(obj2);
keys1.forEach(key => keys.add(key));
keys2.forEach(key => keys.add(key));
return [...keys] // cast as Array
.every(key => {
const val1 = obj1[key];
const val2 = obj2[key];
return isReference(val1) && isReference(val2)
? isEqual(val1, val2) // recurse into object
: val1 === val2
})
}
/** find all methods on an Object */
export const getMethods = (obj: any, all = false) => {
const properties = new Set<PropertyKey>();
let currentObj = obj;
do {
Object
.getOwnPropertyNames(currentObj)
.map(key => properties.add(key))
} while (all && (currentObj = Object.getPrototypeOf(currentObj)));
return [...properties.keys()]
.filter(key => isFunction(obj[key]));
}
/** extract only defined values from Object */
export function ifDefined<T extends Property<any>>(obj: T) {
return ownEntries(obj)
.reduce((acc, [key, val]) => {
if (isDefined<any>(val))
acc[key] = val;
return acc as T;
}, {} as T)
}
/** extract a subset of keys from an object */
export const pick = <T extends Property<T>, K extends string>(obj: T, ...keys: K[]): Partial<T> => {
const ownKeys = Object.getOwnPropertyNames(obj);
return keys.reduce((acc, key) => {
if (ownKeys.includes(key))
acc[key] = obj[key];
return acc;
}, {} as T);
}
/** extract a named key from an array of objects */
export const pluck = <T, K extends keyof T>(objs: T[], key: K): T[K][] =>
objs.map(obj => obj[key]);
/** extend an object with the properties of another */
export const extend = <T extends {}, U>(obj: T, ...objs: U[]) =>
Object.assign(obj, ...objs) as T;
export const countProperties = (obj = {}) =>
ownKeys(obj).length
/**
* helper to define objects with fixed literal properties
* and a loose index signature for further extensions.
* @example
* ```
* const obj = looseIndex<string,string>()({ foo: 'bar', bar: 'foo' });
* type obj = typeof obj
* ```
*/
export function looseIndex<K extends PropertyKey = string, V = any>(): <const T extends object>(obj: T | (() => T)) => Extend<T, K, V>;
export function looseIndex<const T extends object>(obj: T | (() => T)): Extend<T, string, any>;
export function looseIndex(arg?: any): any {
if (isDefined(arg)) return isFunction(arg) ? arg() : arg;
return (obj: any) => isFunction(obj) ? obj() : obj;
}
/** loose object with symbols values */
looseIndex.stringSymbol = looseIndex<string, symbol>();
/** loose object with symbol keys and RegExp values */
looseIndex.symbolRegExp = looseIndex<symbol, RegExp>();
/** loose object with symbol keys and string values */
looseIndex.symbolString = looseIndex<symbol, string>();
/** loose object with string keys and string values */
looseIndex.stringString = looseIndex<string, string>();