wishthis/node_modules/rtlcss/lib/util.js

268 lines
9 KiB
JavaScript
Raw Normal View History

2022-01-21 08:28:41 +00:00
'use strict'
2022-05-29 09:24:36 +00:00
var config
var CHAR_COMMENT_REPLACEMENT = '\uFFFD' // <20>
var CHAR_TOKEN_REPLACEMENT = '\u00A4'// ¤
var CHAR_TOKEN_START = '\u00AB' // «
var CHAR_TOKEN_END = '\u00BB' // »
2022-01-21 08:28:41 +00:00
2022-05-29 09:24:36 +00:00
var REGEX_COMMENT_REPLACEMENT = new RegExp(CHAR_COMMENT_REPLACEMENT, 'ig')
var REGEX_TOKEN_REPLACEMENT = new RegExp(CHAR_TOKEN_REPLACEMENT, 'ig')
2022-01-21 08:28:41 +00:00
2022-05-29 09:24:36 +00:00
var PATTERN_NUMBER = '\\-?(\\d*?\\.\\d+|\\d+)'
var PATTERN_NUMBER_WITH_CALC = '(calc' + CHAR_TOKEN_REPLACEMENT + ')|(' + PATTERN_NUMBER + ')(?!d\\()'
var PATTERN_TOKEN = CHAR_TOKEN_START + '\\d+:\\d+' + CHAR_TOKEN_END // «offset:index»
var PATTERN_TOKEN_WITH_NAME = '\\w*?' + CHAR_TOKEN_START + '\\d+:\\d+' + CHAR_TOKEN_END // «offset:index»
2022-01-21 08:28:41 +00:00
2022-05-29 09:24:36 +00:00
var REGEX_COMMENT = /\/\*[^]*?\*\//igm // none-greedy
var REGEX_DIRECTIVE = /\/\*\s*(?:!)?\s*rtl:[^]*?\*\//img
var REGEX_ESCAPE = /[.*+?^${}()|[\]\\]/g
var REGEX_FUNCTION = /\([^\(\)]+\)/i
var REGEX_HEX_COLOR = /#[a-f0-9]{3,6}/ig
var REGEX_CALC = /calc/
var REGEX_TOKENS = new RegExp(PATTERN_TOKEN, 'ig')
var REGEX_TOKENS_WITH_NAME = new RegExp(PATTERN_TOKEN_WITH_NAME, 'ig')
2022-01-21 08:28:41 +00:00
2022-05-29 09:24:36 +00:00
var REGEX_COMPLEMENT = new RegExp(PATTERN_NUMBER_WITH_CALC, 'i')
var REGEX_NEGATE_ALL = new RegExp(PATTERN_NUMBER_WITH_CALC, 'ig')
var REGEX_NEGATE_ONE = new RegExp(PATTERN_NUMBER_WITH_CALC, 'i')
2022-01-21 08:28:41 +00:00
2022-05-29 09:24:36 +00:00
var DEFAULT_STRING_MAP_OPTIONS = { scope: '*', ignoreCase: true }
var TOKEN_ID = 0
2022-01-21 08:28:41 +00:00
function compare (what, to, ignoreCase) {
2022-05-29 09:24:36 +00:00
if (ignoreCase) {
return what.toLowerCase() === to.toLowerCase()
}
return what === to
2022-01-21 08:28:41 +00:00
}
function escapeRegExp (string) {
return string.replace(REGEX_ESCAPE, '\\$&')
}
module.exports = {
2022-05-29 09:24:36 +00:00
extend: function (dest, src) {
2022-01-21 08:28:41 +00:00
if (typeof dest === 'undefined' || typeof dest !== 'object') {
dest = {}
}
2022-05-29 09:24:36 +00:00
for (var prop in src) {
if (!dest.hasOwnProperty(prop)) {
2022-01-21 08:28:41 +00:00
dest[prop] = src[prop]
}
}
return dest
},
2022-05-29 09:24:36 +00:00
swap: function (value, a, b, options) {
var expr = escapeRegExp(a) + '|' + escapeRegExp(b)
2022-01-21 08:28:41 +00:00
options = options || DEFAULT_STRING_MAP_OPTIONS
2022-05-29 09:24:36 +00:00
var greedy = options.hasOwnProperty('greedy') ? options.greedy : config.greedy
if (!greedy) {
expr = '\\b(' + expr + ')\\b'
}
var flags = options.ignoreCase ? 'img' : 'mg'
return value.replace(new RegExp(expr, flags), function (m) { return compare(m, a, options.ignoreCase) ? b : a })
2022-01-21 08:28:41 +00:00
},
2022-05-29 09:24:36 +00:00
swapLeftRight: function (value) {
2022-01-21 08:28:41 +00:00
return this.swap(value, 'left', 'right')
},
2022-05-29 09:24:36 +00:00
swapLtrRtl: function (value) {
2022-01-21 08:28:41 +00:00
return this.swap(value, 'ltr', 'rtl')
},
2022-05-29 09:24:36 +00:00
applyStringMap: function (value, isUrl) {
var result = value
for (var x = 0; x < config.stringMap.length; x++) {
var map = config.stringMap[x]
var options = this.extend(map.options, DEFAULT_STRING_MAP_OPTIONS)
2022-01-21 08:28:41 +00:00
if (options.scope === '*' || (isUrl && options.scope === 'url') || (!isUrl && options.scope === 'selector')) {
if (Array.isArray(map.search) && Array.isArray(map.replace)) {
2022-05-29 09:24:36 +00:00
for (var mapIndex = 0; mapIndex < map.search.length; mapIndex++) {
2022-01-21 08:28:41 +00:00
result = this.swap(result, map.search[mapIndex], map.replace[mapIndex % map.search.length], options)
}
} else {
result = this.swap(result, map.search, map.replace, options)
}
if (map.exclusive === true) {
break
}
}
}
return result
},
2022-05-29 09:24:36 +00:00
negate: function (value) {
var state = this.saveTokens(value)
state.value = state.value.replace(REGEX_NEGATE_ONE, function (num) {
return REGEX_TOKEN_REPLACEMENT.test(num) ? num.replace(REGEX_TOKEN_REPLACEMENT, function (m) { return '(-1*' + m + ')' }) : parseFloat(num, 10) * -1
2022-01-21 08:28:41 +00:00
})
return this.restoreTokens(state)
},
2022-05-29 09:24:36 +00:00
negateAll: function (value) {
var state = this.saveTokens(value)
state.value = state.value.replace(REGEX_NEGATE_ALL, function (num) {
return REGEX_TOKEN_REPLACEMENT.test(num) ? num.replace(REGEX_TOKEN_REPLACEMENT, function (m) { return '(-1*' + m + ')' }) : parseFloat(num, 10) * -1
2022-01-21 08:28:41 +00:00
})
return this.restoreTokens(state)
},
2022-05-29 09:24:36 +00:00
complement: function (value) {
var state = this.saveTokens(value)
state.value = state.value.replace(REGEX_COMPLEMENT, function (num) {
return REGEX_TOKEN_REPLACEMENT.test(num) ? num.replace(REGEX_TOKEN_REPLACEMENT, function (m) { return '(100% - ' + m + ')' }) : 100 - parseFloat(num, 10)
2022-01-21 08:28:41 +00:00
})
return this.restoreTokens(state)
},
2022-05-29 09:24:36 +00:00
flipLength: function (value) {
return config.useCalc ? 'calc(100% - ' + value + ')' : value
2022-01-21 08:28:41 +00:00
},
2022-05-29 09:24:36 +00:00
save: function (what, who, replacement, restorer, exclude) {
var state = {
2022-01-21 08:28:41 +00:00
value: who,
store: [],
2022-05-29 09:24:36 +00:00
replacement: replacement,
restorer: restorer
2022-01-21 08:28:41 +00:00
}
2022-05-29 09:24:36 +00:00
state.value = state.value.replace(what, function (c) {
2022-01-21 08:28:41 +00:00
if (exclude && c.match(exclude)) {
return c
2022-05-29 09:24:36 +00:00
} else {
state.store.push(c); return state.replacement
2022-01-21 08:28:41 +00:00
}
})
return state
},
2022-05-29 09:24:36 +00:00
restore: function (state) {
var index = 0
var result = state.value.replace(state.restorer, function () {
2022-01-21 08:28:41 +00:00
return state.store[index++]
})
state.store.length = 0
return result
},
2022-05-29 09:24:36 +00:00
saveComments: function (value) {
2022-01-21 08:28:41 +00:00
return this.save(REGEX_COMMENT, value, CHAR_COMMENT_REPLACEMENT, REGEX_COMMENT_REPLACEMENT)
},
2022-05-29 09:24:36 +00:00
restoreComments: function (state) {
2022-01-21 08:28:41 +00:00
return this.restore(state)
},
2022-05-29 09:24:36 +00:00
saveTokens: function (value, excludeCalc) {
2022-01-21 08:28:41 +00:00
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)
},
2022-05-29 09:24:36 +00:00
restoreTokens: function (state) {
2022-01-21 08:28:41 +00:00
return this.restore(state)
},
2022-05-29 09:24:36 +00:00
guard: function (what, who, indexed) {
var state = {
2022-01-21 08:28:41 +00:00
value: who,
store: [],
2022-05-29 09:24:36 +00:00
offset: TOKEN_ID++,
token: CHAR_TOKEN_START + TOKEN_ID,
2022-01-21 08:28:41 +00:00
indexed: indexed === true
}
if (state.indexed === true) {
while (what.test(state.value)) {
2022-05-29 09:24:36 +00:00
state.value = state.value.replace(what, function (m) { state.store.push(m); return state.token + ':' + state.store.length + CHAR_TOKEN_END })
2022-01-21 08:28:41 +00:00
}
} else {
2022-05-29 09:24:36 +00:00
state.value = state.value.replace(what, function (m) { state.store.push(m); return state.token + CHAR_TOKEN_END })
2022-01-21 08:28:41 +00:00
}
return state
},
2022-05-29 09:24:36 +00:00
unguard: function (state, callback) {
2022-01-21 08:28:41 +00:00
if (state.indexed === true) {
2022-05-29 09:24:36 +00:00
var detokenizer = new RegExp('(\\w*?)' + state.token + ':(\\d+)' + CHAR_TOKEN_END, 'i')
2022-01-21 08:28:41 +00:00
while (detokenizer.test(state.value)) {
2022-05-29 09:24:36 +00:00
state.value = state.value.replace(detokenizer, function (match, name, index) {
var value = state.store[index - 1]
if (typeof callback === 'function') {
return name + callback(value, name)
}
return name + value
2022-01-21 08:28:41 +00:00
})
}
return state.value
2022-05-29 09:24:36 +00:00
} else {
return state.value.replace(new RegExp('(\\w*?)' + state.token + CHAR_TOKEN_END, 'i'), function (match, name) {
var value = state.store.shift()
if (typeof callback === 'function') {
return name + callback(value, name)
}
return name + value
})
2022-01-21 08:28:41 +00:00
}
},
2022-05-29 09:24:36 +00:00
guardHexColors: function (value) {
2022-01-21 08:28:41 +00:00
return this.guard(REGEX_HEX_COLOR, value, true)
},
2022-05-29 09:24:36 +00:00
unguardHexColors: function (state, callback) {
2022-01-21 08:28:41 +00:00
return this.unguard(state, callback)
},
2022-05-29 09:24:36 +00:00
guardFunctions: function (value) {
2022-01-21 08:28:41 +00:00
return this.guard(REGEX_FUNCTION, value, true)
},
2022-05-29 09:24:36 +00:00
unguardFunctions: function (state, callback) {
2022-01-21 08:28:41 +00:00
return this.unguard(state, callback)
},
2022-05-29 09:24:36 +00:00
trimDirective: function (value) {
2022-01-21 08:28:41 +00:00
return value.replace(REGEX_DIRECTIVE, '')
},
regexCache: {},
2022-05-29 09:24:36 +00:00
regexDirective: function (name) {
2022-01-21 08:28:41 +00:00
// /(?:\/\*(?:!)?rtl:ignore(?::)?)([^]*?)(?:\*\/)/img
this.regexCache[name] = this.regexCache[name] || new RegExp('(?:\\/\\*\\s*(?:!)?\\s*rtl:' + (name ? escapeRegExp(name) + '(?::)?' : '') + ')([^]*?)(?:\\*\\/)', 'img')
return this.regexCache[name]
},
2022-05-29 09:24:36 +00:00
regex: function (what, options) {
2022-01-21 08:28:41 +00:00
what = what || []
2022-05-29 09:24:36 +00:00
var expression = ''
for (var x = 0; x < what.length; x++) {
switch (what[x]) {
2022-01-21 08:28:41 +00:00
case 'percent':
2022-05-29 09:24:36 +00:00
expression += '|(' + PATTERN_NUMBER + '%)'
2022-01-21 08:28:41 +00:00
break
case 'length':
2022-05-29 09:24:36 +00:00
expression += '|(' + PATTERN_NUMBER + ')(?:ex|ch|r?em|vh|vw|vmin|vmax|px|mm|cm|in|pt|pc)?'
2022-01-21 08:28:41 +00:00
break
case 'number':
2022-05-29 09:24:36 +00:00
expression += '|(' + PATTERN_NUMBER + ')'
2022-01-21 08:28:41 +00:00
break
case 'position':
expression += '|(left|center|right|top|bottom)'
break
case 'calc':
2022-05-29 09:24:36 +00:00
expression += '|(calc' + PATTERN_TOKEN + ')'
2022-01-21 08:28:41 +00:00
break
}
}
return new RegExp(expression.slice(1), options)
},
2022-05-29 09:24:36 +00:00
isLastOfType: function (node) {
var isLast = true
var next = node.next()
2022-01-21 08:28:41 +00:00
while (next) {
2022-05-29 09:24:36 +00:00
if (next && next.type === node.type) {
2022-01-21 08:28:41 +00:00
isLast = false
break
}
next = next.next()
}
return isLast
},
/**
* Simple breakable each: returning false in the callback will break the loop
* returns false if the loop was broken, otherwise true
*/
2022-05-29 09:24:36 +00:00
each: function (array, callback) {
for (var len = 0; len < array.length; len++) {
if (callback(array[len]) === false) {
2022-01-21 08:28:41 +00:00
return false
}
}
return true
}
}
module.exports.configure = function (configuration) {
config = configuration
return this
}