@naturalcycles/js-lib 14.70.1 → 14.73.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.
Files changed (44) hide show
  1. package/dist/error/try.d.ts +1 -1
  2. package/dist/error/try.js +2 -0
  3. package/dist/index.d.ts +28 -26
  4. package/dist/index.js +28 -122
  5. package/dist/math/sma.d.ts +2 -2
  6. package/dist/math/stack.util.d.ts +49 -0
  7. package/dist/math/stack.util.js +84 -0
  8. package/dist/number/number.util.d.ts +1 -1
  9. package/dist/number/number.util.js +1 -1
  10. package/dist/promise/pBatch.d.ts +2 -3
  11. package/dist/promise/pFilter.d.ts +2 -2
  12. package/dist/promise/pMap.d.ts +2 -3
  13. package/dist/promise/pMap.js +13 -7
  14. package/dist/promise/pProps.d.ts +3 -1
  15. package/dist/promise/pProps.js +4 -5
  16. package/dist/seq/seq.d.ts +30 -0
  17. package/dist/seq/seq.js +141 -0
  18. package/dist/string/json.util.js +4 -1
  19. package/dist/typeFest.d.ts +0 -30
  20. package/dist/types.d.ts +13 -1
  21. package/dist/types.js +9 -1
  22. package/dist-esm/error/try.js +2 -0
  23. package/dist-esm/index.js +26 -24
  24. package/dist-esm/math/stack.util.js +79 -0
  25. package/dist-esm/number/number.util.js +1 -1
  26. package/dist-esm/promise/pMap.js +14 -8
  27. package/dist-esm/promise/pProps.js +4 -5
  28. package/dist-esm/seq/seq.js +136 -0
  29. package/dist-esm/string/json.util.js +4 -1
  30. package/dist-esm/types.js +8 -0
  31. package/package.json +1 -1
  32. package/src/error/try.ts +4 -1
  33. package/src/index.ts +36 -195
  34. package/src/math/sma.ts +1 -1
  35. package/src/math/stack.util.ts +90 -0
  36. package/src/number/number.util.ts +1 -1
  37. package/src/promise/pBatch.ts +2 -3
  38. package/src/promise/pFilter.ts +2 -2
  39. package/src/promise/pMap.ts +16 -11
  40. package/src/promise/pProps.ts +6 -7
  41. package/src/seq/seq.ts +143 -0
  42. package/src/string/json.util.ts +5 -1
  43. package/src/typeFest.ts +0 -32
  44. package/src/types.ts +22 -1
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._seq = exports.Seq = void 0;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Inspired by Kotlin Sequences.
7
+ * Similar to arrays, but with lazy evaluation, abortable.
8
+ * Can be useful when it's not feasible/performant to create an array of values to iterate upfront
9
+ * (e.g to construct 1000 Dayjs instances only to find that 2 of them were needed).
10
+ *
11
+ * @experimental
12
+ */
13
+ class Seq {
14
+ constructor(initialValue, nextFn) {
15
+ this.nextFn = nextFn;
16
+ this.sentInitialValue = false;
17
+ this.i = -1;
18
+ this.currentValue = initialValue;
19
+ }
20
+ [Symbol.iterator]() {
21
+ return {
22
+ next: () => {
23
+ const value = this.next();
24
+ return value === types_1.END ? { done: true, value: undefined } : { value };
25
+ },
26
+ };
27
+ }
28
+ static create(initialValue, nextFn) {
29
+ return new Seq(initialValue, nextFn);
30
+ }
31
+ static range(minIncl, maxExcl, step = 1) {
32
+ const max = maxExcl - step;
33
+ return new Seq(minIncl, n => (n < max ? n + step : types_1.END));
34
+ }
35
+ static from(a) {
36
+ const it = a[Symbol.iterator]();
37
+ const v = it.next();
38
+ if (v.done)
39
+ return new Seq(types_1.END, () => { });
40
+ return new Seq(v.value, () => {
41
+ const v = it.next();
42
+ if (v.done)
43
+ return types_1.END;
44
+ return v.value;
45
+ });
46
+ }
47
+ static empty() {
48
+ return new Seq(types_1.END, () => { });
49
+ }
50
+ next() {
51
+ if (this.currentValue === types_1.END)
52
+ return types_1.END;
53
+ this.i++;
54
+ let v;
55
+ if (!this.sentInitialValue) {
56
+ this.sentInitialValue = true;
57
+ v = this.currentValue;
58
+ }
59
+ else {
60
+ v = this.nextFn(this.currentValue, this.i);
61
+ }
62
+ // console.log(`_seq`, v)
63
+ if (v === types_1.SKIP)
64
+ return this.next();
65
+ return (this.currentValue = v);
66
+ }
67
+ // Chainable functions - return another (chained) Sequence
68
+ // map<OUT>(mapper: Mapper<T, OUT | typeof SKIP | typeof END>): Seq<OUT> {
69
+ // if (this.currentValue === END) return this as any
70
+ //
71
+ // // Iterate until first valid value, to have as `initialValue` of the new Sequence
72
+ // let v: OUT | typeof SKIP | typeof END
73
+ //
74
+ // while (true) {
75
+ // v = mapper(this.currentValue, ++this.i)
76
+ // if (v === SKIP) continue
77
+ // if (v === END) return this as any
78
+ // }
79
+ //
80
+ // return new Seq<OUT>(v as OUT, (current, i) => {
81
+ // const v = mapper(current, i)
82
+ //
83
+ // })
84
+ // }
85
+ // Final functions - return final value, not a chained sequence
86
+ find(predicate) {
87
+ do {
88
+ const v = this.next();
89
+ if (v === types_1.END)
90
+ return; // not found, end of sequence
91
+ const r = predicate(v, this.i);
92
+ if (r === types_1.END)
93
+ return;
94
+ if (r)
95
+ return v;
96
+ // otherwise proceed
97
+ } while (true); // eslint-disable-line no-constant-condition
98
+ }
99
+ some(predicate) {
100
+ do {
101
+ const v = this.next();
102
+ if (v === types_1.END)
103
+ return false;
104
+ const r = predicate(v, this.i);
105
+ if (r === types_1.END)
106
+ return false;
107
+ if (r)
108
+ return true;
109
+ } while (true); // eslint-disable-line no-constant-condition
110
+ }
111
+ every(predicate) {
112
+ do {
113
+ const v = this.next();
114
+ if (v === types_1.END)
115
+ return true;
116
+ const r = predicate(v, this.i);
117
+ if (r === types_1.END)
118
+ return true;
119
+ if (!r)
120
+ return false;
121
+ } while (true); // eslint-disable-line no-constant-condition
122
+ }
123
+ toArray() {
124
+ const a = [];
125
+ // eslint-disable-next-line no-constant-condition
126
+ while (true) {
127
+ const v = this.next();
128
+ if (v === types_1.END)
129
+ return a;
130
+ a.push(v);
131
+ }
132
+ }
133
+ }
134
+ exports.Seq = Seq;
135
+ /**
136
+ * Convenience function to create a Sequence.
137
+ */
138
+ function _seq(initialValue, nextFn) {
139
+ return Seq.create(initialValue, nextFn);
140
+ }
141
+ exports._seq = _seq;
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports._jsonParseIfPossible = void 0;
4
+ // const possibleJsonStartTokens = ['{', '[', '"']
5
+ const DETECT_JSON = /^\s*[{["\-\d]/;
4
6
  /**
5
7
  * Attempts to parse object as JSON.
6
8
  * Returns original object if JSON parse failed (silently).
7
9
  */
8
10
  function _jsonParseIfPossible(obj, reviver) {
9
- if (typeof obj === 'string' && obj) {
11
+ // Optimization: only try to parse if it looks like JSON: starts with a json possible character
12
+ if (typeof obj === 'string' && obj && DETECT_JSON.test(obj)) {
10
13
  try {
11
14
  return JSON.parse(obj, reviver);
12
15
  }
@@ -130,36 +130,6 @@ export declare type Merge<FirstType, SecondType> = Simplify<Merge_<FirstType, Se
130
130
  ```
131
131
  */
132
132
  export declare type Promisable<T> = T | PromiseLike<T>;
133
- /**
134
- Returns the type that is wrapped inside a `Promise` type.
135
- If the type is a nested Promise, it is unwrapped recursively until a non-Promise type is obtained.
136
- If the type is not a `Promise`, the type itself is returned.
137
-
138
- @example
139
- ```
140
- import {PromiseValue} from 'type-fest';
141
-
142
- type AsyncData = Promise<string>;
143
- let asyncData: PromiseValue<AsyncData> = Promise.resolve('ABC');
144
-
145
- type Data = PromiseValue<AsyncData>;
146
- let data: Data = await asyncData;
147
-
148
- // Here's an example that shows how this type reacts to non-Promise types.
149
- type SyncData = PromiseValue<string>;
150
- let syncData: SyncData = getSyncData();
151
-
152
- // Here's an example that shows how this type reacts to recursive Promise types.
153
- type RecursiveAsyncData = Promise<Promise<string> >;
154
- let recursiveAsyncData: PromiseValue<RecursiveAsyncData> = Promise.resolve(Promise.resolve('ABC'));
155
- ```
156
-
157
- @category Utilities
158
- */
159
- export declare type PromiseValue<PromiseType, Otherwise = PromiseType> = PromiseType extends Promise<infer Value> ? {
160
- 0: PromiseValue<Value>;
161
- 1: Value;
162
- }[PromiseType extends Promise<unknown> ? 0 : 1] : Otherwise;
163
133
  /**
164
134
  Extract the keys from a type where the value type of the key extends the given `Condition`.
165
135
  Internally this is used for the `ConditionalPick` and `ConditionalExcept` types.
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Merge } from './typeFest';
1
+ import { Merge, Promisable } from './typeFest';
2
2
  /**
3
3
  * Map from String to String (or <T>).
4
4
  *
@@ -37,6 +37,14 @@ export interface AnyObjectWithId extends AnyObject, ObjectWithId {
37
37
  * Because `Function` type is discouraged by eslint.
38
38
  */
39
39
  export declare type AnyFunction = (...args: any[]) => any;
40
+ /**
41
+ * Symbol to indicate END of Sequence.
42
+ */
43
+ export declare const END: unique symbol;
44
+ /**
45
+ * Symbol to indicate SKIP of item (e.g in AbortableMapper)
46
+ */
47
+ export declare const SKIP: unique symbol;
40
48
  /**
41
49
  * Function which is called for every item in `input`. Expected to return a `Promise` or value.
42
50
  */
@@ -50,6 +58,10 @@ export declare const _passUndefinedMapper: Mapper<any, void>;
50
58
  export declare const _noop: (..._args: any[]) => undefined;
51
59
  export declare type Predicate<T> = (item: T, index: number) => boolean;
52
60
  export declare type AsyncPredicate<T> = (item: T, index: number) => boolean | PromiseLike<boolean>;
61
+ export declare type AbortablePredicate<T> = (item: T, i: number) => boolean | typeof END;
62
+ export declare type AbortableAsyncPredicate<T> = (item: T, i: number) => Promisable<boolean | typeof END>;
63
+ export declare type AbortableMapper<IN = any, OUT = any> = (input: IN, i: number) => OUT | typeof SKIP | typeof END;
64
+ export declare type AbortableAsyncMapper<IN = any, OUT = any> = (input: IN, i: number) => Promisable<OUT | typeof SKIP | typeof END>;
53
65
  export declare const _passthroughPredicate: Predicate<any>;
54
66
  export declare const _passNothingPredicate: Predicate<any>;
55
67
  export interface BatchResult<RES = any, ERR = Error> {
package/dist/types.js CHANGED
@@ -1,6 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._passNothingPredicate = exports._passthroughPredicate = exports._noop = exports._passUndefinedMapper = exports._passthroughMapper = void 0;
3
+ exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._passNothingPredicate = exports._passthroughPredicate = exports._noop = exports._passUndefinedMapper = exports._passthroughMapper = exports.SKIP = exports.END = void 0;
4
+ /**
5
+ * Symbol to indicate END of Sequence.
6
+ */
7
+ exports.END = Symbol('END');
8
+ /**
9
+ * Symbol to indicate SKIP of item (e.g in AbortableMapper)
10
+ */
11
+ exports.SKIP = Symbol('SKIP');
4
12
  const _passthroughMapper = item => item;
5
13
  exports._passthroughMapper = _passthroughMapper;
6
14
  const _passUndefinedMapper = () => undefined;
@@ -22,6 +22,8 @@ export function _try(fn) {
22
22
  return [err, undefined];
23
23
  }
24
24
  }
25
+ // todo: remove when eslint starts to know about Awaited
26
+ /* eslint-disable no-undef */
25
27
  /**
26
28
  * Like _try, but for Promises.
27
29
  *
package/dist-esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { _by, _chunk, _countBy, _difference, _dropRightWhile, _dropWhile, _findLast, _flatten, _flattenDeep, _groupBy, _intersection, _last, _mapToObject, _shuffle, _sortBy, _sum, _sumBy, _takeRightWhile, _takeWhile, _uniq, _uniqBy, } from './array/array.util';
2
- import { _defineLazyProperty, _defineLazyProps, _lazyValue } from './lazy';
3
- import { _parseQueryString } from './string/url.util';
4
- 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';
5
5
  import { _createPromiseDecorator, } from './decorators/createPromiseDecorator';
6
6
  import { _debounce, _throttle } from './decorators/debounce';
7
7
  import { _Debounce, _Throttle } from './decorators/debounce.decorator';
@@ -22,35 +22,37 @@ import { generateJsonSchemaFromData } from './json-schema/from-data/generateJson
22
22
  import { JSON_SCHEMA_ORDER } from './json-schema/jsonSchema.cnst';
23
23
  import { mergeJsonSchemaObjects } from './json-schema/jsonSchema.util';
24
24
  import { jsonSchema, JsonSchemaAnyBuilder, } from './json-schema/jsonSchemaBuilder';
25
- import { _average, _averageWeighted, _median, _percentile } from './math/math.util';
26
- import { SimpleMovingAverage } from './math/sma';
27
- import { _createDeterministicRandom } from './number/createDeterministicRandom';
28
- import { _clamp, _inRange, _randomInt, _randomArrayItem, _round, _sortNumbers, _toFixed, _toPrecision, } from './number/number.util';
29
- import { _deepEquals } from './object/deepEquals';
30
- import { _deepCopy, _deepTrim, _filterEmptyArrays, _filterEmptyValues, _filterFalsyValues, _filterNullishValues, _filterObject, _filterUndefinedValues, _findKeyByValue, _get, _has, _invert, _invertMap, _isEmpty, _isEmptyObject, _isObject, _isPrimitive, _mapKeys, _mapObject, _mapValues, _mask, _merge, _objectNullValuesToUndefined, _omit, _pick, _set, _undefinedIfEmpty, _unset, } from './object/object.util';
31
- import { _sortObject } from './object/sortObject';
32
- import { _sortObjectDeep } from './object/sortObjectDeep';
25
+ export * from './math/math.util';
26
+ export * from './math/sma';
27
+ export * from './number/createDeterministicRandom';
28
+ export * from './number/number.util';
29
+ export * from './object/deepEquals';
30
+ export * from './object/object.util';
31
+ export * from './object/sortObject';
32
+ export * from './object/sortObjectDeep';
33
33
  import { AggregatedError } from './promise/AggregatedError';
34
- import { pBatch } from './promise/pBatch';
34
+ export * from './promise/pBatch';
35
35
  import { pDefer } from './promise/pDefer';
36
- import { pDelay } from './promise/pDelay';
37
- import { pFilter } from './promise/pFilter';
38
- import { pHang } from './promise/pHang';
36
+ export * from './promise/pDelay';
37
+ export * from './promise/pFilter';
38
+ export * from './promise/pHang';
39
39
  import { pMap } from './promise/pMap';
40
- import { pProps } from './promise/pProps';
40
+ export * from './promise/pProps';
41
41
  import { pRetry } from './promise/pRetry';
42
- import { pState } from './promise/pState';
42
+ export * from './promise/pState';
43
43
  import { pTimeout } from './promise/pTimeout';
44
- import { pTuple } from './promise/pTuple';
45
- import { _camelCase, _kebabCase, _snakeCase } from './string/case';
46
- import { _jsonParseIfPossible } from './string/json.util';
47
- import { _capitalize, _lowerFirst, _nl2br, _removeWhitespace, _replaceAll, _split, _substringAfter, _substringAfterLast, _substringBefore, _substringBeforeLast, _substringBetweenLast, _truncate, _truncateMiddle, _upperFirst, } from './string/string.util';
44
+ export * from './promise/pTuple';
45
+ export * from './string/case';
46
+ export * from './string/json.util';
47
+ export * from './string/string.util';
48
48
  import { _stringifyAny } from './string/stringifyAny';
49
49
  import { _ms, _since } from './time/time.util';
50
- import { _noop, _objectKeys, _passNothingPredicate, _passthroughMapper, _passthroughPredicate, _passUndefinedMapper, _stringMapEntries, _stringMapValues, } from './types';
50
+ import { END, SKIP, _noop, _objectKeys, _passNothingPredicate, _passthroughMapper, _passthroughPredicate, _passUndefinedMapper, _stringMapEntries, _stringMapValues, } from './types';
51
51
  import { _gb, _hb, _kb, _mb } from './unit/size.util';
52
52
  import { is } from './vendor/is';
53
53
  import { commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, } from './log/commonLogger';
54
54
  import { _safeJsonStringify } from './string/safeJsonStringify';
55
55
  import { PQueue } from './promise/pQueue';
56
- export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _randomInt, _randomArrayItem, _createDeterministicRandom, _inRange, _stringMapValues, _stringMapEntries, _objectKeys, _capitalize, _upperFirst, _lowerFirst, _split, _removeWhitespace, _substringBefore, _substringBeforeLast, _substringAfter, _substringAfterLast, _substringBetweenLast, _replaceAll, _nl2br, _truncate, _truncateMiddle, _pick, _omit, _filterFalsyValues, _filterUndefinedValues, _filterNullishValues, _filterEmptyArrays, _filterEmptyValues, _filterObject, _undefinedIfEmpty, _isObject, _isPrimitive, _mapKeys, _mapValues, _mapObject, _objectNullValuesToUndefined, _deepEquals, _deepCopy, _isEmptyObject, _isEmpty, _merge, _deepTrim, _sortObjectDeep, _sortObject, _get, _set, _has, _unset, _mask, _invert, _invertMap, _by, _groupBy, _sortBy, _sortNumbers, _toFixed, _toPrecision, _round, _findLast, _takeWhile, _takeRightWhile, _dropWhile, _dropRightWhile, _countBy, _intersection, _difference, _shuffle, _mapToObject, _findKeyByValue, _range, _uniq, _uniqBy, _flatten, _flattenDeep, _chunk, SimpleMovingAverage, _average, _averageWeighted, _percentile, _median, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, pBatch, ErrorMode, pFilter, pProps, pDelay, pDefer, pHang, pState, AggregatedError, pRetry, pTimeout, pTuple, _Retry, _Timeout, _tryCatch, _TryCatch, _try, pTry, _jsonParseIfPossible, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, _snakeCase, _camelCase, _kebabCase, _sum, _sumBy, _clamp, _last, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, generateJsonSchemaFromData, _parseQueryString, _defineLazyProperty, _defineLazyProps, _lazyValue, commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, _safeJsonStringify, PQueue, };
56
+ export * from './seq/seq';
57
+ export * from './math/stack.util';
58
+ export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _stringMapValues, _stringMapEntries, _objectKeys, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, ErrorMode, pDefer, AggregatedError, pRetry, pTimeout, _Retry, _Timeout, _tryCatch, _TryCatch, _try, pTry, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, generateJsonSchemaFromData, commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, _safeJsonStringify, PQueue, END, SKIP, };
@@ -0,0 +1,79 @@
1
+ import { _average, _percentile, _range } from '../index';
2
+ /**
3
+ * Implements a "round-robin" Stack ("first-in last-out" aka FILO) with a limited size.
4
+ * Like an array of a fixed size. When it runs out of space - it starts writing on top of itself
5
+ * from index 0.
6
+ *
7
+ *
8
+ */
9
+ export class Stack {
10
+ constructor(size) {
11
+ this.size = size;
12
+ /**
13
+ * Index of a slot to get written TO next.
14
+ * Currently this slot contains OLDEST item (if any).
15
+ */
16
+ this.nextIndex = 0;
17
+ this.items = [];
18
+ }
19
+ push(item) {
20
+ this.items[this.nextIndex] = item;
21
+ this.nextIndex = this.nextIndex === this.size - 1 ? 0 : this.nextIndex + 1;
22
+ return this;
23
+ }
24
+ /**
25
+ * Fill (overwrite) the whole Stack (all its items) with the passed `item`.
26
+ */
27
+ fill(item) {
28
+ _range(this.size).forEach(i => (this.items[i] = item));
29
+ return this;
30
+ }
31
+ /**
32
+ * Returns last items in the right order.
33
+ * Unlike raw `items` property that returns "items buffer" as-is (not ordered properly).
34
+ */
35
+ get itemsOrdered() {
36
+ if (this.items.length < this.size) {
37
+ // Buffer is not filled yet, just return it as-is
38
+ return this.items;
39
+ }
40
+ // Buffer was filled and started to "overwrite itself", will need to return 2 slices
41
+ return [...this.items.slice(this.nextIndex), ...this.items.slice(0, this.nextIndex)];
42
+ }
43
+ }
44
+ /**
45
+ * Fixed-size FILO stack of Numbers.
46
+ * Has convenience stat methods, e.g percentile, avg, etc.
47
+ */
48
+ export class NumberStack extends Stack {
49
+ avg() {
50
+ // _assert(this.items.length, 'NumberStack.avg cannot be called on empty stack')
51
+ return _average(this.items);
52
+ }
53
+ /**
54
+ * Returns null if Stack is empty.
55
+ */
56
+ avgOrNull() {
57
+ return this.items.length === 0 ? null : _average(this.items);
58
+ }
59
+ /**
60
+ * `pc` is a number from 0 to 100 inclusive.
61
+ */
62
+ percentile(pc) {
63
+ // _assert(this.items.length, 'NumberStack.percentile cannot be called on empty stack')
64
+ return _percentile(this.items, pc);
65
+ }
66
+ /**
67
+ * `pc` is a number from 0 to 100 inclusive.
68
+ * Returns null if Stack is empty.
69
+ */
70
+ percentileOrNull(pc) {
71
+ return this.items.length === 0 ? null : _percentile(this.items, pc);
72
+ }
73
+ median() {
74
+ return _percentile(this.items, 50);
75
+ }
76
+ medianOrNull() {
77
+ return this.items.length === 0 ? null : _percentile(this.items, 50);
78
+ }
79
+ }
@@ -58,7 +58,7 @@ export function _toFixed(n, fractionDigits) {
58
58
  * _toPrecision(1634.56, 1)
59
59
  * // 2000
60
60
  *
61
- * _toPrecision(1234.56, 2)
61
+ * _toPrecision(1634.56, 2)
62
62
  * // 1600
63
63
  */
64
64
  export function _toPrecision(n, precision) {
@@ -6,7 +6,7 @@ Improvements:
6
6
  - Included Typescript typings (no need for @types/p-map)
7
7
  - Compatible with pProps (that had typings issues)
8
8
  */
9
- import { ErrorMode } from '..';
9
+ import { END, ErrorMode, SKIP } from '..';
10
10
  import { AggregatedError } from './AggregatedError';
11
11
  /**
12
12
  * Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
@@ -40,25 +40,27 @@ export async function pMap(iterable, mapper, opt = {}) {
40
40
  const ret = [];
41
41
  const iterator = iterable[Symbol.iterator]();
42
42
  const errors = [];
43
- let isRejected = false;
43
+ let isSettled = false;
44
44
  let isIterableDone = false;
45
45
  let resolvingCount = 0;
46
46
  let currentIndex = 0;
47
- const next = () => {
48
- if (isRejected) {
47
+ const next = (skipped = false) => {
48
+ if (isSettled) {
49
49
  return;
50
50
  }
51
51
  const nextItem = iterator.next();
52
52
  const i = currentIndex;
53
- currentIndex++;
53
+ if (!skipped)
54
+ currentIndex++;
54
55
  if (nextItem.done) {
55
56
  isIterableDone = true;
56
57
  if (resolvingCount === 0) {
58
+ const r = ret.filter(r => r !== SKIP);
57
59
  if (errors.length && errorMode === ErrorMode.THROW_AGGREGATED) {
58
- reject(new AggregatedError(errors, ret));
60
+ reject(new AggregatedError(errors, r));
59
61
  }
60
62
  else {
61
- resolve(ret);
63
+ resolve(r);
62
64
  }
63
65
  }
64
66
  return;
@@ -67,12 +69,16 @@ export async function pMap(iterable, mapper, opt = {}) {
67
69
  Promise.resolve(nextItem.value)
68
70
  .then(async (element) => await mapper(element, i))
69
71
  .then(value => {
72
+ if (value === END) {
73
+ isSettled = true;
74
+ return resolve(ret.filter(r => r !== SKIP));
75
+ }
70
76
  ret[i] = value;
71
77
  resolvingCount--;
72
78
  next();
73
79
  }, err => {
74
80
  if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
75
- isRejected = true;
81
+ isSettled = true;
76
82
  reject(err);
77
83
  }
78
84
  else {
@@ -8,16 +8,15 @@ Improvements:
8
8
  - Included Typescript typings (no need for @types/p-props)
9
9
  */
10
10
  import { pMap } from './pMap';
11
+ // todo: remove when eslint starts to know about Awaited
12
+ /* eslint-disable no-undef */
11
13
  /**
12
14
  * Promise.all for Object instead of Array.
13
15
  * Supports concurrency.
14
16
  */
15
17
  export async function pProps(input, opt) {
16
- const keys = Object.keys(input);
17
- const values = await pMap(Object.values(input), r => r, opt);
18
18
  const r = {};
19
- values.forEach((v, i) => {
20
- r[keys[i]] = v;
21
- });
19
+ const keys = Object.keys(input);
20
+ await pMap(Object.values(input), (v, i) => (r[keys[i]] = v), opt);
22
21
  return r;
23
22
  }
@@ -0,0 +1,136 @@
1
+ import { END, SKIP } from '../types';
2
+ /**
3
+ * Inspired by Kotlin Sequences.
4
+ * Similar to arrays, but with lazy evaluation, abortable.
5
+ * Can be useful when it's not feasible/performant to create an array of values to iterate upfront
6
+ * (e.g to construct 1000 Dayjs instances only to find that 2 of them were needed).
7
+ *
8
+ * @experimental
9
+ */
10
+ export class Seq {
11
+ constructor(initialValue, nextFn) {
12
+ this.nextFn = nextFn;
13
+ this.sentInitialValue = false;
14
+ this.i = -1;
15
+ this.currentValue = initialValue;
16
+ }
17
+ [Symbol.iterator]() {
18
+ return {
19
+ next: () => {
20
+ const value = this.next();
21
+ return value === END ? { done: true, value: undefined } : { value };
22
+ },
23
+ };
24
+ }
25
+ static create(initialValue, nextFn) {
26
+ return new Seq(initialValue, nextFn);
27
+ }
28
+ static range(minIncl, maxExcl, step = 1) {
29
+ const max = maxExcl - step;
30
+ return new Seq(minIncl, n => (n < max ? n + step : END));
31
+ }
32
+ static from(a) {
33
+ const it = a[Symbol.iterator]();
34
+ const v = it.next();
35
+ if (v.done)
36
+ return new Seq(END, () => { });
37
+ return new Seq(v.value, () => {
38
+ const v = it.next();
39
+ if (v.done)
40
+ return END;
41
+ return v.value;
42
+ });
43
+ }
44
+ static empty() {
45
+ return new Seq(END, () => { });
46
+ }
47
+ next() {
48
+ if (this.currentValue === END)
49
+ return END;
50
+ this.i++;
51
+ let v;
52
+ if (!this.sentInitialValue) {
53
+ this.sentInitialValue = true;
54
+ v = this.currentValue;
55
+ }
56
+ else {
57
+ v = this.nextFn(this.currentValue, this.i);
58
+ }
59
+ // console.log(`_seq`, v)
60
+ if (v === SKIP)
61
+ return this.next();
62
+ return (this.currentValue = v);
63
+ }
64
+ // Chainable functions - return another (chained) Sequence
65
+ // map<OUT>(mapper: Mapper<T, OUT | typeof SKIP | typeof END>): Seq<OUT> {
66
+ // if (this.currentValue === END) return this as any
67
+ //
68
+ // // Iterate until first valid value, to have as `initialValue` of the new Sequence
69
+ // let v: OUT | typeof SKIP | typeof END
70
+ //
71
+ // while (true) {
72
+ // v = mapper(this.currentValue, ++this.i)
73
+ // if (v === SKIP) continue
74
+ // if (v === END) return this as any
75
+ // }
76
+ //
77
+ // return new Seq<OUT>(v as OUT, (current, i) => {
78
+ // const v = mapper(current, i)
79
+ //
80
+ // })
81
+ // }
82
+ // Final functions - return final value, not a chained sequence
83
+ find(predicate) {
84
+ do {
85
+ const v = this.next();
86
+ if (v === END)
87
+ return; // not found, end of sequence
88
+ const r = predicate(v, this.i);
89
+ if (r === END)
90
+ return;
91
+ if (r)
92
+ return v;
93
+ // otherwise proceed
94
+ } while (true); // eslint-disable-line no-constant-condition
95
+ }
96
+ some(predicate) {
97
+ do {
98
+ const v = this.next();
99
+ if (v === END)
100
+ return false;
101
+ const r = predicate(v, this.i);
102
+ if (r === END)
103
+ return false;
104
+ if (r)
105
+ return true;
106
+ } while (true); // eslint-disable-line no-constant-condition
107
+ }
108
+ every(predicate) {
109
+ do {
110
+ const v = this.next();
111
+ if (v === END)
112
+ return true;
113
+ const r = predicate(v, this.i);
114
+ if (r === END)
115
+ return true;
116
+ if (!r)
117
+ return false;
118
+ } while (true); // eslint-disable-line no-constant-condition
119
+ }
120
+ toArray() {
121
+ const a = [];
122
+ // eslint-disable-next-line no-constant-condition
123
+ while (true) {
124
+ const v = this.next();
125
+ if (v === END)
126
+ return a;
127
+ a.push(v);
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * Convenience function to create a Sequence.
133
+ */
134
+ export function _seq(initialValue, nextFn) {
135
+ return Seq.create(initialValue, nextFn);
136
+ }
@@ -1,9 +1,12 @@
1
+ // const possibleJsonStartTokens = ['{', '[', '"']
2
+ const DETECT_JSON = /^\s*[{["\-\d]/;
1
3
  /**
2
4
  * Attempts to parse object as JSON.
3
5
  * Returns original object if JSON parse failed (silently).
4
6
  */
5
7
  export function _jsonParseIfPossible(obj, reviver) {
6
- if (typeof obj === 'string' && obj) {
8
+ // Optimization: only try to parse if it looks like JSON: starts with a json possible character
9
+ if (typeof obj === 'string' && obj && DETECT_JSON.test(obj)) {
7
10
  try {
8
11
  return JSON.parse(obj, reviver);
9
12
  }
package/dist-esm/types.js CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Symbol to indicate END of Sequence.
3
+ */
4
+ export const END = Symbol('END');
5
+ /**
6
+ * Symbol to indicate SKIP of item (e.g in AbortableMapper)
7
+ */
8
+ export const SKIP = Symbol('SKIP');
1
9
  export const _passthroughMapper = item => item;
2
10
  export const _passUndefinedMapper = () => undefined;
3
11
  /**