pepka 0.12.3 → 0.13.0-b1

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/README.md CHANGED
@@ -1,23 +1,26 @@
1
1
  ![image](https://user-images.githubusercontent.com/7501201/122691868-ae59f800-d23a-11eb-97fa-c0fab3cb0808.png)
2
2
 
3
- HI! Meet pepka - JavaScript/TypeScript functional programming utilities library named after my paraqeet.
3
+ HI! Meet pepka - JavaScript/TypeScript functional programming utility library named after my parakeet.
4
4
 
5
5
  This lib is intended to be a functional toolkit more flexible than ramda is.
6
6
  Its' basic API is similimar to ramda's one.
7
7
  Other goals are:
8
- - Async pipes. They are not super-pure, but super handy.
9
- - Most flexible types as possible (Let'em be any better than crashing because of their failures. I'm currently working on full JSDocs and better basic types).
10
- - Tree-shakeble ans smallest possible. What could be native, is native.
11
- - Has "quick" alternatives of most computation-heavy functions with `q` prefix which are not completely safe by fp means.
8
+ - Async pipes. They are very handy, but are not 100% pure in terms of Haskell c:
9
+ - Most flexible types possible (Let'em be any better than crashing because of their failures. I'm currently working on full JSDocs and better basic types).
10
+ - Tree-shakeble and smallest possible. What could be native, is native.
11
+ - Has "quick" alternatives of most computation-heavy functions with `q` prefix which are not completely safe by fp means: most of them do mutations and it may be needed to `clone` or `cloneShallow` data in a first pipe of `compose(...)`.
12
+ - Has basic toolbelt-types like AnyObject and AnyFunc<ReturnType?, [...args]?> etc.
12
13
  - Has some basic additinal must-have stuff that ramda does not.
13
14
 
14
15
  Full docs are coming,
15
16
  please reference ramda's ones for most operations and examples: https://ramdajs.com/docs/
16
17
 
17
18
  Basic API differences:
19
+ - clone() clones deeply as possible any type possible.
20
+ - cloneShallow() clones only by 1st level of folding also any type possible.
18
21
  - mergeDeep - replaces arrays.
19
- - mergeDeepX - replaces elements with same indexes.
20
- - mergeDeepAdd - adds new element to arrays.
22
+ - mergeDeepX - replaces its' elements with same indexes.
23
+ - mergeDeepAdd - adds new elements to arrays.
21
24
  - type - returns type UpperCased of anything passed to it, including classes and typed arrays.
22
25
  - mapKeys - changes existing keys and data by map or function like usual mapper.
23
26
  - explore(label)(data) - `compose(explore('the number'))(42)` results in `'the number', 42` in console passing by the data.
@@ -1,4 +1,4 @@
1
- const __ = (function Placeholder() { });
1
+ const __ = Symbol('Placeholder');
2
2
  const countArgs = (s) => {
3
3
  let i = 0;
4
4
  for (const v of s)
@@ -37,7 +37,38 @@ const _curry = (fn, args, new_args) => {
37
37
  };
38
38
  const curry = ((fn) => ((...args) => fn.length > countArgs(args)
39
39
  ? _curry(fn, [], args)
40
- : fn(...args)));
40
+ : fn(...args)));
41
+ // type EndlessPh<Func extends FT.Function, ArgT> =
42
+ // (a: ArgT) => ReturnType<Func>
43
+ // | ((a: A.x) => EndlessPh<Func, ArgT>)
44
+ const endlessph = (fn) => {
45
+ function _endlessph(a) {
46
+ return a === __ ? fn : fn(a);
47
+ }
48
+ return _endlessph;
49
+ };
50
+ function curry2(fn) {
51
+ function curried2(a, b) {
52
+ const withPlaceholder1 = a === __;
53
+ const aln = arguments.length;
54
+ if (aln === 1 && withPlaceholder1)
55
+ throw new Error('Senseless placeholder usage.');
56
+ return arguments.length > 1
57
+ ? withPlaceholder1
58
+ ? endlessph((a) => fn(a, b))
59
+ : fn(a, b)
60
+ : (b) => fn(a, b);
61
+ }
62
+ return curried2;
63
+ }
64
+ function curry3(fn) {
65
+ // type p0 = Parameters<Func>[0]
66
+ // type p1 = Parameters<Func>[1]
67
+ // type p2 = Parameters<Func>[2]
68
+ // type ReturnT = ReturnType<Func>
69
+ // TODO: optimize.
70
+ return curry(fn);
71
+ }
41
72
 
42
73
  const undef = undefined;
43
74
  const nul = null;
@@ -63,14 +94,14 @@ const type = (s) => {
63
94
  : caseMap[t[0]] + t.slice(1);
64
95
  };
65
96
 
66
- const qappend = curry((s, xs) => { xs.push(s); return xs; });
67
- const qassoc = curry((prop, v, obj) => {
97
+ const qappend = curry2((s, xs) => { xs.push(s); return xs; });
98
+ const qassoc = curry3((prop, v, obj) => {
68
99
  obj[prop] = v;
69
100
  return obj;
70
101
  });
71
- const qreduce = curry((fn, accum, arr) => arr.reduce(fn, accum));
102
+ const qreduce = curry3((fn, accum, arr) => arr.reduce(fn, accum));
72
103
  // strategy is for arrays: 1->clean, 2->merge, 3->push.
73
- const mergeDeep$1 = curry((strategy, o1, o2) => {
104
+ const mergeDeep$1 = curry3((strategy, o1, o2) => {
74
105
  for (let k in o2) {
75
106
  switch (type(o2[k])) {
76
107
  case 'Array':
@@ -110,7 +141,7 @@ const qmergeDeep = mergeDeep$1(1);
110
141
  const qmergeDeepX = mergeDeep$1(2);
111
142
  const qmergeDeepAdd = mergeDeep$1(3);
112
143
  /** qmapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
113
- const qmapKeys = curry((keyMap, o) => {
144
+ const qmapKeys = curry2((keyMap, o) => {
114
145
  let k, mapped, newKey, newValue;
115
146
  for (k in keyMap) {
116
147
  mapped = keyMap[k];
@@ -124,7 +155,7 @@ const qmapKeys = curry((keyMap, o) => {
124
155
  }
125
156
  return o;
126
157
  });
127
- const qfilter = curry((cond, data) => {
158
+ const qfilter = curry2((cond, data) => {
128
159
  const isArr = isArray(data);
129
160
  for (let k in data) {
130
161
  if (!cond(data[k], k)) {
@@ -140,10 +171,13 @@ const qfilter = curry((cond, data) => {
140
171
  return data;
141
172
  });
142
173
  /** @deprecated */
143
- const qindexOf = curry((x, xs) => xs.indexOf(x));
174
+ const qindexOf = curry2((x, xs) => xs.indexOf(x));
175
+
176
+ // TODO: possibly introduce a second argument limiting unfolding.
177
+ const uncurry = (fn) => (...args) => qreduce(((fn, arg) => fn ? fn(arg) : fn), fn, args);
144
178
 
145
179
  // over, lensProp
146
- const equals = curry((a, b) => {
180
+ const equals = curry2((a, b) => {
147
181
  const typea = type(a);
148
182
  if (typea === type(b) && (typea === 'Object' || typea == 'Array')) {
149
183
  if (isNull(a) || isNull(b)) {
@@ -165,16 +199,17 @@ const equals = curry((a, b) => {
165
199
  return a === b;
166
200
  });
167
201
  const ifElse = curry((cond, pipeYes, pipeNo, s) => cond(s) ? pipeYes(s) : pipeNo(s));
168
- const when = curry((cond, pipe, s) => ifElse(cond, pipe, identity, s));
202
+ const when = curry3((cond, pipe, s) => ifElse(cond, pipe, identity, s));
169
203
  const compose = ((...fns) => (s = __) => {
170
204
  for (let i = length(fns) - 1; i > -1; i--) {
171
205
  s = s === __ ? fns[i]() : fns[i](s);
172
206
  }
173
207
  return s;
174
- }); // as F.Compose
175
- const bind = curry((fn, context) => fn.bind(context));
176
- const nth = curry((i, data) => data[i]);
177
- const includes = curry((s, ss) => {
208
+ });
209
+ const bind = curry2((fn, context) => fn.bind(context));
210
+ const _nth = (i, data) => data[i];
211
+ const nth = curry2(_nth);
212
+ const includes = curry2((s, ss) => {
178
213
  if (isStr(ss)) {
179
214
  return ss.includes(s);
180
215
  }
@@ -187,11 +222,11 @@ const includes = curry((s, ss) => {
187
222
  return false;
188
223
  }
189
224
  });
190
- const slice = curry((from, to, o) => o.slice(from, (isNum(to) ? to : Infinity)));
225
+ const slice = curry3((from, to, o) => o.slice(from, (isNum(to) ? to : Infinity)));
191
226
  const head = nth(0);
192
227
  const tail = slice(1, nul);
193
- const add = curry((n, m) => n + m);
194
- const subtract = curry((n, m) => m - n);
228
+ const add = curry2((n, m) => n + m);
229
+ const subtract = curry2((n, m) => m - n);
195
230
  const flip = (fn) => curry((b, a) => fn(a, b));
196
231
  const isNil = (s) => isNull(s) || isUndef(s);
197
232
  const length = (s) => s.length;
@@ -207,10 +242,10 @@ const complement = (fn) => (...args) => {
207
242
  const keys = (o) => Object.keys(o);
208
243
  const values = (o) => Object.values(o);
209
244
  const toPairs = (o) => Object.entries(o);
210
- const test = curry((re, s) => re.test(s));
211
- const tap = curry((fn, s) => { fn(s); return s; });
212
- const append = curry((s, xs) => [...xs, s]);
213
- const split = curry((s, xs) => xs.split(s));
245
+ const test = curry2((re, s) => re.test(s));
246
+ const tap = curry2((fn, s) => { fn(s); return s; });
247
+ const append = curry2((s, xs) => [...xs, s]);
248
+ const split = curry2((s, xs) => xs.split(s));
214
249
  const T = always(true);
215
250
  const F = always(false);
216
251
  const sizeof = (s) => {
@@ -223,10 +258,10 @@ const sizeof = (s) => {
223
258
  else
224
259
  return length(s);
225
260
  };
226
- const range = curry((from, to) => genBy(add(from), to - from));
261
+ const range = curry2((from, to) => genBy(add(from), to - from));
227
262
  const uniq = (xs) => qreduce((accum, x) => includes(x, accum) ? accum : qappend(x, accum), [], xs);
228
- const intersection = curry((xs1, xs2) => xs1.filter(flip(includes)(xs2)));
229
- const genBy = curry((generator, length) => [...Array(length)].map((_, i) => generator(i)));
263
+ const intersection = curry2((xs1, xs2) => xs1.filter(flip(includes)(xs2)));
264
+ const genBy = curry2((generator, length) => [...Array(length)].map((_, i) => generator(i)));
230
265
  const once = (fn) => {
231
266
  let done = false, cache;
232
267
  return (...args) => {
@@ -240,50 +275,51 @@ const once = (fn) => {
240
275
  };
241
276
  };
242
277
  const reverse = (xs) => compose((ln) => reduce((nxs, _, i) => qappend(xs[ln - i], nxs), [], xs), add(-1), length)(xs);
243
- const gt = curry((a, b) => a > b);
244
- const lt = curry((a, b) => a < b);
245
- const gte = curry((a, b) => b >= a);
246
- const lte = curry((a, b) => b <= a);
247
- // : <U=any>(sortFn: (v: U)=>-1|1, xs: U[]) => U[]
248
- const sort = curry((sortFn, xs) => xs.sort(sortFn));
249
- const find = curry((fn, s) => s.find(fn));
250
- const findIndex = curry((fn, s) => s.findIndex(fn));
251
- const indexOf = curry((x, xs) => findIndex(equals(x), xs));
278
+ const gt = curry2((a, b) => a > b);
279
+ const lt = curry2((a, b) => a < b);
280
+ const gte = curry2((a, b) => b >= a);
281
+ const lte = curry2((a, b) => b <= a);
282
+ const sort = curry2((sortFn, xs) => xs.sort(sortFn));
283
+ const find = curry2((fn, s) => s.find(fn));
284
+ const findIndex = curry2((fn, s) => s.findIndex(fn));
285
+ const indexOf = curry2((x, xs) => findIndex(equals(x), xs));
252
286
  const explore = (caption, level = 'log') => tap((v) => console[level](caption, v));
253
- const cond = curry((pairs, s) => {
287
+ const cond = curry2((pairs, s) => {
254
288
  for (const [cond, fn] of pairs) {
255
289
  if (cond(s)) {
256
290
  return fn(s);
257
291
  }
258
292
  }
259
293
  });
260
- const assoc = curry((prop, v, obj) => ({
294
+ const assoc = curry3((prop, v, obj) => ({
261
295
  ...obj,
262
296
  [prop]: v
263
297
  }));
264
- const assocPath = curry((_path, v, o) => compose((first) => assoc(first, length(_path) < 2
298
+ const assocPath = curry3((_path, v, o) => compose((first) => assoc(first, length(_path) < 2
265
299
  ? v
266
300
  : assocPath(slice(1, null, _path), v, isObj(o[first]) ? o[first] : {}), o), head)(_path));
267
- const all = curry((pred, xs) => xs.every(pred));
268
- const any = curry((pred, xs) => xs.some(pred));
269
- const allPass = curry((preds, x) => preds.every((pred) => pred(x)));
270
- const anyPass = curry((preds, x) => preds.some((pred) => pred(x)));
271
- const prop = curry((key, o) => o[key]);
272
- const propEq = curry((key, value, o) => equals(o[key], value));
273
- const propsEq = curry((key, o1, o2) => equals(o1[key], o2[key]));
274
- const pathOr = curry((_default, path, o) => ifElse(length, () => isNil(o)
301
+ const all = curry2((pred, xs) => xs.every(pred));
302
+ const any = curry2((pred, xs) => xs.some(pred));
303
+ const allPass = curry2((preds, x) => preds.every((pred) => pred(x)));
304
+ const anyPass = curry2((preds, x) => preds.some((pred) => pred(x)));
305
+ const prop = curry2((key, o) => o[key]);
306
+ const propEq = curry3((key, value, o) => equals(o[key], value));
307
+ const propsEq = curry3((key, o1, o2) => equals(o1[key], o2[key]));
308
+ const pathOr = curry3((_default, path, o) => ifElse(length, () => isNil(o)
275
309
  ? _default
276
310
  : compose(ifElse(isNil, always(_default), (o) => pathOr(_default, slice(1, nul, path), o)), flip(prop)(o), head)(path), always(o), path));
277
311
  const path = pathOr(undef);
278
- const pathEq = curry((_path, value, o) => equals(path(_path, o), value));
279
- const pathsEq = curry((_path, o1, o2) => equals(path(_path, o1), path(_path, o2)));
312
+ const pathEq = curry3((_path, value, o) => equals(path(_path, o), value));
313
+ const pathsEq = curry3((_path, o1, o2) => equals(path(_path, o1), path(_path, o2)));
280
314
  const typed_arr_re = /^(.*?)(8|16|32|64)(Clamped)?Array$/;
281
- const clone = (s) => {
315
+ const clone = (s, shallow = false) => {
282
316
  const t = type(s);
283
317
  switch (t) {
284
318
  case 'Null': return s;
285
- case 'Array': return map(clone, s);
319
+ case 'Array': return shallow ? [...s] : map(clone, s);
286
320
  case 'Object':
321
+ if (shallow)
322
+ return { ...s };
287
323
  const out = {};
288
324
  for (let k in s) {
289
325
  out[k] = clone(s[k]);
@@ -295,12 +331,13 @@ const clone = (s) => {
295
331
  case 'Symbol':
296
332
  return s;
297
333
  default:
298
- return typed_arr_re.test(t) ? map(clone, s) : s;
334
+ return typed_arr_re.test(t) ? s.constructor.from(s) : s;
299
335
  }
300
336
  };
301
- const reduce = curry((fn, accum, arr) => qreduce(fn, clone(accum), arr));
302
- const pickBy = curry((cond, o) => filter(cond, o));
303
- const pick = curry((props, o) => {
337
+ const cloneShallow = (s) => clone(s, true);
338
+ const reduce = curry3((fn, accum, arr) => qreduce(fn, clone(accum), arr));
339
+ const pickBy = curry2((cond, o) => filter(cond, o));
340
+ const pick = curry2((props, o) => {
304
341
  const out = {};
305
342
  for (const p of props) {
306
343
  if (p in o) {
@@ -309,13 +346,13 @@ const pick = curry((props, o) => {
309
346
  }
310
347
  return out;
311
348
  });
312
- const omit = curry((props, o) => filter((_, k) => !includes(k, props), o));
349
+ const omit = curry2((props, o) => filter((_, k) => !includes(k, props), o));
313
350
  const fromPairs = (pairs) => reduce((o, pair) => assoc(...pair, o), {}, pairs);
314
- const concat = curry(((a, b) => a.concat(b)));
315
- const join = curry((delimeter, arr) => arr.join(delimeter));
316
- const map = curry((pipe, arr) => arr.map(pipe));
317
- const forEach = curry((pipe, arr) => arr.forEach(pipe));
318
- const both = curry((cond1, cond2, s) => cond2(s) && cond1(s));
351
+ const concat = curry2(((a, b) => a.concat(b)));
352
+ const join = curry2((delimeter, arr) => arr.join(delimeter));
353
+ const map = curry2((pipe, arr) => arr.map(pipe));
354
+ const forEach = curry2((pipe, arr) => arr.forEach(pipe));
355
+ const both = curry3((cond1, cond2, s) => cond2(s) && cond1(s));
319
356
  const isEmpty = (s) => {
320
357
  switch (type(s)) {
321
358
  case 'String':
@@ -335,8 +372,8 @@ const empty = (s) => {
335
372
  default: return undef;
336
373
  }
337
374
  };
338
- const replace = curry((a, b, where) => where.replace(a, b));
339
- const filter = curry((cond, data) => isArray(data)
375
+ const replace = curry3((a, b, where) => where.replace(a, b));
376
+ const filter = curry2((cond, data) => isArray(data)
340
377
  ? data.filter(cond)
341
378
  : compose(fromPairs, filter(([k, v]) => cond(v, k)), toPairs)(data));
342
379
  const memoize = (fn) => {
@@ -344,13 +381,13 @@ const memoize = (fn) => {
344
381
  let cached = false;
345
382
  return () => cached ? cache : (cached = true, cache = fn());
346
383
  };
347
- const mergeShallow = curry((o1, o2) => Object.assign({}, o1, o2));
348
- const mergeDeep = curry((a, b) => qmergeDeep(clone(a), clone(b)));
349
- const mergeDeepX = curry((a, b) => qmergeDeepX(clone(a), clone(b)));
350
- const mergeDeepAdd = curry((a, b) => qmergeDeepAdd(clone(a), clone(b)));
351
- const overProp = curry((prop, pipe, data) => assoc(prop, pipe(data[prop]), data));
384
+ const mergeShallow = curry2((o1, o2) => Object.assign({}, o1, o2));
385
+ const mergeDeep = curry2((a, b) => qmergeDeep(clone(a), clone(b)));
386
+ const mergeDeepX = curry2((a, b) => qmergeDeepX(clone(a), clone(b)));
387
+ const mergeDeepAdd = curry2((a, b) => qmergeDeepAdd(clone(a), clone(b)));
388
+ const overProp = curry3((prop, pipe, data) => assoc(prop, pipe(data[prop]), data));
352
389
  /** mapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
353
- const mapKeys = curry((keyMap, o) => qmapKeys(keyMap, Object.assign({}, o)));
390
+ const mapKeys = curry2((keyMap, o) => qmapKeys(keyMap, Object.assign({}, o)));
354
391
  // ASYNCS
355
392
  /** One promise waits for another. */
356
393
  const forEachSerial = (() => {
@@ -360,12 +397,13 @@ const forEachSerial = (() => {
360
397
  await pipe(fn, items, ++i);
361
398
  }
362
399
  };
363
- return curry((fn, items) => pipe(fn, items, 0));
400
+ return curry2((fn, items) => pipe(fn, items, 0));
364
401
  })();
365
402
  /** Promise.all wrapper for functional pipelining. */
366
403
  const waitAll = (promises) => Promise.all(promises);
404
+ const waitTap = curry2(async (fn, s) => { await fn(s); return s; });
367
405
  /** Waits for all promises mapped by the fn. */
368
- const forEachAsync = curry((fn, items) => Promise.all(items.map(fn)));
406
+ const forEachAsync = curry2((fn, items) => Promise.all(items.map(fn)));
369
407
  /** The same as compose, but waits for promises in chains and returns a Promise. */
370
408
  const composeAsync = (() => {
371
409
  const pipe = async (fns, data, i) => ~i ? await pipe(fns, await fns[i](data), --i) : data;
@@ -422,6 +460,9 @@ var pepka = /*#__PURE__*/Object.freeze({
422
460
  __proto__: null,
423
461
  __: __,
424
462
  curry: curry,
463
+ curry2: curry2,
464
+ curry3: curry3,
465
+ uncurry: uncurry,
425
466
  toLower: toLower,
426
467
  toUpper: toUpper,
427
468
  type: type,
@@ -486,6 +527,7 @@ var pepka = /*#__PURE__*/Object.freeze({
486
527
  pathEq: pathEq,
487
528
  pathsEq: pathsEq,
488
529
  clone: clone,
530
+ cloneShallow: cloneShallow,
489
531
  reduce: reduce,
490
532
  pickBy: pickBy,
491
533
  pick: pick,
@@ -509,6 +551,7 @@ var pepka = /*#__PURE__*/Object.freeze({
509
551
  mapKeys: mapKeys,
510
552
  forEachSerial: forEachSerial,
511
553
  waitAll: waitAll,
554
+ waitTap: waitTap,
512
555
  forEachAsync: forEachAsync,
513
556
  composeAsync: composeAsync,
514
557
  mirror: mirror,
package/package.json CHANGED
@@ -19,6 +19,7 @@
19
19
  "d.ts"
20
20
  ],
21
21
  "license": "MIT",
22
+ "type": "module",
22
23
  "main": "dist/bundle.js",
23
24
  "module": "dist/es/index.js",
24
25
  "name": "pepka",
@@ -38,15 +39,13 @@
38
39
  "prod": "npm run gentypes && npm run prod:es && npm run prod:cjs",
39
40
  "all": "npm run dev && npm run prod"
40
41
  },
41
- "version": "0.12.3",
42
+ "version": "0.13.0b1",
42
43
  "ava": {
43
44
  "files": [
44
45
  "./test/specs/*.ts"
45
46
  ],
46
- "serial": false,
47
47
  "failFast": true,
48
48
  "timeout": "2m",
49
- "compileEnhancements": false,
50
49
  "extensions": [
51
50
  "ts"
52
51
  ],
@@ -55,23 +54,23 @@
55
54
  ]
56
55
  },
57
56
  "devDependencies": {
58
- "@types/node": "^15.12.4",
59
- "ava": "^3.15.0",
57
+ "@types/node": "^18.11.10",
58
+ "ava": "^5.1.0",
60
59
  "codecov": "^3.8.2",
61
60
  "cross-env": "^7.0.3",
62
- "dts-bundle-generator": "^5.9.0",
61
+ "dts-bundle-generator": "^7.1.0",
63
62
  "nyc": "^15.1.0",
64
- "rollup": "^2.52.1",
63
+ "rollup": "^3.5.1",
65
64
  "rollup-plugin-commonjs": "^10.1.0",
66
65
  "rollup-plugin-node-resolve": "^5.2.0",
67
66
  "rollup-plugin-replace": "^2.2.0",
68
67
  "rollup-plugin-resolve-aliases": "^0.3.0",
69
68
  "rollup-plugin-terser": "^7.0.2",
70
- "rollup-plugin-typescript2": "^0.30.0",
71
- "ts-node": "^10.0.0",
69
+ "rollup-plugin-typescript2": "^0.34.1",
70
+ "ts-node": "^10.9.1",
72
71
  "ts-toolbelt": "^9.6.0",
73
72
  "tslint": "^6.1.0",
74
- "typescript": "^4.3.4"
73
+ "typescript": "^4.9.3"
75
74
  },
76
75
  "types": "./dist/bundle.d.ts",
77
76
  "sideEffects": false
package/rollup.config.js CHANGED
@@ -3,6 +3,7 @@ import resolve from 'rollup-plugin-node-resolve'
3
3
  import typescript from 'rollup-plugin-typescript2'
4
4
  import { terser } from 'rollup-plugin-terser'
5
5
  import replace from 'rollup-plugin-replace'
6
+ import tsc from 'typescript'
6
7
 
7
8
  export default {
8
9
  input: process.env.NODE_ENV=='development' ? 'test/in-browser.ts' : 'src/index.ts',
@@ -16,7 +17,7 @@ export default {
16
17
  resolve(),
17
18
  commonjs(),
18
19
  typescript({
19
- typescript: require("typescript"),
20
+ typescript: tsc,
20
21
  tsconfig: "./tsconfig.json",
21
22
  tsconfigOverride: {
22
23
  compilerOptions: {
package/src/curry.ts CHANGED
@@ -1,9 +1,9 @@
1
+ import { F as FT, A } from 'ts-toolbelt'
2
+ import { AnyFunc, AnyArgs } from "./types"
1
3
 
2
- type Args = any[]
4
+ export const __ = Symbol('Placeholder') as A.x
3
5
 
4
- export const __ = (function Placeholder() {})
5
-
6
- const countArgs = (s: Args) => {
6
+ const countArgs = (s: AnyArgs) => {
7
7
  let i = 0
8
8
  for (const v of s) v!==__ && i++
9
9
  return i
@@ -11,7 +11,7 @@ const countArgs = (s: Args) => {
11
11
 
12
12
  // TODO: try to make it mutable.
13
13
  // { 0: __, 1: 10 }, [ 11 ]
14
- const addArgs = (args: Args, _args: Args) => {
14
+ const addArgs = (args: AnyArgs, _args: AnyArgs) => {
15
15
  const len = args.length
16
16
  const new_args = args.slice()
17
17
  const _args_len = _args.length
@@ -29,12 +29,12 @@ const addArgs = (args: Args, _args: Args) => {
29
29
  return new_args
30
30
  }
31
31
 
32
- const _curry = (fn: Function, args: Args, new_args: Args) => {
32
+ const _curry = (fn: Function, args: AnyArgs, new_args: AnyArgs) => {
33
33
  const args2add = fn.length - args.length - countArgs(new_args)
34
34
  if(args2add < 1) {
35
35
  return fn(...addArgs(args, new_args))
36
36
  } else {
37
- const curried = (...__args: Args) => _curry(
37
+ const curried = (...__args: AnyArgs) => _curry(
38
38
  fn,
39
39
  addArgs(args, new_args),
40
40
  __args
@@ -45,9 +45,55 @@ const _curry = (fn: Function, args: Args, new_args: Args) => {
45
45
  }
46
46
 
47
47
  export const curry = (
48
- (fn: Function) => (
49
- (...args: Args) => fn.length>countArgs(args)
48
+ <Func extends AnyFunc>(fn: AnyFunc) => (
49
+ (...args: AnyArgs) => fn.length>countArgs(args)
50
50
  ? _curry(fn, [], args)
51
51
  : fn(...args)
52
- )
53
- )
52
+ ) as FT.Curry<Func>
53
+ )
54
+ // type EndlessPh<Func extends FT.Function, ArgT> =
55
+ // (a: ArgT) => ReturnType<Func>
56
+ // | ((a: A.x) => EndlessPh<Func, ArgT>)
57
+ const endlessph = <Func extends FT.Function>(fn: Func) => {
58
+ type ReturnT = ReturnType<Func>
59
+ type p0 = Parameters<Func>[0]
60
+ function _endlessph(a: p0): ReturnT
61
+ function _endlessph(a: A.x): Func
62
+ function _endlessph(a: p0 | A.x) {
63
+ return a===__ ? fn : fn(a)
64
+ }
65
+ return _endlessph
66
+ }
67
+
68
+ type Func2 = (a: any, b: any) => any
69
+ export function curry2<Func extends Func2>(fn: Func) {
70
+ type p0 = Parameters<Func>[0]
71
+ type p1 = Parameters<Func>[1]
72
+ type ReturnT = ReturnType<Func>
73
+ function curried2( a: p0 ): (b: p1) => ReturnT
74
+ function curried2( a: p0, b: p1 ): ReturnT
75
+ function curried2( a: A.x, b: p1 ): (a: p0) => ReturnT
76
+ function curried2( a: p0, b: A.x ): (b: p1) => ReturnT
77
+ function curried2( a: p0 | A.x, b?: p1 ) {
78
+ const withPlaceholder1 = a===__
79
+ const aln = arguments.length
80
+ if(aln === 1 && withPlaceholder1)
81
+ throw new Error('Senseless placeholder usage.')
82
+ return arguments.length>1
83
+ ? withPlaceholder1
84
+ ? endlessph((a: p0) => fn(a, b))
85
+ : fn(a, b) as ReturnType<Func>
86
+ : (b: p1) => fn(a, b)
87
+ }
88
+ return curried2
89
+ }
90
+
91
+ type Func3 = (a: any, b: any, c: any) => any
92
+ export function curry3<Func extends Func3>(fn: Func) {
93
+ // type p0 = Parameters<Func>[0]
94
+ // type p1 = Parameters<Func>[1]
95
+ // type p2 = Parameters<Func>[2]
96
+ // type ReturnT = ReturnType<Func>
97
+ // TODO: optimize.
98
+ return curry(fn)
99
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
2
  export * from './curry'
3
+ export * from './uncurry'
3
4
  export * from './common'
4
5
  export * from './safe'
5
6
  export * from './quick'
package/src/quick.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { curry } from "./curry"
1
+ import { curry, curry2, curry3 } from "./curry"
2
2
  import { type } from "./common"
3
3
  import { AnyObject, Reducer, AnyFunc } from "./types"
4
4
  import { isFunc, isArray } from "./utils"
5
5
 
6
- export const qappend = curry((s: any, xs: any[]) => {xs.push(s); return xs})
7
- export const qassoc = curry(
6
+ export const qappend = curry2((s: any, xs: any[]) => {xs.push(s); return xs})
7
+ export const qassoc = curry3(
8
8
  (prop: string, v: any, obj: AnyObject) => {
9
9
  obj[prop] = v
10
10
  return obj
11
11
  }
12
12
  )
13
- export const qreduce = curry(
13
+ export const qreduce = curry3(
14
14
  (fn: Reducer, accum: any, arr: any[]) =>
15
15
  arr.reduce(fn, accum)
16
16
  )
17
17
  // strategy is for arrays: 1->clean, 2->merge, 3->push.
18
- const mergeDeep = curry((strategy: 1|2|3, o1: AnyObject, o2: AnyObject): AnyObject => {
18
+ const mergeDeep = curry3((strategy: 1|2|3, o1: AnyObject, o2: AnyObject): AnyObject => {
19
19
  for(let k in o2) {
20
20
  switch(type(o2[k])) {
21
21
  case 'Array':
@@ -54,7 +54,7 @@ export const qmergeDeep = mergeDeep(1)
54
54
  export const qmergeDeepX = mergeDeep(2)
55
55
  export const qmergeDeepAdd = mergeDeep(3)
56
56
  /** qmapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
57
- export const qmapKeys = curry(
57
+ export const qmapKeys = curry2(
58
58
  (
59
59
  keyMap: {[oldKey: string]: string},
60
60
  o: AnyObject
@@ -74,7 +74,7 @@ export const qmapKeys = curry(
74
74
  }
75
75
  )
76
76
 
77
- export const qfilter = curry(
77
+ export const qfilter = curry2(
78
78
  (
79
79
  cond: (v: any, k: string | number) => boolean,
80
80
  data: any[] | AnyObject
@@ -94,6 +94,6 @@ export const qfilter = curry(
94
94
  }
95
95
  )
96
96
  /** @deprecated */
97
- export const qindexOf = curry(
97
+ export const qindexOf = curry2(
98
98
  (x: any, xs: any[]) => xs.indexOf(x)
99
99
  )
package/src/safe.ts CHANGED
@@ -1,11 +1,12 @@
1
- import { __, curry } from './curry'
1
+ import { __, curry, curry2, curry3 } from './curry'
2
2
  import { isNum, nul, isUndef, undef, isNull, isArray, isFunc, isStr, isObj } from './utils'
3
3
  import { qmergeDeep, qreduce, qappend, qmapKeys, qmergeDeepX, qmergeDeepAdd } from './quick'
4
4
  import { AnyFunc, Cond, AnyObject, Reducer } from './types'
5
5
  import { type } from './common'
6
+ import { F as FT } from 'ts-toolbelt'
6
7
  // over, lensProp
7
8
 
8
- export const equals = curry((a: any, b: any) => {
9
+ export const equals = curry2((a: any, b: any) => {
9
10
  const typea = type(a)
10
11
  if(typea===type(b) && (typea==='Object' || typea=='Array')) {
11
12
  if(isNull(a) || isNull(b)) {
@@ -36,30 +37,31 @@ export const ifElse = curry(
36
37
  s: any
37
38
  ) => cond(s) ? pipeYes(s) : pipeNo(s)
38
39
  )
39
- export const when = curry(
40
+ export const when = curry3(
40
41
  (
41
42
  cond: (s: any) => boolean,
42
43
  pipe: (s: any) => any,
43
44
  s: any
44
45
  ) => ifElse(cond, pipe, identity, s)
45
46
  )
46
- export const compose = (
47
- (...fns: Function[]) =>
47
+ export const compose: FT.Compose = (
48
+ (...fns: AnyFunc[]) =>
48
49
  (s: any = __) => {
49
50
  for(let i = length(fns)-1; i>-1; i--) {
50
51
  s = s===__ ? fns[i]() : fns[i](s)
51
52
  }
52
53
  return s
53
54
  }
54
- )// as F.Compose
55
+ )
55
56
 
56
- export const bind = curry(
57
+ export const bind = curry2<AnyFunc>(
57
58
  (fn: AnyFunc, context: any) => fn.bind(context)
58
59
  )
59
- export const nth = curry(
60
- (i: number, data: any[]) => data[i]
61
- )
62
- export const includes = curry(
60
+
61
+ const _nth = <T=any>(i: number, data: T[]) => data[i]
62
+ export const nth = curry2(_nth)
63
+
64
+ export const includes = curry2(
63
65
  (s: any, ss: any[]) => {
64
66
  if(isStr(ss)) {
65
67
  return ss.includes(s)
@@ -73,14 +75,14 @@ export const includes = curry(
73
75
  }
74
76
  }
75
77
  )
76
- export const slice = curry(
78
+ export const slice = curry3(
77
79
  (from: number, to: number|null, o: any[] | string) =>
78
80
  o.slice(from, (isNum(to)?to:Infinity) as number)
79
81
  )
80
82
  export const head = nth(0)
81
83
  export const tail = slice(1, nul)
82
- export const add = curry((n: number, m: number) => n+m)
83
- export const subtract = curry((n: number, m: number) => m-n)
84
+ export const add = curry2((n: number, m: number) => n+m)
85
+ export const subtract = curry2((n: number, m: number) => m-n)
84
86
  export const flip = (fn: Function) => curry((b: any, a: any) => fn(a, b))
85
87
  export const isNil = (s: any) => isNull(s) || isUndef(s)
86
88
  export const length = (s: any[] | string) => s.length
@@ -96,10 +98,10 @@ export const complement = (fn: AnyFunc) => (...args: any) => {
96
98
  export const keys = (o: AnyObject | any[]) => Object.keys(o)
97
99
  export const values = (o: AnyObject | any[]) => Object.values(o)
98
100
  export const toPairs = (o: AnyObject | any[]) => Object.entries(o)
99
- export const test = curry((re: RegExp, s: string) => re.test(s))
100
- export const tap = curry((fn: Function, s: any) => { fn(s); return s })
101
- export const append = curry((s: any, xs: any[]) => [...xs, s])
102
- export const split = curry((s: string, xs: string) => xs.split(s))
101
+ export const test = curry2((re: RegExp, s: string) => re.test(s))
102
+ export const tap = curry2((fn: Function, s: any) => { fn(s); return s })
103
+ export const append = curry2((s: any, xs: any[]) => [...xs, s])
104
+ export const split = curry2((s: string, xs: string) => xs.split(s))
103
105
  export const T = always<true>(true) as (...args: any[]) => true
104
106
  export const F = always<false>(false) as (...args: any[]) => false
105
107
  export const sizeof = (s: any[] | string | AnyObject) => {
@@ -109,17 +111,17 @@ export const sizeof = (s: any[] | string | AnyObject) => {
109
111
  return len
110
112
  } else return length(s as any[])
111
113
  }
112
- export const range = curry((from: number, to: number) =>
114
+ export const range = curry2((from: number, to: number) =>
113
115
  genBy(add(from), to-from)
114
116
  )
115
117
  export const uniq = (xs: any[]) => qreduce(
116
118
  (accum: any[], x: any) =>
117
119
  includes(x, accum) ? accum : qappend(x, accum),
118
120
  [], xs)
119
- export const intersection = curry(
121
+ export const intersection = curry2(
120
122
  (xs1: any[], xs2: any[]) => xs1.filter(flip(includes)(xs2))
121
123
  )
122
- export const genBy = curry(
124
+ export const genBy = curry2(
123
125
  (
124
126
  generator: (i: number) => any,
125
127
  length: number
@@ -144,33 +146,18 @@ export const reverse = (xs: any[]) => compose(
144
146
  add(-1),
145
147
  length
146
148
  )(xs)
147
- export const gt = curry(
148
- (a: number, b: number) => a>b
149
- )
150
- export const lt = curry(
151
- (a: number, b: number) => a<b
152
- )
153
- export const gte = curry(
154
- (a: number, b: number) => b>=a
155
- )
156
- export const lte = curry(
157
- (a: number, b: number) => b<=a
158
- )
159
- // : <U=any>(sortFn: (v: U)=>-1|1, xs: U[]) => U[]
160
- export const sort = curry((sortFn: any, xs: any[]) => xs.sort(sortFn))
161
- export const find = curry(
162
- (fn: Cond, s: any[]) => s.find(fn)
163
- )
164
- export const findIndex = curry(
165
- (fn: Cond, s: any[]) => s.findIndex(fn)
166
- )
167
- export const indexOf = curry(
168
- (x: any, xs: any[]) => findIndex(equals(x), xs)
169
- )
149
+ export const gt = curry2( (a: number, b: number) => a>b )
150
+ export const lt = curry2( (a: number, b: number) => a<b )
151
+ export const gte = curry2( (a: number, b: number) => b>=a )
152
+ export const lte = curry2( (a: number, b: number) => b<=a )
153
+ export const sort = curry2((sortFn: any, xs: any[]) => xs.sort(sortFn))
154
+ export const find = curry2((fn: Cond, s: any[]) => s.find(fn))
155
+ export const findIndex = curry2((fn: Cond, s: any[]) => s.findIndex(fn))
156
+ export const indexOf = curry2((x: any, xs: any[]) => findIndex(equals(x), xs))
170
157
  export const explore = (caption: string, level = 'log') => tap(
171
158
  (v: any) => console[level](caption, v)
172
159
  )
173
- export const cond = curry(
160
+ export const cond = curry2(
174
161
  (pairs: [Cond, Function][], s: any) => {
175
162
  for(const [cond, fn] of pairs) {
176
163
  if(cond(s)) {
@@ -179,13 +166,13 @@ export const cond = curry(
179
166
  }
180
167
  }
181
168
  )
182
- export const assoc = curry(
169
+ export const assoc = curry3(
183
170
  (prop: string, v: any, obj: AnyObject) => ({
184
171
  ...obj,
185
172
  [prop]: v
186
173
  })
187
174
  )
188
- export const assocPath = curry(
175
+ export const assocPath = curry3(
189
176
  (_path: string[], v: any, o: AnyObject) => compose(
190
177
  (first: string) => assoc(
191
178
  first,
@@ -197,24 +184,22 @@ export const assocPath = curry(
197
184
  head
198
185
  )(_path)
199
186
  )
200
- export const all = curry((pred: Cond, xs: any[]) => xs.every(pred))
201
- export const any = curry((pred: Cond, xs: any[]) => xs.some(pred))
202
- export const allPass = curry(
187
+ export const all = curry2((pred: Cond, xs: any[]) => xs.every(pred))
188
+ export const any = curry2((pred: Cond, xs: any[]) => xs.some(pred))
189
+ export const allPass = curry2(
203
190
  (preds: Cond[], x: any) => preds.every((pred) => pred(x))
204
191
  )
205
- export const anyPass = curry(
192
+ export const anyPass = curry2(
206
193
  (preds: Cond[], x: any) => preds.some((pred) => pred(x))
207
194
  )
208
- export const prop = curry(
209
- (key: string, o: AnyObject) => o[key]
210
- )
211
- export const propEq = curry(
195
+ export const prop = curry2( (key: string, o: AnyObject) => o[key] )
196
+ export const propEq = curry3(
212
197
  (key: string, value: any, o: AnyObject) => equals(o[key], value)
213
198
  )
214
- export const propsEq = curry(
199
+ export const propsEq = curry3(
215
200
  (key: string, o1: any, o2: AnyObject) => equals(o1[key], o2[key])
216
201
  )
217
- export const pathOr = curry(
202
+ export const pathOr = curry3(
218
203
  (_default: any, path: string[], o: any) =>
219
204
  ifElse(length,
220
205
  () => isNil(o)
@@ -231,20 +216,21 @@ export const pathOr = curry(
231
216
  path)
232
217
  )
233
218
  export const path = pathOr(undef)
234
- export const pathEq = curry(
219
+ export const pathEq = curry3(
235
220
  (_path: string[], value: any, o: AnyObject) => equals(path(_path, o), value)
236
221
  )
237
- export const pathsEq = curry(
222
+ export const pathsEq = curry3(
238
223
  (_path: string[], o1: AnyObject, o2: AnyObject) =>
239
224
  equals(path(_path, o1), path(_path, o2))
240
225
  )
241
226
  const typed_arr_re = /^(.*?)(8|16|32|64)(Clamped)?Array$/
242
- export const clone = (s: any) => {
227
+ export const clone = (s: any, shallow = false) => {
243
228
  const t = type(s)
244
229
  switch(t) {
245
230
  case 'Null': return s
246
- case 'Array': return map(clone, s)
231
+ case 'Array': return shallow ? [...s] : map(clone, s)
247
232
  case 'Object':
233
+ if(shallow) return {...s}
248
234
  const out = {}
249
235
  for(let k in s) {
250
236
  out[k] = clone(s[k])
@@ -254,17 +240,19 @@ export const clone = (s: any) => {
254
240
  case 'Boolean': case 'Symbol':
255
241
  return s
256
242
  default:
257
- return typed_arr_re.test(t) ? map(clone, s) : s
243
+ return typed_arr_re.test(t) ? s.constructor.from(s) : s
258
244
  }
259
245
  }
260
- export const reduce = curry(
246
+ export const cloneShallow = (s: any) => clone(s, true)
247
+
248
+ export const reduce = curry3(
261
249
  (fn: Reducer, accum: any, arr: any[]) =>
262
250
  qreduce(fn, clone(accum), arr)
263
251
  )
264
- export const pickBy = curry(
252
+ export const pickBy = curry2(
265
253
  (cond: Cond, o: AnyObject) => filter(cond, o)
266
254
  )
267
- export const pick = curry(
255
+ export const pick = curry2(
268
256
  (props: string[], o: AnyObject) => {
269
257
  const out = {}
270
258
  for(const p of props) {
@@ -275,7 +263,7 @@ export const pick = curry(
275
263
  return out
276
264
  }
277
265
  )
278
- export const omit = curry(
266
+ export const omit = curry2(
279
267
  (props: string[], o: AnyObject) => filter(
280
268
  (_: any, k: string) => !includes(k, props),
281
269
  o
@@ -287,19 +275,19 @@ export const fromPairs = (pairs: [string, any][]) => reduce(
287
275
  )
288
276
  type Concat = ((a: string, b: string) => string)
289
277
  | ((a: any[], b: any[]) => any[])
290
- export const concat = curry(
278
+ export const concat = curry2(
291
279
  ((a, b) => a.concat(b)) as Concat
292
280
  )
293
- export const join = curry(
281
+ export const join = curry2(
294
282
  (delimeter: string, arr: string[]) => arr.join(delimeter)
295
283
  )
296
- export const map = curry(
284
+ export const map = curry2(
297
285
  (pipe: (s: any) => any, arr: any[]) => arr.map(pipe)
298
286
  )
299
- export const forEach = curry(
287
+ export const forEach = curry2(
300
288
  (pipe: (s: any) => any, arr: any[]) => arr.forEach(pipe)
301
289
  )
302
- export const both = curry(
290
+ export const both = curry3(
303
291
  (cond1: Cond, cond2: Cond, s: any) => cond2(s) && cond1(s)
304
292
  )
305
293
  export const isEmpty = (s: any) => {
@@ -319,14 +307,14 @@ export const empty = (s: any) => {
319
307
  default: return undef
320
308
  }
321
309
  }
322
- export const replace = curry(
310
+ export const replace = curry3(
323
311
  (
324
312
  a: string | RegExp,
325
313
  b: string,
326
314
  where: string
327
315
  ) => where.replace(a, b)
328
316
  )
329
- export const filter = curry(
317
+ export const filter = curry2(
330
318
  (
331
319
  cond: (v: any, k: string | number) => boolean,
332
320
  data: any[] | AnyObject
@@ -343,25 +331,25 @@ export const memoize = (fn: Function) => {
343
331
  let cached = false
344
332
  return () => cached ? cache : (cached = true, cache = fn())
345
333
  }
346
- export const mergeShallow = curry(
334
+ export const mergeShallow = curry2(
347
335
  (o1: AnyObject, o2: AnyObject): AnyObject =>
348
336
  Object.assign({}, o1, o2)
349
337
  )
350
- export const mergeDeep = curry(
338
+ export const mergeDeep = curry2(
351
339
  (a: AnyObject, b: AnyObject) => qmergeDeep(clone(a), clone(b))
352
340
  )
353
- export const mergeDeepX = curry(
341
+ export const mergeDeepX = curry2(
354
342
  (a: AnyObject, b: AnyObject) => qmergeDeepX(clone(a), clone(b))
355
343
  )
356
- export const mergeDeepAdd = curry(
344
+ export const mergeDeepAdd = curry2(
357
345
  (a: AnyObject, b: AnyObject) => qmergeDeepAdd(clone(a), clone(b))
358
346
  )
359
- export const overProp = curry(
347
+ export const overProp = curry3(
360
348
  (prop: string, pipe: AnyFunc, data: any) =>
361
349
  assoc(prop, pipe(data[prop]), data)
362
350
  )
363
351
  /** mapKeys({ a: 'b' }, { a: 44 }) -> { b: 44 } */
364
- export const mapKeys = curry(
352
+ export const mapKeys = curry2(
365
353
  (
366
354
  keyMap: {[oldKey: string]: string},
367
355
  o: AnyObject
@@ -378,14 +366,15 @@ export const forEachSerial = (() => {
378
366
  await pipe(fn, items, ++i)
379
367
  }
380
368
  }
381
- return curry(
369
+ return curry2(
382
370
  (fn: AnyFunc, items: any[]) => pipe(fn, items, 0)
383
371
  )
384
372
  })()
385
373
  /** Promise.all wrapper for functional pipelining. */
386
374
  export const waitAll = (promises: Promise<any>[]) => Promise.all(promises)
375
+ export const waitTap = curry2(async (fn: Function, s: any) => { await fn(s); return s })
387
376
  /** Waits for all promises mapped by the fn. */
388
- export const forEachAsync = curry(
377
+ export const forEachAsync = curry2(
389
378
  (fn: (item: any) => Promise<any>, items: any[]) =>
390
379
  Promise.all(items.map(fn))
391
380
  )
@@ -395,10 +384,9 @@ export const composeAsync = (() => {
395
384
  ~i ? await pipe(fns, await fns[i](data), --i) : data
396
385
  return <T = any>(...fns: AnyFunc[]) =>
397
386
  (data?: any) => pipe(fns, data, fns.length-1) as Promise<T>
398
- })()
387
+ })() as FT.Compose<'async'>
399
388
 
400
389
  // ALIASES
401
-
402
390
  export const mirror = identity
403
391
  export const reflect = identity
404
- export const echo = identity
392
+ export const echo = identity
package/src/types.ts CHANGED
@@ -1,7 +1,14 @@
1
-
2
1
  export type Cond = (...xs: any[]) => boolean
3
2
  export interface AnyObject {
4
3
  [k: string]: any
5
4
  }
5
+ export type AnyArgs = any[]
6
+ export type Curried<
7
+ Args extends AnyArgs = AnyArgs,
8
+ ReturnT = any
9
+ > = (arg: Args[number]) => Curried<Args> | ReturnT
6
10
  export type Reducer = <T>(accum: T, cur: any, index: number) => T
7
- export type AnyFunc = (...args: any[]) => any
11
+ export type AnyFunc<
12
+ ReturnT = any,
13
+ Args extends AnyArgs = AnyArgs
14
+ > = (...args: Args) => ReturnT
package/src/uncurry.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { qreduce } from "./quick"
2
+ import { AnyFunc, Curried } from "./types"
3
+
4
+ // TODO: possibly introduce a second argument limiting unfolding.
5
+ export const uncurry = <
6
+ Args extends any[] = any[],
7
+ ReturnT = any
8
+ >(fn: Curried<Args>): AnyFunc =>
9
+ (...args: Args) => qreduce(
10
+ ((fn: Curried<Args>, arg: any) => fn ? fn(arg) : fn), fn, args
11
+ ) as ReturnT
package/tsconfig.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "moduleResolution": "Node",
3
4
  "lib": [ "esnext", "DOM" ],
4
5
  "strictNullChecks": true,
5
6
  "target": "esnext",
@@ -14,8 +15,5 @@
14
15
  "rootDir": "src",
15
16
  "baseUrl": "."
16
17
  },
17
- "include": [
18
- "src/**/*",
19
- "src/node_modules/ts-toolbelt/out/index.d.ts"
20
- ]
18
+ "include": [ "src/**/*" ]
21
19
  }