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 +10 -7
- package/dist/bundle.dev.js +112 -69
- package/package.json +9 -10
- package/rollup.config.js +2 -1
- package/src/curry.ts +57 -11
- package/src/index.ts +1 -0
- package/src/quick.ts +8 -8
- package/src/safe.ts +72 -84
- package/src/types.ts +9 -2
- package/src/uncurry.ts +11 -0
- package/tsconfig.json +2 -4
package/README.md
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
HI! Meet pepka - JavaScript/TypeScript functional programming
|
|
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
|
|
9
|
-
- Most flexible types
|
|
10
|
-
- Tree-shakeble
|
|
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
|
|
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.
|
package/dist/bundle.dev.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __ = (
|
|
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 =
|
|
67
|
-
const qassoc =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
});
|
|
175
|
-
const bind =
|
|
176
|
-
const
|
|
177
|
-
const
|
|
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 =
|
|
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 =
|
|
194
|
-
const subtract =
|
|
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 =
|
|
211
|
-
const tap =
|
|
212
|
-
const append =
|
|
213
|
-
const split =
|
|
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 =
|
|
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 =
|
|
229
|
-
const genBy =
|
|
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 =
|
|
244
|
-
const lt =
|
|
245
|
-
const gte =
|
|
246
|
-
const lte =
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
const
|
|
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 =
|
|
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 =
|
|
294
|
+
const assoc = curry3((prop, v, obj) => ({
|
|
261
295
|
...obj,
|
|
262
296
|
[prop]: v
|
|
263
297
|
}));
|
|
264
|
-
const assocPath =
|
|
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 =
|
|
268
|
-
const any =
|
|
269
|
-
const allPass =
|
|
270
|
-
const anyPass =
|
|
271
|
-
const prop =
|
|
272
|
-
const propEq =
|
|
273
|
-
const propsEq =
|
|
274
|
-
const pathOr =
|
|
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 =
|
|
279
|
-
const pathsEq =
|
|
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) ?
|
|
334
|
+
return typed_arr_re.test(t) ? s.constructor.from(s) : s;
|
|
299
335
|
}
|
|
300
336
|
};
|
|
301
|
-
const
|
|
302
|
-
const
|
|
303
|
-
const
|
|
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 =
|
|
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 =
|
|
315
|
-
const join =
|
|
316
|
-
const map =
|
|
317
|
-
const forEach =
|
|
318
|
-
const both =
|
|
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 =
|
|
339
|
-
const filter =
|
|
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 =
|
|
348
|
-
const mergeDeep =
|
|
349
|
-
const mergeDeepX =
|
|
350
|
-
const mergeDeepAdd =
|
|
351
|
-
const overProp =
|
|
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 =
|
|
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
|
|
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 =
|
|
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.
|
|
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": "^
|
|
59
|
-
"ava": "^
|
|
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": "^
|
|
61
|
+
"dts-bundle-generator": "^7.1.0",
|
|
63
62
|
"nyc": "^15.1.0",
|
|
64
|
-
"rollup": "^
|
|
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.
|
|
71
|
-
"ts-node": "^10.
|
|
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
|
|
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:
|
|
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
|
-
|
|
4
|
+
export const __ = Symbol('Placeholder') as A.x
|
|
3
5
|
|
|
4
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
49
|
-
(...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
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 =
|
|
7
|
-
export const qassoc =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
-
)
|
|
55
|
+
)
|
|
55
56
|
|
|
56
|
-
export const bind =
|
|
57
|
+
export const bind = curry2<AnyFunc>(
|
|
57
58
|
(fn: AnyFunc, context: any) => fn.bind(context)
|
|
58
59
|
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
|
|
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 =
|
|
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 =
|
|
83
|
-
export const subtract =
|
|
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 =
|
|
100
|
-
export const tap =
|
|
101
|
-
export const append =
|
|
102
|
-
export const split =
|
|
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 =
|
|
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 =
|
|
121
|
+
export const intersection = curry2(
|
|
120
122
|
(xs1: any[], xs2: any[]) => xs1.filter(flip(includes)(xs2))
|
|
121
123
|
)
|
|
122
|
-
export const genBy =
|
|
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 =
|
|
148
|
-
|
|
149
|
-
)
|
|
150
|
-
export const
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
export const
|
|
154
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
201
|
-
export const any =
|
|
202
|
-
export const allPass =
|
|
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 =
|
|
192
|
+
export const anyPass = curry2(
|
|
206
193
|
(preds: Cond[], x: any) => preds.some((pred) => pred(x))
|
|
207
194
|
)
|
|
208
|
-
export const prop =
|
|
209
|
-
|
|
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 =
|
|
199
|
+
export const propsEq = curry3(
|
|
215
200
|
(key: string, o1: any, o2: AnyObject) => equals(o1[key], o2[key])
|
|
216
201
|
)
|
|
217
|
-
export const pathOr =
|
|
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 =
|
|
219
|
+
export const pathEq = curry3(
|
|
235
220
|
(_path: string[], value: any, o: AnyObject) => equals(path(_path, o), value)
|
|
236
221
|
)
|
|
237
|
-
export const pathsEq =
|
|
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) ?
|
|
243
|
+
return typed_arr_re.test(t) ? s.constructor.from(s) : s
|
|
258
244
|
}
|
|
259
245
|
}
|
|
260
|
-
export const
|
|
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 =
|
|
252
|
+
export const pickBy = curry2(
|
|
265
253
|
(cond: Cond, o: AnyObject) => filter(cond, o)
|
|
266
254
|
)
|
|
267
|
-
export const pick =
|
|
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 =
|
|
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 =
|
|
278
|
+
export const concat = curry2(
|
|
291
279
|
((a, b) => a.concat(b)) as Concat
|
|
292
280
|
)
|
|
293
|
-
export const join =
|
|
281
|
+
export const join = curry2(
|
|
294
282
|
(delimeter: string, arr: string[]) => arr.join(delimeter)
|
|
295
283
|
)
|
|
296
|
-
export const map =
|
|
284
|
+
export const map = curry2(
|
|
297
285
|
(pipe: (s: any) => any, arr: any[]) => arr.map(pipe)
|
|
298
286
|
)
|
|
299
|
-
export const forEach =
|
|
287
|
+
export const forEach = curry2(
|
|
300
288
|
(pipe: (s: any) => any, arr: any[]) => arr.forEach(pipe)
|
|
301
289
|
)
|
|
302
|
-
export const both =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
334
|
+
export const mergeShallow = curry2(
|
|
347
335
|
(o1: AnyObject, o2: AnyObject): AnyObject =>
|
|
348
336
|
Object.assign({}, o1, o2)
|
|
349
337
|
)
|
|
350
|
-
export const mergeDeep =
|
|
338
|
+
export const mergeDeep = curry2(
|
|
351
339
|
(a: AnyObject, b: AnyObject) => qmergeDeep(clone(a), clone(b))
|
|
352
340
|
)
|
|
353
|
-
export const mergeDeepX =
|
|
341
|
+
export const mergeDeepX = curry2(
|
|
354
342
|
(a: AnyObject, b: AnyObject) => qmergeDeepX(clone(a), clone(b))
|
|
355
343
|
)
|
|
356
|
-
export const mergeDeepAdd =
|
|
344
|
+
export const mergeDeepAdd = curry2(
|
|
357
345
|
(a: AnyObject, b: AnyObject) => qmergeDeepAdd(clone(a), clone(b))
|
|
358
346
|
)
|
|
359
|
-
export const overProp =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
}
|