-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
75 lines (59 loc) · 2.13 KB
/
index.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
import escape from 'escape-string-regexp'
const isNil = val => val == null
const isString = val => typeof val === 'string'
const attach = opts => (haystack, needle, attachment) => {
const arr = [needle, attachment]
if (isNil(haystack) || !isString(haystack)) return ''
if (arr.some(isNil) ||
!arr.every(isString) ||
needle.length === 0 ||
attachment.length === 0
) return haystack
const { type, ensureAttached } = opts
const needleEscaped = escape(needle)
let acc = []
return (function recur (subset) {
const locFound = subset.search(needleEscaped)
if (locFound === -1) {
return acc.length ? acc.concat(subset).join('') : subset
}
const locStartNextSubset = locFound + needle.length
const nextSubset = subset.slice(locStartNextSubset)
const accumulateStrPrecedingNextSubset = () =>
acc.concat(subset.slice(0, locStartNextSubset))
if (type === 'prepend') {
const locStartPotential = locFound - attachment.length
// If needle found at 0 then look at last index in accumulator.
const potential = locFound === 0
? acc[acc.length - 1]
: subset.slice(locStartPotential, locFound)
if (ensureAttached && potential === attachment) {
acc = accumulateStrPrecedingNextSubset()
return recur(nextSubset)
}
acc = acc
.concat(subset.slice(0, locFound))
.concat([attachment])
.concat(subset.slice(locFound, locStartNextSubset))
} else {
const locEndPotential = locStartNextSubset + attachment.length
const potential = subset.slice(locStartNextSubset, locEndPotential)
if (ensureAttached && potential === attachment) {
acc = accumulateStrPrecedingNextSubset()
return recur(nextSubset)
}
acc = accumulateStrPrecedingNextSubset().concat([attachment])
}
return recur(nextSubset)
})(haystack)
}
export const prepend = attach({ type: 'prepend' })
export const append = attach({ type: 'append' })
export const ensurePrepended = attach({
type: 'prepend',
ensureAttached: true
})
export const ensureAppended = attach({
type: 'append',
ensureAttached: true
})