EN_REPLACEMENT, (m) => '(100% - ' + m + ')') : 100 - Number.parseFloat(num) }) return this.restoreTokens(state) }, flipLength (value) { return config.useCalc ? `calc(100% - ${value})` : value }, save (what, who, replacement, restorer, exclude) { const state = { value: who, store: [], replacement, restorer } state.value = state.value.replace(what, (c) => { if (exclude && exclude.test(c)) { return c } state.store.push(c) return state.replacement }) return state }, restore (state) { let index = 0 const result = state.value.replace(state.restorer, () => state.store[index++]) state.store.length = 0 return result }, saveComments (value) { return this.save(REGEX_COMMENT, value, CHAR_COMMENT_REPLACEMENT, REGEX_COMMENT_REPLACEMENT) }, restoreComments (state) { return this.restore(state) }, saveTokens (value, excludeCalc) { return excludeCalc === true ? this.save(REGEX_TOKENS_WITH_NAME, value, CHAR_TOKEN_REPLACEMENT, REGEX_TOKEN_REPLACEMENT, REGEX_CALC) : this.save(REGEX_TOKENS, value, CHAR_TOKEN_REPLACEMENT, REGEX_TOKEN_REPLACEMENT) }, restoreTokens (state) { return this.restore(state) }, guard (what, who) { const state = { value: who, store: [], offset: tokenId++, token: CHAR_TOKEN_START + tokenId } while (what.test(state.value)) { state.value = state.value.replace(what, (m) => { state.store.push(m) return `${state.token}:${state.store.length}${CHAR_TOKEN_END}` }) } return state }, unguard (state, callback) { const detokenizer = new RegExp('(\\w*?)' + state.token + ':(\\d+)' + CHAR_TOKEN_END, 'i') while (detokenizer.test(state.value)) { state.value = state.value.replace(detokenizer, (match, name, index) => { const value = state.store[index - 1] return typeof callback === 'function' ? name + callback(value, name) : name + value }) } return state.value }, guardHexColors (value) { return this.guard(REGEX_HEX_COLOR, value) }, unguardHexColors (state, callback) { return this.unguard(state, callback) }, guardFunctions (value) { return this.guard(REGEX_FUNCTION, value) }, unguardFunctions (state, callback) { return this.unguard(state, callback) }, trimDirective (value) { return value.replace(REGEX_DIRECTIVE, '') }, regexCache: {}, regexDirective (name) { // /(?:\/\*(?:!)?rtl:ignore(?::)?)([^]*?)(?:\*\/)/img this.regexCache[name] = this.regexCache[name] || new RegExp('(?:\\/\\*\\s*(?:!)?\\s*rtl:' + (name ? escapeRegExp(name) + '(?::)?' : '') + ')([^]*?)(?:\\*\\/)', 'img') return this.regexCache[name] }, regex (what, options) { let expression = '' for (const exp of what) { switch (exp) { case 'percent': expression += `|(${PATTERN_NUMBER}%)` break case 'length': expression += `|(${PATTERN_NUMBER})(?:ex|ch|r?em|vh|vw|vmin|vmax|px|mm|cm|in|pt|pc)?` break case 'number': expression += `|(${PATTERN_NUMBER})` break case 'position': expression += '|(left|center|right|top|bottom)' break case 'calc': expression += `|(calc${PATTERN_TOKEN})` break case 'func': expression += `|(\\w+${PATTERN_TOKEN})` break } } return new RegExp(expression.slice(1), options) }, isLastOfType (node) { let isLast = true let next = node.next() while (next) { if (next.type === node.type) { isLast = false break } next = next.next() } return isLast }, /** * Simple breakable each returning false if the callback returns false * otherwise it returns true */ each (array, callback) { return !array.some((element) => callback(element) === false) } } module.exports.configure = function (configuration) { config = configuration return