136 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict'
/**
* @module parenthesis
*/
function parse (str, opts) {
// pretend non-string parsed per-se
if (typeof str !== 'string') return [str]
var res = [str]
if (typeof opts === 'string' || Array.isArray(opts)) {
opts = {brackets: opts}
}
else if (!opts) opts = {}
var brackets = opts.brackets ? (Array.isArray(opts.brackets) ? opts.brackets : [opts.brackets]) : ['{}', '[]', '()']
var escape = opts.escape || '___'
var flat = !!opts.flat
brackets.forEach(function (bracket) {
// create parenthesis regex
var pRE = new RegExp(['\\', bracket[0], '[^\\', bracket[0], '\\', bracket[1], ']*\\', bracket[1]].join(''))
var ids = []
function replaceToken(token, idx, str){
// save token to res
var refId = res.push(token.slice(bracket[0].length, -bracket[1].length)) - 1
ids.push(refId)
return escape + refId + escape
}
res.forEach(function (str, i) {
var prevStr
// replace paren tokens till theres none
var a = 0
while (str != prevStr) {
prevStr = str
str = str.replace(pRE, replaceToken)
if (a++ > 10e3) throw Error('References have circular dependency. Please, check them.')
}
res[i] = str
})
// wrap found refs to brackets
ids = ids.reverse()
res = res.map(function (str) {
ids.forEach(function (id) {
str = str.replace(new RegExp('(\\' + escape + id + '\\' + escape + ')', 'g'), bracket[0] + '$1' + bracket[1])
})
return str
})
})
var re = new RegExp('\\' + escape + '([0-9]+)' + '\\' + escape)
// transform references to tree
function nest (str, refs, escape) {
var res = [], match
var a = 0
while (match = re.exec(str)) {
if (a++ > 10e3) throw Error('Circular references in parenthesis')
res.push(str.slice(0, match.index))
res.push(nest(refs[match[1]], refs))
str = str.slice(match.index + match[0].length)
}
res.push(str)
return res
}
return flat ? res : nest(res[0], res)
}
function stringify (arg, opts) {
if (opts && opts.flat) {
var escape = opts && opts.escape || '___'
var str = arg[0], prevStr
// pretend bad string stringified with no parentheses
if (!str) return ''
var re = new RegExp('\\' + escape + '([0-9]+)' + '\\' + escape)
var a = 0
while (str != prevStr) {
if (a++ > 10e3) throw Error('Circular references in ' + arg)
prevStr = str
str = str.replace(re, replaceRef)
}
return str
}
return arg.reduce(function f (prev, curr) {
if (Array.isArray(curr)) {
curr = curr.reduce(f, '')
}
return prev + curr
}, '')
function replaceRef(match, idx){
if (arg[idx] == null) throw Error('Reference ' + idx + 'is undefined')
return arg[idx]
}
}
function parenthesis (arg, opts) {
if (Array.isArray(arg)) {
return stringify(arg, opts)
}
else {
return parse(arg, opts)
}
}
parenthesis.parse = parse
parenthesis.stringify = stringify
module.exports = parenthesis