@naturalcycles/js-lib 14.71.0 → 14.75.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/index.d.ts +24 -23
- package/dist/index.js +25 -122
- package/dist/math/math.util.d.ts +4 -0
- package/dist/math/math.util.js +18 -1
- package/dist/math/sma.d.ts +2 -2
- package/dist/math/stack.util.d.ts +50 -0
- package/dist/math/stack.util.js +87 -0
- package/dist/number/number.util.d.ts +1 -1
- package/dist/number/number.util.js +1 -1
- package/dist/seq/seq.d.ts +29 -7
- package/dist/seq/seq.js +116 -9
- package/dist-esm/index.js +24 -23
- package/dist-esm/math/math.util.js +16 -0
- package/dist-esm/math/stack.util.js +82 -0
- package/dist-esm/number/number.util.js +1 -1
- package/dist-esm/seq/seq.js +114 -8
- package/package.json +1 -1
- package/src/index.ts +23 -193
- package/src/math/math.util.ts +21 -0
- package/src/math/sma.ts +1 -1
- package/src/math/stack.util.ts +94 -0
- package/src/number/number.util.ts +1 -1
- package/src/seq/seq.ts +134 -13
package/src/index.ts
CHANGED
|
@@ -1,29 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
_difference,
|
|
6
|
-
_dropRightWhile,
|
|
7
|
-
_dropWhile,
|
|
8
|
-
_findLast,
|
|
9
|
-
_flatten,
|
|
10
|
-
_flattenDeep,
|
|
11
|
-
_groupBy,
|
|
12
|
-
_intersection,
|
|
13
|
-
_last,
|
|
14
|
-
_mapToObject,
|
|
15
|
-
_shuffle,
|
|
16
|
-
_sortBy,
|
|
17
|
-
_sum,
|
|
18
|
-
_sumBy,
|
|
19
|
-
_takeRightWhile,
|
|
20
|
-
_takeWhile,
|
|
21
|
-
_uniq,
|
|
22
|
-
_uniqBy,
|
|
23
|
-
} from './array/array.util'
|
|
24
|
-
import { _defineLazyProperty, _defineLazyProps, _lazyValue } from './lazy'
|
|
25
|
-
import { _parseQueryString } from './string/url.util'
|
|
26
|
-
import { _range } from './array/range'
|
|
1
|
+
export * from './array/array.util'
|
|
2
|
+
export * from './lazy'
|
|
3
|
+
export * from './string/url.util'
|
|
4
|
+
export * from './array/range'
|
|
27
5
|
import {
|
|
28
6
|
PromiseDecoratorCfg,
|
|
29
7
|
PromiseDecoratorResp,
|
|
@@ -89,82 +67,29 @@ import {
|
|
|
89
67
|
JsonSchemaAnyBuilder,
|
|
90
68
|
JsonSchemaBuilder,
|
|
91
69
|
} from './json-schema/jsonSchemaBuilder'
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
_round,
|
|
101
|
-
_sortNumbers,
|
|
102
|
-
_toFixed,
|
|
103
|
-
_toPrecision,
|
|
104
|
-
} from './number/number.util'
|
|
105
|
-
import { _deepEquals } from './object/deepEquals'
|
|
106
|
-
import {
|
|
107
|
-
_deepCopy,
|
|
108
|
-
_deepTrim,
|
|
109
|
-
_filterEmptyArrays,
|
|
110
|
-
_filterEmptyValues,
|
|
111
|
-
_filterFalsyValues,
|
|
112
|
-
_filterNullishValues,
|
|
113
|
-
_filterObject,
|
|
114
|
-
_filterUndefinedValues,
|
|
115
|
-
_findKeyByValue,
|
|
116
|
-
_get,
|
|
117
|
-
_has,
|
|
118
|
-
_invert,
|
|
119
|
-
_invertMap,
|
|
120
|
-
_isEmpty,
|
|
121
|
-
_isEmptyObject,
|
|
122
|
-
_isObject,
|
|
123
|
-
_isPrimitive,
|
|
124
|
-
_mapKeys,
|
|
125
|
-
_mapObject,
|
|
126
|
-
_mapValues,
|
|
127
|
-
_mask,
|
|
128
|
-
_merge,
|
|
129
|
-
_objectNullValuesToUndefined,
|
|
130
|
-
_omit,
|
|
131
|
-
_pick,
|
|
132
|
-
_set,
|
|
133
|
-
_undefinedIfEmpty,
|
|
134
|
-
_unset,
|
|
135
|
-
} from './object/object.util'
|
|
136
|
-
import { _sortObject } from './object/sortObject'
|
|
137
|
-
import { _sortObjectDeep } from './object/sortObjectDeep'
|
|
70
|
+
export * from './math/math.util'
|
|
71
|
+
export * from './math/sma'
|
|
72
|
+
export * from './number/createDeterministicRandom'
|
|
73
|
+
export * from './number/number.util'
|
|
74
|
+
export * from './object/deepEquals'
|
|
75
|
+
export * from './object/object.util'
|
|
76
|
+
export * from './object/sortObject'
|
|
77
|
+
export * from './object/sortObjectDeep'
|
|
138
78
|
import { AggregatedError } from './promise/AggregatedError'
|
|
139
|
-
|
|
79
|
+
export * from './promise/pBatch'
|
|
140
80
|
import { DeferredPromise, pDefer } from './promise/pDefer'
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
81
|
+
export * from './promise/pDelay'
|
|
82
|
+
export * from './promise/pFilter'
|
|
83
|
+
export * from './promise/pHang'
|
|
144
84
|
import { pMap, PMapOptions } from './promise/pMap'
|
|
145
|
-
|
|
85
|
+
export * from './promise/pProps'
|
|
146
86
|
import { pRetry, PRetryOptions } from './promise/pRetry'
|
|
147
|
-
|
|
87
|
+
export * from './promise/pState'
|
|
148
88
|
import { pTimeout, PTimeoutOptions } from './promise/pTimeout'
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
_capitalize,
|
|
154
|
-
_lowerFirst,
|
|
155
|
-
_nl2br,
|
|
156
|
-
_removeWhitespace,
|
|
157
|
-
_replaceAll,
|
|
158
|
-
_split,
|
|
159
|
-
_substringAfter,
|
|
160
|
-
_substringAfterLast,
|
|
161
|
-
_substringBefore,
|
|
162
|
-
_substringBeforeLast,
|
|
163
|
-
_substringBetweenLast,
|
|
164
|
-
_truncate,
|
|
165
|
-
_truncateMiddle,
|
|
166
|
-
_upperFirst,
|
|
167
|
-
} from './string/string.util'
|
|
89
|
+
export * from './promise/pTuple'
|
|
90
|
+
export * from './string/case'
|
|
91
|
+
export * from './string/json.util'
|
|
92
|
+
export * from './string/string.util'
|
|
168
93
|
import { JsonStringifyFunction, StringifyAnyOptions, _stringifyAny } from './string/stringifyAny'
|
|
169
94
|
import { _ms, _since } from './time/time.util'
|
|
170
95
|
import {
|
|
@@ -236,6 +161,7 @@ import {
|
|
|
236
161
|
import { _safeJsonStringify } from './string/safeJsonStringify'
|
|
237
162
|
import { PQueue, PQueueCfg } from './promise/pQueue'
|
|
238
163
|
export * from './seq/seq'
|
|
164
|
+
export * from './math/stack.util'
|
|
239
165
|
|
|
240
166
|
export type {
|
|
241
167
|
AbortableMapper,
|
|
@@ -334,86 +260,9 @@ export {
|
|
|
334
260
|
_assertIsString,
|
|
335
261
|
_assertIsNumber,
|
|
336
262
|
_assertTypeOf,
|
|
337
|
-
_randomInt,
|
|
338
|
-
_randomArrayItem,
|
|
339
|
-
_createDeterministicRandom,
|
|
340
|
-
_inRange,
|
|
341
263
|
_stringMapValues,
|
|
342
264
|
_stringMapEntries,
|
|
343
265
|
_objectKeys,
|
|
344
|
-
_capitalize,
|
|
345
|
-
_upperFirst,
|
|
346
|
-
_lowerFirst,
|
|
347
|
-
_split,
|
|
348
|
-
_removeWhitespace,
|
|
349
|
-
_substringBefore,
|
|
350
|
-
_substringBeforeLast,
|
|
351
|
-
_substringAfter,
|
|
352
|
-
_substringAfterLast,
|
|
353
|
-
_substringBetweenLast,
|
|
354
|
-
_replaceAll,
|
|
355
|
-
_nl2br,
|
|
356
|
-
_truncate,
|
|
357
|
-
_truncateMiddle,
|
|
358
|
-
_pick,
|
|
359
|
-
_omit,
|
|
360
|
-
_filterFalsyValues,
|
|
361
|
-
_filterUndefinedValues,
|
|
362
|
-
_filterNullishValues,
|
|
363
|
-
_filterEmptyArrays,
|
|
364
|
-
_filterEmptyValues,
|
|
365
|
-
_filterObject,
|
|
366
|
-
_undefinedIfEmpty,
|
|
367
|
-
_isObject,
|
|
368
|
-
_isPrimitive,
|
|
369
|
-
_mapKeys,
|
|
370
|
-
_mapValues,
|
|
371
|
-
_mapObject,
|
|
372
|
-
_objectNullValuesToUndefined,
|
|
373
|
-
_deepEquals,
|
|
374
|
-
_deepCopy,
|
|
375
|
-
_isEmptyObject,
|
|
376
|
-
_isEmpty,
|
|
377
|
-
_merge,
|
|
378
|
-
_deepTrim,
|
|
379
|
-
_sortObjectDeep,
|
|
380
|
-
_sortObject,
|
|
381
|
-
_get,
|
|
382
|
-
_set,
|
|
383
|
-
_has,
|
|
384
|
-
_unset,
|
|
385
|
-
_mask,
|
|
386
|
-
_invert,
|
|
387
|
-
_invertMap,
|
|
388
|
-
_by,
|
|
389
|
-
_groupBy,
|
|
390
|
-
_sortBy,
|
|
391
|
-
_sortNumbers,
|
|
392
|
-
_toFixed,
|
|
393
|
-
_toPrecision,
|
|
394
|
-
_round,
|
|
395
|
-
_findLast,
|
|
396
|
-
_takeWhile,
|
|
397
|
-
_takeRightWhile,
|
|
398
|
-
_dropWhile,
|
|
399
|
-
_dropRightWhile,
|
|
400
|
-
_countBy,
|
|
401
|
-
_intersection,
|
|
402
|
-
_difference,
|
|
403
|
-
_shuffle,
|
|
404
|
-
_mapToObject,
|
|
405
|
-
_findKeyByValue,
|
|
406
|
-
_range,
|
|
407
|
-
_uniq,
|
|
408
|
-
_uniqBy,
|
|
409
|
-
_flatten,
|
|
410
|
-
_flattenDeep,
|
|
411
|
-
_chunk,
|
|
412
|
-
SimpleMovingAverage,
|
|
413
|
-
_average,
|
|
414
|
-
_averageWeighted,
|
|
415
|
-
_percentile,
|
|
416
|
-
_median,
|
|
417
266
|
_debounce,
|
|
418
267
|
_throttle,
|
|
419
268
|
_Debounce,
|
|
@@ -424,25 +273,17 @@ export {
|
|
|
424
273
|
_passthroughPredicate,
|
|
425
274
|
_passNothingPredicate,
|
|
426
275
|
_noop,
|
|
427
|
-
pBatch,
|
|
428
276
|
ErrorMode,
|
|
429
|
-
pFilter,
|
|
430
|
-
pProps,
|
|
431
|
-
pDelay,
|
|
432
277
|
pDefer,
|
|
433
|
-
pHang,
|
|
434
|
-
pState,
|
|
435
278
|
AggregatedError,
|
|
436
279
|
pRetry,
|
|
437
280
|
pTimeout,
|
|
438
|
-
pTuple,
|
|
439
281
|
_Retry,
|
|
440
282
|
_Timeout,
|
|
441
283
|
_tryCatch,
|
|
442
284
|
_TryCatch,
|
|
443
285
|
_try,
|
|
444
286
|
pTry,
|
|
445
|
-
_jsonParseIfPossible,
|
|
446
287
|
_stringifyAny,
|
|
447
288
|
_ms,
|
|
448
289
|
_since,
|
|
@@ -450,22 +291,11 @@ export {
|
|
|
450
291
|
_gb,
|
|
451
292
|
_mb,
|
|
452
293
|
_kb,
|
|
453
|
-
_snakeCase,
|
|
454
|
-
_camelCase,
|
|
455
|
-
_kebabCase,
|
|
456
|
-
_sum,
|
|
457
|
-
_sumBy,
|
|
458
|
-
_clamp,
|
|
459
|
-
_last,
|
|
460
294
|
mergeJsonSchemaObjects,
|
|
461
295
|
jsonSchema,
|
|
462
296
|
JsonSchemaAnyBuilder,
|
|
463
297
|
JSON_SCHEMA_ORDER,
|
|
464
298
|
generateJsonSchemaFromData,
|
|
465
|
-
_parseQueryString,
|
|
466
|
-
_defineLazyProperty,
|
|
467
|
-
_defineLazyProps,
|
|
468
|
-
_lazyValue,
|
|
469
299
|
commonLoggerMinLevel,
|
|
470
300
|
commonLoggerNoop,
|
|
471
301
|
commonLogLevelNumber,
|
package/src/math/math.util.ts
CHANGED
|
@@ -47,6 +47,27 @@ export function _percentile(values: number[], pc: number): number {
|
|
|
47
47
|
return _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A tiny bit more efficient function than calling _percentile individually.
|
|
52
|
+
*/
|
|
53
|
+
export function _percentiles(values: number[], pcs: number[]): Record<number, number> {
|
|
54
|
+
const r = {} as Record<number, number>
|
|
55
|
+
|
|
56
|
+
const sorted = _sortNumbers(values)
|
|
57
|
+
|
|
58
|
+
pcs.forEach(pc => {
|
|
59
|
+
// Floating pos in the range of [0; length - 1]
|
|
60
|
+
const pos = ((values.length - 1) * pc) / 100
|
|
61
|
+
const dec = pos % 1
|
|
62
|
+
const floorPos = Math.floor(pos)
|
|
63
|
+
const ceilPos = Math.ceil(pos)
|
|
64
|
+
|
|
65
|
+
r[pc] = _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return r
|
|
69
|
+
}
|
|
70
|
+
|
|
50
71
|
/**
|
|
51
72
|
* @example
|
|
52
73
|
*
|
package/src/math/sma.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Implements a Simple Moving Average algorithm.
|
|
3
3
|
*/
|
|
4
4
|
export class SimpleMovingAverage {
|
|
5
|
-
constructor(public size: number, public data: number[] = []) {}
|
|
5
|
+
constructor(public readonly size: number, public readonly data: number[] = []) {}
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Next index of array to push to
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { _average, _percentile, _percentiles, _range } from '../index'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Implements a "round-robin" Stack ("first-in last-out" aka FILO) with a limited size.
|
|
5
|
+
* Like an array of a fixed size. When it runs out of space - it starts writing on top of itself
|
|
6
|
+
* from index 0.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
export class Stack<T> {
|
|
11
|
+
constructor(public readonly size: number) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Index of a slot to get written TO next.
|
|
15
|
+
* Currently this slot contains OLDEST item (if any).
|
|
16
|
+
*/
|
|
17
|
+
private nextIndex = 0
|
|
18
|
+
|
|
19
|
+
readonly items: T[] = []
|
|
20
|
+
|
|
21
|
+
push(item: T): this {
|
|
22
|
+
this.items[this.nextIndex] = item
|
|
23
|
+
this.nextIndex = this.nextIndex === this.size - 1 ? 0 : this.nextIndex + 1
|
|
24
|
+
return this
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Fill (overwrite) the whole Stack (all its items) with the passed `item`.
|
|
29
|
+
*/
|
|
30
|
+
fill(item: T): this {
|
|
31
|
+
_range(this.size).forEach(i => (this.items[i] = item))
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns last items in the right order.
|
|
37
|
+
* Unlike raw `items` property that returns "items buffer" as-is (not ordered properly).
|
|
38
|
+
*/
|
|
39
|
+
get itemsOrdered(): T[] {
|
|
40
|
+
if (this.items.length < this.size) {
|
|
41
|
+
// Buffer is not filled yet, just return it as-is
|
|
42
|
+
return this.items
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Buffer was filled and started to "overwrite itself", will need to return 2 slices
|
|
46
|
+
return [...this.items.slice(this.nextIndex), ...this.items.slice(0, this.nextIndex)]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Fixed-size FILO stack of Numbers.
|
|
52
|
+
* Has convenience stat methods, e.g percentile, avg, etc.
|
|
53
|
+
*/
|
|
54
|
+
export class NumberStack extends Stack<number> {
|
|
55
|
+
avg(): number {
|
|
56
|
+
// _assert(this.items.length, 'NumberStack.avg cannot be called on empty stack')
|
|
57
|
+
return _average(this.items)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns null if Stack is empty.
|
|
62
|
+
*/
|
|
63
|
+
avgOrNull(): number | null {
|
|
64
|
+
return this.items.length === 0 ? null : _average(this.items)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
median(): number {
|
|
68
|
+
return _percentile(this.items, 50)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
medianOrNull(): number | null {
|
|
72
|
+
return this.items.length === 0 ? null : _percentile(this.items, 50)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* `pc` is a number from 0 to 100 inclusive.
|
|
77
|
+
*/
|
|
78
|
+
percentile(pc: number): number {
|
|
79
|
+
// _assert(this.items.length, 'NumberStack.percentile cannot be called on empty stack')
|
|
80
|
+
return _percentile(this.items, pc)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* `pc` is a number from 0 to 100 inclusive.
|
|
85
|
+
* Returns null if Stack is empty.
|
|
86
|
+
*/
|
|
87
|
+
percentileOrNull(pc: number): number | null {
|
|
88
|
+
return this.items.length === 0 ? null : _percentile(this.items, pc)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
percentiles(pcs: number[]): Record<number, number> {
|
|
92
|
+
return _percentiles(this.items, pcs)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -65,7 +65,7 @@ export function _toFixed(n: number, fractionDigits: number): number {
|
|
|
65
65
|
* _toPrecision(1634.56, 1)
|
|
66
66
|
* // 2000
|
|
67
67
|
*
|
|
68
|
-
* _toPrecision(
|
|
68
|
+
* _toPrecision(1634.56, 2)
|
|
69
69
|
* // 1600
|
|
70
70
|
*/
|
|
71
71
|
export function _toPrecision(n: number, precision: number): number {
|
package/src/seq/seq.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AbortableAsyncMapper,
|
|
3
|
+
AbortableAsyncPredicate,
|
|
4
|
+
AbortableMapper,
|
|
5
|
+
AbortablePredicate,
|
|
6
|
+
END,
|
|
7
|
+
SKIP,
|
|
8
|
+
} from '../types'
|
|
2
9
|
|
|
3
10
|
/**
|
|
4
11
|
* Inspired by Kotlin Sequences.
|
|
@@ -8,7 +15,7 @@ import { AbortableMapper, AbortablePredicate, END, SKIP } from '../types'
|
|
|
8
15
|
*
|
|
9
16
|
* @experimental
|
|
10
17
|
*/
|
|
11
|
-
export class
|
|
18
|
+
export class Sequence<T> implements Iterable<T> {
|
|
12
19
|
private constructor(initialValue: T | typeof END, private nextFn: AbortableMapper<T, T>) {
|
|
13
20
|
this.currentValue = initialValue
|
|
14
21
|
}
|
|
@@ -22,29 +29,29 @@ export class Seq<T> implements Iterable<T> {
|
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
31
|
|
|
25
|
-
static create<T>(initialValue: T | typeof END, nextFn: AbortableMapper<T, T>):
|
|
26
|
-
return new
|
|
32
|
+
static create<T>(initialValue: T | typeof END, nextFn: AbortableMapper<T, T>): Sequence<T> {
|
|
33
|
+
return new Sequence(initialValue, nextFn)
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
static range(minIncl: number, maxExcl: number, step = 1):
|
|
36
|
+
static range(minIncl: number, maxExcl: number, step = 1): Sequence<number> {
|
|
30
37
|
const max = maxExcl - step
|
|
31
|
-
return new
|
|
38
|
+
return new Sequence(minIncl, n => (n < max ? n + step : END))
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
static from<T>(a: Iterable<T>):
|
|
41
|
+
static from<T>(a: Iterable<T>): Sequence<T> {
|
|
35
42
|
const it = a[Symbol.iterator]()
|
|
36
43
|
const v = it.next()
|
|
37
|
-
if (v.done) return new
|
|
44
|
+
if (v.done) return new Sequence<any>(END, () => {})
|
|
38
45
|
|
|
39
|
-
return new
|
|
46
|
+
return new Sequence(v.value, () => {
|
|
40
47
|
const v = it.next()
|
|
41
48
|
if (v.done) return END
|
|
42
49
|
return v.value
|
|
43
50
|
})
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
static empty<T = any>():
|
|
47
|
-
return new
|
|
53
|
+
static empty<T = any>(): Sequence<T> {
|
|
54
|
+
return new Sequence(END as any, () => {})
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
private currentValue: T | typeof END
|
|
@@ -138,6 +145,120 @@ export class Seq<T> implements Iterable<T> {
|
|
|
138
145
|
/**
|
|
139
146
|
* Convenience function to create a Sequence.
|
|
140
147
|
*/
|
|
141
|
-
export function _seq<T>(initialValue: T | typeof END, nextFn: AbortableMapper<T, T>):
|
|
142
|
-
return
|
|
148
|
+
export function _seq<T>(initialValue: T | typeof END, nextFn: AbortableMapper<T, T>): Sequence<T> {
|
|
149
|
+
return Sequence.create(initialValue, nextFn)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* eslint-disable no-await-in-loop */
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Experimental.
|
|
156
|
+
* Feasibility to be proven.
|
|
157
|
+
*
|
|
158
|
+
* @experimental
|
|
159
|
+
*/
|
|
160
|
+
export class AsyncSequence<T> implements AsyncIterable<T> {
|
|
161
|
+
private constructor(initialValue: T | typeof END, private nextFn: AbortableAsyncMapper<T, T>) {
|
|
162
|
+
this.currentValue = initialValue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
166
|
+
return {
|
|
167
|
+
next: async () => {
|
|
168
|
+
const value = await this.next()
|
|
169
|
+
return value === END ? { done: true, value: undefined } : { value }
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static create<T>(
|
|
175
|
+
initialValue: T | typeof END,
|
|
176
|
+
nextFn: AbortableAsyncMapper<T, T>,
|
|
177
|
+
): AsyncSequence<T> {
|
|
178
|
+
return new AsyncSequence(initialValue, nextFn)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static async from<T>(a: AsyncIterable<T>): Promise<AsyncSequence<T>> {
|
|
182
|
+
const it = a[Symbol.asyncIterator]()
|
|
183
|
+
const v = await it.next()
|
|
184
|
+
if (v.done) return new AsyncSequence<any>(END, () => {})
|
|
185
|
+
|
|
186
|
+
return new AsyncSequence(v.value, async () => {
|
|
187
|
+
const v = await it.next()
|
|
188
|
+
if (v.done) return END
|
|
189
|
+
return v.value
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
static empty<T = any>(): AsyncSequence<T> {
|
|
194
|
+
return new AsyncSequence(END as any, () => {})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private currentValue: T | typeof END
|
|
198
|
+
private sentInitialValue = false
|
|
199
|
+
private i = -1
|
|
200
|
+
|
|
201
|
+
async next(): Promise<T | typeof END> {
|
|
202
|
+
if (this.currentValue === END) return END
|
|
203
|
+
|
|
204
|
+
this.i++
|
|
205
|
+
|
|
206
|
+
let v: T | typeof SKIP | typeof END
|
|
207
|
+
|
|
208
|
+
if (!this.sentInitialValue) {
|
|
209
|
+
this.sentInitialValue = true
|
|
210
|
+
v = this.currentValue
|
|
211
|
+
} else {
|
|
212
|
+
v = await this.nextFn(this.currentValue, this.i)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// console.log(`_seq`, v)
|
|
216
|
+
|
|
217
|
+
if (v === SKIP) return await this.next()
|
|
218
|
+
|
|
219
|
+
return (this.currentValue = v)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Final functions - return final value, not a chained sequence
|
|
223
|
+
async find(predicate: AbortableAsyncPredicate<T>): Promise<T | undefined> {
|
|
224
|
+
do {
|
|
225
|
+
const v = await this.next()
|
|
226
|
+
if (v === END) return // not found, end of sequence
|
|
227
|
+
const r = await predicate(v, this.i)
|
|
228
|
+
if (r === END) return
|
|
229
|
+
if (r) return v
|
|
230
|
+
// otherwise proceed
|
|
231
|
+
} while (true) // eslint-disable-line no-constant-condition
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async some(predicate: AbortableAsyncPredicate<T>): Promise<boolean> {
|
|
235
|
+
do {
|
|
236
|
+
const v = await this.next()
|
|
237
|
+
if (v === END) return false
|
|
238
|
+
const r = await predicate(v, this.i)
|
|
239
|
+
if (r === END) return false
|
|
240
|
+
if (r) return true
|
|
241
|
+
} while (true) // eslint-disable-line no-constant-condition
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async every(predicate: AbortableAsyncPredicate<T>): Promise<boolean> {
|
|
245
|
+
do {
|
|
246
|
+
const v = await this.next()
|
|
247
|
+
if (v === END) return true
|
|
248
|
+
const r = await predicate(v, this.i)
|
|
249
|
+
if (r === END) return true
|
|
250
|
+
if (!r) return false
|
|
251
|
+
} while (true) // eslint-disable-line no-constant-condition
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async toArray(): Promise<T[]> {
|
|
255
|
+
const a: T[] = []
|
|
256
|
+
|
|
257
|
+
// eslint-disable-next-line no-constant-condition
|
|
258
|
+
while (true) {
|
|
259
|
+
const v = await this.next()
|
|
260
|
+
if (v === END) return a
|
|
261
|
+
a.push(v)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
143
264
|
}
|