pepka 1.6.23 → 1.8.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/bundle.cjs CHANGED
@@ -136,9 +136,9 @@ const includes = curry2((s, ss) => {
136
136
  }
137
137
  });
138
138
 
139
- /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
140
- * qflat, qpick, qslice, quniq, qflat, qflatShallow, qreduceAsync
141
- */
139
+ const { min } = Math;
140
+ const z = 0;
141
+ /* qflat, qflatShallow, qreduceAsync */
142
142
  const qappend = curry2((s, xs) => { xs.push(s); return xs; });
143
143
  const qassoc = curry3((prop, v, obj) => { obj[prop] = v; return obj; });
144
144
  const qreduce = curry3((fn, accum, arr) => arr.reduce(fn, accum));
@@ -195,32 +195,46 @@ const qmapKeys = curry2((keyMap, o) => {
195
195
  return o;
196
196
  });
197
197
  // FIXME: qmap(any, tags) -> some function!!!
198
+ /**
199
+ * @param pipe (v, i, list: T[]) -> T.
200
+ * @param data T[].
201
+ * @returns T[].
202
+ */
198
203
  const qmap = curry2((pipe, arr) => {
199
204
  for (const i in arr)
200
205
  arr[i] = pipe(arr[i], +i, arr);
201
206
  return arr;
202
207
  });
208
+ /**
209
+ * @param cond (v, k) -> boolean.
210
+ * @param data T extends AnyObject.
211
+ * @returns T
212
+ */
203
213
  const qmapObj = curry2((pipe, o) => {
204
214
  for (const k in o)
205
215
  o[k] = pipe(o[k], k, o);
206
216
  return o;
207
217
  });
218
+ /**
219
+ * @param cond (v, k) -> boolean.
220
+ * @param data T extends any[] | AnyObject.
221
+ * @returns T
222
+ */
208
223
  const qfilter = curry2((cond, data) => {
209
- const isArr = isArray(data);
210
- let indicies_offset, indicies2rm;
211
- if (isArr) {
212
- indicies_offset = 0;
213
- indicies2rm = [];
224
+ if (isArray(data)) {
225
+ let indicies_offset = 0;
226
+ const indicies2rm = [];
227
+ const len = length(data);
228
+ for (let i = 0; i < len; i++)
229
+ if (!cond(data[i], i))
230
+ indicies2rm.push(i);
231
+ for (const i of indicies2rm)
232
+ data.splice(i - indicies_offset++, 1);
214
233
  }
215
- for (let k in data)
216
- if (!cond(data[k], k)) // @ts-ignore
217
- if (isArr)
218
- indicies2rm.push(+k);
219
- else
234
+ else
235
+ for (const k in data)
236
+ if (!cond(data[k], k))
220
237
  delete data[k];
221
- if (isArr) // @ts-ignore
222
- for (const i of indicies2rm) // @ts-ignore
223
- data.splice(i - indicies_offset++, 1);
224
238
  return data;
225
239
  });
226
240
  const qempty = (o) => {
@@ -254,6 +268,55 @@ const qomit = curry2((props, o) => qfilter((_, k) => !includes(k, props), o));
254
268
  /** @param prop string @param pipe (data[prop]): prop_value @param data any
255
269
  * @returns data with prop over pipe. */
256
270
  const qoverProp = curry3((prop, pipe, data) => qassoc(prop, pipe(data[prop]), data));
271
+ /** Slower than pick() (dictionary mode) !
272
+ * @param props (string|number)[]
273
+ * @param o AnyObject
274
+ * @returns AnyObject
275
+ */
276
+ const qpick = curry2((props, o) => {
277
+ for (const p in o)
278
+ if (!props.includes(p))
279
+ delete o[p];
280
+ return o;
281
+ });
282
+ const qslice = curry3((from, to, xs) => {
283
+ const right = (isNum(to) ? to : inf);
284
+ const window_width = min(right, length(xs)) - from;
285
+ if (isArray(xs)) {
286
+ xs = xs;
287
+ if (from > z)
288
+ for (let i = z; i < window_width; i++)
289
+ xs[i] = xs[from + i];
290
+ xs.length = window_width;
291
+ return xs;
292
+ }
293
+ else
294
+ return xs.slice(from, right); // strings are immutable.
295
+ });
296
+ /** Should be faster than .splice() 'cause does not make a new array. */
297
+ const rmel = (index, xs) => {
298
+ const len = length(xs);
299
+ for (let i = index; i < len; i++)
300
+ xs[i] = xs[i + 1];
301
+ xs.length = len - 1;
302
+ return xs;
303
+ };
304
+ const seen = new Set();
305
+ const quniq = (xs) => {
306
+ seen.clear();
307
+ let size = length(xs);
308
+ for (let i = z; i < size; i++) {
309
+ const x = xs[i];
310
+ if (seen.has(x)) {
311
+ rmel(i, xs);
312
+ size--;
313
+ i--;
314
+ }
315
+ else
316
+ seen.add(x);
317
+ }
318
+ return xs;
319
+ };
257
320
  // Aliases.
258
321
  const qpush = qappend;
259
322
 
@@ -380,7 +443,12 @@ const diff = curry2((_xs1, _xs2) => {
380
443
  }
381
444
  return out;
382
445
  });
383
- const genBy = curry2((generator, length) => [...Array(length)].map((_, i) => generator(i)));
446
+ const genBy = curry2((generator, length) => {
447
+ const a = new Array(length);
448
+ for (let i = 0; i < length; i++)
449
+ a[i] = generator(i);
450
+ return a;
451
+ });
384
452
  const once = (fn) => {
385
453
  let done = false, cache;
386
454
  return function (...args) {
@@ -471,6 +539,11 @@ const freezeShallow = (o) => qfreezeShallow(clone(o));
471
539
  * @param array T2[]
472
540
  */
473
541
  const reduce = curry3((reducer, accum, arr) => qreduce(reducer, clone(accum), arr));
542
+ /**
543
+ * @param props (string|number)[]
544
+ * @param o AnyObject
545
+ * @returns AnyObject
546
+ */
474
547
  const pick = curry2((props, o) => {
475
548
  const out = {};
476
549
  for (const p of props)
@@ -554,6 +627,7 @@ const notf = complement;
554
627
  const push = append;
555
628
  const some = any;
556
629
  const weakEq = eq;
630
+ const uniqBy = uniqWith;
557
631
 
558
632
  /** One promise waits for another. */
559
633
  const forEachSerial = (() => {
@@ -567,6 +641,13 @@ const forEachSerial = (() => {
567
641
  })();
568
642
  /** Promise.all wrapper for functional pipelining. */
569
643
  const waitAll = (promises) => Promise.all(promises);
644
+ const qwaitAll = async (xs) => new Promise((ff, rj) => {
645
+ const len = length(xs);
646
+ let j = len;
647
+ for (let i = 0; i < len; i++)
648
+ xs[i].then((x) => { xs[i] = x; if (--j)
649
+ ff(xs); }).catch(rj);
650
+ });
570
651
  /** Waits for a Promise that been generated by the first arg, then returns an untoched value. Types T.
571
652
  * @param {AnyFunc<Promise>} fn - function to wait.
572
653
  * @param {T} s - any value to tap and return back
@@ -580,6 +661,29 @@ const composeAsync = (() => {
580
661
  const pipe = async (fns, input, i) => ~i ? await pipe(fns, [await fns[i](...input)], --i) : head(input);
581
662
  return (...fns) => (...input) => pipe(fns, input, fns.length - 1);
582
663
  })();
664
+ /**
665
+ * @param cond async (v, k) -> boolean.
666
+ * @param data T extends any[] | AnyObject.
667
+ * @returns T
668
+ */
669
+ const qfilterAsync = curry2(async (cond, data // dunno how to merge it with sync version...
670
+ ) => {
671
+ if (isArray(data)) {
672
+ let indicies_offset = 0;
673
+ const indicies2rm = [];
674
+ const len = length(data);
675
+ for (let i = 0; i < len; i++)
676
+ if (!await cond(data[i], i))
677
+ indicies2rm.push(i);
678
+ for (const i of indicies2rm)
679
+ data.splice(i - indicies_offset++, 1);
680
+ }
681
+ else
682
+ for (const k in data)
683
+ if (!await cond(data[k], k))
684
+ delete data[k];
685
+ return data;
686
+ });
583
687
 
584
688
  const ecran = '\\';
585
689
  // TODO: make it splicy, not accumulatie by symbols.
@@ -764,6 +868,7 @@ exports.qassoc = qassoc;
764
868
  exports.qassocPath = qassocPath;
765
869
  exports.qempty = qempty;
766
870
  exports.qfilter = qfilter;
871
+ exports.qfilterAsync = qfilterAsync;
767
872
  exports.qfreeze = qfreeze;
768
873
  exports.qfreezeShallow = qfreezeShallow;
769
874
  exports.qmap = qmap;
@@ -775,11 +880,15 @@ exports.qmergeDeepX = qmergeDeepX;
775
880
  exports.qmergeShallow = qmergeShallow;
776
881
  exports.qomit = qomit;
777
882
  exports.qoverProp = qoverProp;
883
+ exports.qpick = qpick;
778
884
  exports.qprepend = qprepend;
779
885
  exports.qpush = qpush;
780
886
  exports.qreduce = qreduce;
781
887
  exports.qreverse = qreverse;
888
+ exports.qslice = qslice;
782
889
  exports.qsort = qsort;
890
+ exports.quniq = quniq;
891
+ exports.qwaitAll = qwaitAll;
783
892
  exports.range = range;
784
893
  exports.reduce = reduce;
785
894
  exports.reflect = reflect;
@@ -807,6 +916,7 @@ exports.type = type;
807
916
  exports.typeIs = typeIs;
808
917
  exports.uncurry = uncurry;
809
918
  exports.uniq = uniq;
919
+ exports.uniqBy = uniqBy;
810
920
  exports.uniqWith = uniqWith;
811
921
  exports.values = values;
812
922
  exports.wait = wait;
package/dist/bundle.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
3
  type AnyArgs = any[];
4
- type AnyArray<T = any> = T[] | readonly T[];
4
+ type AnyArray<T = any> = T[] | readonly T[] | (ArrayBufferView & {
5
+ length: number;
6
+ });
5
7
  type Split<S extends string> = S extends `${infer U}${infer V}` ? [
6
8
  U,
7
9
  ...Split<V>
@@ -48,6 +50,7 @@ export declare const forEachSerial: {
48
50
  };
49
51
  /** Promise.all wrapper for functional pipelining. */
50
52
  export declare const waitAll: <T>(promises: Promise<T>[]) => Promise<Awaited<T>[]>;
53
+ export declare const qwaitAll: <T>(xs: Promise<T>[]) => Promise<T[]>;
51
54
  /** Waits for a Promise that been generated by the first arg, then returns an untoched value. Types T.
52
55
  * @param {AnyFunc<Promise>} fn - function to wait.
53
56
  * @param {T} s - any value to tap and return back
@@ -68,6 +71,17 @@ export declare const forEachAsync: {
68
71
  };
69
72
  /** The same as compose, but waits for promises in chains and returns a Promise. */
70
73
  export declare const composeAsync: <TIn extends any[] = any[], TOut = any>(...fns: AnyFunc[]) => Composed<TIn, Promise<TOut>>;
74
+ /**
75
+ * @param cond async (v, k) -> boolean.
76
+ * @param data T extends any[] | AnyObject.
77
+ * @returns T
78
+ */
79
+ export declare const qfilterAsync: {
80
+ (a: Placeholder, b: any[] | AnyObject): (a: (v: any, k: string | number) => Promise<boolean> | boolean) => Promise<any[] | AnyObject>;
81
+ (a: (v: any, k: string | number) => Promise<boolean> | boolean, b: Placeholder): (b: any[] | AnyObject) => Promise<any[] | AnyObject>;
82
+ (a: (v: any, k: string | number) => Promise<boolean> | boolean): (b: any[] | AnyObject) => Promise<any[] | AnyObject>;
83
+ (a: (v: any, k: string | number) => Promise<boolean> | boolean, b: any[] | AnyObject): Promise<any[] | AnyObject>;
84
+ };
71
85
  declare const length$1: <T extends AnyArray | string>(s: T) => T extends string ? StrLen<T> : T["length"];
72
86
  export declare const symbol: unique symbol;
73
87
  export declare const toLower: (s: string) => string;
@@ -145,18 +159,33 @@ export declare const qmapKeys: {
145
159
  [oldKey: string]: string | AnyFunc;
146
160
  }, b: AnyObject): AnyObject;
147
161
  };
162
+ /**
163
+ * @param pipe (v, i, list: T[]) -> T.
164
+ * @param data T[].
165
+ * @returns T[].
166
+ */
148
167
  export declare const qmap: {
149
- (a: Placeholder, b: any[]): (a: (s: any, i?: number, list?: any[]) => any) => any[];
150
- (a: (s: any, i?: number, list?: any[]) => any, b: Placeholder): (b: any[]) => any[];
151
- (a: (s: any, i?: number, list?: any[]) => any): (b: any[]) => any[];
152
- (a: (s: any, i?: number, list?: any[]) => any, b: any[]): any[];
153
- };
168
+ (a: Placeholder, b: any[] | AnyObject): (a: (s: any, i?: number, list?: any[] | AnyObject | undefined) => any) => any[] | AnyObject;
169
+ (a: (s: any, i?: number, list?: any[] | AnyObject | undefined) => any, b: Placeholder): (b: any[] | AnyObject) => any[] | AnyObject;
170
+ (a: (s: any, i?: number, list?: any[] | AnyObject | undefined) => any): (b: any[] | AnyObject) => any[] | AnyObject;
171
+ (a: (s: any, i?: number, list?: any[] | AnyObject | undefined) => any, b: any[] | AnyObject): any[] | AnyObject;
172
+ };
173
+ /**
174
+ * @param cond (v, k) -> boolean.
175
+ * @param data T extends AnyObject.
176
+ * @returns T
177
+ */
154
178
  export declare const qmapObj: {
155
179
  (a: Placeholder, b: AnyObject): (a: (s: any, k?: string, o?: AnyObject) => any) => AnyObject;
156
180
  (a: (s: any, k?: string, o?: AnyObject) => any, b: Placeholder): (b: AnyObject) => AnyObject;
157
181
  (a: (s: any, k?: string, o?: AnyObject) => any): (b: AnyObject) => AnyObject;
158
182
  (a: (s: any, k?: string, o?: AnyObject) => any, b: AnyObject): AnyObject;
159
183
  };
184
+ /**
185
+ * @param cond (v, k) -> boolean.
186
+ * @param data T extends any[] | AnyObject.
187
+ * @returns T
188
+ */
160
189
  export declare const qfilter: {
161
190
  (a: Placeholder, b: any[] | AnyObject): (a: (v: any, k: string | number) => boolean) => any[] | AnyObject;
162
191
  (a: (v: any, k: string | number) => boolean, b: Placeholder): (b: any[] | AnyObject) => any[] | AnyObject;
@@ -190,6 +219,19 @@ export declare const qomit: {
190
219
  /** @param prop string @param pipe (data[prop]): prop_value @param data any
191
220
  * @returns data with prop over pipe. */
192
221
  export declare const qoverProp: (...args: AnyArgs) => any;
222
+ /** Slower than pick() (dictionary mode) !
223
+ * @param props (string|number)[]
224
+ * @param o AnyObject
225
+ * @returns AnyObject
226
+ */
227
+ export declare const qpick: {
228
+ (a: Placeholder, b: AnyObject): (a: string[]) => AnyObject;
229
+ (a: string[], b: Placeholder): (b: AnyObject) => AnyObject;
230
+ (a: string[]): (b: AnyObject) => AnyObject;
231
+ (a: string[], b: AnyObject): AnyObject;
232
+ };
233
+ export declare const qslice: (...args: AnyArgs) => any;
234
+ export declare const quniq: (xs: any[]) => any[];
193
235
  export declare const qpush: {
194
236
  (a: Placeholder, b: any[]): (a: any) => any[];
195
237
  (a: any, b: Placeholder): (b: any[]) => any[];
@@ -543,11 +585,16 @@ export declare const freezeShallow: <T extends AnyObject>(o: T) => Readonly<T>;
543
585
  * @param array T2[]
544
586
  */
545
587
  export declare const reduce: (...args: AnyArgs) => any;
588
+ /**
589
+ * @param props (string|number)[]
590
+ * @param o AnyObject
591
+ * @returns AnyObject
592
+ */
546
593
  export declare const pick: {
547
- (a: Placeholder, b: AnyObject): (a: string[]) => {};
548
- (a: string[], b: Placeholder): (b: AnyObject) => {};
549
- (a: string[]): (b: AnyObject) => {};
550
- (a: string[], b: AnyObject): {};
594
+ (a: Placeholder, b: AnyObject): (a: (string | number)[]) => {};
595
+ (a: (string | number)[], b: Placeholder): (b: AnyObject) => {};
596
+ (a: (string | number)[]): (b: AnyObject) => {};
597
+ (a: (string | number)[], b: AnyObject): {};
551
598
  };
552
599
  export declare const pickBy: {
553
600
  (a: Placeholder, b: AnyObject): (a: Cond) => any;
@@ -715,6 +762,12 @@ export declare const weakEq: {
715
762
  (a: any): (b: any) => boolean;
716
763
  (a: any, b: any): boolean;
717
764
  };
765
+ export declare const uniqBy: {
766
+ (a: Placeholder, b: any[]): (a: (x: any, y: any) => boolean) => any;
767
+ (a: (x: any, y: any) => boolean, b: Placeholder): (b: any[]) => any;
768
+ (a: (x: any, y: any) => boolean): (b: any[]) => any;
769
+ (a: (x: any, y: any) => boolean, b: any[]): any;
770
+ };
718
771
  type StrTmpl = ((data: AnyObject) => string);
719
772
  /** Supports ecrans: '\\{"json": {yes} \\}'
720
773
  @returns getTmpl('one{meme}two')({meme: 42}) -> one42two */
package/dist/bundle.mjs CHANGED
@@ -134,9 +134,9 @@ const includes = curry2((s, ss) => {
134
134
  }
135
135
  });
136
136
 
137
- /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
138
- * qflat, qpick, qslice, quniq, qflat, qflatShallow, qreduceAsync
139
- */
137
+ const { min } = Math;
138
+ const z = 0;
139
+ /* qflat, qflatShallow, qreduceAsync */
140
140
  const qappend = curry2((s, xs) => { xs.push(s); return xs; });
141
141
  const qassoc = curry3((prop, v, obj) => { obj[prop] = v; return obj; });
142
142
  const qreduce = curry3((fn, accum, arr) => arr.reduce(fn, accum));
@@ -193,32 +193,46 @@ const qmapKeys = curry2((keyMap, o) => {
193
193
  return o;
194
194
  });
195
195
  // FIXME: qmap(any, tags) -> some function!!!
196
+ /**
197
+ * @param pipe (v, i, list: T[]) -> T.
198
+ * @param data T[].
199
+ * @returns T[].
200
+ */
196
201
  const qmap = curry2((pipe, arr) => {
197
202
  for (const i in arr)
198
203
  arr[i] = pipe(arr[i], +i, arr);
199
204
  return arr;
200
205
  });
206
+ /**
207
+ * @param cond (v, k) -> boolean.
208
+ * @param data T extends AnyObject.
209
+ * @returns T
210
+ */
201
211
  const qmapObj = curry2((pipe, o) => {
202
212
  for (const k in o)
203
213
  o[k] = pipe(o[k], k, o);
204
214
  return o;
205
215
  });
216
+ /**
217
+ * @param cond (v, k) -> boolean.
218
+ * @param data T extends any[] | AnyObject.
219
+ * @returns T
220
+ */
206
221
  const qfilter = curry2((cond, data) => {
207
- const isArr = isArray(data);
208
- let indicies_offset, indicies2rm;
209
- if (isArr) {
210
- indicies_offset = 0;
211
- indicies2rm = [];
222
+ if (isArray(data)) {
223
+ let indicies_offset = 0;
224
+ const indicies2rm = [];
225
+ const len = length(data);
226
+ for (let i = 0; i < len; i++)
227
+ if (!cond(data[i], i))
228
+ indicies2rm.push(i);
229
+ for (const i of indicies2rm)
230
+ data.splice(i - indicies_offset++, 1);
212
231
  }
213
- for (let k in data)
214
- if (!cond(data[k], k)) // @ts-ignore
215
- if (isArr)
216
- indicies2rm.push(+k);
217
- else
232
+ else
233
+ for (const k in data)
234
+ if (!cond(data[k], k))
218
235
  delete data[k];
219
- if (isArr) // @ts-ignore
220
- for (const i of indicies2rm) // @ts-ignore
221
- data.splice(i - indicies_offset++, 1);
222
236
  return data;
223
237
  });
224
238
  const qempty = (o) => {
@@ -252,6 +266,55 @@ const qomit = curry2((props, o) => qfilter((_, k) => !includes(k, props), o));
252
266
  /** @param prop string @param pipe (data[prop]): prop_value @param data any
253
267
  * @returns data with prop over pipe. */
254
268
  const qoverProp = curry3((prop, pipe, data) => qassoc(prop, pipe(data[prop]), data));
269
+ /** Slower than pick() (dictionary mode) !
270
+ * @param props (string|number)[]
271
+ * @param o AnyObject
272
+ * @returns AnyObject
273
+ */
274
+ const qpick = curry2((props, o) => {
275
+ for (const p in o)
276
+ if (!props.includes(p))
277
+ delete o[p];
278
+ return o;
279
+ });
280
+ const qslice = curry3((from, to, xs) => {
281
+ const right = (isNum(to) ? to : inf);
282
+ const window_width = min(right, length(xs)) - from;
283
+ if (isArray(xs)) {
284
+ xs = xs;
285
+ if (from > z)
286
+ for (let i = z; i < window_width; i++)
287
+ xs[i] = xs[from + i];
288
+ xs.length = window_width;
289
+ return xs;
290
+ }
291
+ else
292
+ return xs.slice(from, right); // strings are immutable.
293
+ });
294
+ /** Should be faster than .splice() 'cause does not make a new array. */
295
+ const rmel = (index, xs) => {
296
+ const len = length(xs);
297
+ for (let i = index; i < len; i++)
298
+ xs[i] = xs[i + 1];
299
+ xs.length = len - 1;
300
+ return xs;
301
+ };
302
+ const seen = new Set();
303
+ const quniq = (xs) => {
304
+ seen.clear();
305
+ let size = length(xs);
306
+ for (let i = z; i < size; i++) {
307
+ const x = xs[i];
308
+ if (seen.has(x)) {
309
+ rmel(i, xs);
310
+ size--;
311
+ i--;
312
+ }
313
+ else
314
+ seen.add(x);
315
+ }
316
+ return xs;
317
+ };
255
318
  // Aliases.
256
319
  const qpush = qappend;
257
320
 
@@ -378,7 +441,12 @@ const diff = curry2((_xs1, _xs2) => {
378
441
  }
379
442
  return out;
380
443
  });
381
- const genBy = curry2((generator, length) => [...Array(length)].map((_, i) => generator(i)));
444
+ const genBy = curry2((generator, length) => {
445
+ const a = new Array(length);
446
+ for (let i = 0; i < length; i++)
447
+ a[i] = generator(i);
448
+ return a;
449
+ });
382
450
  const once = (fn) => {
383
451
  let done = false, cache;
384
452
  return function (...args) {
@@ -469,6 +537,11 @@ const freezeShallow = (o) => qfreezeShallow(clone(o));
469
537
  * @param array T2[]
470
538
  */
471
539
  const reduce = curry3((reducer, accum, arr) => qreduce(reducer, clone(accum), arr));
540
+ /**
541
+ * @param props (string|number)[]
542
+ * @param o AnyObject
543
+ * @returns AnyObject
544
+ */
472
545
  const pick = curry2((props, o) => {
473
546
  const out = {};
474
547
  for (const p of props)
@@ -552,6 +625,7 @@ const notf = complement;
552
625
  const push = append;
553
626
  const some = any;
554
627
  const weakEq = eq;
628
+ const uniqBy = uniqWith;
555
629
 
556
630
  /** One promise waits for another. */
557
631
  const forEachSerial = (() => {
@@ -565,6 +639,13 @@ const forEachSerial = (() => {
565
639
  })();
566
640
  /** Promise.all wrapper for functional pipelining. */
567
641
  const waitAll = (promises) => Promise.all(promises);
642
+ const qwaitAll = async (xs) => new Promise((ff, rj) => {
643
+ const len = length(xs);
644
+ let j = len;
645
+ for (let i = 0; i < len; i++)
646
+ xs[i].then((x) => { xs[i] = x; if (--j)
647
+ ff(xs); }).catch(rj);
648
+ });
568
649
  /** Waits for a Promise that been generated by the first arg, then returns an untoched value. Types T.
569
650
  * @param {AnyFunc<Promise>} fn - function to wait.
570
651
  * @param {T} s - any value to tap and return back
@@ -578,6 +659,29 @@ const composeAsync = (() => {
578
659
  const pipe = async (fns, input, i) => ~i ? await pipe(fns, [await fns[i](...input)], --i) : head(input);
579
660
  return (...fns) => (...input) => pipe(fns, input, fns.length - 1);
580
661
  })();
662
+ /**
663
+ * @param cond async (v, k) -> boolean.
664
+ * @param data T extends any[] | AnyObject.
665
+ * @returns T
666
+ */
667
+ const qfilterAsync = curry2(async (cond, data // dunno how to merge it with sync version...
668
+ ) => {
669
+ if (isArray(data)) {
670
+ let indicies_offset = 0;
671
+ const indicies2rm = [];
672
+ const len = length(data);
673
+ for (let i = 0; i < len; i++)
674
+ if (!await cond(data[i], i))
675
+ indicies2rm.push(i);
676
+ for (const i of indicies2rm)
677
+ data.splice(i - indicies_offset++, 1);
678
+ }
679
+ else
680
+ for (const k in data)
681
+ if (!await cond(data[k], k))
682
+ delete data[k];
683
+ return data;
684
+ });
581
685
 
582
686
  const ecran = '\\';
583
687
  // TODO: make it splicy, not accumulatie by symbols.
@@ -663,4 +767,4 @@ const wait = (time) => new Promise((ff) => setTimeout(ff, time));
663
767
  // TODO: possibly introduce a second argument limiting unfolding.
664
768
  const uncurry = (fn) => (...args) => qreduce(((fn, arg) => fn ? fn(arg) : fn), fn, args);
665
769
 
666
- export { F, T, __, add, all, allPass, always, any, anyPass, append, assoc, assocPath, bind, both, callFrom, callWith, clone, cloneShallow, complement, compose, composeAsync, concat, cond, curry, curry2, curry3, debounce, diff, divide, echo, empty, eq, equals, explore, filter, find, findIndex, flat, flatShallow, flatTo, flip, forEach, forEachAsync, forEachSerial, freeze, freezeShallow, fromPairs, genBy, getTmpl, gt, gte, head, identity, ifElse, includes, indexOf, intersection, isEmpty, isNil, join, keys, last, length, lt, lte, map, mapKeys, mapObj, memoize, mergeDeep, mergeDeepAdd, mergeDeepX, mergeShallow, mirror, multiply, noop, not, notf, nth, omit, once, overProp, path, pathEq, pathExists, pathOr, pathsEq, pick, pickBy, prepend, prop, propEq, propsEq, push, qappend, qassoc, qassocPath, qempty, qfilter, qfreeze, qfreezeShallow, qmap, qmapKeys, qmapObj, qmergeDeep, qmergeDeepAdd, qmergeDeepX, qmergeShallow, qomit, qoverProp, qprepend, qpush, qreduce, qreverse, qsort, range, reduce, reflect, replace, reverse, sizeof, slice, some, sort, split, startsWith, startsWithShallow, subtract, symbol, tail, take, tap, test, throttle, toLower, toPairs, toUpper, trim, type, typeIs, uncurry, uniq, uniqWith, values, wait, waitAll, waitTap, weakEq, when, zip, zipObj, zipWith };
770
+ export { F, T, __, add, all, allPass, always, any, anyPass, append, assoc, assocPath, bind, both, callFrom, callWith, clone, cloneShallow, complement, compose, composeAsync, concat, cond, curry, curry2, curry3, debounce, diff, divide, echo, empty, eq, equals, explore, filter, find, findIndex, flat, flatShallow, flatTo, flip, forEach, forEachAsync, forEachSerial, freeze, freezeShallow, fromPairs, genBy, getTmpl, gt, gte, head, identity, ifElse, includes, indexOf, intersection, isEmpty, isNil, join, keys, last, length, lt, lte, map, mapKeys, mapObj, memoize, mergeDeep, mergeDeepAdd, mergeDeepX, mergeShallow, mirror, multiply, noop, not, notf, nth, omit, once, overProp, path, pathEq, pathExists, pathOr, pathsEq, pick, pickBy, prepend, prop, propEq, propsEq, push, qappend, qassoc, qassocPath, qempty, qfilter, qfilterAsync, qfreeze, qfreezeShallow, qmap, qmapKeys, qmapObj, qmergeDeep, qmergeDeepAdd, qmergeDeepX, qmergeShallow, qomit, qoverProp, qpick, qprepend, qpush, qreduce, qreverse, qslice, qsort, quniq, qwaitAll, range, reduce, reflect, replace, reverse, sizeof, slice, some, sort, split, startsWith, startsWithShallow, subtract, symbol, tail, take, tap, test, throttle, toLower, toPairs, toUpper, trim, type, typeIs, uncurry, uniq, uniqBy, uniqWith, values, wait, waitAll, waitTap, weakEq, when, zip, zipObj, zipWith };
package/package.json CHANGED
@@ -41,15 +41,15 @@
41
41
  "prod": "npm run gentypes && npm run prod:es && npm run prod:cjs",
42
42
  "all": "npm run dev && npm run prod"
43
43
  },
44
- "version": "1.6.23",
44
+ "version": "1.8.0",
45
45
  "devDependencies": {
46
- "@rollup/plugin-commonjs": "^29.0.0",
46
+ "@rollup/plugin-commonjs": "^29.0.2",
47
47
  "@rollup/plugin-node-resolve": "^16.0.3",
48
48
  "@rollup/plugin-replace": "^6.0.3",
49
- "@types/node": "^25.0.3",
49
+ "@types/node": "^25.5.0",
50
50
  "cross-env": "^10.1.0",
51
51
  "dts-bundle-generator": "^9.5.1",
52
- "rollup": "^4.54.0",
52
+ "rollup": "^4.59.0",
53
53
  "rollup-plugin-typescript2": "^0.36.0",
54
54
  "ts-node": "^10.9.2",
55
55
  "tslint": "^6.1.3",
package/src/async.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { curry2 } from "./curry"
2
- import { head } from "./safe"
3
- import { AnyFunc, Composed } from "./types"
2
+ import { head, length } from "./safe"
3
+ import { AnyFunc, AnyObject, Composed } from "./types"
4
+ import { isArray } from "./utils"
4
5
 
5
6
  /** One promise waits for another. */
6
7
  export const forEachSerial = (() => {
@@ -16,6 +17,10 @@ export const forEachSerial = (() => {
16
17
  })()
17
18
  /** Promise.all wrapper for functional pipelining. */
18
19
  export const waitAll = <T>(promises: Promise<T>[]) => Promise.all<T>(promises)
20
+ export const qwaitAll = async <T>(xs: Promise<T>[]) => new Promise<T[]>((ff, rj) => {
21
+ const len = length(xs); let j = len
22
+ for(let i=0; i<len; i++) xs[i].then((x: T) => {xs[i]=x as any; if(--j) ff(xs as any)}).catch(rj)
23
+ })
19
24
  /** Waits for a Promise that been generated by the first arg, then returns an untoched value. Types T.
20
25
  * @param {AnyFunc<Promise>} fn - function to wait.
21
26
  * @param {T} s - any value to tap and return back
@@ -32,4 +37,26 @@ export const composeAsync = (() => {
32
37
  ~i ? await pipe(fns, [await fns[i](...input)], --i) : head(input)
33
38
  return <TIn extends any[] = any[], TOut = any>(...fns: AnyFunc[]): Composed<TIn, Promise<TOut>> =>
34
39
  (...input: any[]) => pipe(fns, input, fns.length-1)
35
- })()
40
+ })()
41
+ /**
42
+ * @param cond async (v, k) -> boolean.
43
+ * @param data T extends any[] | AnyObject.
44
+ * @returns T
45
+ */
46
+ export const qfilterAsync = curry2(async <T extends any[] | AnyObject>(
47
+ cond: (v: any, k: string | number) => Promise<boolean> | boolean,
48
+ data: T // dunno how to merge it with sync version...
49
+ ): Promise<T> => {
50
+ if(isArray(data)) {
51
+ let indicies_offset = 0
52
+ const indicies2rm: number[] = []
53
+ const len = length(data as any[])
54
+ for(let i = 0; i<len; i++)
55
+ if(!await cond(data[i], i))
56
+ indicies2rm.push(i)
57
+ for(const i of indicies2rm)
58
+ data.splice(i - indicies_offset++, 1)
59
+ } else for(const k in data)
60
+ if(!await cond(data[k], k)) delete data[k]
61
+ return data
62
+ })
package/src/bench.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { qpick } from "./quick"
2
+ import { genBy, identity, range } from "./safe"
3
+
4
+
5
+ if(false) {
6
+ // genBy with [...Array(length)].map(...) performs @ average 53.193s/1e5, 303ms/1e4.
7
+ console.time('genBy') // now: 17s/1e5, 65ms/1e4
8
+ for(let i=0; i<1e5; i++) genBy(identity, i)
9
+ console.timeEnd('genBy')
10
+ }
11
+
12
+ // qpick:
13
+ // if o = {1: 'yep', 4: 'yep', 'kakashka': 'noooo', 'anotherkakashka': 'nonono!'}:
14
+ // w/ Set: with range(0, 5) -> 83ms; range(0, 50) -> 189ms.
15
+ // w/o Set: with range(0, 5) -> 69ms; range(0, 50) -> 75ms.
16
+ // if o is generated with 52+ leaset keys are not included in props (generator included!):
17
+ // w/ Set: with range(0, 5) -> 998ms; range(0, 50) -> 1100ms.
18
+ // w/o Set: with range(0, 5) -> 1000ms; range(0, 50) -> 1065ms.
19
+ // pick:
20
+ // if o = {1: 'yep', 4: 'yep', 'kakashka': 'noooo', 'anotherkakashka': 'nonono!'}:
21
+ // w/o Set: with range(0, 5) -> 18ms; range(0, 50) -> 40ms.
22
+ // if o is generated with 52+ leaset keys are not included in props (generator included!):
23
+ // w/o Set: with range(0, 5) -> 600ms; range(0, 50) -> 647ms.
24
+ for(let j=0; j<1e4; j+=1e3) {
25
+ console.time('qpick @'+j)
26
+ const props = range(0, 5)
27
+ for(let i=0; i<1e5; i++) {
28
+ const o = {1: 'yep', 4: 'yep', 'kakashka': 'noooo', 'anotherkakashka': 'nonono!'}
29
+ // for(const x of range(0, 50)) o['_'+x] = x
30
+ qpick(props, o)
31
+ }
32
+ console.timeEnd('qpick @'+j)
33
+ }
package/src/internal.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { curry2 } from "./curry"
2
2
  import { AnyArray, StrLen } from "./internal_types"
3
3
 
4
- export const length = <T extends AnyArray | string>(s: T): T extends string ? StrLen<T> : T["length"] => s.length as any
4
+ export const length = <T extends AnyArray | string>(s: T): T extends string ? StrLen<T> : T['length'] => s.length as any
5
5
  const typed_arr_re = /^(.*?)(8|16|32|64)(Clamped)?Array$/
6
6
  export const is_typed_arr = (t: string) => typed_arr_re.test(t)
7
7
  /** @param start string | any[] @param s string | any[] */
@@ -2,7 +2,7 @@ export type AnyArgs = any[]
2
2
  export type BasicType = 'String'|'Object'|'Number'|'Symbol'|'Array'|'Null'|'Undefined'
3
3
  export type TupleFn<ARG1=any, ARG2=any, Out=any> = (a: ARG1, b: ARG2) => Out
4
4
  export type IDArray = Uint8Array|Uint16Array|Uint32Array
5
- export type AnyArray<T=any> = T[] | readonly T[]
5
+ export type AnyArray<T=any> = T[] | readonly T[] | (ArrayBufferView&{length: number})
6
6
  export type Split<S extends string> = S extends `${infer U}${infer V}` ? [U, ...Split<V>] : []
7
7
  export type IndexesOfArray<A> = Exclude<keyof A, keyof []>
8
8
  export type StrLen<S extends string, Acc extends 0[] = []> =
package/src/quick.ts CHANGED
@@ -1,10 +1,10 @@
1
+ import { includes, length, type } from "./common"
1
2
  import { curry2, curry3 } from "./curry"
2
- import { includes, type } from "./common"
3
- import { AnyObject, Reducer, AnyFunc } from "./types"
4
- import { isFunc, isArray, isObj, isNil } from "./utils"
5
- /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
6
- * qflat, qpick, qslice, quniq, qflat, qflatShallow, qreduceAsync
7
- */
3
+ import { AnyFunc, AnyObject, Reducer } from "./types"
4
+ import { inf, isArray, isFunc, isNil, isNum, isObj } from "./utils"
5
+ const {min} = Math
6
+ const z = 0
7
+ /* qflat, qflatShallow, qreduceAsync */
8
8
 
9
9
  export const qappend = curry2((s: any, xs: any[]) => {xs.push(s); return xs})
10
10
  export const qassoc = curry3((prop: string, v: any, obj: AnyObject) => { obj[prop] = v; return obj })
@@ -63,39 +63,51 @@ export const qmapKeys = curry2(
63
63
  }
64
64
  )
65
65
  // FIXME: qmap(any, tags) -> some function!!!
66
+ /**
67
+ * @param pipe (v, i, list: T[]) -> T.
68
+ * @param data T[].
69
+ * @returns T[].
70
+ */
66
71
  export const qmap = curry2(
67
- (pipe: (s: any, i?: number, list?: any[]) => any, arr: any[]) => {
72
+ <T extends any[]|AnyObject>(pipe: (s: any, i?: number, list?: T) => T[Extract<keyof T, string>], arr: T) => {
68
73
  for(const i in arr) arr[i] = pipe(arr[i], +i, arr)
69
74
  return arr
70
75
  }
71
76
  )
77
+ /**
78
+ * @param cond (v, k) -> boolean.
79
+ * @param data T extends AnyObject.
80
+ * @returns T
81
+ */
72
82
  export const qmapObj = curry2(
73
83
  (pipe: (s: any, k?: string, o?: AnyObject) => any, o: AnyObject) => {
74
84
  for(const k in o) o[k] = pipe(o[k], k, o)
75
85
  return o
76
86
  }
77
87
  )
88
+ /**
89
+ * @param cond (v, k) -> boolean.
90
+ * @param data T extends any[] | AnyObject.
91
+ * @returns T
92
+ */
78
93
  export const qfilter = curry2(
79
- <T extends any[] | AnyObject>(
80
- cond: (v: any, k: string | number) => boolean,
81
- data: T
82
- ): T => {
83
- const isArr = isArray(data)
84
- let indicies_offset: number, indicies2rm: number[]
85
- if(isArr) {
86
- indicies_offset = 0
87
- indicies2rm = []
88
- }
89
- for(let k in data)
90
- if(!cond(data[k], k)) // @ts-ignore
91
- if(isArr) indicies2rm.push(+k)
92
- else delete data[k]
93
- if(isArr)// @ts-ignore
94
- for(const i of indicies2rm) // @ts-ignore
95
- data.splice(i - indicies_offset++, 1)
96
- return data
97
- }
98
- )
94
+ <T extends any[] | AnyObject>(
95
+ cond: (v: any, k: string | number) => boolean,
96
+ data: T
97
+ ): T => {
98
+ if(isArray(data)) {
99
+ let indicies_offset = 0
100
+ const indicies2rm: number[] = []
101
+ const len = length(data as any[])
102
+ for(let i = 0; i<len; i++)
103
+ if(!cond(data[i], i))
104
+ indicies2rm.push(i)
105
+ for(const i of indicies2rm)
106
+ data.splice(i - indicies_offset++, 1)
107
+ } else for(const k in data)
108
+ if(!cond(data[k], k)) delete data[k]
109
+ return data
110
+ })
99
111
  export const qempty = <T extends AnyObject|any[]>(o: T): T extends any[] ? [] : {} => {
100
112
  if(isArray(o)) o.splice(0)
101
113
  else for(const i in o) delete o[i]
@@ -132,6 +144,45 @@ export const qomit = curry2(
132
144
  export const qoverProp = curry3(
133
145
  (prop: string, pipe: AnyFunc, data: any) => qassoc(prop, pipe(data[prop]), data)
134
146
  )
147
+ /** Slower than pick() (dictionary mode) !
148
+ * @param props (string|number)[]
149
+ * @param o AnyObject
150
+ * @returns AnyObject
151
+ */
152
+ export const qpick = curry2((props: string[], o: AnyObject) => {
153
+ for(const p in o) if(!props.includes(p)) delete o[p]
154
+ return o
155
+ })
156
+ export const qslice = curry3(
157
+ (from: number, to: number, xs: any[] | string) => {
158
+ const right = (isNum(to)?to:inf) as number
159
+ const window_width = min(right, length(xs))-from
160
+ if(isArray(xs)) {
161
+ xs = xs as any[]
162
+ if(from>z) for(let i=z; i<window_width; i++) xs[i] = xs[from+i]
163
+ xs.length = window_width
164
+ return xs
165
+ } else return xs.slice(from, right) // strings are immutable.
166
+ }
167
+ )
168
+ /** Should be faster than .splice() 'cause does not make a new array. */
169
+ const rmel = (index: number, xs: any[]) => {
170
+ const len = length(xs)
171
+ for(let i=index; i<len; i++) xs[i]=xs[i+1]
172
+ xs.length = len-1
173
+ return xs
174
+ }
175
+ const seen = new Set()
176
+ export const quniq = (xs: any[]) => {
177
+ seen.clear()
178
+ let size = length(xs)
179
+ for(let i=z; i<size; i++) {
180
+ const x = xs[i]
181
+ if(seen.has(x)) {rmel(i, xs); size--; i--}
182
+ else seen.add(x)
183
+ }
184
+ return xs
185
+ }
135
186
 
136
187
  // Aliases.
137
188
  export const qpush = qappend
package/src/safe.ts CHANGED
@@ -198,7 +198,11 @@ export const genBy = curry2(
198
198
  (
199
199
  generator: (i: number) => any,
200
200
  length: number
201
- ) => [...Array(length)].map((_, i) => generator(i))
201
+ ) => {
202
+ const a = new Array(length)
203
+ for(let i=0; i<length; i++) a[i] = generator(i)
204
+ return a
205
+ }
202
206
  )
203
207
  export const once = <Func extends AnyFunc>(fn: Func) => {
204
208
  let done = false, cache: ReturnType<Func>
@@ -314,8 +318,13 @@ export const reduce = curry3(
314
318
  <T = any>(reducer: Reducer<T>, accum: T, arr: any[]) =>
315
319
  qreduce(reducer, clone(accum), arr)
316
320
  )
321
+ /**
322
+ * @param props (string|number)[]
323
+ * @param o AnyObject
324
+ * @returns AnyObject
325
+ */
317
326
  export const pick = curry2(
318
- (props: string[], o: AnyObject) => {
327
+ (props: (string|number)[], o: AnyObject) => {
319
328
  const out = {}
320
329
  for(const p of props) if(p in o) out[p] = o[p]
321
330
  return out
@@ -453,4 +462,5 @@ export const echo = identity
453
462
  export const notf = complement
454
463
  export const push = append
455
464
  export const some = any
456
- export const weakEq = eq
465
+ export const weakEq = eq
466
+ export const uniqBy = uniqWith