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 +127 -17
- package/dist/bundle.d.ts +63 -10
- package/dist/bundle.mjs +122 -18
- package/package.json +4 -4
- package/src/async.ts +30 -3
- package/src/bench.ts +33 -0
- package/src/internal.ts +1 -1
- package/src/internal_types.ts +1 -1
- package/src/quick.ts +78 -27
- package/src/safe.ts +13 -3
package/dist/bundle.cjs
CHANGED
|
@@ -136,9 +136,9 @@ const includes = curry2((s, ss) => {
|
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
if (
|
|
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) =>
|
|
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
|
-
|
|
138
|
-
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
if (
|
|
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) =>
|
|
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.
|
|
44
|
+
"version": "1.8.0",
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@rollup/plugin-commonjs": "^29.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
|
|
49
|
+
"@types/node": "^25.5.0",
|
|
50
50
|
"cross-env": "^10.1.0",
|
|
51
51
|
"dts-bundle-generator": "^9.5.1",
|
|
52
|
-
"rollup": "^4.
|
|
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[
|
|
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[] */
|
package/src/internal_types.ts
CHANGED
|
@@ -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 {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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?:
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
) =>
|
|
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
|