pepka 1.5.3 → 1.6.1

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,15 +136,14 @@ const qstartsWithWith = (comparator) => curry2((start, s) => {
136
136
  return true;
137
137
  });
138
138
 
139
- // TODO: qoverProp, qover array ?
140
- /** Then next fns seem to be excess due to their safe ver performance should be the same or better:
141
- * qflat, qpick
142
- */
139
+ /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
140
+ * qflat, qpick
141
+ */
143
142
  const qappend = curry2((s, xs) => { xs.push(s); return xs; });
144
143
  const qassoc = curry3((prop, v, obj) => { obj[prop] = v; return obj; });
145
144
  const qreduce = curry3((fn, accum, arr) => arr.reduce(fn, accum));
146
145
  // strategy is for arrays: 1->clean, 2->merge, 3->push.
147
- const mergeDeep$1 = curry3((strategy, o1, o2) => {
146
+ const mergeDeep$1 = (strategy) => curry2((o1, o2) => {
148
147
  for (let k in o2) {
149
148
  switch (type(o2[k])) {
150
149
  case 'Array':
@@ -154,7 +153,7 @@ const mergeDeep$1 = curry3((strategy, o1, o2) => {
154
153
  const o1k = o1[k], o2k = o2[k];
155
154
  for (const i in o2k)
156
155
  if (o1k[i])
157
- mergeDeep$1(strategy, o1k[i], o2k[i]);
156
+ mergeDeep$1(strategy)(o1k[i], o2k[i]);
158
157
  else
159
158
  o1k[i] = o2k[i];
160
159
  break;
@@ -165,7 +164,7 @@ const mergeDeep$1 = curry3((strategy, o1, o2) => {
165
164
  break;
166
165
  case 'Object':
167
166
  if (type(o1[k]) === 'Object') {
168
- mergeDeep$1(strategy, o1[k], o2[k]);
167
+ mergeDeep$1(strategy)(o1[k], o2[k]);
169
168
  break;
170
169
  }
171
170
  default:
@@ -194,8 +193,9 @@ const qmapKeys = curry2((keyMap, o) => {
194
193
  }
195
194
  return o;
196
195
  });
196
+ // FIXME: qmap(any, tags) -> some function!!!
197
197
  const qmap = curry2((pipe, arr) => {
198
- for (let i in arr)
198
+ for (const i in arr)
199
199
  arr[i] = pipe(arr[i], +i, arr);
200
200
  return arr;
201
201
  });
@@ -247,13 +247,15 @@ const qreverse = (arr) => arr.reverse();
247
247
  const qomit = curry2((props, o) => qfilter((_, k) => !includes(k, props), o));
248
248
  /** @param start string | any[] @param s string | any[] */
249
249
  const qstartsWith = qstartsWithWith(eq);
250
+ /** @param prop string @param pipe (data[prop]): prop_value @param data any
251
+ * @returns data with prop over pipe. */
252
+ const qoverProp = curry3((prop, pipe, data) => qassoc(prop, pipe(data[prop]), data));
250
253
 
251
254
  // TODO: possibly introduce a second argument limiting unfolding.
252
255
  const uncurry = (fn) => (...args) => qreduce(((fn, arg) => fn ? fn(arg) : fn), fn, args);
253
256
 
254
- // over, lensProp
257
+ // TODO: over, lensProp. propsEq is up to 20x slow due to deep equals.
255
258
  const take = (argN) => (...args) => args[argN];
256
- const weakEq = curry2((a, b) => a == b);
257
259
  const ifElse = curry((cond, pipeYes, pipeNo, s) => cond(s) ? pipeYes(s) : pipeNo(s));
258
260
  const when = curry3((cond, pipe, s) => ifElse(cond, pipe, identity, s));
259
261
  const compose = ((...fns) => (...args) => {
@@ -273,10 +275,14 @@ const bind = curry2((fn, context) => fn.bind(context));
273
275
  const nth = curry2((i, data) => data[i]);
274
276
  const slice = curry3((from, to, o) => o.slice(from, (isNum(to) ? to : inf)));
275
277
  const flip = (fn) => curry2((b, a) => fn(a, b));
276
- /** @returns first element of an array. */
278
+ /** @returns first element of an array or a string. */
277
279
  const head = nth(0);
278
- /** @returns last element of an array. */
280
+ /** @returns last element of an array or a string. */
279
281
  const tail = slice(1, inf);
282
+ /** Returns last element of an array, readonly array or a string.
283
+ * @param s Array to extract that element.
284
+ * @returns undefined if s is empty or last element. */
285
+ const last = (s) => s[length(s) - 1];
280
286
  /** @param a @param b @returns a+b */
281
287
  const add = curry2((a, b) => a + b);
282
288
  /** @param a @param b @returns b-a */
@@ -295,11 +301,10 @@ const sort = curry2((sortFn, xs) => xs.sort(sortFn));
295
301
  const find = curry2((fn, s) => s.find(fn));
296
302
  const findIndex = curry2((fn, s) => s.findIndex(fn));
297
303
  const indexOf = curry2((x, xs) => findIndex(equals(x), xs));
298
- const divide = curry2((n, m) => n / m);
304
+ const divide = curry2((a, b) => b / a);
299
305
  const always = (s) => () => s;
300
306
  const identity = (s) => s;
301
307
  const trim = (s) => s.trim();
302
- const last = (s) => s[length(s) - 1];
303
308
  /** @param start string | any[] @param s string | any[] */
304
309
  const startsWith = qstartsWithWith((x, y) => equals(x, y));
305
310
  const not = (x) => !x;
@@ -339,18 +344,19 @@ const sizeof = (s) => {
339
344
  return length(s);
340
345
  };
341
346
  const range = curry2((from, to) => genBy(add(from), to - from));
347
+ /** @param cond (x, y): bool @param xs any[] @returns xs without duplicates, using cond as a comparator. */
348
+ const uniqWith = curry2((cond, xs) => qreduce((accum, x) => find((y) => cond(x, y), accum) ? accum : qappend(x, accum), [], xs));
342
349
  /** @param xs any[] @returns xs without duplicates. */
343
- const uniq = (xs) => qreduce((accum, x) => find(equals(x), accum) ? accum : qappend(x, accum), [], xs);
350
+ const uniq = uniqWith(equals);
344
351
  const intersection = curry2((xs1, xs2) => xs1.filter(flip(includes)(xs2)));
345
352
  const diff = curry2((_xs1, _xs2) => {
346
- // BUG: if _xs1 is empty, results in [undefined, ...]
347
353
  let len1 = length(_xs1);
348
- let len2 = length(_xs2); // xs2 should be shorter 4 Set mem consumption.
349
- const xs1 = len1 > len2 ? _xs1 : _xs2; // ['qwe', 'qwe2'].
350
- const xs2 = len1 > len2 ? _xs2 : _xs1; // [].
351
- if (len1 <= len2)
354
+ let len2 = length(_xs2);
355
+ const xs1 = len1 > len2 ? _xs1 : _xs2;
356
+ const xs2 = len1 > len2 ? _xs2 : _xs1;
357
+ if (len1 < len2)
352
358
  [len1, len2] = [len2, len1];
353
- const xset2 = new Set(xs2); // empty set.
359
+ const xset2 = new Set(xs2);
354
360
  const common = new Set();
355
361
  const out = [];
356
362
  let i;
@@ -378,7 +384,10 @@ const once = (fn) => {
378
384
  return cache = fn(...args);
379
385
  };
380
386
  };
381
- const reverse = (xs) => compose((ln) => reduce((nxs, _, i) => qappend(xs[ln - i], nxs), [], xs), add(-1), length)(xs);
387
+ const reverse = (xs) => {
388
+ const ln = length(xs) - 1;
389
+ return map((_, i) => xs[ln - i], xs);
390
+ };
382
391
  const explore = (caption, level = 'log') => tap((v) => console[level](caption, v));
383
392
  const cond = curry2((pairs, s) => {
384
393
  for (const [cond, fn] of pairs)
@@ -444,7 +453,6 @@ const freezeShallow = (o) => qfreezeShallow(clone(o));
444
453
  * @param array T2[]
445
454
  */
446
455
  const reduce = curry3((reducer, accum, arr) => qreduce(reducer, clone(accum), arr));
447
- const pickBy = curry2((cond, o) => filter(cond, o));
448
456
  const pick = curry2((props, o) => {
449
457
  const out = {};
450
458
  for (const p of props)
@@ -452,6 +460,7 @@ const pick = curry2((props, o) => {
452
460
  out[p] = o[p];
453
461
  return out;
454
462
  });
463
+ const pickBy = curry2((cond, o) => compose(flip(pick)(o), qfilter(cond), keys)(o));
455
464
  const omit = curry2((props, o) => filter((_, k) => !includes(k, props), o));
456
465
  const fromPairs = (pairs) => Object.fromEntries(pairs);
457
466
  const concat = curry2(((a, b) => b.concat(a)));
@@ -502,9 +511,10 @@ const memoize = curry2((keyGen, fn) => {
502
511
  };
503
512
  });
504
513
  const mergeShallow = curry2((o1, o2) => Object.assign({}, o1, o2));
505
- const mergeDeep = curry2((a, b) => qmergeDeep(clone(a), clone(b)));
506
- const mergeDeepX = curry2((a, b) => qmergeDeepX(clone(a), clone(b)));
507
- const mergeDeepAdd = curry2((a, b) => qmergeDeepAdd(clone(a), clone(b)));
514
+ const mergeDeep = curry2((a, b) => qmergeDeep(clone(a), b));
515
+ const mergeDeepX = curry2((a, b) => qmergeDeepX(clone(a), b));
516
+ const mergeDeepAdd = curry2((a, b) => qmergeDeepAdd(clone(a), b));
517
+ /** @param prop string @param pipe(data[prop]) @param data any @returns data with prop over pipe. */
508
518
  const overProp = curry3((prop, pipe, data) => assoc(prop, pipe(data[prop]), data));
509
519
  /** mapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
510
520
  const mapKeys = curry2((keyMap, o) => qmapKeys(keyMap, Object.assign({}, o)));
@@ -525,16 +535,17 @@ const echo = identity;
525
535
  const notf = complement;
526
536
  const push = append;
527
537
  const some = any;
538
+ const weakEq = eq;
528
539
 
529
540
  const ecran = '\\';
530
541
  // TODO: make it splicy, not accumulatie by symbols.
531
542
  /** Supports ecrans: '\\{"json": {yes} \\}'
532
- @returns get_tmpl(one{meme}two)({meme: 42}) -> one42two */
543
+ @returns getTmpl('one{meme}two')({meme: 42}) -> one42two */
533
544
  const getTmpl = (tmpl) => {
534
545
  const parts = [];
535
546
  const keymap = [];
536
547
  const len = tmpl.length;
537
- let i = 0, s, ln, start = 0, open = false, hasEcran = head(tmpl), hasEcranNext = false, nextChar;
548
+ let i = 0, s, ln, start = 0, open = false, hasEcran = false, hasEcranNext = false, nextChar;
538
549
  for (i = 0; i < len; i++) {
539
550
  s = tmpl[i];
540
551
  switch (s) {
@@ -713,6 +724,7 @@ exports.qmergeDeepAdd = qmergeDeepAdd;
713
724
  exports.qmergeDeepX = qmergeDeepX;
714
725
  exports.qmergeShallow = qmergeShallow;
715
726
  exports.qomit = qomit;
727
+ exports.qoverProp = qoverProp;
716
728
  exports.qprepend = qprepend;
717
729
  exports.qreduce = qreduce;
718
730
  exports.qreverse = qreverse;
@@ -743,6 +755,7 @@ exports.type = type;
743
755
  exports.typeIs = typeIs;
744
756
  exports.uncurry = uncurry;
745
757
  exports.uniq = uniq;
758
+ exports.uniqWith = uniqWith;
746
759
  exports.values = values;
747
760
  exports.waitAll = waitAll;
748
761
  exports.waitTap = waitTap;
package/dist/bundle.d.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
+ type AnyArgs = any[];
4
+ type AnyArray<T = any> = T[] | readonly T[];
5
+ type Split<S extends string> = S extends `${infer U}${infer V}` ? [
6
+ U,
7
+ ...Split<V>
8
+ ] : [
9
+ ];
10
+ type IndexesOfArray<A> = Exclude<keyof A, keyof [
11
+ ]>;
12
+ type StrLen<S extends string, Acc extends 0[] = [
13
+ ]> = S extends `${string}${infer Rest}` ? StrLen<Rest, [
14
+ ...Acc,
15
+ 0
16
+ ]> : Acc["length"];
3
17
  export type Cond = (x1?: any, x2?: any, x3?: any) => boolean;
4
18
  export interface AnyObject {
5
19
  [k: string]: any;
6
20
  }
7
- export type AnyArgs = any[];
8
21
  export type Reducer<T = any> = (accum: T, cur: any, index: number) => T;
9
22
  export type AnyFunc<ReturnT = any, Args extends AnyArgs = AnyArgs> = (...args: Args) => ReturnT;
10
- export type TupleFn<ARG1 = any, ARG2 = any, Out = any> = (a: ARG1, b: ARG2) => Out;
11
23
  export type Curried<Args extends AnyArgs = AnyArgs, ReturnT = any> = (arg: Args[number]) => Curried<Args> | ReturnT;
12
- export type BasicType = "String" | "Object" | "Number" | "Symbol" | "Array" | "Null" | "Undefined";
13
24
  type Placeholder = symbol;
14
25
  export declare const __: Placeholder;
15
26
  export declare const curry: (fn: AnyFunc) => (...args: AnyArgs) => any;
@@ -33,7 +44,7 @@ export declare const typeIs: {
33
44
  (a: string): (b: any) => boolean;
34
45
  (a: string, b: any): boolean;
35
46
  };
36
- declare const length$1: (s: any[] | string) => number;
47
+ declare const length$1: <T extends string | AnyArray>(s: T) => T extends string ? StrLen<T> : T["length"];
37
48
  export declare const isNil: (s: any) => boolean;
38
49
  export declare const eq: {
39
50
  (a: symbol, b: any): (a: any) => boolean;
@@ -61,12 +72,6 @@ export declare const qstartsWithWith: (comparator: (x: any, y: any) => boolean)
61
72
  (a: string | any[], b: string | any[]): boolean;
62
73
  };
63
74
  export declare const take: (argN: number) => (...args: any[]) => any;
64
- export declare const weakEq: {
65
- (a: symbol, b: any): (a: any) => boolean;
66
- (a: any, b: symbol): (b: any) => boolean;
67
- (a: any): (b: any) => boolean;
68
- (a: any, b: any): boolean;
69
- };
70
75
  export declare const ifElse: (...args: AnyArgs) => any;
71
76
  export declare const when: (...args: AnyArgs) => any;
72
77
  type Composed<TIn extends any[], TOut> = (...xs: TIn) => TOut;
@@ -78,10 +83,10 @@ export declare const bind: {
78
83
  (a: any, b: any): any;
79
84
  };
80
85
  export declare const nth: {
81
- (a: symbol, b: string | unknown[]): (a: number) => unknown;
82
- (a: number, b: symbol): (b: string | unknown[]) => unknown;
83
- (a: number): (b: string | unknown[]) => unknown;
84
- (a: number, b: string | unknown[]): unknown;
86
+ (a: symbol, b: string | any[]): (a: number) => any;
87
+ (a: number, b: symbol): (b: string | any[]) => any;
88
+ (a: number): (b: string | any[]) => any;
89
+ (a: number, b: string | any[]): any;
85
90
  };
86
91
  export declare const slice: (...args: AnyArgs) => any;
87
92
  export declare const flip: <T extends AnyFunc>(fn: T) => {
@@ -90,10 +95,42 @@ export declare const flip: <T extends AnyFunc>(fn: T) => {
90
95
  (a: Parameters<T>[1]): (b: Parameters<T>[0]) => any;
91
96
  (a: Parameters<T>[1], b: Parameters<T>[0]): any;
92
97
  };
93
- /** @returns first element of an array. */
94
- export declare const head: <T = any>(xs: T[] | string) => T;
95
- /** @returns last element of an array. */
96
- export declare const tail: any;
98
+ type FirstChar<T extends string> = T extends `${infer First}${string}` ? Split<T>["length"] extends 1 ? T : FirstChar<First> : T;
99
+ type HeadOverload = {
100
+ <T extends string>(s: T): FirstChar<T>;
101
+ <T extends readonly any[]>(s: T): T extends Array<0> ? undefined : T extends readonly [
102
+ infer U,
103
+ ...any[]
104
+ ] ? U : T extends (infer Y)[] ? Y : any;
105
+ <T extends any>(s: T[]): null;
106
+ };
107
+ /** @returns first element of an array or a string. */
108
+ export declare const head: HeadOverload;
109
+ type Tail<T extends string> = T extends `${string}${infer Tail}` ? Tail : T extends "" ? "" : string;
110
+ type TailOverload = {
111
+ <T extends string>(s: T): Tail<T>;
112
+ <T extends readonly any[]>(s: T): T extends Array<0> ? [
113
+ ] : T extends readonly [
114
+ any,
115
+ ...infer U
116
+ ] ? U : T;
117
+ <T extends any>(s: T[]): null;
118
+ };
119
+ /** @returns last element of an array or a string. */
120
+ export declare const tail: TailOverload;
121
+ type LastChar<T extends string> = T extends `${string}${infer Rest}` ? (Split<T>["length"] extends 1 ? T : LastChar<Rest>) : T;
122
+ type LastOverload = {
123
+ <T extends string>(s: T): LastChar<T>;
124
+ <T extends readonly any[]>(s: T): T extends Array<0> ? undefined : T extends readonly [
125
+ ...any[],
126
+ infer U
127
+ ] ? U : T extends (infer Y)[] ? Y : any;
128
+ <T extends any>(s: T[]): null;
129
+ };
130
+ /** Returns last element of an array, readonly array or a string.
131
+ * @param s Array to extract that element.
132
+ * @returns undefined if s is empty or last element. */
133
+ export declare const last: LastOverload;
97
134
  /** @param a @param b @returns a+b */
98
135
  export declare const add: {
99
136
  (a: symbol, b: number): (a: number) => number;
@@ -144,10 +181,10 @@ export declare const lte: {
144
181
  (a: number, b: number): boolean;
145
182
  };
146
183
  export declare const sort: {
147
- (a: symbol, b: any[]): (a: any) => any[];
148
- (a: any, b: symbol): (b: any[]) => any[];
149
- (a: any): (b: any[]) => any[];
150
- (a: any, b: any[]): any[];
184
+ (a: symbol, b: any[]): (a: (a: any, b: any) => number) => any[];
185
+ (a: (a: any, b: any) => number, b: symbol): (b: any[]) => any[];
186
+ (a: (a: any, b: any) => number): (b: any[]) => any[];
187
+ (a: (a: any, b: any) => number, b: any[]): any[];
151
188
  };
152
189
  export declare const find: {
153
190
  (a: symbol, b: any[]): (a: Cond) => any;
@@ -173,10 +210,9 @@ export declare const divide: {
173
210
  (a: number): (b: number) => number;
174
211
  (a: number, b: number): number;
175
212
  };
176
- export declare const always: <T = any>(s: T) => () => T;
177
- export declare const identity: (s: any) => any;
213
+ export declare const always: <T extends unknown>(s: T) => () => T;
214
+ export declare const identity: <T extends unknown>(s: T) => T;
178
215
  export declare const trim: (s: string) => string;
179
- export declare const last: (s: any[] | string) => any;
180
216
  /** @param start string | any[] @param s string | any[] */
181
217
  export declare const startsWith: {
182
218
  (a: symbol, b: string | any[]): (a: string | any[]) => boolean;
@@ -190,11 +226,9 @@ type NotOverload = {
190
226
  (x: any): boolean;
191
227
  };
192
228
  export declare const not: NotOverload;
193
- type IndexesOfArray<A> = Exclude<keyof A, keyof [
194
- ]>;
195
229
  type KeysOverload = {
196
- <T extends any[]>(o: T): string[];
197
230
  <T extends readonly any[]>(o: T): IndexesOfArray<T>[];
231
+ <T extends any[]>(o: T): string[];
198
232
  <T extends AnyObject>(o: T): (keyof T)[];
199
233
  };
200
234
  export declare const keys: KeysOverload;
@@ -263,8 +297,15 @@ export declare const range: {
263
297
  (a: number): (b: number) => any[];
264
298
  (a: number, b: number): any[];
265
299
  };
300
+ /** @param cond (x, y): bool @param xs any[] @returns xs without duplicates, using cond as a comparator. */
301
+ export declare const uniqWith: {
302
+ (a: symbol, b: any[]): (a: (x: any, y: any) => boolean) => any;
303
+ (a: (x: any, y: any) => boolean, b: symbol): (b: any[]) => any;
304
+ (a: (x: any, y: any) => boolean): (b: any[]) => any;
305
+ (a: (x: any, y: any) => boolean, b: any[]): any;
306
+ };
266
307
  /** @param xs any[] @returns xs without duplicates. */
267
- export declare const uniq: (xs: any[]) => any;
308
+ export declare const uniq: (b: any[]) => any;
268
309
  export declare const intersection: {
269
310
  (a: symbol, b: any[]): (a: any[]) => any[];
270
311
  (a: any[], b: symbol): (b: any[]) => any[];
@@ -284,7 +325,7 @@ export declare const genBy: {
284
325
  (a: (i: number) => any, b: number): any[];
285
326
  };
286
327
  export declare const once: <Func extends AnyFunc>(fn: Func) => (...args: Parameters<Func>) => any;
287
- export declare const reverse: (xs: any[]) => any;
328
+ export declare const reverse: <T extends unknown>(xs: T[]) => T[];
288
329
  export declare const explore: (caption: string, level?: string) => (b: any) => any;
289
330
  export declare const cond: {
290
331
  (a: symbol, b: any): (a: [
@@ -361,18 +402,18 @@ export declare const freezeShallow: <T extends AnyObject>(o: T) => Readonly<T>;
361
402
  * @param array T2[]
362
403
  */
363
404
  export declare const reduce: (...args: AnyArgs) => any;
364
- export declare const pickBy: {
365
- (a: symbol, b: AnyObject): (a: Cond) => any;
366
- (a: Cond, b: symbol): (b: AnyObject) => any;
367
- (a: Cond): (b: AnyObject) => any;
368
- (a: Cond, b: AnyObject): any;
369
- };
370
405
  export declare const pick: {
371
406
  (a: symbol, b: AnyObject): (a: string[]) => {};
372
407
  (a: string[], b: symbol): (b: AnyObject) => {};
373
408
  (a: string[]): (b: AnyObject) => {};
374
409
  (a: string[], b: AnyObject): {};
375
410
  };
411
+ export declare const pickBy: {
412
+ (a: symbol, b: AnyObject): (a: Cond) => any;
413
+ (a: Cond, b: symbol): (b: AnyObject) => any;
414
+ (a: Cond): (b: AnyObject) => any;
415
+ (a: Cond, b: AnyObject): any;
416
+ };
376
417
  export declare const omit: {
377
418
  (a: symbol, b: AnyObject): (a: string[]) => any;
378
419
  (a: string[], b: symbol): (b: AnyObject) => any;
@@ -459,6 +500,7 @@ export declare const mergeDeepAdd: {
459
500
  (a: AnyObject): (b: AnyObject) => AnyObject;
460
501
  (a: AnyObject, b: AnyObject): AnyObject;
461
502
  };
503
+ /** @param prop string @param pipe(data[prop]) @param data any @returns data with prop over pipe. */
462
504
  export declare const overProp: (...args: AnyArgs) => any;
463
505
  /** mapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
464
506
  export declare const mapKeys: {
@@ -494,9 +536,9 @@ export declare const zipObj: {
494
536
  * @param b T2[]
495
537
  */
496
538
  export declare const zipWith: (...args: AnyArgs) => any;
497
- export declare const mirror: (s: any) => any;
498
- export declare const reflect: (s: any) => any;
499
- export declare const echo: (s: any) => any;
539
+ export declare const mirror: <T extends unknown>(s: T) => T;
540
+ export declare const reflect: <T extends unknown>(s: T) => T;
541
+ export declare const echo: <T extends unknown>(s: T) => T;
500
542
  export declare const notf: (fn: AnyFunc) => (...args: any) => boolean | any;
501
543
  export declare const push: {
502
544
  (a: symbol, b: any[]): (a: any) => any[];
@@ -510,9 +552,12 @@ export declare const some: {
510
552
  (a: Cond): (b: any[]) => boolean;
511
553
  (a: Cond, b: any[]): boolean;
512
554
  };
513
- /** Then next fns seem to be excess due to their safe ver performance should be the same or better:
514
- * qflat, qpick
515
- */
555
+ export declare const weakEq: {
556
+ (a: symbol, b: any): (a: any) => boolean;
557
+ (a: any, b: symbol): (b: any) => boolean;
558
+ (a: any): (b: any) => boolean;
559
+ (a: any, b: any): boolean;
560
+ };
516
561
  export declare const qappend: {
517
562
  (a: symbol, b: any[]): (a: any) => any[];
518
563
  (a: any, b: symbol): (b: any[]) => any[];
@@ -521,9 +566,24 @@ export declare const qappend: {
521
566
  };
522
567
  export declare const qassoc: (...args: AnyArgs) => any;
523
568
  export declare const qreduce: (...args: AnyArgs) => any;
524
- export declare const qmergeDeep: any;
525
- export declare const qmergeDeepX: any;
526
- export declare const qmergeDeepAdd: any;
569
+ export declare const qmergeDeep: {
570
+ (a: symbol, b: AnyObject): (a: AnyObject) => AnyObject;
571
+ (a: AnyObject, b: symbol): (b: AnyObject) => AnyObject;
572
+ (a: AnyObject): (b: AnyObject) => AnyObject;
573
+ (a: AnyObject, b: AnyObject): AnyObject;
574
+ };
575
+ export declare const qmergeDeepX: {
576
+ (a: symbol, b: AnyObject): (a: AnyObject) => AnyObject;
577
+ (a: AnyObject, b: symbol): (b: AnyObject) => AnyObject;
578
+ (a: AnyObject): (b: AnyObject) => AnyObject;
579
+ (a: AnyObject, b: AnyObject): AnyObject;
580
+ };
581
+ export declare const qmergeDeepAdd: {
582
+ (a: symbol, b: AnyObject): (a: AnyObject) => AnyObject;
583
+ (a: AnyObject, b: symbol): (b: AnyObject) => AnyObject;
584
+ (a: AnyObject): (b: AnyObject) => AnyObject;
585
+ (a: AnyObject, b: AnyObject): AnyObject;
586
+ };
527
587
  export declare const qmergeShallow: {
528
588
  (a: symbol, b: AnyObject): (a: AnyObject) => AnyObject;
529
589
  (a: AnyObject, b: symbol): (b: AnyObject) => AnyObject;
@@ -563,7 +623,8 @@ export declare const qfilter: {
563
623
  (a: (v: any, k: string | number) => boolean): (b: any[] | AnyObject) => any[] | AnyObject;
564
624
  (a: (v: any, k: string | number) => boolean, b: any[] | AnyObject): any[] | AnyObject;
565
625
  };
566
- export declare const qempty: (o: AnyObject | any[]) => any[] | AnyObject;
626
+ export declare const qempty: <T extends any[] | AnyObject>(o: T) => T extends any[] ? [
627
+ ] : {};
567
628
  export declare const qfreeze: <T extends AnyObject>(o: T) => Readonly<T>;
568
629
  export declare const qfreezeShallow: <T extends AnyObject>(o: T) => Readonly<T>;
569
630
  export declare const qprepend: {
@@ -587,9 +648,12 @@ export declare const qstartsWith: {
587
648
  (a: string | any[]): (b: string | any[]) => boolean;
588
649
  (a: string | any[], b: string | any[]): boolean;
589
650
  };
651
+ /** @param prop string @param pipe (data[prop]): prop_value @param data any
652
+ * @returns data with prop over pipe. */
653
+ export declare const qoverProp: (...args: AnyArgs) => any;
590
654
  type StrTmpl = ((data: AnyObject) => string);
591
655
  /** Supports ecrans: '\\{"json": {yes} \\}'
592
- @returns get_tmpl(one{meme}two)({meme: 42}) -> one42two */
656
+ @returns getTmpl('one{meme}two')({meme: 42}) -> one42two */
593
657
  export declare const getTmpl: (tmpl: string) => StrTmpl;
594
658
  /** One promise waits for another. */
595
659
  export declare const forEachSerial: {
package/dist/bundle.mjs CHANGED
@@ -134,15 +134,14 @@ const qstartsWithWith = (comparator) => curry2((start, s) => {
134
134
  return true;
135
135
  });
136
136
 
137
- // TODO: qoverProp, qover array ?
138
- /** Then next fns seem to be excess due to their safe ver performance should be the same or better:
139
- * qflat, qpick
140
- */
137
+ /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
138
+ * qflat, qpick
139
+ */
141
140
  const qappend = curry2((s, xs) => { xs.push(s); return xs; });
142
141
  const qassoc = curry3((prop, v, obj) => { obj[prop] = v; return obj; });
143
142
  const qreduce = curry3((fn, accum, arr) => arr.reduce(fn, accum));
144
143
  // strategy is for arrays: 1->clean, 2->merge, 3->push.
145
- const mergeDeep$1 = curry3((strategy, o1, o2) => {
144
+ const mergeDeep$1 = (strategy) => curry2((o1, o2) => {
146
145
  for (let k in o2) {
147
146
  switch (type(o2[k])) {
148
147
  case 'Array':
@@ -152,7 +151,7 @@ const mergeDeep$1 = curry3((strategy, o1, o2) => {
152
151
  const o1k = o1[k], o2k = o2[k];
153
152
  for (const i in o2k)
154
153
  if (o1k[i])
155
- mergeDeep$1(strategy, o1k[i], o2k[i]);
154
+ mergeDeep$1(strategy)(o1k[i], o2k[i]);
156
155
  else
157
156
  o1k[i] = o2k[i];
158
157
  break;
@@ -163,7 +162,7 @@ const mergeDeep$1 = curry3((strategy, o1, o2) => {
163
162
  break;
164
163
  case 'Object':
165
164
  if (type(o1[k]) === 'Object') {
166
- mergeDeep$1(strategy, o1[k], o2[k]);
165
+ mergeDeep$1(strategy)(o1[k], o2[k]);
167
166
  break;
168
167
  }
169
168
  default:
@@ -192,8 +191,9 @@ const qmapKeys = curry2((keyMap, o) => {
192
191
  }
193
192
  return o;
194
193
  });
194
+ // FIXME: qmap(any, tags) -> some function!!!
195
195
  const qmap = curry2((pipe, arr) => {
196
- for (let i in arr)
196
+ for (const i in arr)
197
197
  arr[i] = pipe(arr[i], +i, arr);
198
198
  return arr;
199
199
  });
@@ -245,13 +245,15 @@ const qreverse = (arr) => arr.reverse();
245
245
  const qomit = curry2((props, o) => qfilter((_, k) => !includes(k, props), o));
246
246
  /** @param start string | any[] @param s string | any[] */
247
247
  const qstartsWith = qstartsWithWith(eq);
248
+ /** @param prop string @param pipe (data[prop]): prop_value @param data any
249
+ * @returns data with prop over pipe. */
250
+ const qoverProp = curry3((prop, pipe, data) => qassoc(prop, pipe(data[prop]), data));
248
251
 
249
252
  // TODO: possibly introduce a second argument limiting unfolding.
250
253
  const uncurry = (fn) => (...args) => qreduce(((fn, arg) => fn ? fn(arg) : fn), fn, args);
251
254
 
252
- // over, lensProp
255
+ // TODO: over, lensProp. propsEq is up to 20x slow due to deep equals.
253
256
  const take = (argN) => (...args) => args[argN];
254
- const weakEq = curry2((a, b) => a == b);
255
257
  const ifElse = curry((cond, pipeYes, pipeNo, s) => cond(s) ? pipeYes(s) : pipeNo(s));
256
258
  const when = curry3((cond, pipe, s) => ifElse(cond, pipe, identity, s));
257
259
  const compose = ((...fns) => (...args) => {
@@ -271,10 +273,14 @@ const bind = curry2((fn, context) => fn.bind(context));
271
273
  const nth = curry2((i, data) => data[i]);
272
274
  const slice = curry3((from, to, o) => o.slice(from, (isNum(to) ? to : inf)));
273
275
  const flip = (fn) => curry2((b, a) => fn(a, b));
274
- /** @returns first element of an array. */
276
+ /** @returns first element of an array or a string. */
275
277
  const head = nth(0);
276
- /** @returns last element of an array. */
278
+ /** @returns last element of an array or a string. */
277
279
  const tail = slice(1, inf);
280
+ /** Returns last element of an array, readonly array or a string.
281
+ * @param s Array to extract that element.
282
+ * @returns undefined if s is empty or last element. */
283
+ const last = (s) => s[length(s) - 1];
278
284
  /** @param a @param b @returns a+b */
279
285
  const add = curry2((a, b) => a + b);
280
286
  /** @param a @param b @returns b-a */
@@ -293,11 +299,10 @@ const sort = curry2((sortFn, xs) => xs.sort(sortFn));
293
299
  const find = curry2((fn, s) => s.find(fn));
294
300
  const findIndex = curry2((fn, s) => s.findIndex(fn));
295
301
  const indexOf = curry2((x, xs) => findIndex(equals(x), xs));
296
- const divide = curry2((n, m) => n / m);
302
+ const divide = curry2((a, b) => b / a);
297
303
  const always = (s) => () => s;
298
304
  const identity = (s) => s;
299
305
  const trim = (s) => s.trim();
300
- const last = (s) => s[length(s) - 1];
301
306
  /** @param start string | any[] @param s string | any[] */
302
307
  const startsWith = qstartsWithWith((x, y) => equals(x, y));
303
308
  const not = (x) => !x;
@@ -337,18 +342,19 @@ const sizeof = (s) => {
337
342
  return length(s);
338
343
  };
339
344
  const range = curry2((from, to) => genBy(add(from), to - from));
345
+ /** @param cond (x, y): bool @param xs any[] @returns xs without duplicates, using cond as a comparator. */
346
+ const uniqWith = curry2((cond, xs) => qreduce((accum, x) => find((y) => cond(x, y), accum) ? accum : qappend(x, accum), [], xs));
340
347
  /** @param xs any[] @returns xs without duplicates. */
341
- const uniq = (xs) => qreduce((accum, x) => find(equals(x), accum) ? accum : qappend(x, accum), [], xs);
348
+ const uniq = uniqWith(equals);
342
349
  const intersection = curry2((xs1, xs2) => xs1.filter(flip(includes)(xs2)));
343
350
  const diff = curry2((_xs1, _xs2) => {
344
- // BUG: if _xs1 is empty, results in [undefined, ...]
345
351
  let len1 = length(_xs1);
346
- let len2 = length(_xs2); // xs2 should be shorter 4 Set mem consumption.
347
- const xs1 = len1 > len2 ? _xs1 : _xs2; // ['qwe', 'qwe2'].
348
- const xs2 = len1 > len2 ? _xs2 : _xs1; // [].
349
- if (len1 <= len2)
352
+ let len2 = length(_xs2);
353
+ const xs1 = len1 > len2 ? _xs1 : _xs2;
354
+ const xs2 = len1 > len2 ? _xs2 : _xs1;
355
+ if (len1 < len2)
350
356
  [len1, len2] = [len2, len1];
351
- const xset2 = new Set(xs2); // empty set.
357
+ const xset2 = new Set(xs2);
352
358
  const common = new Set();
353
359
  const out = [];
354
360
  let i;
@@ -376,7 +382,10 @@ const once = (fn) => {
376
382
  return cache = fn(...args);
377
383
  };
378
384
  };
379
- const reverse = (xs) => compose((ln) => reduce((nxs, _, i) => qappend(xs[ln - i], nxs), [], xs), add(-1), length)(xs);
385
+ const reverse = (xs) => {
386
+ const ln = length(xs) - 1;
387
+ return map((_, i) => xs[ln - i], xs);
388
+ };
380
389
  const explore = (caption, level = 'log') => tap((v) => console[level](caption, v));
381
390
  const cond = curry2((pairs, s) => {
382
391
  for (const [cond, fn] of pairs)
@@ -442,7 +451,6 @@ const freezeShallow = (o) => qfreezeShallow(clone(o));
442
451
  * @param array T2[]
443
452
  */
444
453
  const reduce = curry3((reducer, accum, arr) => qreduce(reducer, clone(accum), arr));
445
- const pickBy = curry2((cond, o) => filter(cond, o));
446
454
  const pick = curry2((props, o) => {
447
455
  const out = {};
448
456
  for (const p of props)
@@ -450,6 +458,7 @@ const pick = curry2((props, o) => {
450
458
  out[p] = o[p];
451
459
  return out;
452
460
  });
461
+ const pickBy = curry2((cond, o) => compose(flip(pick)(o), qfilter(cond), keys)(o));
453
462
  const omit = curry2((props, o) => filter((_, k) => !includes(k, props), o));
454
463
  const fromPairs = (pairs) => Object.fromEntries(pairs);
455
464
  const concat = curry2(((a, b) => b.concat(a)));
@@ -500,9 +509,10 @@ const memoize = curry2((keyGen, fn) => {
500
509
  };
501
510
  });
502
511
  const mergeShallow = curry2((o1, o2) => Object.assign({}, o1, o2));
503
- const mergeDeep = curry2((a, b) => qmergeDeep(clone(a), clone(b)));
504
- const mergeDeepX = curry2((a, b) => qmergeDeepX(clone(a), clone(b)));
505
- const mergeDeepAdd = curry2((a, b) => qmergeDeepAdd(clone(a), clone(b)));
512
+ const mergeDeep = curry2((a, b) => qmergeDeep(clone(a), b));
513
+ const mergeDeepX = curry2((a, b) => qmergeDeepX(clone(a), b));
514
+ const mergeDeepAdd = curry2((a, b) => qmergeDeepAdd(clone(a), b));
515
+ /** @param prop string @param pipe(data[prop]) @param data any @returns data with prop over pipe. */
506
516
  const overProp = curry3((prop, pipe, data) => assoc(prop, pipe(data[prop]), data));
507
517
  /** mapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
508
518
  const mapKeys = curry2((keyMap, o) => qmapKeys(keyMap, Object.assign({}, o)));
@@ -523,16 +533,17 @@ const echo = identity;
523
533
  const notf = complement;
524
534
  const push = append;
525
535
  const some = any;
536
+ const weakEq = eq;
526
537
 
527
538
  const ecran = '\\';
528
539
  // TODO: make it splicy, not accumulatie by symbols.
529
540
  /** Supports ecrans: '\\{"json": {yes} \\}'
530
- @returns get_tmpl(one{meme}two)({meme: 42}) -> one42two */
541
+ @returns getTmpl('one{meme}two')({meme: 42}) -> one42two */
531
542
  const getTmpl = (tmpl) => {
532
543
  const parts = [];
533
544
  const keymap = [];
534
545
  const len = tmpl.length;
535
- let i = 0, s, ln, start = 0, open = false, hasEcran = head(tmpl), hasEcranNext = false, nextChar;
546
+ let i = 0, s, ln, start = 0, open = false, hasEcran = false, hasEcranNext = false, nextChar;
536
547
  for (i = 0; i < len; i++) {
537
548
  s = tmpl[i];
538
549
  switch (s) {
@@ -603,4 +614,4 @@ const composeAsync = (() => {
603
614
  return (...fns) => (...input) => pipe(fns, input, fns.length - 1);
604
615
  })();
605
616
 
606
- 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, 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, qprepend, qreduce, qreverse, qstartsWith, qstartsWithWith, range, reduce, reflect, replace, reverse, sizeof, slice, some, sort, split, startsWith, subtract, symbol, tail, take, tap, test, toLower, toPairs, toUpper, trim, type, typeIs, uncurry, uniq, values, waitAll, waitTap, weakEq, when, zip, zipObj, zipWith };
617
+ 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, 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, qreduce, qreverse, qstartsWith, qstartsWithWith, range, reduce, reflect, replace, reverse, sizeof, slice, some, sort, split, startsWith, subtract, symbol, tail, take, tap, test, toLower, toPairs, toUpper, trim, type, typeIs, uncurry, uniq, uniqWith, values, waitAll, waitTap, weakEq, when, zip, zipObj, zipWith };
package/package.json CHANGED
@@ -42,7 +42,7 @@
42
42
  "prod": "npm run gentypes && npm run prod:es && npm run prod:cjs",
43
43
  "all": "npm run dev && npm run prod"
44
44
  },
45
- "version": "1.5.3",
45
+ "version": "1.6.1",
46
46
  "ava": {
47
47
  "files": [
48
48
  "./test/specs/*.ts"
@@ -67,7 +67,7 @@
67
67
  "dts-bundle-generator": "^9.5.1",
68
68
  "nyc": "^15.1.0",
69
69
  "prepend": "^1.0.2",
70
- "rollup": "^4.16.1",
70
+ "rollup": "^4.17.0",
71
71
  "rollup-plugin-typescript2": "^0.36.0",
72
72
  "ts-node": "^10.9.2",
73
73
  "tslint": "^6.1.3",
package/src/common.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { curry2 } from "./curry"
2
+ import { AnyArray, StrLen } from "./internal_types"
2
3
  import { to, isNull, isStr, isUndef } from "./utils"
3
4
 
4
5
  // It's faster that toUpperCase() !
@@ -14,7 +15,8 @@ export const type = (s: any): string => {
14
15
  : caseMap[t[0]] + t.slice(1)
15
16
  }
16
17
  export const typeIs = curry2((t: string, s: any) => type(s)===t)
17
- export const length = (s: any[] | string) => s.length
18
+
19
+ export const length = <T extends AnyArray | string>(s: T): T extends string ? StrLen<T> : T["length"] => s.length as any
18
20
  export const isNil = (s: any) => isNull(s) || isUndef(s)
19
21
  export const eq = curry2((a: any, b: any) => a===b)
20
22
  export const equals = curry2((a: any, b: any) => {
package/src/curry.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { AnyFunc, AnyArgs } from "./types"
1
+ import { AnyArgs } from "./internal_types"
2
+ import { AnyFunc } from "./types"
2
3
 
3
4
  type Placeholder = symbol
4
5
  export const __: Placeholder = Symbol('Placeholder')
@@ -74,10 +75,10 @@ export function curry2<Func extends Func2>(fn: Func) {
74
75
  if(aln === 1 && withPlaceholder1)
75
76
  throw new Error('Senseless placeholder usage.')
76
77
  return aln>1
77
- ? withPlaceholder1
78
- ? endlessph((a: p0) => fn(a, b))
79
- : fn(a, b) as ReturnType<Func>
80
- : (b: p1) => fn(a, b)
78
+ ? withPlaceholder1
79
+ ? endlessph((a: p0) => fn(a, b))
80
+ : fn(a, b) as ReturnType<Func>
81
+ : (b: p1) => fn(a, b)
81
82
  }
82
83
  return curried2
83
84
  }
@@ -0,0 +1,11 @@
1
+ export type AnyArgs = any[]
2
+ export type BasicType = 'String'|'Object'|'Number'|'Symbol'|'Array'|'Null'|'Undefined'
3
+ export type TupleFn<ARG1=any, ARG2=any, Out=any> = (a: ARG1, b: ARG2) => Out
4
+ export type IDArray = Uint8Array|Uint16Array|Uint32Array
5
+ export type AnyArray<T=any> = T[] | readonly T[]
6
+ export type Split<S extends string> = S extends `${infer U}${infer V}` ? [U, ...Split<V>] : []
7
+ export type IndexesOfArray<A> = Exclude<keyof A, keyof []>
8
+ export type StrLen<S extends string, Acc extends 0[] = []> =
9
+ S extends `${string}${infer Rest}`
10
+ ? StrLen<Rest, [...Acc, 0]>
11
+ : Acc["length"]
package/src/quick.ts CHANGED
@@ -2,17 +2,15 @@ import { curry2, curry3 } from "./curry"
2
2
  import { includes, isNil, type, eq, qstartsWithWith } from "./common"
3
3
  import { AnyObject, Reducer, AnyFunc } from "./types"
4
4
  import { isFunc, isArray, isObj } from "./utils"
5
- // TODO: qoverProp, qover array ?
6
-
7
- /** Then next fns seem to be excess due to their safe ver performance should be the same or better:
8
- * qflat, qpick
9
- */
5
+ /* Then next fns seem to be excess due to their safe ver performance should be the same or better:
6
+ * qflat, qpick
7
+ */
10
8
 
11
9
  export const qappend = curry2((s: any, xs: any[]) => {xs.push(s); return xs})
12
10
  export const qassoc = curry3((prop: string, v: any, obj: AnyObject) => { obj[prop] = v; return obj })
13
11
  export const qreduce = curry3(<T>(fn: Reducer, accum: any, arr: T[]) => arr.reduce(fn, accum))
14
12
  // strategy is for arrays: 1->clean, 2->merge, 3->push.
15
- const mergeDeep = curry3((strategy: 1|2|3, o1: AnyObject, o2: AnyObject): AnyObject => {
13
+ const mergeDeep = (strategy: 1|2|3) => curry2((o1: AnyObject, o2: AnyObject): AnyObject => {
16
14
  for(let k in o2) {
17
15
  switch(type(o2[k])) {
18
16
  case 'Array':
@@ -21,7 +19,7 @@ const mergeDeep = curry3((strategy: 1|2|3, o1: AnyObject, o2: AnyObject): AnyObj
21
19
  case 2:
22
20
  const o1k = o1[k], o2k = o2[k]
23
21
  for(const i in o2k)
24
- if(o1k[i]) mergeDeep(strategy, o1k[i], o2k[i])
22
+ if(o1k[i]) mergeDeep(strategy)(o1k[i], o2k[i])
25
23
  else o1k[i] = o2k[i]
26
24
  break
27
25
  case 3: o1[k].push(...o2[k])
@@ -31,7 +29,7 @@ const mergeDeep = curry3((strategy: 1|2|3, o1: AnyObject, o2: AnyObject): AnyObj
31
29
  break
32
30
  case 'Object':
33
31
  if(type(o1[k])==='Object') {
34
- mergeDeep(strategy, o1[k], o2[k])
32
+ mergeDeep(strategy)(o1[k], o2[k])
35
33
  break
36
34
  }
37
35
  default:
@@ -63,9 +61,10 @@ export const qmapKeys = curry2(
63
61
  return o
64
62
  }
65
63
  )
64
+ // FIXME: qmap(any, tags) -> some function!!!
66
65
  export const qmap = curry2(
67
66
  (pipe: (s: any, i?: number, list?: any[]) => any, arr: any[]) => {
68
- for(let i in arr) arr[i] = pipe(arr[i], +i, arr)
67
+ for(const i in arr) arr[i] = pipe(arr[i], +i, arr)
69
68
  return arr
70
69
  }
71
70
  )
@@ -93,10 +92,10 @@ export const qfilter = curry2(
93
92
  return data
94
93
  }
95
94
  )
96
- export const qempty = (o: AnyObject|any[]) => {
95
+ export const qempty = <T extends AnyObject|any[]>(o: T): T extends any[] ? [] : {} => {
97
96
  if(isArray(o)) o.splice(0)
98
97
  else for(const i in o) delete o[i]
99
- return o
98
+ return o as any
100
99
  }
101
100
  export const qfreeze = <T extends AnyObject>(o: T): Readonly<T> => {
102
101
  let v: any
@@ -124,4 +123,9 @@ export const qomit = curry2(
124
123
  )
125
124
  )
126
125
  /** @param start string | any[] @param s string | any[] */
127
- export const qstartsWith = qstartsWithWith(eq)
126
+ export const qstartsWith = qstartsWithWith(eq)
127
+ /** @param prop string @param pipe (data[prop]): prop_value @param data any
128
+ * @returns data with prop over pipe. */
129
+ export const qoverProp = curry3(
130
+ (prop: string, pipe: AnyFunc, data: any) => qassoc(prop, pipe(data[prop]), data)
131
+ )
package/src/safe.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { __, curry, curry2, curry3 } from './curry'
2
- import { isNum, undef, isNull, isArray, isFunc, isObj, inf } from './utils'
2
+ import { isNum, undef, isArray, isFunc, isObj, inf } from './utils'
3
3
  import { qmergeDeep, qreduce, qappend, qmapKeys, qmergeDeepX, qmergeDeepAdd, qfilter, qfreeze, qfreezeShallow, qmapObj } from './quick'
4
4
  import { AnyFunc, Cond, AnyObject, Reducer } from './types'
5
- import { symbol, type, length, equals, includes, isNil, qstartsWithWith } from './common'
6
- // over, lensProp
5
+ import { symbol, type, length, equals, includes, isNil, qstartsWithWith, eq } from './common'
6
+ import { Split, AnyArray, IndexesOfArray } from './internal_types'
7
+ // TODO: over, lensProp. propsEq is up to 20x slow due to deep equals.
7
8
 
8
9
  export const take = (argN: number) => (...args: any[]) => args[argN]
9
- export const weakEq = curry2((a: any, b: any) => a==b)
10
10
  export const ifElse = curry(
11
11
  (
12
12
  cond: (s: any) => boolean,
@@ -38,10 +38,8 @@ export const compose = (
38
38
  return s as any as TOut
39
39
  }
40
40
  )
41
- export const bind = curry2<AnyFunc>(
42
- (fn: AnyFunc, context: any) => fn.bind(context)
43
- )
44
- export const nth = curry2(<T=any>(i: number, data: T[] | string) => data[i])
41
+ export const bind = curry2<AnyFunc>((fn: AnyFunc, context: any) => fn.bind(context))
42
+ export const nth = curry2((i: number, data: any[] | string) => data[i])
45
43
  export const slice = curry3(
46
44
  (from: number, to: number, o: any[] | string) =>
47
45
  o.slice(from, (isNum(to)?to:inf) as number)
@@ -49,10 +47,42 @@ export const slice = curry3(
49
47
  export const flip = <T extends AnyFunc>(fn: T) => curry2(
50
48
  (b: Parameters<T>[1], a: Parameters<T>[0]) => fn(a, b)
51
49
  )
52
- /** @returns first element of an array. */
53
- export const head = nth(0) as <T = any>(xs: T[] | string) => T
54
- /** @returns last element of an array. */
55
- export const tail = slice(1, inf)
50
+ type FirstChar<T extends string> = T extends `${infer First}${string}`
51
+ ? Split<T>['length'] extends 1 ? T : FirstChar<First>
52
+ : T
53
+ type HeadOverload = {
54
+ <T extends string>(s: T): FirstChar<T>
55
+ <T extends readonly any[]>(s: T): T extends Array<0> ? undefined
56
+ : T extends readonly [infer U, ...any[]] ? U
57
+ : T extends (infer Y)[] ? Y : any
58
+ <T extends any>(s: T[]): null
59
+ }
60
+ /** @returns first element of an array or a string. */
61
+ export const head = nth(0) as HeadOverload
62
+ type Tail<T extends string> = T extends `${string}${infer Tail}`
63
+ ? Tail : T extends '' ? '' : string
64
+ type TailOverload = {
65
+ <T extends string>(s: T): Tail<T>
66
+ <T extends readonly any[]>(s: T): T extends Array<0> ? []
67
+ : T extends readonly [any, ...infer U] ? U : T
68
+ <T extends any>(s: T[]): null
69
+ }
70
+ /** @returns last element of an array or a string. */
71
+ export const tail = slice(1, inf) as TailOverload
72
+ type LastChar<T extends string> = T extends `${string}${infer Rest}`
73
+ ? (Split<T>['length'] extends 1 ? T : LastChar<Rest>) : T
74
+ type LastOverload = {
75
+ <T extends string>(s: T): LastChar<T>
76
+ <T extends readonly any[]>(s: T): T extends Array<0>
77
+ ? undefined
78
+ : T extends readonly [...any[], infer U] ? U
79
+ : T extends (infer Y)[] ? Y : any
80
+ <T extends any>(s: T[]): null
81
+ }
82
+ /** Returns last element of an array, readonly array or a string.
83
+ * @param s Array to extract that element.
84
+ * @returns undefined if s is empty or last element. */
85
+ export const last: LastOverload = (s: string | AnyArray) => s[length(s)-1]
56
86
  /** @param a @param b @returns a+b */
57
87
  export const add = curry2((a: number, b: number) => a+b)
58
88
  /** @param a @param b @returns b-a */
@@ -67,15 +97,15 @@ export const lt = curry2( (a: number, b: number) => a>b )
67
97
  export const gte = curry2( (a: number, b: number) => a<=b )
68
98
  /** @param a @param b @returns a≥b */
69
99
  export const lte = curry2( (a: number, b: number) => a>=b )
70
- export const sort = curry2((sortFn: any, xs: any[]) => xs.sort(sortFn))
100
+ export const sort = curry2((sortFn: (a: any, b: any) => number , xs: any[]) => xs.sort(sortFn))
71
101
  export const find = curry2((fn: Cond, s: any[]) => s.find(fn))
72
102
  export const findIndex = curry2((fn: Cond, s: any[]) => s.findIndex(fn))
73
103
  export const indexOf = curry2((x: any, xs: any[]) => findIndex(equals(x), xs))
74
- export const divide = curry2((n: number, m: number) => n/m)
75
- export const always = <T=any>(s: T) => () => s
76
- export const identity = (s: any) => s
104
+ export const divide = curry2((a: number, b: number) => b/a)
105
+ export const always = <T extends any>(s: T) => () => s
106
+ export const identity = <T extends any>(s: T) => s
77
107
  export const trim = (s: string) => s.trim()
78
- export const last = (s: any[] | string) => s[length(s)-1]
108
+
79
109
  /** @param start string | any[] @param s string | any[] */
80
110
  export const startsWith = qstartsWithWith((x: any, y: any) => equals(x, y))
81
111
  type NotOverload = {
@@ -84,14 +114,12 @@ type NotOverload = {
84
114
  (x: any): boolean
85
115
  }
86
116
  export const not: NotOverload = (x: any) => !x as any
87
- type IndexesOfArray<A> = Exclude<keyof A, keyof []>
88
117
  type KeysOverload = {
89
- <T extends any[]>(o: T): string[]
90
118
  <T extends readonly any[]>(o: T): IndexesOfArray<T>[]
119
+ <T extends any[]>(o: T): string[]
91
120
  <T extends AnyObject>(o: T): (keyof T)[]
92
121
  }
93
- export const keys: KeysOverload = (o: number[]) => Object.keys(o)
94
-
122
+ export const keys: KeysOverload = (o: any) => Object.keys(o)
95
123
  export const values = (o: AnyObject | any[]) => Object.values(o)
96
124
  export const toPairs = (o: AnyObject | any[]) => Object.entries(o)
97
125
  export const test = curry2((re: RegExp, s: string) => re.test(s))
@@ -124,20 +152,21 @@ export const sizeof = (s: any[] | string | AnyObject) => {
124
152
  } else return length(s as any[])
125
153
  }
126
154
  export const range = curry2((from: number, to: number) => genBy(add(from), to-from))
127
- /** @param xs any[] @returns xs without duplicates. */
128
- export const uniq = (xs: any[]) => qreduce(
155
+ /** @param cond (x, y): bool @param xs any[] @returns xs without duplicates, using cond as a comparator. */
156
+ export const uniqWith = curry2((cond: (x: any, y: any) => boolean, xs: any[]) => qreduce(
129
157
  <T>(accum: any, x: T) =>
130
- find(equals(x), accum) ? accum : qappend(x, accum),
131
- [], xs)
158
+ find((y) => cond(x as any, y), accum) ? accum : qappend(x, accum),
159
+ [], xs))
160
+ /** @param xs any[] @returns xs without duplicates. */
161
+ export const uniq = uniqWith(equals)
132
162
  export const intersection = curry2((xs1: any[], xs2: any[]) => xs1.filter(flip(includes)(xs2)))
133
163
  export const diff = curry2((_xs1: any[], _xs2: any[]) => {
134
- // BUG: if _xs1 is empty, results in [undefined, ...]
135
164
  let len1 = length(_xs1)
136
- let len2 = length(_xs2) // xs2 should be shorter 4 Set mem consumption.
137
- const xs1 = len1>len2 ? _xs1 : _xs2 // ['qwe', 'qwe2'].
138
- const xs2 = len1>len2 ? _xs2 : _xs1 // [].
139
- if(len1<=len2) [len1, len2] = [len2, len1]
140
- const xset2 = new Set(xs2) // empty set.
165
+ let len2 = length(_xs2)
166
+ const xs1 = len1>len2 ? _xs1 : _xs2
167
+ const xs2 = len1>len2 ? _xs2 : _xs1
168
+ if(len1<len2) [len1, len2] = [len2, len1]
169
+ const xset2 = new Set(xs2)
141
170
  const common = new Set()
142
171
  const out: any[] = []
143
172
  let i: number
@@ -166,14 +195,10 @@ export const once = <Func extends AnyFunc>(fn: Func) => {
166
195
  return cache = fn(...args)
167
196
  }
168
197
  }
169
- export const reverse = (xs: any[]) => compose(
170
- <T>(ln: number) => reduce(
171
- (nxs: T[], _: any, i: number) => qappend(xs[ln-i], nxs),
172
- [], xs
173
- ),
174
- add(-1),
175
- length
176
- )(xs)
198
+ export const reverse = <T extends any>(xs: T[]): T[] => {
199
+ const ln = length(xs)-1
200
+ return map((_: any, i: number) => xs[ln-i], xs)
201
+ }
177
202
  export const explore = (caption: string, level = 'log') => tap(
178
203
  (v: any) => console[level](caption, v)
179
204
  )
@@ -266,17 +291,16 @@ export const reduce = curry3(
266
291
  <T = any>(reducer: Reducer<T>, accum: T, arr: any[]) =>
267
292
  qreduce(reducer, clone(accum), arr)
268
293
  )
269
- export const pickBy = curry2(
270
- (cond: Cond, o: AnyObject) => filter(cond, o)
271
- )
272
294
  export const pick = curry2(
273
295
  (props: string[], o: AnyObject) => {
274
296
  const out = {}
275
- for(const p of props)
276
- if(p in o) out[p] = o[p]
297
+ for(const p of props) if(p in o) out[p] = o[p]
277
298
  return out
278
299
  }
279
300
  )
301
+ export const pickBy = curry2(
302
+ (cond: Cond, o: AnyObject) => compose(flip(pick)(o), qfilter(cond), keys)(o)
303
+ )
280
304
  export const omit = curry2(
281
305
  (props: string[], o: AnyObject) => filter(
282
306
  (_: any, k: string) => !includes(k, props),
@@ -354,14 +378,15 @@ export const mergeShallow = curry2(
354
378
  Object.assign({}, o1, o2)
355
379
  )
356
380
  export const mergeDeep = curry2(
357
- (a: AnyObject, b: AnyObject) => qmergeDeep(clone(a), clone(b)) as AnyObject
381
+ (a: AnyObject, b: AnyObject) => qmergeDeep(clone(a), b) as AnyObject
358
382
  )
359
383
  export const mergeDeepX = curry2(
360
- (a: AnyObject, b: AnyObject) => qmergeDeepX(clone(a), clone(b)) as AnyObject
384
+ (a: AnyObject, b: AnyObject) => qmergeDeepX(clone(a), b) as AnyObject
361
385
  )
362
386
  export const mergeDeepAdd = curry2(
363
- (a: AnyObject, b: AnyObject) => qmergeDeepAdd(clone(a), clone(b)) as AnyObject
387
+ (a: AnyObject, b: AnyObject) => qmergeDeepAdd(clone(a), b) as AnyObject
364
388
  )
389
+ /** @param prop string @param pipe(data[prop]) @param data any @returns data with prop over pipe. */
365
390
  export const overProp = curry3(
366
391
  (prop: string, pipe: AnyFunc, data: any) =>
367
392
  assoc(prop, pipe(data[prop]), data)
@@ -401,4 +426,5 @@ export const reflect = identity
401
426
  export const echo = identity
402
427
  export const notf = complement
403
428
  export const push = append
404
- export const some = any
429
+ export const some = any
430
+ export const weakEq = eq
package/src/strings.ts CHANGED
@@ -6,13 +6,13 @@ const ecran = '\\'
6
6
 
7
7
  // TODO: make it splicy, not accumulatie by symbols.
8
8
  /** Supports ecrans: '\\{"json": {yes} \\}'
9
- @returns get_tmpl(one{meme}two)({meme: 42}) -> one42two */
9
+ @returns getTmpl('one{meme}two')({meme: 42}) -> one42two */
10
10
  export const getTmpl = (tmpl: string): StrTmpl => {
11
11
  const parts: string[] = []
12
12
  const keymap: string[] = []
13
13
  const len = tmpl.length
14
14
  let i = 0, s: string, ln: number, start = 0, open = false,
15
- hasEcran = head(tmpl), hasEcranNext = false, nextChar: string
15
+ hasEcran = false, hasEcranNext = false, nextChar: string
16
16
  for(i=0; i<len; i++) {
17
17
  s = tmpl[i]
18
18
  switch(s) {
package/src/types.ts CHANGED
@@ -1,11 +1,7 @@
1
+ import { AnyArgs } from "./internal_types"
2
+
1
3
  export type Cond = (x1?: any, x2?: any, x3?: any) => boolean
2
4
  export interface AnyObject { [k: string]: any }
3
- export type AnyArgs = any[]
4
5
  export type Reducer<T=any> = (accum: T, cur: any, index: number) => T
5
6
  export type AnyFunc<ReturnT = any, Args extends AnyArgs = AnyArgs> = (...args: Args) => ReturnT
6
- export type TupleFn<ARG1=any, ARG2=any, Out=any> = (a: ARG1, b: ARG2) => Out
7
- export type Curried<
8
- Args extends AnyArgs = AnyArgs,
9
- ReturnT = any
10
- > = (arg: Args[number]) => Curried<Args> | ReturnT
11
- export type BasicType = 'String'|'Object'|'Number'|'Symbol'|'Array'|'Null'|'Undefined'
7
+ export type Curried<Args extends AnyArgs = AnyArgs, ReturnT = any> = (arg: Args[number]) => Curried<Args> | ReturnT