-
Notifications
You must be signed in to change notification settings - Fork 11
/
index.js
106 lines (98 loc) · 4.17 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
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
const { sentences } = require('sbd')
const getTweetLength = require('../getTweetLength')
const sliceTweet = require('../sliceTweet')
module.exports = split
const limit = 280
const splitStr = '[...]'
const ellipsis = '…'
function split(text, options = {}) {
const { numbering } = options
let globalAccLength = 0
return text
.split(splitStr)
.map(textChunk => {
const tweets = sentences(textChunk)
.reduce(
(acc, sentence) => {
const lastIndex = acc.length - 1
const currentNumber = globalAccLength + acc.length
const nextNumber = currentNumber + 1
const extraNumberWidth = 2 // "/" plus <space>
const nextNumberWidth =
nextNumber.toString().length + extraNumberWidth
const lastTweet = acc[lastIndex]
const concatCandidate = joinSentences(
numbering ? lastTweet || `${currentNumber}/` : lastTweet,
sentence
)
// If the current sentence fits the last tweet.
if (getTweetLength(concatCandidate) <= limit) {
// Add the sentence to the last tweet.
acc[lastIndex] = concatCandidate
// If the current sentence is bigger than the tweet limit
} else if (
getTweetLength(sentence) + (numbering ? nextNumberWidth : 0) >
limit
) {
let indexShift = 0
let rest = concatCandidate
while (getTweetLength(rest) > limit) {
// Split the last tweet + sentence into two chunks 140 symbols
// minus 2 reserved for the ellipsis.
const slicePos = limit - 1 // - 2 because ellipses weight is equal 2 TODO change number 2 to ellipsis weight
const [head, tail] = sliceTweet(rest, slicePos)
// Find the last space position excluding the number's space
let lastSpaceIndex
const numberingCaptures = head.match(/^(\d+\/\s)(.+)$/)
// If the head has number (\d+\/\s)
if (numberingCaptures) {
// Find the last space index excluding the number's space
const [, number, headWithoutNumber] = numberingCaptures
const index = headWithoutNumber.lastIndexOf(' ')
lastSpaceIndex = index === -1 ? index : number.length + index
} else {
lastSpaceIndex = head.lastIndexOf(' ')
}
if (lastSpaceIndex !== -1) {
const tweet = head.slice(0, lastSpaceIndex)
const leftover = head.slice(lastSpaceIndex)
acc[lastIndex + indexShift] = `${tweet}…`
rest = `${
numbering ? `${currentNumber + indexShift + 1}/ ` : ''
}…${(leftover + tail).trim()}`
} else {
// If the string has no spaces.
// Cut off the last symbol in order to give space for the ellipsis
// const tweet = head.slice(0, limit - 2) // TODO change number 2 to ellipsis weight
// const leftover = head.slice(lastSpaceIndex)
const [tweet, leftover] = sliceTweet(
head,
limit - getTweetLength(ellipsis)
)
acc[lastIndex + indexShift] = `${tweet}${ellipsis}`
rest = `${
numbering ? `${currentNumber + indexShift + 1}/ ` : ''
}${ellipsis}${leftover}${tail}`
}
indexShift++
}
acc[lastIndex + indexShift] = rest
// Otherwise
} else {
// Push the sentence as an individual tweet.
acc.push(`${numbering ? `${nextNumber}/ ` : ''}${sentence}`)
}
return acc
},
['']
)
.filter(str => str)
globalAccLength += tweets.length
return tweets
})
.reduce((acc, chunkTweets) => acc.concat(chunkTweets), [])
.filter(str => str)
}
function joinSentences(a, b) {
return ((a && [a]) || []).concat(b).join(' ')
}