@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/src/index.ts CHANGED
@@ -1,29 +1,7 @@
1
- import {
2
- _by,
3
- _chunk,
4
- _countBy,
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
- import { _average, _averageWeighted, _median, _percentile } from './math/math.util'
93
- import { SimpleMovingAverage } from './math/sma'
94
- import { _createDeterministicRandom } from './number/createDeterministicRandom'
95
- import {
96
- _clamp,
97
- _inRange,
98
- _randomInt,
99
- _randomArrayItem,
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
- import { pBatch } from './promise/pBatch'
79
+ export * from './promise/pBatch'
140
80
  import { DeferredPromise, pDefer } from './promise/pDefer'
141
- import { pDelay } from './promise/pDelay'
142
- import { pFilter } from './promise/pFilter'
143
- import { pHang } from './promise/pHang'
81
+ export * from './promise/pDelay'
82
+ export * from './promise/pFilter'
83
+ export * from './promise/pHang'
144
84
  import { pMap, PMapOptions } from './promise/pMap'
145
- import { pProps } from './promise/pProps'
85
+ export * from './promise/pProps'
146
86
  import { pRetry, PRetryOptions } from './promise/pRetry'
147
- import { pState } from './promise/pState'
87
+ export * from './promise/pState'
148
88
  import { pTimeout, PTimeoutOptions } from './promise/pTimeout'
149
- import { pTuple } from './promise/pTuple'
150
- import { _camelCase, _kebabCase, _snakeCase } from './string/case'
151
- import { _jsonParseIfPossible } from './string/json.util'
152
- import {
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,
@@ -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(1234.56, 2)
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 { AbortableMapper, AbortablePredicate, END, SKIP } from '../types'
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 Seq<T> implements Iterable<T> {
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>): Seq<T> {
26
- return new Seq(initialValue, nextFn)
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): Seq<number> {
36
+ static range(minIncl: number, maxExcl: number, step = 1): Sequence<number> {
30
37
  const max = maxExcl - step
31
- return new Seq(minIncl, n => (n < max ? n + step : END))
38
+ return new Sequence(minIncl, n => (n < max ? n + step : END))
32
39
  }
33
40
 
34
- static from<T>(a: Iterable<T>): Seq<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 Seq<any>(END, () => {})
44
+ if (v.done) return new Sequence<any>(END, () => {})
38
45
 
39
- return new Seq(v.value, () => {
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>(): Seq<T> {
47
- return new Seq(END as any, () => {})
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>): Seq<T> {
142
- return Seq.create(initialValue, nextFn)
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
  }