/** * @param {string} s - input string * @param {RegExp} re - regular expression for attributes * @param {number} [limit=65536] - limit of attribute count * @return {{attr: [string, string][]}|null} */ function parseAttrs(s, re, limit=65536) { let count = 0; /** @type {string[]} */ const classes = []; /** @type {[string, string][]} */ const attrs = []; let m; while ((m = re.exec(s)) && count=0; i--) { const token = tokens[i]; if (token.level === level) return token; } return null; } /** * @param {Array} arr * @param {number} startIndex * @param {function(any, number): boolean} test * @param {function(any, number): boolean} [constraint] * @return {any|undefined} element; */ function find(arr, startIndex, test, constraint=()=>true) { for (let i=startIndex, len=arr.length; itrue) { for (let i=startIndex; i>=0; i--) { const elm = arr[i]; if (!constraint(elm)) return; if (test(elm)) return elm; } return; } /** * @param {Array} arr * @param {number} startIndex * @param {function(any, number): boolean} test * @param {function(any, number): boolean} [constraint] * @return {number} index ?? -1; */ function rfindIndex(arr, startIndex, test, constraint=()=>true) { for (let i=startIndex; i>=0; i--) { const elm = arr[i]; if (!constraint(elm)) return -1; if (test(elm)) return i; } return -1; } /** * @param {Token} dst - Destination Token * @param {Token} src - Source Token */ function attrConcat(dst, src) { const {attrs} = src; if (attrs) attrs.forEach(attr => dst.attrPush(attr)); } module.exports = { parseAttrs, findOpenToken, find, rfind, rfindIndex, attrConcat, };