rubyfy
Version:
Easily write ruby annotations and output it as HTML.
63 lines (59 loc) • 2.55 kB
JavaScript
module.exports = class Parser {
constructor(opts = {}) {
Object.assign(this, opts, {
openRt: '(', // fullwidth left parenthesis
closeRt: ')', // fullwidth right parenthesis
openRb: '((',
closeRb: '))',
// generated from tools/generate-regex.js
autoRb: /[0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u3005\u30F6\u3400-\u4DBF\u4E00-\u9FFF\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uF900-\uFAFF\uFF10-\uFF19\u{104A0}-\u{104A9}\u{11066}-\u{1106F}\u{110F0}-\u{110F9}\u{11136}-\u{1113F}\u{111D0}-\u{111D9}\u{112F0}-\u{112F9}\u{11450}-\u{11459}\u{114D0}-\u{114D9}\u{11650}-\u{11659}\u{116C0}-\u{116C9}\u{11730}-\u{11739}\u{118E0}-\u{118E9}\u{11C50}-\u{11C59}\u{16A60}-\u{16A69}\u{16B50}-\u{16B59}\u{1D7CE}-\u{1D7FF}\u{1E950}-\u{1E959}\u{20000}-\u{2A6DF}\u{2A700}-\u{2CEAF}\u{2F800}-\u{2FA1F}]/u.source
})
}
parse(text) {
if (text == null) {
return undefined
}
let { openRt, closeRt, openRb, closeRb, autoRb } = this
let regex = new RegExp(
`(?:${openRb}(.*?)${closeRb}|(${autoRb}+)(?!${openRb}(?:.*?)${closeRb}))(?:${openRt}(.*?)${closeRt})?`,
'ug'
)
let parsed = []
let regexResult
let startIndex = 0
let lastIsString = false
let hasRuby
const push = x => {
if (x === '') {
return
}
let curIsString = typeof x === 'string'
if (lastIsString && curIsString) {
parsed[parsed.length - 1] = `${parsed[parsed.length - 1]}${x}`
}
else {
parsed.push(x)
}
lastIsString = curIsString
}
while ((regexResult = regex.exec(text)) != null) {
let [, rb1, rb2, rt] = regexResult
let rb = rb1 && rb1.length ? rb1 : rb2
let { index } = regexResult
let leadingSubstring = text.substring(startIndex, index)
push(leadingSubstring)
startIndex = regex.lastIndex
if (rt && rt.length) {
push({ rb, rt })
hasRuby = true
continue
}
if (rb) {
push(rb)
}
}
push(text.substring(startIndex))
parsed.hasRuby = hasRuby
return parsed
}
}