@naturalcycles/js-lib 14.276.0 → 15.0.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/cfg/frontend/tsconfig.json +3 -3
- package/dist/abort.js +1 -4
- package/dist/array/array.util.d.ts +1 -1
- package/dist/array/array.util.js +47 -88
- package/dist/array/range.d.ts +2 -2
- package/dist/array/range.js +7 -12
- package/dist/bot.js +6 -10
- package/dist/browser/adminService.d.ts +1 -1
- package/dist/browser/adminService.js +10 -14
- package/dist/browser/analytics.util.js +10 -15
- package/dist/browser/i18n/fetchTranslationLoader.d.ts +3 -3
- package/dist/browser/i18n/fetchTranslationLoader.js +1 -5
- package/dist/browser/i18n/translation.service.d.ts +1 -1
- package/dist/browser/i18n/translation.service.js +5 -10
- package/dist/browser/imageFitter.js +1 -5
- package/dist/browser/script.util.js +8 -12
- package/dist/browser/topbar.js +7 -10
- package/dist/datetime/dateInterval.d.ts +2 -2
- package/dist/datetime/dateInterval.js +7 -11
- package/dist/datetime/localDate.d.ts +3 -3
- package/dist/datetime/localDate.js +40 -44
- package/dist/datetime/localTime.d.ts +3 -3
- package/dist/datetime/localTime.js +36 -40
- package/dist/datetime/timeInterval.d.ts +2 -2
- package/dist/datetime/timeInterval.js +6 -10
- package/dist/datetime/wallTime.d.ts +3 -3
- package/dist/datetime/wallTime.js +5 -9
- package/dist/decorators/asyncMemo.decorator.d.ts +3 -3
- package/dist/decorators/asyncMemo.decorator.js +12 -17
- package/dist/decorators/createPromiseDecorator.js +3 -6
- package/dist/decorators/debounce.d.ts +1 -1
- package/dist/decorators/debounce.decorator.d.ts +1 -1
- package/dist/decorators/debounce.decorator.js +5 -9
- package/dist/decorators/debounce.js +2 -6
- package/dist/decorators/decorator.util.d.ts +1 -1
- package/dist/decorators/decorator.util.js +3 -8
- package/dist/decorators/logMethod.decorator.d.ts +1 -1
- package/dist/decorators/logMethod.decorator.js +11 -14
- package/dist/decorators/memo.decorator.d.ts +3 -3
- package/dist/decorators/memo.decorator.js +11 -16
- package/dist/decorators/memo.util.d.ts +2 -2
- package/dist/decorators/memo.util.js +11 -17
- package/dist/decorators/memoFn.d.ts +3 -3
- package/dist/decorators/memoFn.js +3 -6
- package/dist/decorators/memoFnAsync.d.ts +3 -3
- package/dist/decorators/memoFnAsync.js +5 -8
- package/dist/decorators/memoSimple.decorator.d.ts +1 -1
- package/dist/decorators/memoSimple.decorator.js +6 -10
- package/dist/decorators/retry.decorator.d.ts +1 -1
- package/dist/decorators/retry.decorator.js +3 -6
- package/dist/decorators/swarmSafe.decorator.js +3 -7
- package/dist/decorators/timeout.decorator.d.ts +1 -1
- package/dist/decorators/timeout.decorator.js +7 -10
- package/dist/define.d.ts +1 -1
- package/dist/define.js +11 -19
- package/dist/deviceIdService.js +7 -11
- package/dist/enum.util.d.ts +1 -1
- package/dist/enum.util.js +20 -42
- package/dist/env/buildInfo.d.ts +1 -1
- package/dist/env/buildInfo.js +3 -6
- package/dist/env.js +2 -6
- package/dist/error/assert.d.ts +3 -3
- package/dist/error/assert.js +30 -44
- package/dist/error/error.model.d.ts +2 -2
- package/dist/error/error.model.js +1 -2
- package/dist/error/error.util.d.ts +1 -1
- package/dist/error/error.util.js +25 -44
- package/dist/error/errorMode.js +2 -5
- package/dist/error/try.d.ts +2 -2
- package/dist/error/try.js +15 -23
- package/dist/error/tryCatch.d.ts +2 -2
- package/dist/error/tryCatch.js +6 -11
- package/dist/form.util.d.ts +1 -1
- package/dist/form.util.js +2 -6
- package/dist/http/fetcher.d.ts +3 -3
- package/dist/http/fetcher.js +48 -53
- package/dist/http/fetcher.model.d.ts +5 -5
- package/dist/http/fetcher.model.js +1 -2
- package/dist/http/http.model.js +1 -4
- package/dist/index.d.ts +96 -96
- package/dist/index.js +96 -99
- package/dist/is.util.d.ts +2 -2
- package/dist/is.util.js +12 -27
- package/dist/iter/asyncIterable2.d.ts +3 -3
- package/dist/iter/asyncIterable2.js +8 -12
- package/dist/iter/iterable2.d.ts +2 -2
- package/dist/iter/iterable2.js +8 -12
- package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +1 -1
- package/dist/json-schema/from-data/generateJsonSchemaFromData.js +4 -7
- package/dist/json-schema/jsonSchema.cnst.d.ts +1 -1
- package/dist/json-schema/jsonSchema.cnst.js +1 -4
- package/dist/json-schema/jsonSchema.model.d.ts +1 -1
- package/dist/json-schema/jsonSchema.model.js +1 -2
- package/dist/json-schema/jsonSchema.util.d.ts +2 -2
- package/dist/json-schema/jsonSchema.util.js +5 -8
- package/dist/json-schema/jsonSchemaBuilder.d.ts +2 -2
- package/dist/json-schema/jsonSchemaBuilder.js +16 -25
- package/dist/json-schema/jsonSchemas.d.ts +2 -2
- package/dist/json-schema/jsonSchemas.js +5 -8
- package/dist/log/commonLogger.js +14 -21
- package/dist/math/accumulatingAverage.js +1 -5
- package/dist/math/math.util.js +11 -19
- package/dist/math/sma.js +1 -5
- package/dist/math/stack.util.js +11 -16
- package/dist/nanoid.js +2 -6
- package/dist/number/createDeterministicRandom.js +1 -4
- package/dist/number/number.util.d.ts +1 -1
- package/dist/number/number.util.js +9 -20
- package/dist/object/deepEquals.js +3 -8
- package/dist/object/map2.js +1 -5
- package/dist/object/object.util.d.ts +2 -2
- package/dist/object/object.util.js +40 -70
- package/dist/object/set2.js +1 -5
- package/dist/object/sortObject.d.ts +1 -1
- package/dist/object/sortObject.js +1 -4
- package/dist/object/sortObjectDeep.js +1 -4
- package/dist/polyfill.js +1 -4
- package/dist/promise/abortable.d.ts +1 -1
- package/dist/promise/abortable.js +2 -7
- package/dist/promise/pDefer.js +1 -4
- package/dist/promise/pDelay.d.ts +2 -2
- package/dist/promise/pDelay.js +4 -8
- package/dist/promise/pFilter.d.ts +1 -1
- package/dist/promise/pFilter.js +1 -4
- package/dist/promise/pHang.js +1 -4
- package/dist/promise/pMap.d.ts +2 -2
- package/dist/promise/pMap.js +17 -20
- package/dist/promise/pProps.js +1 -4
- package/dist/promise/pQueue.d.ts +2 -2
- package/dist/promise/pQueue.js +7 -11
- package/dist/promise/pRetry.d.ts +1 -1
- package/dist/promise/pRetry.js +8 -12
- package/dist/promise/pState.js +1 -4
- package/dist/promise/pTimeout.d.ts +3 -3
- package/dist/promise/pTimeout.js +7 -11
- package/dist/semver.d.ts +1 -1
- package/dist/semver.js +13 -18
- package/dist/string/case.js +9 -14
- package/dist/string/escape.js +2 -6
- package/dist/string/hash.util.d.ts +1 -1
- package/dist/string/hash.util.js +4 -10
- package/dist/string/json.util.d.ts +1 -1
- package/dist/string/json.util.js +5 -10
- package/dist/string/leven.js +1 -4
- package/dist/string/lodash/unicodeWords.js +1 -4
- package/dist/string/lodash/words.js +3 -6
- package/dist/string/pupa.d.ts +1 -1
- package/dist/string/pupa.js +4 -9
- package/dist/string/readingTime.d.ts +1 -1
- package/dist/string/readingTime.js +1 -4
- package/dist/string/regex.js +1 -4
- package/dist/string/safeJsonStringify.d.ts +1 -1
- package/dist/string/safeJsonStringify.js +1 -4
- package/dist/string/slugify.js +1 -4
- package/dist/string/string.util.js +15 -32
- package/dist/string/stringify.d.ts +1 -1
- package/dist/string/stringify.js +10 -14
- package/dist/string/url.util.d.ts +1 -1
- package/dist/string/url.util.js +2 -6
- package/dist/time/time.util.d.ts +1 -1
- package/dist/time/time.util.js +3 -8
- package/dist/typeFest.js +1 -2
- package/dist/types.d.ts +7 -3
- package/dist/types.js +21 -23
- package/dist/unit/size.util.js +5 -12
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -5
- package/dist/zod/index.d.ts +2 -2
- package/dist/zod/index.js +4 -10
- package/dist/zod/zod.shared.schemas.js +36 -39
- package/dist/zod/zod.util.js +7 -14
- package/package.json +7 -8
- package/src/array/array.util.ts +3 -3
- package/src/array/range.ts +2 -2
- package/src/bot.ts +1 -1
- package/src/browser/adminService.ts +4 -4
- package/src/browser/analytics.util.ts +1 -1
- package/src/browser/i18n/fetchTranslationLoader.ts +3 -3
- package/src/browser/i18n/translation.service.ts +2 -2
- package/src/browser/script.util.ts +2 -2
- package/src/datetime/dateInterval.ts +3 -3
- package/src/datetime/localDate.ts +5 -5
- package/src/datetime/localTime.ts +6 -6
- package/src/datetime/timeInterval.ts +3 -3
- package/src/datetime/wallTime.ts +4 -4
- package/src/decorators/asyncMemo.decorator.ts +7 -7
- package/src/decorators/createPromiseDecorator.ts +1 -1
- package/src/decorators/debounce.decorator.ts +2 -2
- package/src/decorators/debounce.ts +1 -1
- package/src/decorators/decorator.util.ts +1 -1
- package/src/decorators/logMethod.decorator.ts +4 -4
- package/src/decorators/memo.decorator.ts +7 -7
- package/src/decorators/memo.util.ts +4 -4
- package/src/decorators/memoFn.ts +4 -4
- package/src/decorators/memoFnAsync.ts +5 -5
- package/src/decorators/memoSimple.decorator.ts +4 -4
- package/src/decorators/retry.decorator.ts +2 -2
- package/src/decorators/swarmSafe.decorator.ts +2 -2
- package/src/decorators/timeout.decorator.ts +4 -4
- package/src/define.ts +3 -3
- package/src/deviceIdService.ts +3 -3
- package/src/enum.util.ts +1 -1
- package/src/env/buildInfo.ts +2 -2
- package/src/error/assert.ts +7 -7
- package/src/error/error.model.ts +2 -2
- package/src/error/error.util.ts +5 -5
- package/src/error/try.ts +5 -5
- package/src/error/tryCatch.ts +3 -3
- package/src/form.util.ts +1 -1
- package/src/http/fetcher.model.ts +5 -5
- package/src/http/fetcher.ts +20 -15
- package/src/index.ts +96 -96
- package/src/is.util.ts +2 -2
- package/src/iter/asyncIterable2.ts +3 -3
- package/src/iter/iterable2.ts +2 -2
- package/src/json-schema/from-data/generateJsonSchemaFromData.ts +2 -2
- package/src/json-schema/jsonSchema.cnst.ts +1 -1
- package/src/json-schema/jsonSchema.model.ts +1 -1
- package/src/json-schema/jsonSchema.util.ts +4 -4
- package/src/json-schema/jsonSchemaBuilder.ts +5 -5
- package/src/json-schema/jsonSchemas.ts +2 -2
- package/src/math/math.util.ts +2 -2
- package/src/math/stack.util.ts +1 -1
- package/src/number/number.util.ts +1 -1
- package/src/object/object.util.ts +3 -3
- package/src/object/sortObject.ts +1 -1
- package/src/promise/abortable.ts +1 -1
- package/src/promise/pDelay.ts +3 -3
- package/src/promise/pFilter.ts +1 -1
- package/src/promise/pMap.ts +2 -2
- package/src/promise/pQueue.ts +4 -4
- package/src/promise/pRetry.ts +2 -2
- package/src/promise/pTimeout.ts +4 -4
- package/src/semver.ts +3 -3
- package/src/string/case.ts +2 -2
- package/src/string/hash.util.ts +1 -1
- package/src/string/json.util.ts +2 -2
- package/src/string/lodash/words.ts +1 -1
- package/src/string/pupa.ts +2 -2
- package/src/string/readingTime.ts +1 -1
- package/src/string/safeJsonStringify.ts +1 -1
- package/src/string/stringify.ts +4 -4
- package/src/string/url.util.ts +1 -1
- package/src/time/time.util.ts +1 -1
- package/src/types.ts +15 -3
- package/src/web.ts +1 -1
- package/src/zod/index.ts +2 -2
- package/src/zod/zod.util.ts +1 -1
- package/dist-esm/abort.js +0 -12
- package/dist-esm/array/array.util.js +0 -458
- package/dist-esm/array/range.js +0 -34
- package/dist-esm/bot.js +0 -130
- package/dist-esm/browser/adminService.js +0 -94
- package/dist-esm/browser/analytics.util.js +0 -54
- package/dist-esm/browser/i18n/fetchTranslationLoader.js +0 -13
- package/dist-esm/browser/i18n/translation.service.js +0 -56
- package/dist-esm/browser/imageFitter.js +0 -65
- package/dist-esm/browser/script.util.js +0 -46
- package/dist-esm/browser/topbar.js +0 -135
- package/dist-esm/datetime/dateInterval.js +0 -80
- package/dist-esm/datetime/localDate.js +0 -719
- package/dist-esm/datetime/localTime.js +0 -996
- package/dist-esm/datetime/timeInterval.js +0 -88
- package/dist-esm/datetime/wallTime.js +0 -70
- package/dist-esm/decorators/asyncMemo.decorator.js +0 -111
- package/dist-esm/decorators/createPromiseDecorator.js +0 -82
- package/dist-esm/decorators/debounce.decorator.js +0 -17
- package/dist-esm/decorators/debounce.js +0 -114
- package/dist-esm/decorators/decorator.util.js +0 -31
- package/dist-esm/decorators/logMethod.decorator.js +0 -85
- package/dist-esm/decorators/memo.decorator.js +0 -80
- package/dist-esm/decorators/memo.util.js +0 -97
- package/dist-esm/decorators/memoFn.js +0 -29
- package/dist-esm/decorators/memoFnAsync.js +0 -35
- package/dist-esm/decorators/memoSimple.decorator.js +0 -55
- package/dist-esm/decorators/retry.decorator.js +0 -9
- package/dist-esm/decorators/swarmSafe.decorator.js +0 -38
- package/dist-esm/decorators/timeout.decorator.js +0 -19
- package/dist-esm/define.js +0 -109
- package/dist-esm/deviceIdService.js +0 -105
- package/dist-esm/enum.util.js +0 -157
- package/dist-esm/env/buildInfo.js +0 -19
- package/dist-esm/env.js +0 -19
- package/dist-esm/error/assert.js +0 -122
- package/dist-esm/error/error.model.js +0 -1
- package/dist-esm/error/error.util.js +0 -337
- package/dist-esm/error/errorMode.js +0 -20
- package/dist-esm/error/try.js +0 -105
- package/dist-esm/error/tryCatch.js +0 -41
- package/dist-esm/form.util.js +0 -16
- package/dist-esm/http/fetcher.js +0 -704
- package/dist-esm/http/fetcher.model.js +0 -3
- package/dist-esm/http/http.model.js +0 -1
- package/dist-esm/index.js +0 -96
- package/dist-esm/is.util.js +0 -70
- package/dist-esm/iter/asyncIterable2.js +0 -103
- package/dist-esm/iter/iterable2.js +0 -87
- package/dist-esm/json-schema/from-data/generateJsonSchemaFromData.js +0 -86
- package/dist-esm/json-schema/jsonSchema.cnst.js +0 -38
- package/dist-esm/json-schema/jsonSchema.model.js +0 -1
- package/dist-esm/json-schema/jsonSchema.util.js +0 -27
- package/dist-esm/json-schema/jsonSchemaBuilder.js +0 -352
- package/dist-esm/json-schema/jsonSchemas.js +0 -6
- package/dist-esm/log/commonLogger.js +0 -78
- package/dist-esm/math/accumulatingAverage.js +0 -32
- package/dist-esm/math/math.util.js +0 -85
- package/dist-esm/math/sma.js +0 -43
- package/dist-esm/math/stack.util.js +0 -82
- package/dist-esm/nanoid.js +0 -57
- package/dist-esm/number/createDeterministicRandom.js +0 -18
- package/dist-esm/number/number.util.js +0 -109
- package/dist-esm/object/deepEquals.js +0 -170
- package/dist-esm/object/map2.js +0 -21
- package/dist-esm/object/object.util.js +0 -435
- package/dist-esm/object/set2.js +0 -15
- package/dist-esm/object/sortObject.js +0 -21
- package/dist-esm/object/sortObjectDeep.js +0 -17
- package/dist-esm/polyfill.js +0 -6
- package/dist-esm/promise/abortable.js +0 -31
- package/dist-esm/promise/pDefer.js +0 -17
- package/dist-esm/promise/pDelay.js +0 -37
- package/dist-esm/promise/pFilter.js +0 -5
- package/dist-esm/promise/pHang.js +0 -6
- package/dist-esm/promise/pMap.js +0 -174
- package/dist-esm/promise/pProps.js +0 -20
- package/dist-esm/promise/pQueue.js +0 -101
- package/dist-esm/promise/pRetry.js +0 -64
- package/dist-esm/promise/pState.js +0 -14
- package/dist-esm/promise/pTimeout.js +0 -64
- package/dist-esm/semver.js +0 -149
- package/dist-esm/string/case.js +0 -24
- package/dist-esm/string/escape.js +0 -49
- package/dist-esm/string/hash.util.js +0 -67
- package/dist-esm/string/json.util.js +0 -46
- package/dist-esm/string/leven.js +0 -77
- package/dist-esm/string/lodash/unicodeWords.js +0 -68
- package/dist-esm/string/lodash/words.js +0 -31
- package/dist-esm/string/pupa.js +0 -54
- package/dist-esm/string/readingTime.js +0 -102
- package/dist-esm/string/regex.js +0 -6
- package/dist-esm/string/safeJsonStringify.js +0 -39
- package/dist-esm/string/slugify.js +0 -66
- package/dist-esm/string/string.util.js +0 -99
- package/dist-esm/string/stringify.js +0 -133
- package/dist-esm/string/url.util.js +0 -42
- package/dist-esm/time/time.util.js +0 -61
- package/dist-esm/typeFest.js +0 -2
- package/dist-esm/types.js +0 -59
- package/dist-esm/unit/size.util.js +0 -43
- package/dist-esm/web.js +0 -40
- package/dist-esm/zod/index.js +0 -4
- package/dist-esm/zod/zod.shared.schemas.js +0 -92
- package/dist-esm/zod/zod.util.js +0 -52
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { localTime } from './localTime';
|
|
2
|
-
/**
|
|
3
|
-
* Class that supports an "interval of time" between 2 timestamps - start and end.
|
|
4
|
-
* Example: `1649267185/1649267187`.
|
|
5
|
-
*
|
|
6
|
-
* @experimental
|
|
7
|
-
*/
|
|
8
|
-
export class TimeInterval {
|
|
9
|
-
constructor($start, $end) {
|
|
10
|
-
this.$start = $start;
|
|
11
|
-
this.$end = $end;
|
|
12
|
-
}
|
|
13
|
-
static of(start, end) {
|
|
14
|
-
return new TimeInterval(localTime.fromInput(start).unix, localTime.fromInput(end).unix);
|
|
15
|
-
}
|
|
16
|
-
get start() {
|
|
17
|
-
return this.$start;
|
|
18
|
-
}
|
|
19
|
-
get end() {
|
|
20
|
-
return this.$end;
|
|
21
|
-
}
|
|
22
|
-
get startTime() {
|
|
23
|
-
return localTime(this.$start);
|
|
24
|
-
}
|
|
25
|
-
get endTime() {
|
|
26
|
-
return localTime(this.$end);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Parses string like `1649267185/1649267187` into a TimeInterval.
|
|
30
|
-
*/
|
|
31
|
-
static parse(d) {
|
|
32
|
-
if (d instanceof TimeInterval)
|
|
33
|
-
return d;
|
|
34
|
-
const [start, end] = d.split('/').map(Number);
|
|
35
|
-
if (!end || !start) {
|
|
36
|
-
throw new Error(`Cannot parse "${d}" into TimeInterval`);
|
|
37
|
-
}
|
|
38
|
-
return new TimeInterval(start, end);
|
|
39
|
-
}
|
|
40
|
-
isSame(d) {
|
|
41
|
-
return this.cmp(d) === 0;
|
|
42
|
-
}
|
|
43
|
-
isBefore(d, inclusive = false) {
|
|
44
|
-
const r = this.cmp(d);
|
|
45
|
-
return r === -1 || (r === 0 && inclusive);
|
|
46
|
-
}
|
|
47
|
-
isSameOrBefore(d) {
|
|
48
|
-
return this.cmp(d) <= 0;
|
|
49
|
-
}
|
|
50
|
-
isAfter(d, inclusive = false) {
|
|
51
|
-
const r = this.cmp(d);
|
|
52
|
-
return r === 1 || (r === 0 && inclusive);
|
|
53
|
-
}
|
|
54
|
-
isSameOrAfter(d) {
|
|
55
|
-
return this.cmp(d) >= 0;
|
|
56
|
-
}
|
|
57
|
-
includes(d, incl = '[)') {
|
|
58
|
-
d = localTime.fromInput(d).unix;
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
60
|
-
if (d < this.$start || (d === this.$start && incl[0] === '('))
|
|
61
|
-
return false;
|
|
62
|
-
if (d > this.$end || (d === this.$end && incl[1] === ')'))
|
|
63
|
-
return false;
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* TimeIntervals compare by start date.
|
|
68
|
-
* If it's the same - then by end date.
|
|
69
|
-
*/
|
|
70
|
-
cmp(d) {
|
|
71
|
-
d = TimeInterval.parse(d);
|
|
72
|
-
if (this.$start > d.$start)
|
|
73
|
-
return 1;
|
|
74
|
-
if (this.$start < d.$start)
|
|
75
|
-
return -1;
|
|
76
|
-
if (this.$end > d.$end)
|
|
77
|
-
return 1;
|
|
78
|
-
if (this.$end < d.$end)
|
|
79
|
-
return -1;
|
|
80
|
-
return 0;
|
|
81
|
-
}
|
|
82
|
-
toString() {
|
|
83
|
-
return [this.$start, this.$end].join('/');
|
|
84
|
-
}
|
|
85
|
-
toJSON() {
|
|
86
|
-
return this.toString();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { LocalDate } from './localDate';
|
|
2
|
-
import { localTime } from './localTime';
|
|
3
|
-
/**
|
|
4
|
-
* Representation of a "time on the wall clock",
|
|
5
|
-
* which means "local time, regardless of timezone".
|
|
6
|
-
*
|
|
7
|
-
* Experimental simplified container object to hold
|
|
8
|
-
* date and time components as numbers.
|
|
9
|
-
* No math or manipulation is possible here.
|
|
10
|
-
* Can be pretty-printed as Date, Time or DateAndTime.
|
|
11
|
-
*/
|
|
12
|
-
export class WallTime {
|
|
13
|
-
constructor(obj) {
|
|
14
|
-
Object.assign(this, obj);
|
|
15
|
-
}
|
|
16
|
-
toLocalDate() {
|
|
17
|
-
return new LocalDate(this.year, this.month, this.day);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Example:
|
|
21
|
-
* WallTime is 1984-06-21 17:56:21
|
|
22
|
-
* .toLocalTime() will return a LocalTime Date instance
|
|
23
|
-
* holding that time in the local timezone.
|
|
24
|
-
*/
|
|
25
|
-
toLocalTime() {
|
|
26
|
-
return localTime.fromDateTimeObject(this);
|
|
27
|
-
}
|
|
28
|
-
toJSON() {
|
|
29
|
-
return this.toISODateTime();
|
|
30
|
-
}
|
|
31
|
-
toString() {
|
|
32
|
-
return this.toISODateTime();
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Returns e.g: `1984-06-21 17:56:21`
|
|
36
|
-
* or (if seconds=false):
|
|
37
|
-
* `1984-06-21 17:56`
|
|
38
|
-
*/
|
|
39
|
-
toPretty(seconds = true) {
|
|
40
|
-
return this.toISODate() + ' ' + this.toISOTime(seconds);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Returns e.g: `1984-06-21T17:56:21`
|
|
44
|
-
*/
|
|
45
|
-
toISODateTime() {
|
|
46
|
-
return (this.toISODate() + 'T' + this.toISOTime());
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Returns e.g: `1984-06-21`, only the date part of DateTime
|
|
50
|
-
*/
|
|
51
|
-
toISODate() {
|
|
52
|
-
return [
|
|
53
|
-
String(this.year).padStart(4, '0'),
|
|
54
|
-
String(this.month).padStart(2, '0'),
|
|
55
|
-
String(this.day).padStart(2, '0'),
|
|
56
|
-
].join('-');
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Returns e.g: `17:03:15` (or `17:03` with seconds=false)
|
|
60
|
-
*/
|
|
61
|
-
toISOTime(seconds = true) {
|
|
62
|
-
return [
|
|
63
|
-
String(this.hour).padStart(2, '0'),
|
|
64
|
-
String(this.minute).padStart(2, '0'),
|
|
65
|
-
seconds && String(this.second).padStart(2, '0'),
|
|
66
|
-
]
|
|
67
|
-
.filter(Boolean)
|
|
68
|
-
.join(':');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { _assert, _assertTypeOf } from '../error/assert';
|
|
2
|
-
import { _objectAssign, MISS } from '../types';
|
|
3
|
-
import { _getTargetMethodSignature } from './decorator.util';
|
|
4
|
-
import { jsonMemoSerializer } from './memo.util';
|
|
5
|
-
/**
|
|
6
|
-
* Like @_Memo, but allowing async MemoCache implementation.
|
|
7
|
-
*
|
|
8
|
-
* Implementation is more complex than @_Memo, because it needs to handle "in-flight" Promises
|
|
9
|
-
* while waiting for cache to resolve, to prevent "async swarm" issue.
|
|
10
|
-
*
|
|
11
|
-
* @experimental consider normal @_Memo for most of the cases, it's stable and predictable
|
|
12
|
-
*/
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
-
export const _AsyncMemo = (opt) => (target, key, descriptor) => {
|
|
15
|
-
_assertTypeOf(descriptor.value, 'function', 'Memoization can be applied only to methods');
|
|
16
|
-
const originalFn = descriptor.value;
|
|
17
|
-
// Map from "instance" of the Class where @_AsyncMemo is applied to AsyncMemoCache instance.
|
|
18
|
-
const instanceCache = new Map();
|
|
19
|
-
// Cache from Instance to Map<key, Promise>
|
|
20
|
-
// This cache is temporary, with only one purpose - to prevent "async swarm"
|
|
21
|
-
// It only holds values that are "in-flight", until Promise is resolved
|
|
22
|
-
// After it's resolved - it's evicted from the cache and moved to the "proper" `instanceCache`
|
|
23
|
-
const instancePromiseCache = new Map();
|
|
24
|
-
const { logger = console, cacheFactory, cacheKeyFn = jsonMemoSerializer } = opt;
|
|
25
|
-
const keyStr = String(key);
|
|
26
|
-
const methodSignature = _getTargetMethodSignature(target, keyStr);
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
28
|
-
descriptor.value = function (...args) {
|
|
29
|
-
const ctx = this;
|
|
30
|
-
const cacheKey = cacheKeyFn(args);
|
|
31
|
-
let cache = instanceCache.get(ctx);
|
|
32
|
-
let promiseCache = instancePromiseCache.get(ctx);
|
|
33
|
-
if (!cache) {
|
|
34
|
-
cache = cacheFactory();
|
|
35
|
-
instanceCache.set(ctx, cache);
|
|
36
|
-
// here, no need to check the cache. It's definitely a miss, because the cacheLayers is just created
|
|
37
|
-
// UPD: no! AsyncMemo supports "persistent caches" (e.g Database-backed cache)
|
|
38
|
-
}
|
|
39
|
-
if (!promiseCache) {
|
|
40
|
-
promiseCache = new Map();
|
|
41
|
-
instancePromiseCache.set(ctx, promiseCache);
|
|
42
|
-
}
|
|
43
|
-
let promise = promiseCache.get(cacheKey);
|
|
44
|
-
// If there's already "in-flight" cache request - return that, to avoid "async swarm"
|
|
45
|
-
if (promise) {
|
|
46
|
-
// console.log('return promise', promiseCache.size)
|
|
47
|
-
return promise;
|
|
48
|
-
}
|
|
49
|
-
promise = cache.get(cacheKey).then(async (value) => {
|
|
50
|
-
if (value !== MISS) {
|
|
51
|
-
// console.log('hit', promiseCache.size)
|
|
52
|
-
promiseCache.delete(cacheKey);
|
|
53
|
-
return value;
|
|
54
|
-
}
|
|
55
|
-
// Miss
|
|
56
|
-
// console.log('miss', promiseCache.size)
|
|
57
|
-
return await onMiss();
|
|
58
|
-
}, async (err) => {
|
|
59
|
-
// Log the cache error and proceed "as cache Miss"
|
|
60
|
-
logger.error(err);
|
|
61
|
-
return await onMiss();
|
|
62
|
-
});
|
|
63
|
-
promiseCache.set(cacheKey, promise);
|
|
64
|
-
return promise;
|
|
65
|
-
//
|
|
66
|
-
async function onMiss() {
|
|
67
|
-
try {
|
|
68
|
-
const value = await originalFn.apply(ctx, args);
|
|
69
|
-
// Save the value in the Cache, in parallel,
|
|
70
|
-
// not to slow down the main function execution
|
|
71
|
-
// and not to fail on possible cache issues
|
|
72
|
-
void (async () => {
|
|
73
|
-
try {
|
|
74
|
-
await cache.set(cacheKey, value);
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
logger.error(err); // log and ignore the error
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
// Clear the "in-flight" promise cache entry, as we now have a "permanent" cache entry
|
|
81
|
-
promiseCache.delete(cacheKey);
|
|
82
|
-
// console.log('cache set and cleared', promiseCache!.size)
|
|
83
|
-
}
|
|
84
|
-
})();
|
|
85
|
-
return value;
|
|
86
|
-
}
|
|
87
|
-
catch (err) {
|
|
88
|
-
promiseCache.delete(cacheKey);
|
|
89
|
-
throw err;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
_objectAssign(descriptor.value, {
|
|
94
|
-
clear: async () => {
|
|
95
|
-
logger.log(`${methodSignature} @_AsyncMemo.clear()`);
|
|
96
|
-
await Promise.all([...instanceCache.values()].map(c => c.clear()));
|
|
97
|
-
instanceCache.clear();
|
|
98
|
-
},
|
|
99
|
-
getInstanceCache: () => instanceCache,
|
|
100
|
-
getCache: instance => instanceCache.get(instance),
|
|
101
|
-
});
|
|
102
|
-
return descriptor;
|
|
103
|
-
};
|
|
104
|
-
/**
|
|
105
|
-
Call it on a method that is decorated with `@_AsyncMemo` to get access to additional functions,
|
|
106
|
-
e.g `clear` to clear the cache, or get its underlying data.
|
|
107
|
-
*/
|
|
108
|
-
export function _getAsyncMemo(method) {
|
|
109
|
-
_assert(typeof method?.getInstanceCache === 'function', 'method is not an AsyncMemo instance');
|
|
110
|
-
return method;
|
|
111
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { _getTargetMethodSignature } from './decorator.util';
|
|
2
|
-
/**
|
|
3
|
-
* @example
|
|
4
|
-
* // decorators.ts
|
|
5
|
-
* export const BlockingLoader = () => _createPromiseDecorator({
|
|
6
|
-
* decoratorName: 'BlockingLoader',
|
|
7
|
-
* beforeFn: () => store.commit('setBlockingLoader'),
|
|
8
|
-
* finallyFn: () => store.commit('setBlockingLoader', false),
|
|
9
|
-
* })
|
|
10
|
-
*
|
|
11
|
-
* @experimental
|
|
12
|
-
*/
|
|
13
|
-
export function _createPromiseDecorator(cfg, decoratorParams = {}) {
|
|
14
|
-
const { decoratorName } = cfg;
|
|
15
|
-
return function decoratorFunction(target, propertyKey, pd) {
|
|
16
|
-
// console.log(`@Decorator.${cfg.decoratorName} called: ` + propertyKey, pd, target)
|
|
17
|
-
const originalMethod = pd.value;
|
|
18
|
-
const key = String(propertyKey);
|
|
19
|
-
const methodSignature = _getTargetMethodSignature(target, key);
|
|
20
|
-
pd.value = async function (...args) {
|
|
21
|
-
// console.log(`@${cfg.decoratorName} called inside function`)
|
|
22
|
-
const started = Date.now();
|
|
23
|
-
try {
|
|
24
|
-
// Before function
|
|
25
|
-
// console.log(`@${cfg.decoratorName} Before`)
|
|
26
|
-
if (cfg.beforeFn) {
|
|
27
|
-
await cfg.beforeFn({
|
|
28
|
-
decoratorParams,
|
|
29
|
-
args,
|
|
30
|
-
key,
|
|
31
|
-
target,
|
|
32
|
-
decoratorName,
|
|
33
|
-
started,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
// Original function
|
|
37
|
-
let res = await originalMethod.apply(this, args);
|
|
38
|
-
// console.log(`${cfg.decoratorName} After`)
|
|
39
|
-
const resp = {
|
|
40
|
-
decoratorParams,
|
|
41
|
-
args,
|
|
42
|
-
key,
|
|
43
|
-
target,
|
|
44
|
-
decoratorName,
|
|
45
|
-
started,
|
|
46
|
-
};
|
|
47
|
-
if (cfg.thenFn) {
|
|
48
|
-
res = cfg.thenFn({
|
|
49
|
-
...resp,
|
|
50
|
-
res,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
cfg.finallyFn?.(resp);
|
|
54
|
-
return res;
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
console.error(`@${decoratorName} ${methodSignature} catch:`, err);
|
|
58
|
-
const resp = {
|
|
59
|
-
decoratorParams,
|
|
60
|
-
args,
|
|
61
|
-
key,
|
|
62
|
-
target,
|
|
63
|
-
decoratorName,
|
|
64
|
-
started,
|
|
65
|
-
};
|
|
66
|
-
let handled = false;
|
|
67
|
-
if (cfg.catchFn) {
|
|
68
|
-
cfg.catchFn({
|
|
69
|
-
...resp,
|
|
70
|
-
err,
|
|
71
|
-
});
|
|
72
|
-
handled = true;
|
|
73
|
-
}
|
|
74
|
-
cfg.finallyFn?.(resp);
|
|
75
|
-
if (!handled) {
|
|
76
|
-
throw err; // rethrow
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
return pd;
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { _debounce, _throttle } from './debounce';
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3
|
-
export function _Debounce(wait, opt = {}) {
|
|
4
|
-
return (_target, _key, descriptor) => {
|
|
5
|
-
const originalFn = descriptor.value;
|
|
6
|
-
descriptor.value = _debounce(originalFn, wait, opt);
|
|
7
|
-
return descriptor;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
11
|
-
export function _Throttle(wait, opt = {}) {
|
|
12
|
-
return (_target, _key, descriptor) => {
|
|
13
|
-
const originalFn = descriptor.value;
|
|
14
|
-
descriptor.value = _throttle(originalFn, wait, opt);
|
|
15
|
-
return descriptor;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
export function _debounce(func, wait, opt = {}) {
|
|
2
|
-
let lastArgs;
|
|
3
|
-
let lastThis;
|
|
4
|
-
let result;
|
|
5
|
-
let timerId;
|
|
6
|
-
let lastCallTime;
|
|
7
|
-
let lastInvokeTime = 0;
|
|
8
|
-
const maxing = 'maxWait' in opt;
|
|
9
|
-
const { leading = false, trailing = true } = opt;
|
|
10
|
-
const maxWait = maxing ? Math.max(Number(opt.maxWait) || 0, wait) : opt.maxWait;
|
|
11
|
-
function invokeFunc(time) {
|
|
12
|
-
const args = lastArgs;
|
|
13
|
-
const thisArg = lastThis;
|
|
14
|
-
lastArgs = lastThis = undefined;
|
|
15
|
-
lastInvokeTime = time;
|
|
16
|
-
result = func.apply(thisArg, args);
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
function startTimer(pendingFunc, wait) {
|
|
20
|
-
return setTimeout(pendingFunc, wait);
|
|
21
|
-
}
|
|
22
|
-
function cancelTimer(id) {
|
|
23
|
-
clearTimeout(id);
|
|
24
|
-
}
|
|
25
|
-
function leadingEdge(time) {
|
|
26
|
-
// Reset any `maxWait` timer.
|
|
27
|
-
lastInvokeTime = time;
|
|
28
|
-
// Start the timer for the trailing edge.
|
|
29
|
-
timerId = startTimer(timerExpired, wait);
|
|
30
|
-
// Invoke the leading edge.
|
|
31
|
-
return leading ? invokeFunc(time) : result;
|
|
32
|
-
}
|
|
33
|
-
function remainingWait(time) {
|
|
34
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
35
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
36
|
-
const timeWaiting = wait - timeSinceLastCall;
|
|
37
|
-
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
|
|
38
|
-
}
|
|
39
|
-
function shouldInvoke(time) {
|
|
40
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
41
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
42
|
-
// Either this is the first call, activity has stopped and we're at the
|
|
43
|
-
// trailing edge, the system time has gone backwards and we're treating
|
|
44
|
-
// it as the trailing edge, or we've hit the `maxWait` limit.
|
|
45
|
-
return (lastCallTime === undefined ||
|
|
46
|
-
timeSinceLastCall >= wait ||
|
|
47
|
-
timeSinceLastCall < 0 ||
|
|
48
|
-
(maxing && timeSinceLastInvoke >= maxWait));
|
|
49
|
-
}
|
|
50
|
-
function timerExpired() {
|
|
51
|
-
const time = Date.now();
|
|
52
|
-
if (shouldInvoke(time)) {
|
|
53
|
-
return trailingEdge(time);
|
|
54
|
-
}
|
|
55
|
-
// Restart the timer.
|
|
56
|
-
timerId = startTimer(timerExpired, remainingWait(time));
|
|
57
|
-
}
|
|
58
|
-
function trailingEdge(time) {
|
|
59
|
-
timerId = undefined;
|
|
60
|
-
// Only invoke if we have `lastArgs` which means `func` has been
|
|
61
|
-
// debounced at least once.
|
|
62
|
-
if (trailing && lastArgs) {
|
|
63
|
-
return invokeFunc(time);
|
|
64
|
-
}
|
|
65
|
-
lastArgs = lastThis = undefined;
|
|
66
|
-
return result;
|
|
67
|
-
}
|
|
68
|
-
function cancel() {
|
|
69
|
-
if (timerId !== undefined) {
|
|
70
|
-
cancelTimer(timerId);
|
|
71
|
-
}
|
|
72
|
-
lastInvokeTime = 0;
|
|
73
|
-
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
|
74
|
-
}
|
|
75
|
-
function flush() {
|
|
76
|
-
return timerId === undefined ? result : trailingEdge(Date.now());
|
|
77
|
-
}
|
|
78
|
-
function pending() {
|
|
79
|
-
return timerId !== undefined;
|
|
80
|
-
}
|
|
81
|
-
function debounced(...args) {
|
|
82
|
-
const time = Date.now();
|
|
83
|
-
const isInvoking = shouldInvoke(time);
|
|
84
|
-
lastArgs = args;
|
|
85
|
-
lastThis = this;
|
|
86
|
-
lastCallTime = time;
|
|
87
|
-
if (isInvoking) {
|
|
88
|
-
if (timerId === undefined) {
|
|
89
|
-
return leadingEdge(lastCallTime);
|
|
90
|
-
}
|
|
91
|
-
if (maxing) {
|
|
92
|
-
// Handle invocations in a tight loop.
|
|
93
|
-
timerId = startTimer(timerExpired, wait);
|
|
94
|
-
return invokeFunc(lastCallTime);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (timerId === undefined) {
|
|
98
|
-
timerId = startTimer(timerExpired, wait);
|
|
99
|
-
}
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
debounced.cancel = cancel;
|
|
103
|
-
debounced.flush = flush;
|
|
104
|
-
debounced.pending = pending;
|
|
105
|
-
return debounced;
|
|
106
|
-
}
|
|
107
|
-
export function _throttle(func, wait, opt = {}) {
|
|
108
|
-
return _debounce(func, wait, {
|
|
109
|
-
leading: true,
|
|
110
|
-
trailing: true,
|
|
111
|
-
...opt,
|
|
112
|
-
maxWait: wait,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @returns
|
|
3
|
-
* e.g `NameOfYourClass.methodName`
|
|
4
|
-
* or `NameOfYourClass(instanceId).methodName`
|
|
5
|
-
*/
|
|
6
|
-
export function _getMethodSignature(ctx, keyStr) {
|
|
7
|
-
const { instanceId } = ctx;
|
|
8
|
-
return `${ctx.constructor.name}${instanceId ? `#${instanceId}` : ''}.${keyStr}`;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* @returns `NameOfYourClass.methodName`
|
|
12
|
-
*/
|
|
13
|
-
export function _getTargetMethodSignature(target, keyStr) {
|
|
14
|
-
return `${target.constructor.name}.${keyStr}`;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* @example
|
|
18
|
-
* e.g for method (a: string, b: string, c: string)
|
|
19
|
-
* returns:
|
|
20
|
-
* a, b, c
|
|
21
|
-
*/
|
|
22
|
-
export function _getArgsSignature(args = [], logArgs = true) {
|
|
23
|
-
if (!logArgs)
|
|
24
|
-
return '';
|
|
25
|
-
return args
|
|
26
|
-
.map(arg => {
|
|
27
|
-
const s = arg && typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
|
28
|
-
return s.length > 30 ? '...' : s;
|
|
29
|
-
})
|
|
30
|
-
.join(', ');
|
|
31
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { _assert, _stringify, SimpleMovingAverage } from '..';
|
|
2
|
-
import { _ms } from '../time/time.util';
|
|
3
|
-
import { _getArgsSignature, _getMethodSignature } from './decorator.util';
|
|
4
|
-
/**
|
|
5
|
-
* Console-logs when method had started, when it finished, time taken and if error happened.
|
|
6
|
-
* Supports both sync and async methods.
|
|
7
|
-
* Awaits if method returns a Promise.
|
|
8
|
-
*
|
|
9
|
-
* @example output:
|
|
10
|
-
*
|
|
11
|
-
* >> syncMethodSuccess()
|
|
12
|
-
* << syncMethodSuccess() took 124 ms
|
|
13
|
-
*
|
|
14
|
-
* >> asyncMethod()
|
|
15
|
-
* << asyncMethodThrow() took 10 ms ERROR: MyError
|
|
16
|
-
*/
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
18
|
-
export function _LogMethod(opt = {}) {
|
|
19
|
-
return (target, key, descriptor) => {
|
|
20
|
-
_assert(typeof descriptor.value === 'function', '@_LogMethod can be applied only to methods');
|
|
21
|
-
const originalFn = descriptor.value;
|
|
22
|
-
const keyStr = String(key);
|
|
23
|
-
const { avg, logArgs = true, logStart, logResult, logResultLength = true, logger = console, } = opt;
|
|
24
|
-
let { logResultFn } = opt;
|
|
25
|
-
if (!logResultFn) {
|
|
26
|
-
if (logResult) {
|
|
27
|
-
logResultFn = r => ['result:', _stringify(r)];
|
|
28
|
-
}
|
|
29
|
-
else if (logResultLength) {
|
|
30
|
-
logResultFn = r => (Array.isArray(r) ? [`result: ${r.length} items`] : []);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const sma = avg ? new SimpleMovingAverage(avg) : undefined;
|
|
34
|
-
let count = 0;
|
|
35
|
-
descriptor.value = function (...args) {
|
|
36
|
-
const started = Date.now();
|
|
37
|
-
const ctx = this;
|
|
38
|
-
// e.g `NameOfYourClass.methodName`
|
|
39
|
-
// or `NameOfYourClass(instanceId).methodName`
|
|
40
|
-
const methodSignature = _getMethodSignature(ctx, keyStr);
|
|
41
|
-
const argsStr = _getArgsSignature(args, logArgs);
|
|
42
|
-
const callSignature = `${methodSignature}(${argsStr}) #${++count}`;
|
|
43
|
-
if (logStart)
|
|
44
|
-
logger.log(`>> ${callSignature}`);
|
|
45
|
-
try {
|
|
46
|
-
const res = originalFn.apply(ctx, args);
|
|
47
|
-
if (res && typeof res.then === 'function') {
|
|
48
|
-
// Result is a Promise, will wait for resolution or rejection
|
|
49
|
-
return res
|
|
50
|
-
.then((r) => {
|
|
51
|
-
logFinished(logger, callSignature, started, sma, logResultFn, r);
|
|
52
|
-
return r;
|
|
53
|
-
})
|
|
54
|
-
.catch((err) => {
|
|
55
|
-
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err);
|
|
56
|
-
throw err;
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
// not a Promise
|
|
60
|
-
logFinished(logger, callSignature, started, sma, logResultFn, res);
|
|
61
|
-
return res;
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
logFinished(logger, callSignature, started, sma, logResultFn, undefined, err);
|
|
65
|
-
throw err; // rethrow
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
return descriptor;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
// eslint-disable-next-line max-params
|
|
72
|
-
function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
|
|
73
|
-
const millis = Date.now() - started;
|
|
74
|
-
const t = ['<<', callSignature, 'took', _ms(millis)];
|
|
75
|
-
if (sma) {
|
|
76
|
-
t.push(`(avg ${_ms(sma.pushGetAvg(millis))})`);
|
|
77
|
-
}
|
|
78
|
-
if (err !== undefined) {
|
|
79
|
-
t.push('ERROR:', err);
|
|
80
|
-
}
|
|
81
|
-
else if (logResultFn) {
|
|
82
|
-
t.push(...logResultFn(res));
|
|
83
|
-
}
|
|
84
|
-
logger.log(...t.filter(Boolean));
|
|
85
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { _assert, _assertTypeOf } from '../error/assert';
|
|
2
|
-
import { _objectAssign } from '../types';
|
|
3
|
-
import { _getTargetMethodSignature } from './decorator.util';
|
|
4
|
-
import { jsonMemoSerializer, MapMemoCache } from './memo.util';
|
|
5
|
-
/**
|
|
6
|
-
* Memoizes the method of the class, so it caches the output and returns the cached version if the "key"
|
|
7
|
-
* of the cache is the same. Key, by defaul, is calculated as `JSON.stringify(...args)`.
|
|
8
|
-
* Cache is stored indefinitely in the internal Map.
|
|
9
|
-
*
|
|
10
|
-
* If origin function throws an Error - it is NOT cached.
|
|
11
|
-
* So, error-throwing functions will be called multiple times.
|
|
12
|
-
* Therefor, if the origin function can possibly throw - it should try to be idempotent.
|
|
13
|
-
*
|
|
14
|
-
* Cache is stored **per instance** - separate cache for separate instances of the class.
|
|
15
|
-
* If you don't want it that way - you can use a static method, then there will be only one "instance".
|
|
16
|
-
*
|
|
17
|
-
* Supports dropping it's cache by calling .clear() method of decorated function (useful in unit testing).
|
|
18
|
-
*
|
|
19
|
-
* Based on:
|
|
20
|
-
* https://github.com/mgechev/memo-decorator/blob/master/index.ts
|
|
21
|
-
* http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
|
|
22
|
-
* http://inlehmansterms.net/2015/03/01/javascript-memoization/
|
|
23
|
-
* https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
|
|
24
|
-
*/
|
|
25
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
26
|
-
export const _Memo = (opt = {}) => (target, key, descriptor) => {
|
|
27
|
-
_assertTypeOf(descriptor.value, 'function', 'Memoization can be applied only to methods');
|
|
28
|
-
const originalFn = descriptor.value;
|
|
29
|
-
// Map<ctx => MemoCache<cacheKey, result>>
|
|
30
|
-
//
|
|
31
|
-
// Internal map is from cacheKey to result
|
|
32
|
-
// External map (instanceCache) is from ctx (instance of class) to Internal map
|
|
33
|
-
// External map is Weak to not cause memory leaks, to allow ctx objects to be garbage collected
|
|
34
|
-
// UPD: tests show that normal Map also doesn't leak (to be tested further)
|
|
35
|
-
// Normal Map is needed to allow .clear()
|
|
36
|
-
const instanceCache = new Map();
|
|
37
|
-
const { logger = console, cacheFactory = () => new MapMemoCache(), cacheKeyFn = jsonMemoSerializer, } = opt;
|
|
38
|
-
const keyStr = String(key);
|
|
39
|
-
const methodSignature = _getTargetMethodSignature(target, keyStr);
|
|
40
|
-
descriptor.value = function (...args) {
|
|
41
|
-
const ctx = this;
|
|
42
|
-
const cacheKey = cacheKeyFn(args);
|
|
43
|
-
let cache = instanceCache.get(ctx);
|
|
44
|
-
if (!cache) {
|
|
45
|
-
cache = cacheFactory();
|
|
46
|
-
instanceCache.set(ctx, cache);
|
|
47
|
-
}
|
|
48
|
-
if (cache.has(cacheKey)) {
|
|
49
|
-
// Hit
|
|
50
|
-
return cache.get(cacheKey);
|
|
51
|
-
}
|
|
52
|
-
// Miss
|
|
53
|
-
const value = originalFn.apply(ctx, args);
|
|
54
|
-
try {
|
|
55
|
-
cache.set(cacheKey, value);
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
logger.error(err);
|
|
59
|
-
}
|
|
60
|
-
return value;
|
|
61
|
-
};
|
|
62
|
-
_objectAssign(descriptor.value, {
|
|
63
|
-
clear: () => {
|
|
64
|
-
logger.log(`${methodSignature} @_Memo.clear()`);
|
|
65
|
-
instanceCache.forEach(memoCache => memoCache.clear());
|
|
66
|
-
instanceCache.clear();
|
|
67
|
-
},
|
|
68
|
-
getInstanceCache: () => instanceCache,
|
|
69
|
-
getCache: instance => instanceCache.get(instance),
|
|
70
|
-
});
|
|
71
|
-
return descriptor;
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
Call it on a method that is decorated with `@_Memo` to get access to additional functions,
|
|
75
|
-
e.g `clear` to clear the cache, or get its underlying data.
|
|
76
|
-
*/
|
|
77
|
-
export function _getMemo(method) {
|
|
78
|
-
_assert(typeof method?.getInstanceCache === 'function', 'method is not a Memo instance');
|
|
79
|
-
return method;
|
|
80
|
-
}
|