@naturalcycles/js-lib 14.116.0 → 14.117.1
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.js +4 -4
- package/dist/datetime/dateInterval.js +1 -0
- package/dist/datetime/localDate.js +2 -0
- package/dist/datetime/localTime.js +2 -3
- package/dist/datetime/timeInterval.js +1 -0
- package/dist/decorators/asyncMemo.decorator.d.ts +2 -2
- package/dist/decorators/createPromiseDecorator.d.ts +6 -6
- package/dist/decorators/logMethod.decorator.js +4 -5
- package/dist/decorators/memo.decorator.d.ts +2 -2
- package/dist/error/tryCatch.d.ts +1 -1
- package/dist/object/deepEquals.js +1 -0
- package/dist/object/object.util.js +8 -10
- package/dist/promise/pRetry.d.ts +1 -1
- package/dist/promise/pTimeout.d.ts +4 -1
- package/dist/promise/pTimeout.js +5 -6
- package/dist/string/pupa.d.ts +2 -2
- package/dist/string/readingTime.d.ts +1 -1
- package/dist/string/safeJsonStringify.js +5 -7
- package/dist/string/url.util.js +1 -1
- package/dist-esm/array/array.util.js +4 -4
- package/dist-esm/datetime/dateInterval.js +1 -0
- package/dist-esm/datetime/localDate.js +2 -0
- package/dist-esm/datetime/localTime.js +2 -3
- package/dist-esm/datetime/timeInterval.js +1 -0
- package/dist-esm/decorators/logMethod.decorator.js +4 -5
- package/dist-esm/object/deepEquals.js +1 -0
- package/dist-esm/object/object.util.js +8 -10
- package/dist-esm/promise/pTimeout.js +5 -6
- package/dist-esm/string/safeJsonStringify.js +5 -7
- package/dist-esm/string/url.util.js +1 -1
- package/package.json +1 -1
- package/src/array/array.util.ts +4 -4
- package/src/datetime/dateInterval.ts +1 -0
- package/src/datetime/localDate.ts +2 -0
- package/src/datetime/localTime.ts +2 -2
- package/src/datetime/timeInterval.ts +1 -0
- package/src/decorators/asyncMemo.decorator.ts +2 -2
- package/src/decorators/createPromiseDecorator.ts +4 -4
- package/src/decorators/logMethod.decorator.ts +4 -4
- package/src/decorators/memo.decorator.ts +2 -2
- package/src/error/tryCatch.ts +1 -1
- package/src/object/deepEquals.ts +1 -0
- package/src/object/object.util.ts +7 -8
- package/src/promise/pRetry.ts +1 -1
- package/src/promise/pTimeout.ts +9 -9
- package/src/string/pupa.ts +1 -1
- package/src/string/readingTime.ts +1 -1
- package/src/string/safeJsonStringify.ts +3 -5
- package/src/string/url.util.ts +1 -1
package/dist/array/array.util.js
CHANGED
|
@@ -160,24 +160,24 @@ function _findLast(items, predicate) {
|
|
|
160
160
|
exports._findLast = _findLast;
|
|
161
161
|
function _takeWhile(items, predicate) {
|
|
162
162
|
let proceed = true;
|
|
163
|
-
return items.filter((v, index) => (proceed
|
|
163
|
+
return items.filter((v, index) => (proceed &&= predicate(v, index)));
|
|
164
164
|
}
|
|
165
165
|
exports._takeWhile = _takeWhile;
|
|
166
166
|
function _takeRightWhile(items, predicate) {
|
|
167
167
|
let proceed = true;
|
|
168
|
-
return [...items].reverse().filter((v, index) => (proceed
|
|
168
|
+
return [...items].reverse().filter((v, index) => (proceed &&= predicate(v, index)));
|
|
169
169
|
}
|
|
170
170
|
exports._takeRightWhile = _takeRightWhile;
|
|
171
171
|
function _dropWhile(items, predicate) {
|
|
172
172
|
let proceed = false;
|
|
173
|
-
return items.filter((v, index) => (proceed
|
|
173
|
+
return items.filter((v, index) => (proceed ||= !predicate(v, index)));
|
|
174
174
|
}
|
|
175
175
|
exports._dropWhile = _dropWhile;
|
|
176
176
|
function _dropRightWhile(items, predicate) {
|
|
177
177
|
let proceed = false;
|
|
178
178
|
return [...items]
|
|
179
179
|
.reverse()
|
|
180
|
-
.filter((v, index) => (proceed
|
|
180
|
+
.filter((v, index) => (proceed ||= !predicate(v, index)))
|
|
181
181
|
.reverse();
|
|
182
182
|
}
|
|
183
183
|
exports._dropRightWhile = _dropRightWhile;
|
|
@@ -49,6 +49,7 @@ class DateInterval {
|
|
|
49
49
|
*/
|
|
50
50
|
includes(d, incl = '[]') {
|
|
51
51
|
d = localDate_1.LocalDate.of(d);
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
52
53
|
return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']');
|
|
53
54
|
}
|
|
54
55
|
intersects(int, inclusive = true) {
|
|
@@ -112,6 +112,7 @@ class LocalDate {
|
|
|
112
112
|
const $min = LocalDate.of(min);
|
|
113
113
|
const $max = LocalDate.of(max).startOf(stepUnit);
|
|
114
114
|
let current = $min.startOf(stepUnit);
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
115
116
|
if (current.isAfter($min, incl[0] === '[')) {
|
|
116
117
|
// ok
|
|
117
118
|
}
|
|
@@ -170,6 +171,7 @@ class LocalDate {
|
|
|
170
171
|
}
|
|
171
172
|
isBetween(min, max, incl = '[)') {
|
|
172
173
|
let r = this.cmp(min);
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
173
175
|
if (r < 0 || (r === 0 && incl[0] === '('))
|
|
174
176
|
return false;
|
|
175
177
|
r = this.cmp(max);
|
|
@@ -347,6 +347,7 @@ class LocalTime {
|
|
|
347
347
|
}
|
|
348
348
|
isBetween(min, max, incl = '[)') {
|
|
349
349
|
let r = this.cmp(min);
|
|
350
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
350
351
|
if (r < 0 || (r === 0 && incl[0] === '('))
|
|
351
352
|
return false;
|
|
352
353
|
r = this.cmp(max);
|
|
@@ -525,9 +526,7 @@ function getWeekYear(date) {
|
|
|
525
526
|
else if (date.getTime() >= startOfThisYear.getTime()) {
|
|
526
527
|
return year;
|
|
527
528
|
}
|
|
528
|
-
|
|
529
|
-
return year - 1;
|
|
530
|
-
}
|
|
529
|
+
return year - 1;
|
|
531
530
|
}
|
|
532
531
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
533
532
|
function startOfWeek(date, mutate = false) {
|
|
@@ -59,6 +59,7 @@ class TimeInterval {
|
|
|
59
59
|
}
|
|
60
60
|
includes(d, incl = '[)') {
|
|
61
61
|
d = localTime_1.LocalTime.parseToUnixTimestamp(d);
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
62
63
|
if (d < this.$start || (d === this.$start && incl[0] === '('))
|
|
63
64
|
return false;
|
|
64
65
|
if (d > this.$end || (d === this.$end && incl[1] === ')'))
|
|
@@ -6,11 +6,11 @@ export interface AsyncMemoOptions {
|
|
|
6
6
|
* Function that creates an instance of `MemoCache`.
|
|
7
7
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
|
|
8
8
|
*/
|
|
9
|
-
cacheFactory
|
|
9
|
+
cacheFactory?(): AsyncMemoCache;
|
|
10
10
|
/**
|
|
11
11
|
* Provide a custom implementation of CacheKey function.
|
|
12
12
|
*/
|
|
13
|
-
cacheKeyFn
|
|
13
|
+
cacheKeyFn?(args: any[]): any;
|
|
14
14
|
/**
|
|
15
15
|
* Default true.
|
|
16
16
|
*
|
|
@@ -4,15 +4,15 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
4
4
|
* Called BEFORE the original function.
|
|
5
5
|
* If Promise is returned - it will be awaited.
|
|
6
6
|
*/
|
|
7
|
-
beforeFn
|
|
7
|
+
beforeFn?(r: PromiseDecoratorResp<PARAMS>): void | Promise<void>;
|
|
8
8
|
/**
|
|
9
9
|
* Called just AFTER the original function.
|
|
10
10
|
* The output of this hook will be passed further,
|
|
11
11
|
* so, pay attention to pass through (or modify) the result.
|
|
12
12
|
*/
|
|
13
|
-
thenFn
|
|
13
|
+
thenFn?(r: PromiseDecoratorResp<PARAMS> & {
|
|
14
14
|
res: RES;
|
|
15
|
-
})
|
|
15
|
+
}): RES;
|
|
16
16
|
/**
|
|
17
17
|
* Called on Promise.reject.
|
|
18
18
|
* If `catchFn` is not present - will re-throw the error,
|
|
@@ -20,14 +20,14 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
20
20
|
* If `catchFn` is present - it's responsible for handling or re-throwing the error.
|
|
21
21
|
* Whatever `catchFn` returns - passed to the original output.
|
|
22
22
|
*/
|
|
23
|
-
catchFn
|
|
23
|
+
catchFn?(r: PromiseDecoratorResp<PARAMS> & {
|
|
24
24
|
err: any;
|
|
25
|
-
})
|
|
25
|
+
}): RES;
|
|
26
26
|
/**
|
|
27
27
|
* Fires AFTER thenFn / catchFn, like a usual Promise.finally().
|
|
28
28
|
* Doesn't have access to neither res nor err (same as Promise.finally).
|
|
29
29
|
*/
|
|
30
|
-
finallyFn
|
|
30
|
+
finallyFn?(r: PromiseDecoratorResp<PARAMS>): any;
|
|
31
31
|
}
|
|
32
32
|
export interface PromiseDecoratorResp<PARAMS> {
|
|
33
33
|
decoratorParams: PARAMS;
|
|
@@ -59,11 +59,9 @@ function _LogMethod(opt = {}) {
|
|
|
59
59
|
throw err;
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return res;
|
|
66
|
-
}
|
|
62
|
+
// not a Promise
|
|
63
|
+
logFinished(logger, callSignature, started, sma, logResultFn, res);
|
|
64
|
+
return res;
|
|
67
65
|
}
|
|
68
66
|
catch (err) {
|
|
69
67
|
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err);
|
|
@@ -74,6 +72,7 @@ function _LogMethod(opt = {}) {
|
|
|
74
72
|
};
|
|
75
73
|
}
|
|
76
74
|
exports._LogMethod = _LogMethod;
|
|
75
|
+
// eslint-disable-next-line max-params
|
|
77
76
|
function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
|
|
78
77
|
const millis = Date.now() - started;
|
|
79
78
|
const t = ['<<', callSignature, 'took', (0, time_util_1._ms)(millis)];
|
|
@@ -6,11 +6,11 @@ export interface MemoOptions {
|
|
|
6
6
|
* Function that creates an instance of `MemoCache`.
|
|
7
7
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
|
|
8
8
|
*/
|
|
9
|
-
cacheFactory
|
|
9
|
+
cacheFactory?(): MemoCache;
|
|
10
10
|
/**
|
|
11
11
|
* Provide a custom implementation of CacheKey function.
|
|
12
12
|
*/
|
|
13
|
-
cacheKeyFn
|
|
13
|
+
cacheKeyFn?(args: any[]): any;
|
|
14
14
|
/**
|
|
15
15
|
* Defaults to true.
|
|
16
16
|
* Set to false to skip caching errors.
|
package/dist/error/tryCatch.d.ts
CHANGED
|
@@ -15,14 +15,12 @@ function _pick(obj, props, mutate = false) {
|
|
|
15
15
|
return r;
|
|
16
16
|
}, obj);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}, {});
|
|
25
|
-
}
|
|
18
|
+
// Start as empty object, pick/add needed properties
|
|
19
|
+
return props.reduce((r, prop) => {
|
|
20
|
+
if (prop in obj)
|
|
21
|
+
r[prop] = obj[prop];
|
|
22
|
+
return r;
|
|
23
|
+
}, {});
|
|
26
24
|
}
|
|
27
25
|
exports._pick = _pick;
|
|
28
26
|
/**
|
|
@@ -259,7 +257,7 @@ function _unset(obj, prop) {
|
|
|
259
257
|
}
|
|
260
258
|
const segs = prop.split('.');
|
|
261
259
|
let last = segs.pop();
|
|
262
|
-
while (segs.length && segs[segs.length - 1].
|
|
260
|
+
while (segs.length && segs[segs.length - 1].endsWith('\\')) {
|
|
263
261
|
last = segs.pop().slice(0, -1) + '.' + last;
|
|
264
262
|
}
|
|
265
263
|
while (segs.length && (0, is_util_1._isObject)(obj)) {
|
|
@@ -329,7 +327,7 @@ function _set(obj, path, value) {
|
|
|
329
327
|
a[c]
|
|
330
328
|
: // No: create the key. Is the next key a potential array-index?
|
|
331
329
|
(a[c] =
|
|
332
|
-
// @ts-
|
|
330
|
+
// @ts-expect-error
|
|
333
331
|
// eslint-disable-next-line
|
|
334
332
|
Math.abs(path[i + 1]) >> 0 === +path[i + 1]
|
|
335
333
|
? [] // Yes: assign a new array object
|
package/dist/promise/pRetry.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface PRetryOptions {
|
|
|
35
35
|
*
|
|
36
36
|
* @default () => true
|
|
37
37
|
*/
|
|
38
|
-
predicate
|
|
38
|
+
predicate?(err: Error, attempt: number, maxAttempts: number): boolean;
|
|
39
39
|
/**
|
|
40
40
|
* Log the first attempt (which is not a "retry" yet).
|
|
41
41
|
*
|
|
@@ -16,8 +16,11 @@ export interface PTimeoutOptions {
|
|
|
16
16
|
/**
|
|
17
17
|
* If provided - will be called INSTEAD of throwing an error.
|
|
18
18
|
* Can be used to thrown a custom error OR resolve a promise without throwing.
|
|
19
|
+
*
|
|
20
|
+
* err (which is TimeoutError) is passed as an argument for convenience, so it can
|
|
21
|
+
* be logged or such. You don't have to consume it in any way though.
|
|
19
22
|
*/
|
|
20
|
-
onTimeout
|
|
23
|
+
onTimeout?(err: TimeoutError): any;
|
|
21
24
|
/**
|
|
22
25
|
* Defaults to true.
|
|
23
26
|
* If true - preserves the stack trace in case of a Timeout (usually - very useful!).
|
package/dist/promise/pTimeout.js
CHANGED
|
@@ -26,16 +26,18 @@ exports.pTimeoutFn = pTimeoutFn;
|
|
|
26
26
|
* If the Function rejects - passes this rejection further.
|
|
27
27
|
*/
|
|
28
28
|
async function pTimeout(fn, opt) {
|
|
29
|
-
|
|
30
|
-
const { timeout, name, onTimeout, keepStackTrace = true } = opt;
|
|
29
|
+
const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt;
|
|
31
30
|
const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined;
|
|
32
31
|
// eslint-disable-next-line no-async-promise-executor
|
|
33
32
|
return await new Promise(async (resolve, reject) => {
|
|
34
33
|
// Prepare the timeout timer
|
|
35
34
|
const timer = setTimeout(() => {
|
|
35
|
+
const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData);
|
|
36
|
+
if (fakeError)
|
|
37
|
+
err.stack = fakeError.stack; // keep original stack
|
|
36
38
|
if (onTimeout) {
|
|
37
39
|
try {
|
|
38
|
-
resolve(onTimeout());
|
|
40
|
+
resolve(onTimeout(err));
|
|
39
41
|
}
|
|
40
42
|
catch (err) {
|
|
41
43
|
if (fakeError)
|
|
@@ -48,9 +50,6 @@ async function pTimeout(fn, opt) {
|
|
|
48
50
|
}
|
|
49
51
|
return;
|
|
50
52
|
}
|
|
51
|
-
const err = new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms`, opt.errorData);
|
|
52
|
-
if (fakeError)
|
|
53
|
-
err.stack = fakeError.stack; // keep original stack
|
|
54
53
|
reject(err);
|
|
55
54
|
}, timeout);
|
|
56
55
|
// Execute the Function
|
package/dist/string/pupa.d.ts
CHANGED
|
@@ -11,10 +11,10 @@ export interface PupaOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Performs arbitrary operation for each interpolation. If the returned value was `undefined`, it behaves differently depending on the `ignoreMissing` option. Otherwise, the returned value will be interpolated into a string (and escaped when double-braced) and embedded into the template.
|
|
13
13
|
*/
|
|
14
|
-
transform
|
|
14
|
+
transform?(data: {
|
|
15
15
|
value: any;
|
|
16
16
|
key: string;
|
|
17
|
-
})
|
|
17
|
+
}): unknown;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* API: https://github.com/sindresorhus/pupa
|
|
@@ -4,7 +4,7 @@ export interface ReadingTimeOptions {
|
|
|
4
4
|
* A function that returns a boolean value depending on if a character is considered as a word bound.
|
|
5
5
|
* Default: spaces, new lines and tabs
|
|
6
6
|
*/
|
|
7
|
-
wordBound
|
|
7
|
+
wordBound?(char: string): boolean;
|
|
8
8
|
/**
|
|
9
9
|
* Default 200
|
|
10
10
|
*/
|
|
@@ -21,13 +21,11 @@ exports._safeJsonStringify = _safeJsonStringify;
|
|
|
21
21
|
function serializer(replacer, cycleReplacer) {
|
|
22
22
|
const stack = [];
|
|
23
23
|
const keys = [];
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
};
|
|
30
|
-
}
|
|
24
|
+
cycleReplacer ??= function (key, value) {
|
|
25
|
+
if (stack[0] === value)
|
|
26
|
+
return '[Circular ~]';
|
|
27
|
+
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
|
|
28
|
+
};
|
|
31
29
|
return function (key, value) {
|
|
32
30
|
if (stack.length > 0) {
|
|
33
31
|
const thisPos = stack.indexOf(this);
|
package/dist/string/url.util.js
CHANGED
|
@@ -148,21 +148,21 @@ export function _findLast(items, predicate) {
|
|
|
148
148
|
}
|
|
149
149
|
export function _takeWhile(items, predicate) {
|
|
150
150
|
let proceed = true;
|
|
151
|
-
return items.filter((v, index) => (proceed
|
|
151
|
+
return items.filter((v, index) => (proceed && (proceed = predicate(v, index))));
|
|
152
152
|
}
|
|
153
153
|
export function _takeRightWhile(items, predicate) {
|
|
154
154
|
let proceed = true;
|
|
155
|
-
return [...items].reverse().filter((v, index) => (proceed
|
|
155
|
+
return [...items].reverse().filter((v, index) => (proceed && (proceed = predicate(v, index))));
|
|
156
156
|
}
|
|
157
157
|
export function _dropWhile(items, predicate) {
|
|
158
158
|
let proceed = false;
|
|
159
|
-
return items.filter((v, index) => (proceed
|
|
159
|
+
return items.filter((v, index) => (proceed || (proceed = !predicate(v, index))));
|
|
160
160
|
}
|
|
161
161
|
export function _dropRightWhile(items, predicate) {
|
|
162
162
|
let proceed = false;
|
|
163
163
|
return [...items]
|
|
164
164
|
.reverse()
|
|
165
|
-
.filter((v, index) => (proceed
|
|
165
|
+
.filter((v, index) => (proceed || (proceed = !predicate(v, index))))
|
|
166
166
|
.reverse();
|
|
167
167
|
}
|
|
168
168
|
export function _countBy(items, mapper) {
|
|
@@ -46,6 +46,7 @@ export class DateInterval {
|
|
|
46
46
|
*/
|
|
47
47
|
includes(d, incl = '[]') {
|
|
48
48
|
d = LocalDate.of(d);
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
49
50
|
return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']');
|
|
50
51
|
}
|
|
51
52
|
intersects(int, inclusive = true) {
|
|
@@ -109,6 +109,7 @@ export class LocalDate {
|
|
|
109
109
|
const $min = LocalDate.of(min);
|
|
110
110
|
const $max = LocalDate.of(max).startOf(stepUnit);
|
|
111
111
|
let current = $min.startOf(stepUnit);
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
112
113
|
if (current.isAfter($min, incl[0] === '[')) {
|
|
113
114
|
// ok
|
|
114
115
|
}
|
|
@@ -167,6 +168,7 @@ export class LocalDate {
|
|
|
167
168
|
}
|
|
168
169
|
isBetween(min, max, incl = '[)') {
|
|
169
170
|
let r = this.cmp(min);
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
170
172
|
if (r < 0 || (r === 0 && incl[0] === '('))
|
|
171
173
|
return false;
|
|
172
174
|
r = this.cmp(max);
|
|
@@ -345,6 +345,7 @@ export class LocalTime {
|
|
|
345
345
|
}
|
|
346
346
|
isBetween(min, max, incl = '[)') {
|
|
347
347
|
let r = this.cmp(min);
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
348
349
|
if (r < 0 || (r === 0 && incl[0] === '('))
|
|
349
350
|
return false;
|
|
350
351
|
r = this.cmp(max);
|
|
@@ -521,9 +522,7 @@ function getWeekYear(date) {
|
|
|
521
522
|
else if (date.getTime() >= startOfThisYear.getTime()) {
|
|
522
523
|
return year;
|
|
523
524
|
}
|
|
524
|
-
|
|
525
|
-
return year - 1;
|
|
526
|
-
}
|
|
525
|
+
return year - 1;
|
|
527
526
|
}
|
|
528
527
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
529
528
|
function startOfWeek(date, mutate = false) {
|
|
@@ -56,6 +56,7 @@ export class TimeInterval {
|
|
|
56
56
|
}
|
|
57
57
|
includes(d, incl = '[)') {
|
|
58
58
|
d = LocalTime.parseToUnixTimestamp(d);
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
59
60
|
if (d < this.$start || (d === this.$start && incl[0] === '('))
|
|
60
61
|
return false;
|
|
61
62
|
if (d > this.$end || (d === this.$end && incl[1] === ')'))
|
|
@@ -56,11 +56,9 @@ export function _LogMethod(opt = {}) {
|
|
|
56
56
|
throw err;
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return res;
|
|
63
|
-
}
|
|
59
|
+
// not a Promise
|
|
60
|
+
logFinished(logger, callSignature, started, sma, logResultFn, res);
|
|
61
|
+
return res;
|
|
64
62
|
}
|
|
65
63
|
catch (err) {
|
|
66
64
|
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err);
|
|
@@ -70,6 +68,7 @@ export function _LogMethod(opt = {}) {
|
|
|
70
68
|
return descriptor;
|
|
71
69
|
};
|
|
72
70
|
}
|
|
71
|
+
// eslint-disable-next-line max-params
|
|
73
72
|
function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
|
|
74
73
|
const millis = Date.now() - started;
|
|
75
74
|
const t = ['<<', callSignature, 'took', _ms(millis)];
|
|
@@ -12,14 +12,12 @@ export function _pick(obj, props, mutate = false) {
|
|
|
12
12
|
return r;
|
|
13
13
|
}, obj);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}, {});
|
|
22
|
-
}
|
|
15
|
+
// Start as empty object, pick/add needed properties
|
|
16
|
+
return props.reduce((r, prop) => {
|
|
17
|
+
if (prop in obj)
|
|
18
|
+
r[prop] = obj[prop];
|
|
19
|
+
return r;
|
|
20
|
+
}, {});
|
|
23
21
|
}
|
|
24
22
|
/**
|
|
25
23
|
* Returns clone of `obj` with `props` omitted.
|
|
@@ -239,7 +237,7 @@ export function _unset(obj, prop) {
|
|
|
239
237
|
}
|
|
240
238
|
const segs = prop.split('.');
|
|
241
239
|
let last = segs.pop();
|
|
242
|
-
while (segs.length && segs[segs.length - 1].
|
|
240
|
+
while (segs.length && segs[segs.length - 1].endsWith('\\')) {
|
|
243
241
|
last = segs.pop().slice(0, -1) + '.' + last;
|
|
244
242
|
}
|
|
245
243
|
while (segs.length && _isObject(obj)) {
|
|
@@ -305,7 +303,7 @@ export function _set(obj, path, value) {
|
|
|
305
303
|
a[c]
|
|
306
304
|
: // No: create the key. Is the next key a potential array-index?
|
|
307
305
|
(a[c] =
|
|
308
|
-
// @ts-
|
|
306
|
+
// @ts-expect-error
|
|
309
307
|
// eslint-disable-next-line
|
|
310
308
|
Math.abs(path[i + 1]) >> 0 === +path[i + 1]
|
|
311
309
|
? [] // Yes: assign a new array object
|
|
@@ -21,16 +21,18 @@ export function pTimeoutFn(fn, opt) {
|
|
|
21
21
|
* If the Function rejects - passes this rejection further.
|
|
22
22
|
*/
|
|
23
23
|
export async function pTimeout(fn, opt) {
|
|
24
|
-
|
|
25
|
-
const { timeout, name, onTimeout, keepStackTrace = true } = opt;
|
|
24
|
+
const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt;
|
|
26
25
|
const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined;
|
|
27
26
|
// eslint-disable-next-line no-async-promise-executor
|
|
28
27
|
return await new Promise(async (resolve, reject) => {
|
|
29
28
|
// Prepare the timeout timer
|
|
30
29
|
const timer = setTimeout(() => {
|
|
30
|
+
const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData);
|
|
31
|
+
if (fakeError)
|
|
32
|
+
err.stack = fakeError.stack; // keep original stack
|
|
31
33
|
if (onTimeout) {
|
|
32
34
|
try {
|
|
33
|
-
resolve(onTimeout());
|
|
35
|
+
resolve(onTimeout(err));
|
|
34
36
|
}
|
|
35
37
|
catch (err) {
|
|
36
38
|
if (fakeError)
|
|
@@ -40,9 +42,6 @@ export async function pTimeout(fn, opt) {
|
|
|
40
42
|
}
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
const err = new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms`, opt.errorData);
|
|
44
|
-
if (fakeError)
|
|
45
|
-
err.stack = fakeError.stack; // keep original stack
|
|
46
45
|
reject(err);
|
|
47
46
|
}, timeout);
|
|
48
47
|
// Execute the Function
|
|
@@ -17,13 +17,11 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
|
|
|
17
17
|
function serializer(replacer, cycleReplacer) {
|
|
18
18
|
const stack = [];
|
|
19
19
|
const keys = [];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
}
|
|
20
|
+
cycleReplacer !== null && cycleReplacer !== void 0 ? cycleReplacer : (cycleReplacer = function (key, value) {
|
|
21
|
+
if (stack[0] === value)
|
|
22
|
+
return '[Circular ~]';
|
|
23
|
+
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
|
|
24
|
+
});
|
|
27
25
|
return function (key, value) {
|
|
28
26
|
if (stack.length > 0) {
|
|
29
27
|
const thisPos = stack.indexOf(this);
|
package/package.json
CHANGED
package/src/array/array.util.ts
CHANGED
|
@@ -164,24 +164,24 @@ export function _findLast<T>(items: T[], predicate: Predicate<T>): T | undefined
|
|
|
164
164
|
|
|
165
165
|
export function _takeWhile<T>(items: T[], predicate: Predicate<T>): T[] {
|
|
166
166
|
let proceed = true
|
|
167
|
-
return items.filter((v, index) => (proceed
|
|
167
|
+
return items.filter((v, index) => (proceed &&= predicate(v, index)))
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export function _takeRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
|
|
171
171
|
let proceed = true
|
|
172
|
-
return [...items].reverse().filter((v, index) => (proceed
|
|
172
|
+
return [...items].reverse().filter((v, index) => (proceed &&= predicate(v, index)))
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
export function _dropWhile<T>(items: T[], predicate: Predicate<T>): T[] {
|
|
176
176
|
let proceed = false
|
|
177
|
-
return items.filter((v, index) => (proceed
|
|
177
|
+
return items.filter((v, index) => (proceed ||= !predicate(v, index)))
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
export function _dropRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
|
|
181
181
|
let proceed = false
|
|
182
182
|
return [...items]
|
|
183
183
|
.reverse()
|
|
184
|
-
.filter((v, index) => (proceed
|
|
184
|
+
.filter((v, index) => (proceed ||= !predicate(v, index)))
|
|
185
185
|
.reverse()
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -58,6 +58,7 @@ export class DateInterval {
|
|
|
58
58
|
*/
|
|
59
59
|
includes(d: LocalDateConfig, incl: Inclusiveness = '[]'): boolean {
|
|
60
60
|
d = LocalDate.of(d)
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
61
62
|
return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']')
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -154,6 +154,7 @@ export class LocalDate {
|
|
|
154
154
|
const $max = LocalDate.of(max).startOf(stepUnit)
|
|
155
155
|
|
|
156
156
|
let current = $min.startOf(stepUnit)
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
157
158
|
if (current.isAfter($min, incl[0] === '[')) {
|
|
158
159
|
// ok
|
|
159
160
|
} else {
|
|
@@ -228,6 +229,7 @@ export class LocalDate {
|
|
|
228
229
|
|
|
229
230
|
isBetween(min: LocalDateConfig, max: LocalDateConfig, incl: Inclusiveness = '[)'): boolean {
|
|
230
231
|
let r = this.cmp(min)
|
|
232
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
231
233
|
if (r < 0 || (r === 0 && incl[0] === '(')) return false
|
|
232
234
|
r = this.cmp(max)
|
|
233
235
|
if (r > 0 || (r === 0 && incl[1] === ')')) return false
|
|
@@ -431,6 +431,7 @@ export class LocalTime {
|
|
|
431
431
|
|
|
432
432
|
isBetween(min: LocalTimeConfig, max: LocalTimeConfig, incl: Inclusiveness = '[)'): boolean {
|
|
433
433
|
let r = this.cmp(min)
|
|
434
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
434
435
|
if (r < 0 || (r === 0 && incl[0] === '(')) return false
|
|
435
436
|
r = this.cmp(max)
|
|
436
437
|
if (r > 0 || (r === 0 && incl[1] === ')')) return false
|
|
@@ -641,9 +642,8 @@ function getWeekYear(date: Date): number {
|
|
|
641
642
|
return year + 1
|
|
642
643
|
} else if (date.getTime() >= startOfThisYear.getTime()) {
|
|
643
644
|
return year
|
|
644
|
-
} else {
|
|
645
|
-
return year - 1
|
|
646
645
|
}
|
|
646
|
+
return year - 1
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
@@ -77,6 +77,7 @@ export class TimeInterval {
|
|
|
77
77
|
|
|
78
78
|
includes(d: LocalTimeConfig, incl: Inclusiveness = '[)'): boolean {
|
|
79
79
|
d = LocalTime.parseToUnixTimestamp(d)
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
80
81
|
if (d < this.$start || (d === this.$start && incl[0] === '(')) return false
|
|
81
82
|
if (d > this.$end || (d === this.$end && incl[1] === ')')) return false
|
|
82
83
|
return true
|
|
@@ -11,12 +11,12 @@ export interface AsyncMemoOptions {
|
|
|
11
11
|
* Function that creates an instance of `MemoCache`.
|
|
12
12
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
|
|
13
13
|
*/
|
|
14
|
-
cacheFactory
|
|
14
|
+
cacheFactory?(): AsyncMemoCache
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Provide a custom implementation of CacheKey function.
|
|
18
18
|
*/
|
|
19
|
-
cacheKeyFn
|
|
19
|
+
cacheKeyFn?(args: any[]): any
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Default true.
|
|
@@ -7,14 +7,14 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
7
7
|
* Called BEFORE the original function.
|
|
8
8
|
* If Promise is returned - it will be awaited.
|
|
9
9
|
*/
|
|
10
|
-
beforeFn
|
|
10
|
+
beforeFn?(r: PromiseDecoratorResp<PARAMS>): void | Promise<void>
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Called just AFTER the original function.
|
|
14
14
|
* The output of this hook will be passed further,
|
|
15
15
|
* so, pay attention to pass through (or modify) the result.
|
|
16
16
|
*/
|
|
17
|
-
thenFn
|
|
17
|
+
thenFn?(r: PromiseDecoratorResp<PARAMS> & { res: RES }): RES
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Called on Promise.reject.
|
|
@@ -23,13 +23,13 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
23
23
|
* If `catchFn` is present - it's responsible for handling or re-throwing the error.
|
|
24
24
|
* Whatever `catchFn` returns - passed to the original output.
|
|
25
25
|
*/
|
|
26
|
-
catchFn
|
|
26
|
+
catchFn?(r: PromiseDecoratorResp<PARAMS> & { err: any }): RES
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Fires AFTER thenFn / catchFn, like a usual Promise.finally().
|
|
30
30
|
* Doesn't have access to neither res nor err (same as Promise.finally).
|
|
31
31
|
*/
|
|
32
|
-
finallyFn
|
|
32
|
+
finallyFn?(r: PromiseDecoratorResp<PARAMS>): any
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface PromiseDecoratorResp<PARAMS> {
|
|
@@ -122,11 +122,10 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
122
122
|
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err)
|
|
123
123
|
throw err
|
|
124
124
|
})
|
|
125
|
-
} else {
|
|
126
|
-
// not a Promise
|
|
127
|
-
logFinished(logger, callSignature, started, sma, logResultFn, res)
|
|
128
|
-
return res
|
|
129
125
|
}
|
|
126
|
+
// not a Promise
|
|
127
|
+
logFinished(logger, callSignature, started, sma, logResultFn, res)
|
|
128
|
+
return res
|
|
130
129
|
} catch (err) {
|
|
131
130
|
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err)
|
|
132
131
|
throw err // rethrow
|
|
@@ -137,6 +136,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
138
|
|
|
139
|
+
// eslint-disable-next-line max-params
|
|
140
140
|
function logFinished(
|
|
141
141
|
logger: CommonLogger,
|
|
142
142
|
callSignature: string,
|
|
@@ -11,12 +11,12 @@ export interface MemoOptions {
|
|
|
11
11
|
* Function that creates an instance of `MemoCache`.
|
|
12
12
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
|
|
13
13
|
*/
|
|
14
|
-
cacheFactory
|
|
14
|
+
cacheFactory?(): MemoCache
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Provide a custom implementation of CacheKey function.
|
|
18
18
|
*/
|
|
19
|
-
cacheKeyFn
|
|
19
|
+
cacheKeyFn?(args: any[]): any
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Defaults to true.
|
package/src/error/tryCatch.ts
CHANGED
package/src/object/deepEquals.ts
CHANGED
|
@@ -17,13 +17,12 @@ export function _pick<T extends AnyObject, K extends keyof T>(
|
|
|
17
17
|
if (!props.includes(prop as K)) delete r[prop]
|
|
18
18
|
return r
|
|
19
19
|
}, obj)
|
|
20
|
-
} else {
|
|
21
|
-
// Start as empty object, pick/add needed properties
|
|
22
|
-
return props.reduce((r, prop) => {
|
|
23
|
-
if (prop in obj) r[prop] = obj[prop]
|
|
24
|
-
return r
|
|
25
|
-
}, {} as T)
|
|
26
20
|
}
|
|
21
|
+
// Start as empty object, pick/add needed properties
|
|
22
|
+
return props.reduce((r, prop) => {
|
|
23
|
+
if (prop in obj) r[prop] = obj[prop]
|
|
24
|
+
return r
|
|
25
|
+
}, {} as T)
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
/**
|
|
@@ -285,7 +284,7 @@ export function _unset<T extends AnyObject>(obj: T, prop: string): void {
|
|
|
285
284
|
|
|
286
285
|
const segs = prop.split('.')
|
|
287
286
|
let last = segs.pop()
|
|
288
|
-
while (segs.length && segs[segs.length - 1]!.
|
|
287
|
+
while (segs.length && segs[segs.length - 1]!.endsWith('\\')) {
|
|
289
288
|
last = segs.pop()!.slice(0, -1) + '.' + last
|
|
290
289
|
}
|
|
291
290
|
while (segs.length && _isObject(obj)) {
|
|
@@ -359,7 +358,7 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
|
|
|
359
358
|
a[c]
|
|
360
359
|
: // No: create the key. Is the next key a potential array-index?
|
|
361
360
|
(a[c] =
|
|
362
|
-
// @ts-
|
|
361
|
+
// @ts-expect-error
|
|
363
362
|
// eslint-disable-next-line
|
|
364
363
|
Math.abs(path[i + 1]) >> 0 === +path[i + 1]
|
|
365
364
|
? [] // Yes: assign a new array object
|
package/src/promise/pRetry.ts
CHANGED
|
@@ -43,7 +43,7 @@ export interface PRetryOptions {
|
|
|
43
43
|
*
|
|
44
44
|
* @default () => true
|
|
45
45
|
*/
|
|
46
|
-
predicate
|
|
46
|
+
predicate?(err: Error, attempt: number, maxAttempts: number): boolean
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Log the first attempt (which is not a "retry" yet).
|
package/src/promise/pTimeout.ts
CHANGED
|
@@ -19,8 +19,11 @@ export interface PTimeoutOptions {
|
|
|
19
19
|
/**
|
|
20
20
|
* If provided - will be called INSTEAD of throwing an error.
|
|
21
21
|
* Can be used to thrown a custom error OR resolve a promise without throwing.
|
|
22
|
+
*
|
|
23
|
+
* err (which is TimeoutError) is passed as an argument for convenience, so it can
|
|
24
|
+
* be logged or such. You don't have to consume it in any way though.
|
|
22
25
|
*/
|
|
23
|
-
onTimeout
|
|
26
|
+
onTimeout?(err: TimeoutError): any
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
29
|
* Defaults to true.
|
|
@@ -59,17 +62,19 @@ export function pTimeoutFn<T extends AnyAsyncFunction>(fn: T, opt: PTimeoutOptio
|
|
|
59
62
|
* If the Function rejects - passes this rejection further.
|
|
60
63
|
*/
|
|
61
64
|
export async function pTimeout<T>(fn: AnyAsyncFunction<T>, opt: PTimeoutOptions): Promise<T> {
|
|
62
|
-
|
|
63
|
-
const { timeout, name, onTimeout, keepStackTrace = true } = opt
|
|
65
|
+
const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt
|
|
64
66
|
const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined
|
|
65
67
|
|
|
66
68
|
// eslint-disable-next-line no-async-promise-executor
|
|
67
69
|
return await new Promise(async (resolve, reject) => {
|
|
68
70
|
// Prepare the timeout timer
|
|
69
71
|
const timer = setTimeout(() => {
|
|
72
|
+
const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData)
|
|
73
|
+
if (fakeError) err.stack = fakeError.stack // keep original stack
|
|
74
|
+
|
|
70
75
|
if (onTimeout) {
|
|
71
76
|
try {
|
|
72
|
-
resolve(onTimeout())
|
|
77
|
+
resolve(onTimeout(err))
|
|
73
78
|
} catch (err: any) {
|
|
74
79
|
if (fakeError) err.stack = fakeError.stack // keep original stack
|
|
75
80
|
err.data = {
|
|
@@ -81,11 +86,6 @@ export async function pTimeout<T>(fn: AnyAsyncFunction<T>, opt: PTimeoutOptions)
|
|
|
81
86
|
return
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
const err = new TimeoutError(
|
|
85
|
-
`"${name || 'pTimeout function'}" timed out after ${timeout} ms`,
|
|
86
|
-
opt.errorData,
|
|
87
|
-
)
|
|
88
|
-
if (fakeError) err.stack = fakeError.stack // keep original stack
|
|
89
89
|
reject(err)
|
|
90
90
|
}, timeout)
|
|
91
91
|
|
package/src/string/pupa.ts
CHANGED
|
@@ -31,7 +31,7 @@ export interface PupaOptions {
|
|
|
31
31
|
/**
|
|
32
32
|
* Performs arbitrary operation for each interpolation. If the returned value was `undefined`, it behaves differently depending on the `ignoreMissing` option. Otherwise, the returned value will be interpolated into a string (and escaped when double-braced) and embedded into the template.
|
|
33
33
|
*/
|
|
34
|
-
transform
|
|
34
|
+
transform?(data: { value: any; key: string }): unknown
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -16,7 +16,7 @@ export interface ReadingTimeOptions {
|
|
|
16
16
|
* A function that returns a boolean value depending on if a character is considered as a word bound.
|
|
17
17
|
* Default: spaces, new lines and tabs
|
|
18
18
|
*/
|
|
19
|
-
wordBound
|
|
19
|
+
wordBound?(char: string): boolean
|
|
20
20
|
/**
|
|
21
21
|
* Default 200
|
|
22
22
|
*/
|
|
@@ -26,11 +26,9 @@ function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
|
|
|
26
26
|
const stack: any[] = []
|
|
27
27
|
const keys: string[] = []
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']'
|
|
33
|
-
}
|
|
29
|
+
cycleReplacer ??= function (key, value) {
|
|
30
|
+
if (stack[0] === value) return '[Circular ~]'
|
|
31
|
+
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']'
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
return function (key, value) {
|
package/src/string/url.util.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type { StringMap } from '../types'
|
|
|
16
16
|
export function _parseQueryString(search: string): StringMap {
|
|
17
17
|
const qs: StringMap = {}
|
|
18
18
|
search
|
|
19
|
-
.slice(search
|
|
19
|
+
.slice(search.startsWith('?') ? 1 : 0)
|
|
20
20
|
.split('&')
|
|
21
21
|
.forEach(p => {
|
|
22
22
|
const [k, v] = p.split('=')
|