typeshi 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/object.d.ts +10 -2
- package/dist/utils/object.js +35 -4
- package/dist/utils/regex/email.d.ts +27 -4
- package/dist/utils/regex/email.js +39 -8
- package/dist/utils/regex/stringOperations.d.ts +5 -2
- package/dist/utils/regex/stringOperations.js +6 -3
- package/dist/utils/typeValidation.d.ts +32 -61
- package/dist/utils/typeValidation.js +71 -103
- package/dist/utils/utilityTypes.d.ts +40 -0
- package/dist/utils/utilityTypes.js +5 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Copy/paste into your project if you find something useful.
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -21,4 +21,5 @@ __exportStar(require("./io"), exports);
|
|
|
21
21
|
__exportStar(require("./regex"), exports);
|
|
22
22
|
__exportStar(require("./argumentValidation"), exports);
|
|
23
23
|
__exportStar(require("./typeValidation"), exports);
|
|
24
|
+
__exportStar(require("./utilityTypes"), exports);
|
|
24
25
|
__exportStar(require("./object"), exports);
|
package/dist/utils/object.d.ts
CHANGED
|
@@ -54,8 +54,7 @@ export declare function picked<T extends object, K extends keyof T>(obj: T, keys
|
|
|
54
54
|
* - `'FIFO'` - remove elements from front (`'First-In-First-Out'`)
|
|
55
55
|
* @note **assumes newest elements were pushed to end** i.e. `stack.push()` or `queue.enque()`
|
|
56
56
|
* @param inPlace `boolean (optional)` `default = true`
|
|
57
|
-
* - `true` - modify and return original array
|
|
58
|
-
* - - if `'LIFO'`, can use JS trick by setting `arr.length = maxLength`
|
|
57
|
+
* - `true` - modify and return original array using: `arr.length = maxLength (LIFO)` or `arr.splice() (FIFO)`
|
|
59
58
|
* - `false` - return new array with: `arr.slice()` `arr.slice(0, maxLength) (LIFO) or arr.slice(i, n) (FIFO)` where `n - i === maxLength`
|
|
60
59
|
* @returns **`arr`** `T[]` where `arr.length <= maxLength`
|
|
61
60
|
*/
|
|
@@ -101,3 +100,12 @@ export declare function hasDefinedEntry<T extends object>(obj: any, key: keyof T
|
|
|
101
100
|
export declare function containsKey<T extends object, K extends (keyof T | (keyof any & {})) = any>(obj: T, ...keys: K[]): obj is {
|
|
102
101
|
[K in keyof T]: T[K];
|
|
103
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* @deprecated
|
|
105
|
+
* @param objA `Record<string, any>`
|
|
106
|
+
* @param objB `Record<string, any>`
|
|
107
|
+
* @returns **`areEquivalentObjects`** `boolean`
|
|
108
|
+
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
109
|
+
* - `false` `otherwise`.
|
|
110
|
+
*/
|
|
111
|
+
export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
|
package/dist/utils/object.js
CHANGED
|
@@ -11,7 +11,9 @@ exports.picked = picked;
|
|
|
11
11
|
exports.enforceMaxLength = enforceMaxLength;
|
|
12
12
|
exports.hasDefinedEntry = hasDefinedEntry;
|
|
13
13
|
exports.containsKey = containsKey;
|
|
14
|
+
exports.areEquivalentObjects = areEquivalentObjects;
|
|
14
15
|
const typeValidation_1 = require("./typeValidation");
|
|
16
|
+
const index_1 = require("./regex/index");
|
|
15
17
|
/**
|
|
16
18
|
* @param obj `S` - source object (e.g., Request Body)
|
|
17
19
|
* @param schema {@link TransformationSchema}`<T, S>` - map of keys to transformation functions.
|
|
@@ -90,8 +92,7 @@ function picked(obj, keys) {
|
|
|
90
92
|
* - `'FIFO'` - remove elements from front (`'First-In-First-Out'`)
|
|
91
93
|
* @note **assumes newest elements were pushed to end** i.e. `stack.push()` or `queue.enque()`
|
|
92
94
|
* @param inPlace `boolean (optional)` `default = true`
|
|
93
|
-
* - `true` - modify and return original array
|
|
94
|
-
* - - if `'LIFO'`, can use JS trick by setting `arr.length = maxLength`
|
|
95
|
+
* - `true` - modify and return original array using: `arr.length = maxLength (LIFO)` or `arr.splice() (FIFO)`
|
|
95
96
|
* - `false` - return new array with: `arr.slice()` `arr.slice(0, maxLength) (LIFO) or arr.slice(i, n) (FIFO)` where `n - i === maxLength`
|
|
96
97
|
* @returns **`arr`** `T[]` where `arr.length <= maxLength`
|
|
97
98
|
*/
|
|
@@ -116,7 +117,7 @@ function enforceMaxLength(arr, maxLength, principle = 'LIFO', inPlace = true) {
|
|
|
116
117
|
if (principle === 'LIFO') {
|
|
117
118
|
arr.length = maxLength;
|
|
118
119
|
}
|
|
119
|
-
else {
|
|
120
|
+
else { // 'FIFO'
|
|
120
121
|
arr.splice(0, excess);
|
|
121
122
|
}
|
|
122
123
|
return arr;
|
|
@@ -125,7 +126,7 @@ function enforceMaxLength(arr, maxLength, principle = 'LIFO', inPlace = true) {
|
|
|
125
126
|
if (principle === 'LIFO') {
|
|
126
127
|
return arr.slice(0, maxLength);
|
|
127
128
|
}
|
|
128
|
-
else {
|
|
129
|
+
else { // 'FIFO'
|
|
129
130
|
return arr.slice(excess);
|
|
130
131
|
}
|
|
131
132
|
}
|
|
@@ -178,3 +179,33 @@ function containsKey(obj, ...keys) {
|
|
|
178
179
|
}
|
|
179
180
|
return true;
|
|
180
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* @deprecated
|
|
184
|
+
* @param objA `Record<string, any>`
|
|
185
|
+
* @param objB `Record<string, any>`
|
|
186
|
+
* @returns **`areEquivalentObjects`** `boolean`
|
|
187
|
+
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
188
|
+
* - `false` `otherwise`.
|
|
189
|
+
*/
|
|
190
|
+
function areEquivalentObjects(objA, objB) {
|
|
191
|
+
if (!(0, typeValidation_1.isObject)(objA) || !(0, typeValidation_1.isObject)(objB))
|
|
192
|
+
return false;
|
|
193
|
+
const keysA = Object.keys(objA);
|
|
194
|
+
const keysB = Object.keys(objB);
|
|
195
|
+
if (keysA.length !== keysB.length)
|
|
196
|
+
return false;
|
|
197
|
+
return keysA.every(key => {
|
|
198
|
+
if (!containsKey(objB, key))
|
|
199
|
+
return false; // key not in both objects
|
|
200
|
+
const valA = objA[key];
|
|
201
|
+
const valB = objB[key];
|
|
202
|
+
if (Array.isArray(valA) && Array.isArray(valB)) {
|
|
203
|
+
return valA.length === valB.length
|
|
204
|
+
&& valA.every((item) => valB.includes(item));
|
|
205
|
+
}
|
|
206
|
+
else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
|
|
207
|
+
return areEquivalentObjects(valA, valB);
|
|
208
|
+
}
|
|
209
|
+
return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
export interface ParsedEmailAddress {
|
|
2
|
+
/** the whole email address */
|
|
3
|
+
address: string;
|
|
4
|
+
/** `localPart` the part before the @ sign */
|
|
5
|
+
local: string;
|
|
6
|
+
/** the part after the @ sign */
|
|
7
|
+
domain: string;
|
|
8
|
+
/** sender's display name if present in source string */
|
|
9
|
+
displayName?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @param s `string`
|
|
13
|
+
* - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
|
|
14
|
+
* @returns **`result`** {@link ParsedEmailAddress}` | null`
|
|
15
|
+
* @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
|
|
16
|
+
* - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseEmailAddress(s: string): ParsedEmailAddress | null;
|
|
19
|
+
/** @deprecated
|
|
20
|
+
* `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
|
|
2
21
|
export declare const EMAIL_REGEX: RegExp;
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated
|
|
24
|
+
* return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
|
|
25
|
+
export declare function isValidEmail(email: string, excludeSubstrings?: string | string[] | RegExp): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated
|
|
28
|
+
* @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
|
|
6
29
|
export declare function extractEmail(email: string): RegExpMatchArray | null;
|
|
@@ -1,24 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EMAIL_REGEX = void 0;
|
|
4
|
+
exports.parseEmailAddress = parseEmailAddress;
|
|
4
5
|
exports.isValidEmail = isValidEmail;
|
|
5
6
|
exports.extractEmail = extractEmail;
|
|
6
7
|
/**
|
|
7
8
|
* @file src/utils/regex/email.ts
|
|
8
9
|
*/
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const Str_1 = require("./Str");
|
|
11
|
+
/**
|
|
12
|
+
* @param s `string`
|
|
13
|
+
* - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
|
|
14
|
+
* @returns **`result`** {@link ParsedEmailAddress}` | null`
|
|
15
|
+
* @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
|
|
16
|
+
* - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
|
|
17
|
+
*/
|
|
18
|
+
function parseEmailAddress(s) {
|
|
19
|
+
const emailRegex = /([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
|
|
20
|
+
const matchArrays = Array.from(s.matchAll(emailRegex));
|
|
21
|
+
if (matchArrays.length === 0)
|
|
22
|
+
return null;
|
|
23
|
+
const match = matchArrays[0];
|
|
24
|
+
const [address, local, domain] = match;
|
|
25
|
+
const displayName = (s
|
|
26
|
+
.slice(0, match.index ?? 0)
|
|
27
|
+
.trim()
|
|
28
|
+
.replace(/^no(-)?reply\s*(?=\w)/i, '')
|
|
29
|
+
.replace(/<$/, '')
|
|
30
|
+
.trim());
|
|
31
|
+
const result = { address, local, domain };
|
|
32
|
+
if (displayName)
|
|
33
|
+
result.displayName = displayName;
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/** @deprecated
|
|
37
|
+
* `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
|
|
38
|
+
exports.EMAIL_REGEX = new RegExp(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated
|
|
41
|
+
* return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
|
|
14
42
|
function isValidEmail(email, excludeSubstrings) {
|
|
15
43
|
if (!email)
|
|
16
44
|
return false;
|
|
17
45
|
email = email.trim();
|
|
18
|
-
return
|
|
19
|
-
|
|
46
|
+
return (excludeSubstrings
|
|
47
|
+
? exports.EMAIL_REGEX.test(email) && !Str_1.Str.contains(email, excludeSubstrings)
|
|
48
|
+
: exports.EMAIL_REGEX.test(email));
|
|
20
49
|
}
|
|
21
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* @deprecated
|
|
52
|
+
* @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
|
|
22
53
|
function extractEmail(email) {
|
|
23
54
|
if (!email)
|
|
24
55
|
return null;
|
|
@@ -40,6 +40,9 @@ export declare function stringContainsAnyOf(s: string, substrings: string | stri
|
|
|
40
40
|
* - **`false`** `otherwise`.
|
|
41
41
|
*/
|
|
42
42
|
export declare function equivalentAlphanumericStrings(s1: string, s2: string, tolerance?: number): boolean;
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated
|
|
45
|
+
* for simple regular expressions...
|
|
46
|
+
* so like not ones that have parentheses, pipes, or curly braced numbers
|
|
47
|
+
* */
|
|
45
48
|
export declare function extractSource(regex: RegExp): string;
|
|
@@ -128,7 +128,7 @@ function stringContainsAnyOf(s, substrings, ...flags) {
|
|
|
128
128
|
regex = new RegExp(substrings, flagString);
|
|
129
129
|
}
|
|
130
130
|
if (!regex) {
|
|
131
|
-
config_1.typeshiLogger.warn('containsAnyOf() Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
|
|
131
|
+
config_1.typeshiLogger.warn('[containsAnyOf()] Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
|
|
132
132
|
return false; // Invalid substrings type
|
|
133
133
|
}
|
|
134
134
|
return regex.test(s);
|
|
@@ -178,8 +178,11 @@ function equivalentAlphanumericStrings(s1, s2, tolerance = 0.90) {
|
|
|
178
178
|
}
|
|
179
179
|
return false;
|
|
180
180
|
}
|
|
181
|
-
/**
|
|
182
|
-
*
|
|
181
|
+
/**
|
|
182
|
+
* @deprecated
|
|
183
|
+
* for simple regular expressions...
|
|
184
|
+
* so like not ones that have parentheses, pipes, or curly braced numbers
|
|
185
|
+
* */
|
|
183
186
|
function extractSource(regex) {
|
|
184
187
|
if (!regex)
|
|
185
188
|
return '';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - **`true`** if `value` is an array and has at least one element,
|
|
8
8
|
* - **`false`** otherwise.
|
|
9
9
|
*/
|
|
10
|
-
export declare function isNonEmptyArray<T>(value:
|
|
10
|
+
export declare function isNonEmptyArray<T>(value: unknown): value is Array<T> & {
|
|
11
11
|
length: number;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
@@ -16,7 +16,7 @@ export declare function isNonEmptyArray<T>(value: any): value is Array<T> & {
|
|
|
16
16
|
* - **`true`** if `value` is an array and has no elements,
|
|
17
17
|
* - **`false`** `otherwise`
|
|
18
18
|
*/
|
|
19
|
-
export declare function isEmptyArray<T>(value:
|
|
19
|
+
export declare function isEmptyArray<T>(value: unknown): value is Array<T> & {
|
|
20
20
|
length: 0;
|
|
21
21
|
};
|
|
22
22
|
/**
|
|
@@ -27,13 +27,12 @@ export declare function isEmptyArray<T>(value: any): value is Array<T> & {
|
|
|
27
27
|
* - `if` `false` then `value` can be empty array
|
|
28
28
|
* @returns **`isIntegerArray`** `boolean` = `value is number[] & { length: number }`
|
|
29
29
|
*/
|
|
30
|
-
export declare function isIntegerArray(value:
|
|
30
|
+
export declare function isIntegerArray(value: unknown, requireNonNegative?: boolean, requireNonEmpty?: boolean): value is number[] & {
|
|
31
31
|
length: number;
|
|
32
32
|
};
|
|
33
33
|
/**
|
|
34
|
-
* @consideration add param to allow for empty strings?
|
|
35
34
|
* @param value `any`
|
|
36
|
-
* @param requireNonEmpty `boolean` `default = true`
|
|
35
|
+
* @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
|
|
37
36
|
* - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
|
|
38
37
|
* - `if` `false` then `value` can be empty array
|
|
39
38
|
* @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
|
|
@@ -41,40 +40,6 @@ export declare function isIntegerArray(value: any, requireNonNegative?: boolean,
|
|
|
41
40
|
export declare function isStringArray(value: any, requireNonEmpty?: boolean): value is string[] & {
|
|
42
41
|
length: number;
|
|
43
42
|
};
|
|
44
|
-
/**
|
|
45
|
-
* `fka hasNonTrivialKeys`
|
|
46
|
-
* @note **passing in an array will return `false`.**
|
|
47
|
-
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
48
|
-
* @param obj `any` The object to check.
|
|
49
|
-
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
50
|
-
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
51
|
-
* - **`true`** `if` the `obj` has non-empty keys,
|
|
52
|
-
* - **`false`** `otherwise`
|
|
53
|
-
*/
|
|
54
|
-
export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
|
|
55
|
-
/**
|
|
56
|
-
* @note uses `key in obj` for each element of param `keys`
|
|
57
|
-
* @param obj `T extends Object` the object to check
|
|
58
|
-
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
59
|
-
* @param requireAll `boolean` defaults to `true`
|
|
60
|
-
* - `if` `true`, all keys must be present in the object;
|
|
61
|
-
* - `if` `false`, at least one key must be present
|
|
62
|
-
* @param restrictKeys `boolean` defaults to `false`
|
|
63
|
-
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
64
|
-
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
65
|
-
* @returns **`hasKeys`** `boolean`
|
|
66
|
-
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
67
|
-
* - **`false`** `otherwise`
|
|
68
|
-
*/
|
|
69
|
-
export declare function hasKeys<T extends object>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
|
|
70
|
-
/**
|
|
71
|
-
* @param objA `Record<string, any>`
|
|
72
|
-
* @param objB `Record<string, any>`
|
|
73
|
-
* @returns **`areEquivalentObjects`** `boolean`
|
|
74
|
-
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
75
|
-
* - `false` `otherwise`.
|
|
76
|
-
*/
|
|
77
|
-
export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
|
|
78
43
|
/**
|
|
79
44
|
* @param value `any`
|
|
80
45
|
* @param requireInteger `boolean` `default = false`
|
|
@@ -243,25 +208,31 @@ export declare function isNull(value: unknown): value is null;
|
|
|
243
208
|
*/
|
|
244
209
|
export declare function isUndefined(value: any): value is undefined;
|
|
245
210
|
export declare function isUndefinedOrNull(value: unknown): value is undefined | null;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
211
|
+
/**
|
|
212
|
+
* @deprecated
|
|
213
|
+
* `fka hasNonTrivialKeys`
|
|
214
|
+
* @note **passing in an array will return `false`.**
|
|
215
|
+
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
216
|
+
* @param obj `any` The object to check.
|
|
217
|
+
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
218
|
+
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
219
|
+
* - **`true`** `if` the `obj` has non-empty keys,
|
|
220
|
+
* - **`false`** `otherwise`
|
|
221
|
+
*/
|
|
222
|
+
export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
|
|
223
|
+
/**
|
|
224
|
+
* @deprecated
|
|
225
|
+
* @note uses `key in obj` for each element of param `keys`
|
|
226
|
+
* @param obj `T extends Object` the object to check
|
|
227
|
+
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
228
|
+
* @param requireAll `boolean` defaults to `true`
|
|
229
|
+
* - `if` `true`, all keys must be present in the object;
|
|
230
|
+
* - `if` `false`, at least one key must be present
|
|
231
|
+
* @param restrictKeys `boolean` defaults to `false`
|
|
232
|
+
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
233
|
+
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
234
|
+
* @returns **`hasKeys`** `boolean`
|
|
235
|
+
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
236
|
+
* - **`false`** `otherwise`
|
|
237
|
+
*/
|
|
238
|
+
export declare function hasKeys<T extends object>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
|
|
@@ -8,9 +8,6 @@ exports.isNonEmptyArray = isNonEmptyArray;
|
|
|
8
8
|
exports.isEmptyArray = isEmptyArray;
|
|
9
9
|
exports.isIntegerArray = isIntegerArray;
|
|
10
10
|
exports.isStringArray = isStringArray;
|
|
11
|
-
exports.hasNonTrivialEntries = hasNonTrivialEntries;
|
|
12
|
-
exports.hasKeys = hasKeys;
|
|
13
|
-
exports.areEquivalentObjects = areEquivalentObjects;
|
|
14
11
|
exports.isNumeric = isNumeric;
|
|
15
12
|
exports.isNonEmptyString = isNonEmptyString;
|
|
16
13
|
exports.isPrimitiveValue = isPrimitiveValue;
|
|
@@ -23,7 +20,8 @@ exports.isFunction = isFunction;
|
|
|
23
20
|
exports.isNull = isNull;
|
|
24
21
|
exports.isUndefined = isUndefined;
|
|
25
22
|
exports.isUndefinedOrNull = isUndefinedOrNull;
|
|
26
|
-
|
|
23
|
+
exports.hasNonTrivialEntries = hasNonTrivialEntries;
|
|
24
|
+
exports.hasKeys = hasKeys;
|
|
27
25
|
/**
|
|
28
26
|
* @param value
|
|
29
27
|
* @returns **`isNonEmptyArray`** `boolean` = `value is Array<T> & { length: number }`
|
|
@@ -55,10 +53,10 @@ function isIntegerArray(value, requireNonNegative = false, requireNonEmpty = tru
|
|
|
55
53
|
? isNonEmptyArray(value) && value.every(el => isInteger(el, requireNonNegative))
|
|
56
54
|
: isEmptyArray(value));
|
|
57
55
|
}
|
|
56
|
+
// * @consideration add param to allow for empty strings?
|
|
58
57
|
/**
|
|
59
|
-
* @consideration add param to allow for empty strings?
|
|
60
58
|
* @param value `any`
|
|
61
|
-
* @param requireNonEmpty `boolean` `default = true`
|
|
59
|
+
* @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
|
|
62
60
|
* - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
|
|
63
61
|
* - `if` `false` then `value` can be empty array
|
|
64
62
|
* @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
|
|
@@ -68,103 +66,6 @@ function isStringArray(value, requireNonEmpty = true) {
|
|
|
68
66
|
? isNonEmptyArray(value) && value.every(el => isNonEmptyString(el))
|
|
69
67
|
: isEmptyArray(value));
|
|
70
68
|
}
|
|
71
|
-
// maybe deprecate this
|
|
72
|
-
/**
|
|
73
|
-
* `fka hasNonTrivialKeys`
|
|
74
|
-
* @note **passing in an array will return `false`.**
|
|
75
|
-
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
76
|
-
* @param obj `any` The object to check.
|
|
77
|
-
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
78
|
-
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
79
|
-
* - **`true`** `if` the `obj` has non-empty keys,
|
|
80
|
-
* - **`false`** `otherwise`
|
|
81
|
-
*/
|
|
82
|
-
function hasNonTrivialEntries(obj, requireAll = false) {
|
|
83
|
-
if (!isObject(obj)) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
return (requireAll
|
|
87
|
-
? Object.values(obj).every(v => !isEmpty(v))
|
|
88
|
-
: Object.values(obj).some(v => !isEmpty(v)));
|
|
89
|
-
}
|
|
90
|
-
// @TODO add overload on param `keys` where keys = `{ required: string[], optional: string[] }`
|
|
91
|
-
// maybe deprecate this
|
|
92
|
-
/**
|
|
93
|
-
* @note uses `key in obj` for each element of param `keys`
|
|
94
|
-
* @param obj `T extends Object` the object to check
|
|
95
|
-
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
96
|
-
* @param requireAll `boolean` defaults to `true`
|
|
97
|
-
* - `if` `true`, all keys must be present in the object;
|
|
98
|
-
* - `if` `false`, at least one key must be present
|
|
99
|
-
* @param restrictKeys `boolean` defaults to `false`
|
|
100
|
-
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
101
|
-
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
102
|
-
* @returns **`hasKeys`** `boolean`
|
|
103
|
-
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
104
|
-
* - **`false`** `otherwise`
|
|
105
|
-
*/
|
|
106
|
-
function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
|
|
107
|
-
if (!obj || typeof obj !== 'object') {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
if (keys === null || keys === undefined) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
if (!isNonEmptyArray(keys)) {
|
|
114
|
-
keys = [keys]; // Convert string (assumed to be single key) to array of keys
|
|
115
|
-
}
|
|
116
|
-
let numKeysFound = 0;
|
|
117
|
-
for (const key of keys) {
|
|
118
|
-
if (key in obj) {
|
|
119
|
-
numKeysFound++;
|
|
120
|
-
if (!requireAll && !restrictKeys) {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
else if (requireAll) { // and a key is not found
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (restrictKeys) {
|
|
129
|
-
// If restrictKeys is true, check that no other keys are present in the object
|
|
130
|
-
const objKeys = Object.keys(obj);
|
|
131
|
-
const extraKeys = objKeys.filter(k => !keys.includes(k));
|
|
132
|
-
if (extraKeys.length > 0) {
|
|
133
|
-
return false; // Found keys not in the allowed list
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* @param objA `Record<string, any>`
|
|
140
|
-
* @param objB `Record<string, any>`
|
|
141
|
-
* @returns **`areEquivalentObjects`** `boolean`
|
|
142
|
-
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
143
|
-
* - `false` `otherwise`.
|
|
144
|
-
*/
|
|
145
|
-
function areEquivalentObjects(objA, objB) {
|
|
146
|
-
if (!objA || typeof objA !== 'object' || !objB || typeof objB !== 'object') {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
const keysA = Object.keys(objA);
|
|
150
|
-
const keysB = Object.keys(objB);
|
|
151
|
-
if (keysA.length !== keysB.length)
|
|
152
|
-
return false;
|
|
153
|
-
return keysA.every(key => {
|
|
154
|
-
if (!hasKeys(objB, key))
|
|
155
|
-
return false; // key not in both objects
|
|
156
|
-
const valA = objA[key];
|
|
157
|
-
const valB = objB[key];
|
|
158
|
-
if (Array.isArray(valA) && Array.isArray(valB)) {
|
|
159
|
-
return valA.length === valB.length
|
|
160
|
-
&& valA.every((item) => valB.includes(item));
|
|
161
|
-
}
|
|
162
|
-
else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
|
|
163
|
-
return areEquivalentObjects(valA, valB);
|
|
164
|
-
}
|
|
165
|
-
return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
69
|
/**
|
|
169
70
|
* @param value `any`
|
|
170
71
|
* @param requireInteger `boolean` `default = false`
|
|
@@ -456,3 +357,70 @@ function isUndefined(value) {
|
|
|
456
357
|
function isUndefinedOrNull(value) {
|
|
457
358
|
return value === undefined || value === null;
|
|
458
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* @deprecated
|
|
362
|
+
* `fka hasNonTrivialKeys`
|
|
363
|
+
* @note **passing in an array will return `false`.**
|
|
364
|
+
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
365
|
+
* @param obj `any` The object to check.
|
|
366
|
+
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
367
|
+
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
368
|
+
* - **`true`** `if` the `obj` has non-empty keys,
|
|
369
|
+
* - **`false`** `otherwise`
|
|
370
|
+
*/
|
|
371
|
+
function hasNonTrivialEntries(obj, requireAll = false) {
|
|
372
|
+
if (!isObject(obj)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return (requireAll
|
|
376
|
+
? Object.values(obj).every(v => !isEmpty(v))
|
|
377
|
+
: Object.values(obj).some(v => !isEmpty(v)));
|
|
378
|
+
}
|
|
379
|
+
// @TODO add overload on param `keys` where keys = `{ required: string[], optional: string[] }`
|
|
380
|
+
/**
|
|
381
|
+
* @deprecated
|
|
382
|
+
* @note uses `key in obj` for each element of param `keys`
|
|
383
|
+
* @param obj `T extends Object` the object to check
|
|
384
|
+
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
385
|
+
* @param requireAll `boolean` defaults to `true`
|
|
386
|
+
* - `if` `true`, all keys must be present in the object;
|
|
387
|
+
* - `if` `false`, at least one key must be present
|
|
388
|
+
* @param restrictKeys `boolean` defaults to `false`
|
|
389
|
+
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
390
|
+
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
391
|
+
* @returns **`hasKeys`** `boolean`
|
|
392
|
+
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
393
|
+
* - **`false`** `otherwise`
|
|
394
|
+
*/
|
|
395
|
+
function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
|
|
396
|
+
if (!obj || typeof obj !== 'object') {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
if (keys === null || keys === undefined) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
if (!isNonEmptyArray(keys)) {
|
|
403
|
+
keys = [keys]; // Convert string (assumed to be single key) to array of keys
|
|
404
|
+
}
|
|
405
|
+
let numKeysFound = 0;
|
|
406
|
+
for (const key of keys) {
|
|
407
|
+
if (key in obj) {
|
|
408
|
+
numKeysFound++;
|
|
409
|
+
if (!requireAll && !restrictKeys) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else if (requireAll) { // and a key is not found
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (restrictKeys) {
|
|
418
|
+
// If restrictKeys is true, check that no other keys are present in the object
|
|
419
|
+
const objKeys = Object.keys(obj);
|
|
420
|
+
const extraKeys = objKeys.filter(k => !keys.includes(k));
|
|
421
|
+
if (extraKeys.length > 0) {
|
|
422
|
+
return false; // Found keys not in the allowed list
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
|
|
426
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/utils/utilityTypes.ts
|
|
3
|
+
*/
|
|
4
|
+
export type NumberKeys<T, Required extends boolean = false> = {
|
|
5
|
+
[K in keyof T]: Required extends true ? (T[K] extends number ? K : never) : (T[K] extends number | undefined ? K : never);
|
|
6
|
+
}[keyof T][];
|
|
7
|
+
export type ArrayKeys<T, Required extends boolean = false> = {
|
|
8
|
+
[K in keyof T]: Required extends true ? (T[K] extends Array<any> ? K : never) : (T[K] extends Array<any> | undefined ? K : never);
|
|
9
|
+
}[keyof T][];
|
|
10
|
+
export type ArrayOfTypeKeys<T, U, Required extends boolean = false> = {
|
|
11
|
+
[K in keyof T]: Required extends true ? (T[K] extends Array<U> ? K : never) : (T[K] extends Array<U> | undefined ? K : never);
|
|
12
|
+
}[keyof T][];
|
|
13
|
+
export type StringKeys<T, Required extends boolean = false> = {
|
|
14
|
+
[K in keyof T]: Required extends true ? (T[K] extends string ? K : never) : (T[K] extends string | undefined ? K : never);
|
|
15
|
+
}[keyof T][];
|
|
16
|
+
export type PrimitiveKeys<T, Required extends boolean = false> = {
|
|
17
|
+
[K in keyof T]: Required extends true ? (T[K] extends string | number | boolean | null ? K : never) : (T[K] extends string | number | boolean | null | undefined ? K : never);
|
|
18
|
+
}[keyof T][];
|
|
19
|
+
export type Primitive = string | number | boolean | null | undefined;
|
|
20
|
+
/** Get the union of all values of `T` (like `valueof T`) */
|
|
21
|
+
export type ValueOf<T> = T[keyof T];
|
|
22
|
+
/**
|
|
23
|
+
* Keys of `T` whose values extend a given type `U`
|
|
24
|
+
* @template T - The object type
|
|
25
|
+
* @template U - The type to check each `T[K]` against
|
|
26
|
+
* @template Required - Whether the key is required (allows for `undefined` values if `false`) `default = false`
|
|
27
|
+
*/
|
|
28
|
+
export type KeysOfType<T, U, Required extends boolean = false> = {
|
|
29
|
+
[K in keyof T]: Required extends true ? (T[K] extends U ? K : never) : (T[K] extends U | undefined ? K : never);
|
|
30
|
+
}[keyof T][];
|
|
31
|
+
/**
|
|
32
|
+
* use for non-strict autocomplete of enum/literal value types
|
|
33
|
+
* @example
|
|
34
|
+
* JobPlatformEnum = { GREENHOUSE: 'GREENHOUSE', WORKDAY: 'WORKDAY' } as const;
|
|
35
|
+
* type JobPlatformEnum = (typeof JobPlatformEnum)[keyof typeof JobPlatformEnum]; // 'GREENHOUSE' | 'WORKDAY'
|
|
36
|
+
* let key: NonStrict<JobPlatformEnum>; // `key` allows any string, but will have the enum values as suggested auto-complete values
|
|
37
|
+
* key = 'hello'; // ok
|
|
38
|
+
* key = 9; // Error: Type '9' is not assignable to type 'NonStrict<JobPlatformEnum>'
|
|
39
|
+
* */
|
|
40
|
+
export type NonStrict<T extends string | number> = T | (T extends string ? (string & {}) : (number & {}));
|