@naturalcycles/js-lib 15.34.0 → 15.35.0
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/dist/array/array.util.d.ts +1 -1
- package/dist/array/array.util.js +7 -13
- package/dist/decorators/asyncMemo.decorator.d.ts +3 -3
- package/dist/decorators/asyncMemo.decorator.js +3 -3
- package/dist/decorators/logMethod.decorator.js +1 -1
- package/dist/error/error.util.d.ts +1 -1
- package/dist/error/error.util.js +1 -1
- package/dist/json-schema/jsonSchemaBuilder.d.ts +20 -2
- package/dist/json-schema/jsonSchemaBuilder.js +35 -1
- package/dist/object/object.util.d.ts +1 -3
- package/dist/object/object.util.js +3 -5
- package/dist/promise/pMap.js +2 -2
- package/dist/string/safeJsonStringify.js +2 -1
- package/dist/string/string.util.d.ts +1 -1
- package/dist/string/string.util.js +1 -1
- package/dist/typeFest.d.ts +0 -7
- package/dist/types.d.ts +1 -3
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/src/array/array.util.ts +7 -13
- package/src/browser/analytics.util.ts +2 -0
- package/src/decorators/asyncMemo.decorator.ts +3 -3
- package/src/decorators/logMethod.decorator.ts +1 -1
- package/src/error/error.util.ts +1 -1
- package/src/json-schema/jsonSchemaBuilder.ts +44 -2
- package/src/object/object.util.ts +3 -5
- package/src/promise/pMap.ts +2 -2
- package/src/string/safeJsonStringify.ts +2 -2
- package/src/string/string.util.ts +1 -1
- package/src/typeFest.ts +0 -7
- package/src/types.ts +1 -3
|
@@ -5,7 +5,7 @@ import type { AbortablePredicate, FalsyValue, Mapper, Predicate, SortDirection,
|
|
|
5
5
|
*
|
|
6
6
|
* @param array The array to process.
|
|
7
7
|
* @param size The length of each chunk.
|
|
8
|
-
* @
|
|
8
|
+
* @returns Returns the new array containing chunks.
|
|
9
9
|
*
|
|
10
10
|
* https://lodash.com/docs#chunk
|
|
11
11
|
*
|
package/dist/array/array.util.js
CHANGED
|
@@ -6,7 +6,7 @@ import { END } from '../types.js';
|
|
|
6
6
|
*
|
|
7
7
|
* @param array The array to process.
|
|
8
8
|
* @param size The length of each chunk.
|
|
9
|
-
* @
|
|
9
|
+
* @returns Returns the new array containing chunks.
|
|
10
10
|
*
|
|
11
11
|
* https://lodash.com/docs#chunk
|
|
12
12
|
*
|
|
@@ -79,8 +79,7 @@ export function _pushUniqBy(a, mapper, ...items) {
|
|
|
79
79
|
*/
|
|
80
80
|
export function _uniqBy(arr, mapper) {
|
|
81
81
|
const map = new Map();
|
|
82
|
-
for (
|
|
83
|
-
const item = arr[i];
|
|
82
|
+
for (const item of arr) {
|
|
84
83
|
const key = item === undefined || item === null ? item : mapper(item);
|
|
85
84
|
if (!map.has(key))
|
|
86
85
|
map.set(key, item);
|
|
@@ -109,8 +108,7 @@ export function _uniqBy(arr, mapper) {
|
|
|
109
108
|
*/
|
|
110
109
|
export function _by(items, mapper) {
|
|
111
110
|
const map = {};
|
|
112
|
-
for (
|
|
113
|
-
const v = items[i];
|
|
111
|
+
for (const v of items) {
|
|
114
112
|
const k = mapper(v);
|
|
115
113
|
if (k !== undefined) {
|
|
116
114
|
map[k] = v;
|
|
@@ -123,8 +121,7 @@ export function _by(items, mapper) {
|
|
|
123
121
|
*/
|
|
124
122
|
export function _mapBy(items, mapper) {
|
|
125
123
|
const map = new Map();
|
|
126
|
-
for (
|
|
127
|
-
const item = items[i];
|
|
124
|
+
for (const item of items) {
|
|
128
125
|
const key = mapper(item);
|
|
129
126
|
if (key !== undefined) {
|
|
130
127
|
map.set(key, item);
|
|
@@ -145,8 +142,7 @@ export function _mapBy(items, mapper) {
|
|
|
145
142
|
*/
|
|
146
143
|
export function _groupBy(items, mapper) {
|
|
147
144
|
const map = {};
|
|
148
|
-
for (
|
|
149
|
-
const item = items[i];
|
|
145
|
+
for (const item of items) {
|
|
150
146
|
const key = mapper(item);
|
|
151
147
|
if (key !== undefined) {
|
|
152
148
|
;
|
|
@@ -444,8 +440,7 @@ export function _maxByOrUndefined(array, mapper) {
|
|
|
444
440
|
return;
|
|
445
441
|
let maxItem;
|
|
446
442
|
let max;
|
|
447
|
-
for (
|
|
448
|
-
const item = array[i];
|
|
443
|
+
for (const item of array) {
|
|
449
444
|
const v = mapper(item);
|
|
450
445
|
if (v !== undefined && (max === undefined || v > max)) {
|
|
451
446
|
maxItem = item;
|
|
@@ -459,8 +454,7 @@ export function _minByOrUndefined(array, mapper) {
|
|
|
459
454
|
return;
|
|
460
455
|
let minItem;
|
|
461
456
|
let min;
|
|
462
|
-
for (
|
|
463
|
-
const item = array[i];
|
|
457
|
+
for (const item of array) {
|
|
464
458
|
const v = mapper(item);
|
|
465
459
|
if (v !== undefined && (min === undefined || v < min)) {
|
|
466
460
|
minItem = item;
|
|
@@ -25,12 +25,12 @@ export interface AsyncMemoInstance {
|
|
|
25
25
|
getCache: (instance: AnyAsyncFunction) => AsyncMemoCache | undefined;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Like
|
|
28
|
+
* Like `@_Memo`, but allowing async MemoCache implementation.
|
|
29
29
|
*
|
|
30
|
-
* Implementation is more complex than
|
|
30
|
+
* Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
|
|
31
31
|
* while waiting for cache to resolve, to prevent "async swarm" issue.
|
|
32
32
|
*
|
|
33
|
-
* @experimental consider normal
|
|
33
|
+
* @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
|
|
34
34
|
*/
|
|
35
35
|
export declare const _AsyncMemo: <FN>(opt: AsyncMemoOptions<FN>) => MethodDecorator<FN>;
|
|
36
36
|
/**
|
|
@@ -3,12 +3,12 @@ import { _objectAssign, MISS } from '../types.js';
|
|
|
3
3
|
import { _getTargetMethodSignature } from './decorator.util.js';
|
|
4
4
|
import { jsonMemoSerializer } from './memo.util.js';
|
|
5
5
|
/**
|
|
6
|
-
* Like
|
|
6
|
+
* Like `@_Memo`, but allowing async MemoCache implementation.
|
|
7
7
|
*
|
|
8
|
-
* Implementation is more complex than
|
|
8
|
+
* Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
|
|
9
9
|
* while waiting for cache to resolve, to prevent "async swarm" issue.
|
|
10
10
|
*
|
|
11
|
-
* @experimental consider normal
|
|
11
|
+
* @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
|
|
12
12
|
*/
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
14
|
export const _AsyncMemo = (opt) => (target, key, descriptor) => {
|
|
@@ -70,7 +70,7 @@ export function _LogMethod(opt = {}) {
|
|
|
70
70
|
return descriptor;
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
//
|
|
73
|
+
// oxlint-disable-next-line max-params
|
|
74
74
|
function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
|
|
75
75
|
const millis = Date.now() - started;
|
|
76
76
|
const t = ['<<', callSignature, 'took', _ms(millis)];
|
|
@@ -83,7 +83,7 @@ export interface AppErrorOptions {
|
|
|
83
83
|
* data - optional "any" payload.
|
|
84
84
|
* data.userFriendly - if present, will be displayed to the User as is.
|
|
85
85
|
*
|
|
86
|
-
* Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
|
|
86
|
+
* Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
|
|
87
87
|
*/
|
|
88
88
|
export declare class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
89
89
|
data: DATA_TYPE;
|
package/dist/error/error.util.js
CHANGED
|
@@ -221,7 +221,7 @@ export function _errorDataAppend(err, data) {
|
|
|
221
221
|
* data - optional "any" payload.
|
|
222
222
|
* data.userFriendly - if present, will be displayed to the User as is.
|
|
223
223
|
*
|
|
224
|
-
* Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
|
|
224
|
+
* Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
|
|
225
225
|
*/
|
|
226
226
|
export class AppError extends Error {
|
|
227
227
|
data;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyObject, BaseDBEntity, IsoDate, UnixTimestamp } from '../types.js';
|
|
1
|
+
import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js';
|
|
2
2
|
import type { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './jsonSchema.model.js';
|
|
3
3
|
export interface JsonSchemaBuilder<T = unknown> {
|
|
4
4
|
build: () => JsonSchema<T>;
|
|
@@ -20,8 +20,17 @@ export declare const j: {
|
|
|
20
20
|
unixTimestamp(): JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
21
21
|
unixTimestamp2000(): JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
22
22
|
string<T extends string = string>(): JsonSchemaStringBuilder<T>;
|
|
23
|
+
/**
|
|
24
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
25
|
+
*/
|
|
23
26
|
isoDate(): JsonSchemaStringBuilder<IsoDate>;
|
|
27
|
+
/**
|
|
28
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
29
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
30
|
+
*/
|
|
31
|
+
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
|
|
24
32
|
object: typeof object;
|
|
33
|
+
dbEntity<T extends AnyObject>(props: T): JsonSchemaObjectBuilder<BaseDBEntity & { [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<infer U, any> ? U : never; }>;
|
|
25
34
|
rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T>;
|
|
26
35
|
array<T extends JsonSchemaAnyBuilder<any>>(itemSchema: T): JsonSchemaArrayBuilder<T["infer"]>;
|
|
27
36
|
tuple<T extends any[] = unknown[]>(items: JsonSchemaAnyBuilder[]): JsonSchemaTupleBuilder<T>;
|
|
@@ -87,13 +96,13 @@ export declare class JsonSchemaNumberBuilder<T extends number = number> extends
|
|
|
87
96
|
}
|
|
88
97
|
export declare class JsonSchemaStringBuilder<T extends string = string> extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>> {
|
|
89
98
|
constructor();
|
|
99
|
+
regex(pattern: RegExp): this;
|
|
90
100
|
pattern(pattern: string): this;
|
|
91
101
|
min(minLength: number): this;
|
|
92
102
|
max(maxLength: number): this;
|
|
93
103
|
length(minLength: number, maxLength: number): this;
|
|
94
104
|
format(format: string): this;
|
|
95
105
|
email: () => this;
|
|
96
|
-
isoDate: () => this;
|
|
97
106
|
url: () => this;
|
|
98
107
|
ipv4: () => this;
|
|
99
108
|
ipv6: () => this;
|
|
@@ -108,6 +117,15 @@ export declare class JsonSchemaStringBuilder<T extends string = string> extends
|
|
|
108
117
|
toLowerCase: (toLowerCase?: boolean) => this;
|
|
109
118
|
toUpperCase: (toUpperCase?: boolean) => this;
|
|
110
119
|
branded<B extends string>(): JsonSchemaStringBuilder<B>;
|
|
120
|
+
/**
|
|
121
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
122
|
+
*/
|
|
123
|
+
isoDate(): JsonSchemaStringBuilder<IsoDate>;
|
|
124
|
+
/**
|
|
125
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
126
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
127
|
+
*/
|
|
128
|
+
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
|
|
111
129
|
private transformModify;
|
|
112
130
|
}
|
|
113
131
|
export declare class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>> {
|
|
@@ -56,12 +56,31 @@ export const j = {
|
|
|
56
56
|
string() {
|
|
57
57
|
return new JsonSchemaStringBuilder();
|
|
58
58
|
},
|
|
59
|
+
/**
|
|
60
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
61
|
+
*/
|
|
59
62
|
isoDate() {
|
|
60
63
|
return new JsonSchemaStringBuilder().isoDate();
|
|
61
64
|
},
|
|
65
|
+
/**
|
|
66
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
67
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
68
|
+
*/
|
|
69
|
+
isoDateTime() {
|
|
70
|
+
return new JsonSchemaStringBuilder().isoDateTime();
|
|
71
|
+
},
|
|
62
72
|
// email: () => new JsonSchemaStringBuilder().email(),
|
|
63
73
|
// complex types
|
|
64
74
|
object,
|
|
75
|
+
dbEntity(props) {
|
|
76
|
+
return j
|
|
77
|
+
.object({
|
|
78
|
+
id: j.string(),
|
|
79
|
+
created: j.unixTimestamp2000(),
|
|
80
|
+
updated: j.unixTimestamp2000(),
|
|
81
|
+
})
|
|
82
|
+
.extend(j.object(props));
|
|
83
|
+
},
|
|
65
84
|
rootObject(props) {
|
|
66
85
|
return new JsonSchemaObjectBuilder().addProperties(props).$schemaDraft7();
|
|
67
86
|
},
|
|
@@ -222,6 +241,9 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
222
241
|
type: 'string',
|
|
223
242
|
});
|
|
224
243
|
}
|
|
244
|
+
regex(pattern) {
|
|
245
|
+
return this.pattern(pattern.source);
|
|
246
|
+
}
|
|
225
247
|
pattern(pattern) {
|
|
226
248
|
Object.assign(this.schema, { pattern });
|
|
227
249
|
return this;
|
|
@@ -243,7 +265,6 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
243
265
|
return this;
|
|
244
266
|
}
|
|
245
267
|
email = () => this.format('email');
|
|
246
|
-
isoDate = () => this.format('date').description('IsoDate'); // todo: make it custom isoDate instead
|
|
247
268
|
url = () => this.format('url');
|
|
248
269
|
ipv4 = () => this.format('ipv4');
|
|
249
270
|
ipv6 = () => this.format('ipv6');
|
|
@@ -260,6 +281,19 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
260
281
|
branded() {
|
|
261
282
|
return this;
|
|
262
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
286
|
+
*/
|
|
287
|
+
isoDate() {
|
|
288
|
+
return this.format('IsoDate').branded().description('IsoDate');
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
292
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
293
|
+
*/
|
|
294
|
+
isoDateTime() {
|
|
295
|
+
return this.format('IsoDateTime').branded().description('IsoDateTime');
|
|
296
|
+
}
|
|
263
297
|
transformModify(t, add) {
|
|
264
298
|
if (add) {
|
|
265
299
|
this.schema.transform = _uniq([...(this.schema.transform || []), t]);
|
|
@@ -126,7 +126,6 @@ export declare function _filterEmptyValues<T extends AnyObject>(obj: T, opt?: Mu
|
|
|
126
126
|
*
|
|
127
127
|
* **Note:** This method mutates `object`.
|
|
128
128
|
*
|
|
129
|
-
* @category Object
|
|
130
129
|
* @param target The destination object.
|
|
131
130
|
* @param sources The source objects.
|
|
132
131
|
* @returns Returns `object`.
|
|
@@ -177,7 +176,7 @@ type PropertyPath = Many<PropertyKey>;
|
|
|
177
176
|
* @param obj The object to modify.
|
|
178
177
|
* @param path The path of the property to set.
|
|
179
178
|
* @param value The value to set.
|
|
180
|
-
* @
|
|
179
|
+
* @returns Returns object.
|
|
181
180
|
*
|
|
182
181
|
* Based on: https://stackoverflow.com/a/54733755/4919972
|
|
183
182
|
*/
|
|
@@ -185,7 +184,6 @@ export declare function _set<T extends AnyObject>(obj: T, path: PropertyPath, va
|
|
|
185
184
|
/**
|
|
186
185
|
* Checks if `path` is a direct property of `object` (not null, not undefined).
|
|
187
186
|
*
|
|
188
|
-
* @category Object
|
|
189
187
|
* @param obj The object to query.
|
|
190
188
|
* @param path The path to check.
|
|
191
189
|
* @returns Returns `true` if `path` exists, else `false`.
|
|
@@ -236,7 +236,6 @@ export function _filterEmptyValues(obj, opt = {}) {
|
|
|
236
236
|
*
|
|
237
237
|
* **Note:** This method mutates `object`.
|
|
238
238
|
*
|
|
239
|
-
* @category Object
|
|
240
239
|
* @param target The destination object.
|
|
241
240
|
* @param sources The source objects.
|
|
242
241
|
* @returns Returns `object`.
|
|
@@ -340,7 +339,7 @@ export function _get(obj = {}, path = '') {
|
|
|
340
339
|
return (path
|
|
341
340
|
.replaceAll(/\[([^\]]+)]/g, '.$1')
|
|
342
341
|
.split('.')
|
|
343
|
-
//
|
|
342
|
+
// oxlint-disable-next-line unicorn/no-array-reduce
|
|
344
343
|
.reduce((o, p) => o?.[p], obj));
|
|
345
344
|
}
|
|
346
345
|
/**
|
|
@@ -350,7 +349,7 @@ export function _get(obj = {}, path = '') {
|
|
|
350
349
|
* @param obj The object to modify.
|
|
351
350
|
* @param path The path of the property to set.
|
|
352
351
|
* @param value The value to set.
|
|
353
|
-
* @
|
|
352
|
+
* @returns Returns object.
|
|
354
353
|
*
|
|
355
354
|
* Based on: https://stackoverflow.com/a/54733755/4919972
|
|
356
355
|
*/
|
|
@@ -365,7 +364,7 @@ export function _set(obj, path, value) {
|
|
|
365
364
|
else if (!path.length) {
|
|
366
365
|
return obj;
|
|
367
366
|
}
|
|
368
|
-
//
|
|
367
|
+
// oxlint-disable-next-line unicorn/no-array-reduce
|
|
369
368
|
;
|
|
370
369
|
path.slice(0, -1).reduce((a, c, i) =>
|
|
371
370
|
// biome-ignore lint/style/useConsistentBuiltinInstantiation: ok
|
|
@@ -384,7 +383,6 @@ export function _set(obj, path, value) {
|
|
|
384
383
|
/**
|
|
385
384
|
* Checks if `path` is a direct property of `object` (not null, not undefined).
|
|
386
385
|
*
|
|
387
|
-
* @category Object
|
|
388
386
|
* @param obj The object to query.
|
|
389
387
|
* @param path The path to check.
|
|
390
388
|
* @returns Returns `true` if `path` exists, else `false`.
|
package/dist/promise/pMap.js
CHANGED
|
@@ -85,7 +85,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
85
85
|
}
|
|
86
86
|
ret[i] = value;
|
|
87
87
|
resolvingCount--;
|
|
88
|
-
next();
|
|
88
|
+
next(); // oxlint-disable-line no-callback-in-promise
|
|
89
89
|
}, (err) => {
|
|
90
90
|
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
91
91
|
isSettled = true;
|
|
@@ -100,7 +100,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
100
100
|
logger?.error(err);
|
|
101
101
|
}
|
|
102
102
|
resolvingCount--;
|
|
103
|
-
next();
|
|
103
|
+
next(); // oxlint-disable-line no-callback-in-promise
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
106
|
};
|
|
@@ -13,7 +13,8 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
|
|
|
13
13
|
return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
/* eslint-disable
|
|
16
|
+
/* eslint-disable no-bitwise, no-implicit-coercion */
|
|
17
|
+
// oxlint-disable no-unused-expressions
|
|
17
18
|
function serializer(replacer, cycleReplacer) {
|
|
18
19
|
const stack = [];
|
|
19
20
|
const keys = [];
|
|
@@ -16,7 +16,7 @@ export declare function _lowerFirst(s: string): Uncapitalize<string>;
|
|
|
16
16
|
/**
|
|
17
17
|
* Like String.split(), but with limit, returning the tail together with last element.
|
|
18
18
|
*
|
|
19
|
-
* @
|
|
19
|
+
* @returns Returns the new array of string segments.
|
|
20
20
|
*/
|
|
21
21
|
export declare function _split(str: string, separator: string, limit: number): string[];
|
|
22
22
|
export declare function _removeWhitespace(s: string): string;
|
|
@@ -26,7 +26,7 @@ export function _lowerFirst(s) {
|
|
|
26
26
|
/**
|
|
27
27
|
* Like String.split(), but with limit, returning the tail together with last element.
|
|
28
28
|
*
|
|
29
|
-
* @
|
|
29
|
+
* @returns Returns the new array of string segments.
|
|
30
30
|
*/
|
|
31
31
|
export function _split(str, separator, limit) {
|
|
32
32
|
const parts = str.split(separator);
|
package/dist/typeFest.d.ts
CHANGED
|
@@ -37,8 +37,6 @@ type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ?
|
|
|
37
37
|
type FooWithoutA = Except<Foo, 'a' | 'c'>;
|
|
38
38
|
//=> {b: string};
|
|
39
39
|
```
|
|
40
|
-
|
|
41
|
-
@category Utilities
|
|
42
40
|
*/
|
|
43
41
|
export type Except<ObjectType, KeysType extends keyof ObjectType> = {
|
|
44
42
|
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
|
|
@@ -82,8 +80,6 @@ export type OmitIndexSignature<ObjectType> = {
|
|
|
82
80
|
|
|
83
81
|
const ab: Merge<Foo, Bar> = {a: 1, b: 2};
|
|
84
82
|
```
|
|
85
|
-
|
|
86
|
-
@category Utilities
|
|
87
83
|
*/
|
|
88
84
|
export type Merge<Destination, Source> = {
|
|
89
85
|
[Key in keyof OmitIndexSignature<Destination & Source>]: Key extends keyof Source ? Source[Key] : Key extends keyof Destination ? Destination[Key] : never;
|
|
@@ -109,7 +105,6 @@ export type Merge<Destination, Source> = {
|
|
|
109
105
|
type StringKeysAndUndefined = ConditionalKeys<Example, string | undefined>;
|
|
110
106
|
//=> 'a' | 'c'
|
|
111
107
|
```
|
|
112
|
-
@category Utilities
|
|
113
108
|
*/
|
|
114
109
|
export type ConditionalKeys<Base, Condition> = NonNullable<{
|
|
115
110
|
[Key in keyof Base]: Base[Key] extends Condition ? Key : never;
|
|
@@ -141,7 +136,6 @@ export type ConditionalKeys<Base, Condition> = NonNullable<{
|
|
|
141
136
|
type NonStringKeysOnly = ConditionalExcept<Example, string>;
|
|
142
137
|
//=> {b: string | number; c: () => void; d: {}}
|
|
143
138
|
```
|
|
144
|
-
@category Utilities
|
|
145
139
|
*/
|
|
146
140
|
export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Base, Condition>>;
|
|
147
141
|
/**
|
|
@@ -171,7 +165,6 @@ export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Ba
|
|
|
171
165
|
type StringKeysOnly = ConditionalPick<Example, string>;
|
|
172
166
|
//=> {a: string}
|
|
173
167
|
```
|
|
174
|
-
@category Utilities
|
|
175
168
|
*/
|
|
176
169
|
export type ConditionalPick<Base, Condition> = Pick<Base, ConditionalKeys<Base, Condition>>;
|
|
177
170
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -310,7 +310,7 @@ export type FalsyValue = false | '' | 0 | null | undefined;
|
|
|
310
310
|
* err.data = {} // can be done, because it was casted
|
|
311
311
|
* }
|
|
312
312
|
*/
|
|
313
|
-
export declare function _typeCast<T>(
|
|
313
|
+
export declare function _typeCast<T>(_v: any): asserts _v is T;
|
|
314
314
|
/**
|
|
315
315
|
* Type-safe Object.assign that checks that part is indeed a Partial<T>
|
|
316
316
|
*/
|
|
@@ -371,8 +371,6 @@ export type Class<T = any> = new (...args: any[]) => T;
|
|
|
371
371
|
data.foo.push('bar');
|
|
372
372
|
//=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
|
|
373
373
|
```
|
|
374
|
-
|
|
375
|
-
@category Utilities
|
|
376
374
|
*/
|
|
377
375
|
export type ReadonlyDeep<T> = T extends Primitive | ((...args: any[]) => unknown) ? T : T extends ReadonlyMap<infer KeyType, infer ValueType> ? ReadonlyMapDeep<KeyType, ValueType> : T extends ReadonlySet<infer ItemType> ? ReadonlySetDeep<ItemType> : T extends object ? ReadonlyObjectDeep<T> : unknown;
|
|
378
376
|
/**
|
package/dist/types.js
CHANGED
|
@@ -59,7 +59,7 @@ export const _objectEntries = Object.entries;
|
|
|
59
59
|
* err.data = {} // can be done, because it was casted
|
|
60
60
|
* }
|
|
61
61
|
*/
|
|
62
|
-
export function _typeCast(
|
|
62
|
+
export function _typeCast(_v) { }
|
|
63
63
|
/**
|
|
64
64
|
* Type-safe Object.assign that checks that part is indeed a Partial<T>
|
|
65
65
|
*/
|
package/package.json
CHANGED
package/src/array/array.util.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { END } from '../types.js'
|
|
|
15
15
|
*
|
|
16
16
|
* @param array The array to process.
|
|
17
17
|
* @param size The length of each chunk.
|
|
18
|
-
* @
|
|
18
|
+
* @returns Returns the new array containing chunks.
|
|
19
19
|
*
|
|
20
20
|
* https://lodash.com/docs#chunk
|
|
21
21
|
*
|
|
@@ -91,8 +91,7 @@ export function _pushUniqBy<T>(a: T[], mapper: Mapper<T, any>, ...items: T[]): T
|
|
|
91
91
|
*/
|
|
92
92
|
export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
|
|
93
93
|
const map = new Map<any, T>()
|
|
94
|
-
for (
|
|
95
|
-
const item = arr[i]!
|
|
94
|
+
for (const item of arr) {
|
|
96
95
|
const key = item === undefined || item === null ? item : mapper(item)
|
|
97
96
|
if (!map.has(key)) map.set(key, item)
|
|
98
97
|
}
|
|
@@ -121,8 +120,7 @@ export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
|
|
|
121
120
|
*/
|
|
122
121
|
export function _by<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T> {
|
|
123
122
|
const map: StringMap<T> = {}
|
|
124
|
-
for (
|
|
125
|
-
const v = items[i]!
|
|
123
|
+
for (const v of items) {
|
|
126
124
|
const k = mapper(v)
|
|
127
125
|
if (k !== undefined) {
|
|
128
126
|
map[k] = v
|
|
@@ -140,8 +138,7 @@ export function _mapBy<ITEM, KEY>(
|
|
|
140
138
|
mapper: Mapper<ITEM, KEY>,
|
|
141
139
|
): Map<KEY, ITEM> {
|
|
142
140
|
const map = new Map<KEY, ITEM>()
|
|
143
|
-
for (
|
|
144
|
-
const item = items[i]!
|
|
141
|
+
for (const item of items) {
|
|
145
142
|
const key = mapper(item)
|
|
146
143
|
if (key !== undefined) {
|
|
147
144
|
map.set(key, item)
|
|
@@ -164,8 +161,7 @@ export function _mapBy<ITEM, KEY>(
|
|
|
164
161
|
export function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T[]> {
|
|
165
162
|
const map: StringMap<T[]> = {}
|
|
166
163
|
|
|
167
|
-
for (
|
|
168
|
-
const item = items[i]!
|
|
164
|
+
for (const item of items) {
|
|
169
165
|
const key = mapper(item)
|
|
170
166
|
if (key !== undefined) {
|
|
171
167
|
;(map[key] ||= []).push(item)
|
|
@@ -531,8 +527,7 @@ export function _maxByOrUndefined<T>(
|
|
|
531
527
|
let maxItem: T | undefined
|
|
532
528
|
let max: number | string | undefined
|
|
533
529
|
|
|
534
|
-
for (
|
|
535
|
-
const item = array[i]!
|
|
530
|
+
for (const item of array) {
|
|
536
531
|
const v = mapper(item)
|
|
537
532
|
if (v !== undefined && (max === undefined || v > max)) {
|
|
538
533
|
maxItem = item
|
|
@@ -551,8 +546,7 @@ export function _minByOrUndefined<T>(
|
|
|
551
546
|
let minItem: T | undefined
|
|
552
547
|
let min: number | string | undefined
|
|
553
548
|
|
|
554
|
-
for (
|
|
555
|
-
const item = array[i]!
|
|
549
|
+
for (const item of array) {
|
|
556
550
|
const v = mapper(item)
|
|
557
551
|
if (v !== undefined && (min === undefined || v < min)) {
|
|
558
552
|
minItem = item
|
|
@@ -36,12 +36,12 @@ export interface AsyncMemoInstance {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Like
|
|
39
|
+
* Like `@_Memo`, but allowing async MemoCache implementation.
|
|
40
40
|
*
|
|
41
|
-
* Implementation is more complex than
|
|
41
|
+
* Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
|
|
42
42
|
* while waiting for cache to resolve, to prevent "async swarm" issue.
|
|
43
43
|
*
|
|
44
|
-
* @experimental consider normal
|
|
44
|
+
* @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
|
|
45
45
|
*/
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
47
47
|
export const _AsyncMemo =
|
|
@@ -138,7 +138,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
//
|
|
141
|
+
// oxlint-disable-next-line max-params
|
|
142
142
|
function logFinished(
|
|
143
143
|
logger: CommonLogger,
|
|
144
144
|
callSignature: string,
|
package/src/error/error.util.ts
CHANGED
|
@@ -304,7 +304,7 @@ export interface AppErrorOptions {
|
|
|
304
304
|
* data - optional "any" payload.
|
|
305
305
|
* data.userFriendly - if present, will be displayed to the User as is.
|
|
306
306
|
*
|
|
307
|
-
* Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
|
|
307
|
+
* Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
|
|
308
308
|
*/
|
|
309
309
|
export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
310
310
|
data!: DATA_TYPE
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _uniq } from '../array/array.util.js'
|
|
2
2
|
import { _deepCopy } from '../object/object.util.js'
|
|
3
3
|
import { _sortObject } from '../object/sortObject.js'
|
|
4
|
-
import type { AnyObject, BaseDBEntity, IsoDate, UnixTimestamp } from '../types.js'
|
|
4
|
+
import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js'
|
|
5
5
|
import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js'
|
|
6
6
|
import type {
|
|
7
7
|
JsonSchema,
|
|
@@ -77,16 +77,40 @@ export const j = {
|
|
|
77
77
|
unixTimestamp2000() {
|
|
78
78
|
return new JsonSchemaNumberBuilder<UnixTimestamp>().unixTimestamp2000()
|
|
79
79
|
},
|
|
80
|
+
|
|
80
81
|
// string types
|
|
81
82
|
string<T extends string = string>() {
|
|
82
83
|
return new JsonSchemaStringBuilder<T>()
|
|
83
84
|
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
88
|
+
*/
|
|
84
89
|
isoDate() {
|
|
85
90
|
return new JsonSchemaStringBuilder<IsoDate>().isoDate()
|
|
86
91
|
},
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
95
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
96
|
+
*/
|
|
97
|
+
isoDateTime() {
|
|
98
|
+
return new JsonSchemaStringBuilder<IsoDateTime>().isoDateTime()
|
|
99
|
+
},
|
|
100
|
+
|
|
87
101
|
// email: () => new JsonSchemaStringBuilder().email(),
|
|
88
102
|
// complex types
|
|
89
103
|
object,
|
|
104
|
+
dbEntity<T extends AnyObject>(props: T) {
|
|
105
|
+
return j
|
|
106
|
+
.object<BaseDBEntity>({
|
|
107
|
+
id: j.string(),
|
|
108
|
+
created: j.unixTimestamp2000(),
|
|
109
|
+
updated: j.unixTimestamp2000(),
|
|
110
|
+
})
|
|
111
|
+
.extend(j.object(props))
|
|
112
|
+
},
|
|
113
|
+
|
|
90
114
|
rootObject<T extends AnyObject>(props: {
|
|
91
115
|
[K in keyof T]: JsonSchemaAnyBuilder<T[K]>
|
|
92
116
|
}) {
|
|
@@ -292,6 +316,10 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
|
|
|
292
316
|
})
|
|
293
317
|
}
|
|
294
318
|
|
|
319
|
+
regex(pattern: RegExp): this {
|
|
320
|
+
return this.pattern(pattern.source)
|
|
321
|
+
}
|
|
322
|
+
|
|
295
323
|
pattern(pattern: string): this {
|
|
296
324
|
Object.assign(this.schema, { pattern })
|
|
297
325
|
return this
|
|
@@ -318,7 +346,6 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
|
|
|
318
346
|
}
|
|
319
347
|
|
|
320
348
|
email = (): this => this.format('email')
|
|
321
|
-
isoDate = (): this => this.format('date').description('IsoDate') // todo: make it custom isoDate instead
|
|
322
349
|
url = (): this => this.format('url')
|
|
323
350
|
ipv4 = (): this => this.format('ipv4')
|
|
324
351
|
ipv6 = (): this => this.format('ipv6')
|
|
@@ -338,6 +365,21 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
|
|
|
338
365
|
return this as unknown as JsonSchemaStringBuilder<B>
|
|
339
366
|
}
|
|
340
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
370
|
+
*/
|
|
371
|
+
isoDate(): JsonSchemaStringBuilder<IsoDate> {
|
|
372
|
+
return this.format('IsoDate').branded<IsoDate>().description('IsoDate')
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
377
|
+
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
378
|
+
*/
|
|
379
|
+
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime> {
|
|
380
|
+
return this.format('IsoDateTime').branded<IsoDateTime>().description('IsoDateTime')
|
|
381
|
+
}
|
|
382
|
+
|
|
341
383
|
private transformModify(t: 'trim' | 'toLowerCase' | 'toUpperCase', add: boolean): this {
|
|
342
384
|
if (add) {
|
|
343
385
|
this.schema.transform = _uniq([...(this.schema.transform || []), t])
|
|
@@ -292,7 +292,6 @@ export function _filterEmptyValues<T extends AnyObject>(obj: T, opt: MutateOptio
|
|
|
292
292
|
*
|
|
293
293
|
* **Note:** This method mutates `object`.
|
|
294
294
|
*
|
|
295
|
-
* @category Object
|
|
296
295
|
* @param target The destination object.
|
|
297
296
|
* @param sources The source objects.
|
|
298
297
|
* @returns Returns `object`.
|
|
@@ -402,7 +401,7 @@ export function _get<T extends AnyObject>(obj = {} as T, path = ''): unknown {
|
|
|
402
401
|
path
|
|
403
402
|
.replaceAll(/\[([^\]]+)]/g, '.$1')
|
|
404
403
|
.split('.')
|
|
405
|
-
//
|
|
404
|
+
// oxlint-disable-next-line unicorn/no-array-reduce
|
|
406
405
|
.reduce((o, p) => o?.[p], obj)
|
|
407
406
|
)
|
|
408
407
|
}
|
|
@@ -417,7 +416,7 @@ type PropertyPath = Many<PropertyKey>
|
|
|
417
416
|
* @param obj The object to modify.
|
|
418
417
|
* @param path The path of the property to set.
|
|
419
418
|
* @param value The value to set.
|
|
420
|
-
* @
|
|
419
|
+
* @returns Returns object.
|
|
421
420
|
*
|
|
422
421
|
* Based on: https://stackoverflow.com/a/54733755/4919972
|
|
423
422
|
*/
|
|
@@ -432,7 +431,7 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
|
|
|
432
431
|
return obj as any
|
|
433
432
|
}
|
|
434
433
|
|
|
435
|
-
//
|
|
434
|
+
// oxlint-disable-next-line unicorn/no-array-reduce
|
|
436
435
|
;(path as any[]).slice(0, -1).reduce(
|
|
437
436
|
(
|
|
438
437
|
a,
|
|
@@ -458,7 +457,6 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
|
|
|
458
457
|
/**
|
|
459
458
|
* Checks if `path` is a direct property of `object` (not null, not undefined).
|
|
460
459
|
*
|
|
461
|
-
* @category Object
|
|
462
460
|
* @param obj The object to query.
|
|
463
461
|
* @param path The path to check.
|
|
464
462
|
* @returns Returns `true` if `path` exists, else `false`.
|
package/src/promise/pMap.ts
CHANGED
|
@@ -126,7 +126,7 @@ export async function pMap<IN, OUT>(
|
|
|
126
126
|
|
|
127
127
|
ret[i] = value
|
|
128
128
|
resolvingCount--
|
|
129
|
-
next()
|
|
129
|
+
next() // oxlint-disable-line no-callback-in-promise
|
|
130
130
|
},
|
|
131
131
|
(err: Error) => {
|
|
132
132
|
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
@@ -140,7 +140,7 @@ export async function pMap<IN, OUT>(
|
|
|
140
140
|
logger?.error(err)
|
|
141
141
|
}
|
|
142
142
|
resolvingCount--
|
|
143
|
-
next()
|
|
143
|
+
next() // oxlint-disable-line no-callback-in-promise
|
|
144
144
|
}
|
|
145
145
|
},
|
|
146
146
|
)
|
|
@@ -20,8 +20,8 @@ export function _safeJsonStringify(
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/* eslint-disable
|
|
24
|
-
|
|
23
|
+
/* eslint-disable no-bitwise, no-implicit-coercion */
|
|
24
|
+
// oxlint-disable no-unused-expressions
|
|
25
25
|
function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
|
|
26
26
|
const stack: any[] = []
|
|
27
27
|
const keys: string[] = []
|
|
@@ -31,7 +31,7 @@ export function _lowerFirst(s: string): Uncapitalize<string> {
|
|
|
31
31
|
/**
|
|
32
32
|
* Like String.split(), but with limit, returning the tail together with last element.
|
|
33
33
|
*
|
|
34
|
-
* @
|
|
34
|
+
* @returns Returns the new array of string segments.
|
|
35
35
|
*/
|
|
36
36
|
export function _split(str: string, separator: string, limit: number): string[] {
|
|
37
37
|
const parts = str.split(separator)
|
package/src/typeFest.ts
CHANGED
|
@@ -42,8 +42,6 @@ type Filter<KeyType, ExcludeType> =
|
|
|
42
42
|
type FooWithoutA = Except<Foo, 'a' | 'c'>;
|
|
43
43
|
//=> {b: string};
|
|
44
44
|
```
|
|
45
|
-
|
|
46
|
-
@category Utilities
|
|
47
45
|
*/
|
|
48
46
|
export type Except<ObjectType, KeysType extends keyof ObjectType> = {
|
|
49
47
|
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType]
|
|
@@ -94,8 +92,6 @@ export type OmitIndexSignature<ObjectType> = {
|
|
|
94
92
|
|
|
95
93
|
const ab: Merge<Foo, Bar> = {a: 1, b: 2};
|
|
96
94
|
```
|
|
97
|
-
|
|
98
|
-
@category Utilities
|
|
99
95
|
*/
|
|
100
96
|
export type Merge<Destination, Source> = {
|
|
101
97
|
[Key in keyof OmitIndexSignature<Destination & Source>]: Key extends keyof Source
|
|
@@ -126,7 +122,6 @@ export type Merge<Destination, Source> = {
|
|
|
126
122
|
type StringKeysAndUndefined = ConditionalKeys<Example, string | undefined>;
|
|
127
123
|
//=> 'a' | 'c'
|
|
128
124
|
```
|
|
129
|
-
@category Utilities
|
|
130
125
|
*/
|
|
131
126
|
export type ConditionalKeys<Base, Condition> = NonNullable<
|
|
132
127
|
// Wrap in `NonNullable` to strip away the `undefined` type from the produced union.
|
|
@@ -169,7 +164,6 @@ export type ConditionalKeys<Base, Condition> = NonNullable<
|
|
|
169
164
|
type NonStringKeysOnly = ConditionalExcept<Example, string>;
|
|
170
165
|
//=> {b: string | number; c: () => void; d: {}}
|
|
171
166
|
```
|
|
172
|
-
@category Utilities
|
|
173
167
|
*/
|
|
174
168
|
export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Base, Condition>>
|
|
175
169
|
|
|
@@ -200,7 +194,6 @@ export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Ba
|
|
|
200
194
|
type StringKeysOnly = ConditionalPick<Example, string>;
|
|
201
195
|
//=> {a: string}
|
|
202
196
|
```
|
|
203
|
-
@category Utilities
|
|
204
197
|
*/
|
|
205
198
|
export type ConditionalPick<Base, Condition> = Pick<Base, ConditionalKeys<Base, Condition>>
|
|
206
199
|
|
package/src/types.ts
CHANGED
|
@@ -396,7 +396,7 @@ export type FalsyValue = false | '' | 0 | null | undefined
|
|
|
396
396
|
* err.data = {} // can be done, because it was casted
|
|
397
397
|
* }
|
|
398
398
|
*/
|
|
399
|
-
export function _typeCast<T>(
|
|
399
|
+
export function _typeCast<T>(_v: any): asserts _v is T {}
|
|
400
400
|
|
|
401
401
|
/**
|
|
402
402
|
* Type-safe Object.assign that checks that part is indeed a Partial<T>
|
|
@@ -469,8 +469,6 @@ export type Class<T = any> = new (...args: any[]) => T
|
|
|
469
469
|
data.foo.push('bar');
|
|
470
470
|
//=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
|
|
471
471
|
```
|
|
472
|
-
|
|
473
|
-
@category Utilities
|
|
474
472
|
*/
|
|
475
473
|
/* eslint-disable @typescript-eslint/no-restricted-types */
|
|
476
474
|
export type ReadonlyDeep<T> = T extends Primitive | ((...args: any[]) => unknown)
|