-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfn.js
208 lines (152 loc) · 4.07 KB
/
fn.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// utils
const pipe =
(...fns) =>
value =>
fns.reduce((acc, fn) => fn(acc), value)
const identity = x => x
const not = x => !x
const value = x => () => x
const truthy = value(true)
const falsy = value(false)
const branch =
(cond, p1 = identity, p2 = identity) =>
(...args) =>
cond(...args) ? p1(...args) : p2(...args)
const log = x => (console.log(x), x)
// object
const update = (key, fn) => obj =>
Object.assign({}, obj, { [key]: fn(obj[key], key, obj) })
// array
const length = arr => arr.length
const includes = arr => item => arr.includes(item)
const slice =
(start = 0, end) =>
arr =>
arr.slice(start, end)
const reverse = arr => arr.reverse()
const sort = fn => arr => arr.sort(fn)
const map = fn => arr => arr.map(fn)
const filter = fn => arr => arr.filter(fn)
const flat = arr => arr.flat()
// NOTE improved to be usable with string args, too
// const reduce = (fn, value) => arr => arr.reduce(fn, value)
const reduce = (fn, value) => arr => Array.prototype.reduce.call(arr, fn, value)
const partition = fn =>
reduce((acc, v) => (fn(v) ? acc[0].push(v) : acc[1].push(v), acc), [[], []])
const concat = (arr, v) => arr.concat(v)
// string
const toLowerCase = str => str.toLowerCase()
const toUpperCase = str => str.toUpperCase()
const capitalize = str => `${str.charAt(0).toUpperCase()}${str.slice(1)}`
const prefix = prefix => str => `${prefix}${str}`
const padStart = (length, padString) => str => str.padStart(length, padString)
const split = ch => str => str.split(ch)
const join = ch => arr => arr.join(ch)
const toCharArray = split('')
const pluralize = (count, name) => `${count} ${name + (count > 1 ? 's' : '')}`
const replace = (target, replacement) => str => str.replace(target, replacement)
const reverseStr = pipe(toCharArray, reverse, join(''))
// pipe(reverseStr, replace(reverseStr(target), reverseStr(replacement)), reverseStr)
const replaceLast = (target, replacement) => str => {
const index = str.lastIndexOf(',')
return index >= 0
? str.slice(0, index) + replacement + str.slice(index + target.length)
: str
}
const traverseStr = fn => pipe(toCharArray, map(fn), join(''))
const getWords = split(/\s+/)
// REVIEW should this be responsible for joining the words back?
const mapWords = fn => pipe(getWords, map(fn), join(' '))
// math
const clamp = (min, max) => n => Math.min(max, Math.max(min, n))
const add = (a, b) => a + b
const substract = (a, b) => a - b
const sub = substract
const difference = (n1, n2) => Math.abs(sub(n1, n2))
const multiply = a => b => a * b
const mult = multiply
const eq = a => b => a === b
const neq = a => b => a !== b
const gt = right => left => left > right
const gte = right => left => left >= right
const lt = right => left => left < right
const lte = right => left => left <= right
const possitive = n => Math.max(0, n)
const toBase = base => n => n.toString(base)
const toBinary = toBase(2)
const toOctal = toBase(8)
const toHex = toBase(16)
const sum = reduce(add, 0)
const sumLt = n => pipe(sum, lt(n))
const divisionBy = divisor => dividend => dividend / divisor
const avg = arr => pipe(sum, divisionBy(arr.length))(arr)
const numberToDigits = pipe(String, toCharArray, map(Number))
const digitsToNumber = pipe(join(''), Number)
// advanced (use at your own risk)
// REVIEW this is iterating over the entire array
const takeWhile = cond =>
reduce((acc, v) => (cond(v) ? concat(acc, v) : acc), [])
const countUntil = n => m => (n -= m) > 0
module.exports = {
pipe,
identity,
not,
value,
truthy,
falsy,
branch,
log,
update,
length,
includes,
slice,
reverse,
sort,
map,
filter,
flat,
reduce,
partition,
concat,
toLowerCase,
toUpperCase,
capitalize,
prefix,
padStart,
split,
join,
toCharArray,
pluralize,
replace,
reverseStr,
replaceLast,
traverseStr,
getWords,
mapWords,
clamp,
add,
substract,
sub,
difference,
multiply,
mult,
eq,
neq,
gt,
gte,
lt,
lte,
possitive,
toBase,
toBinary,
toOctal,
toHex,
sum,
sumLt,
divisionBy,
avg,
numberToDigits,
digitsToNumber,
takeWhile,
countUntil,
}