UNPKG

stylelint-declaration-strict-value

Version:

Specify properties for which a variable, function, keyword or value must be used

1 lines 201 kB
{"version":3,"file":"index.cjs","sources":["../node_modules/shortcss/lib/list.js","../node_modules/css-shorthand-properties/index.js","../node_modules/shortcss/lib/index.js","../node_modules/postcss-value-parser/lib/parse.js","../node_modules/postcss-value-parser/lib/walk.js","../node_modules/postcss-value-parser/lib/stringify.js","../node_modules/postcss-value-parser/lib/unit.js","../node_modules/postcss-value-parser/lib/index.js","../node_modules/css-values/dist/index.js","../node_modules/ends-with/index.js","../src/defaults.ts","../src/lib/validation.ts","../src/index.ts"],"sourcesContent":["var SPACES = [' ', '\\n', '\\t'];\nvar COMMAS = [','];\n\nvar list = module.exports = {\n\n split: function(string, separators, last) {\n var array = [];\n var current = '';\n var split = false;\n\n var func = 0;\n var quote = false;\n var escape = false;\n\n for ( var i = 0; i < string.length; i++ ) {\n var letter = string[i];\n\n if ( quote ) {\n if ( escape ) {\n escape = false;\n } else if ( letter === '\\\\' ) {\n escape = true;\n } else if ( letter === quote ) {\n quote = false;\n }\n } else if ( letter === '\"' || letter === \"'\" ) {\n quote = letter;\n } else if ( letter === '(' ) {\n func += 1;\n } else if ( letter === ')' ) {\n if ( func > 0 ) func -= 1;\n } else if ( func === 0 ) {\n if ( separators.indexOf(letter) !== -1 ) split = true;\n }\n\n if ( split ) {\n if ( current !== '' ) array.push(current.trim());\n current = '';\n split = false;\n } else {\n current += letter;\n }\n }\n\n if ( last || current !== '' ) array.push(current.trim());\n return array;\n },\n\n space: function(string) {\n return list.split(string, SPACES);\n },\n\n comma: function(string) {\n return list.split(string, COMMAS, true);\n }\n\n};\n","/*!\n * https://github.com/gilmoreorless/css-shorthand-properties\n * MIT Licensed: https://gilmoreorless.mit-license.org/\n */\n(function (exports) {\n /**\n * Data collated from multiple W3C specs: https://www.w3.org/Style/CSS/current-work\n * Only specs that are Candidate Recommendations or better are counted, with the\n * exception of some Working Drafts that have a lot of traction in browser implementations.\n * So far the WD specs included here are Animation and Transitions.\n *\n * @type {Object}\n */\n var props = exports.shorthandProperties = {\n // CSS 2.1: https://www.w3.org/TR/CSS2/propidx.html\n 'list-style': ['-type', '-position', '-image'],\n 'margin': ['-top', '-right', '-bottom', '-left'],\n 'outline': ['-width', '-style', '-color'],\n 'padding': ['-top', '-right', '-bottom', '-left'],\n\n // CSS Backgrounds and Borders Module Level 3: https://www.w3.org/TR/css3-background/\n 'background': ['-image', '-position', '-size', '-repeat', '-origin', '-clip', '-attachment', '-color'],\n 'background-position': ['-x', '-y'], // Not found in the spec, but already implemented by every stable browser\n 'border': ['-width', '-style', '-color'],\n 'border-color': ['border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color'],\n 'border-style': ['border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style'],\n 'border-width': ['border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'],\n 'border-top': ['-width', '-style', '-color'],\n 'border-right': ['-width', '-style', '-color'],\n 'border-bottom': ['-width', '-style', '-color'],\n 'border-left': ['-width', '-style', '-color'],\n 'border-radius': ['border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius'],\n 'border-image': ['-source', '-slice', '-width', '-outset', '-repeat'],\n\n // CSS Fonts Module Level 3: https://www.w3.org/TR/css3-fonts/\n 'font': ['-style', '-variant', '-weight', '-stretch', '-size', 'line-height', '-family'],\n 'font-variant': ['-ligatures', '-alternates', '-caps', '-numeric', '-east-asian'],\n\n // CSS Flexible Box Layout Module Level 1: https://www.w3.org/TR/css3-flexbox-1/\n 'flex': ['-grow', '-shrink', '-basis'],\n 'flex-flow': ['flex-direction', 'flex-wrap'],\n\n // CSS Grid Layout Module Level 1: https://www.w3.org/TR/css-grid-1/\n 'grid': ['-template-rows', '-template-columns', '-template-areas', '-auto-rows', '-auto-columns', '-auto-flow'],\n 'grid-template': ['-rows', '-columns', '-areas'],\n 'grid-row': ['-start', '-end'],\n 'grid-column': ['-start', '-end'],\n 'grid-area': ['grid-row-start', 'grid-column-start', 'grid-row-end', 'grid-column-end'],\n 'grid-gap': ['grid-row-gap', 'grid-column-gap'],\n\n // CSS Masking Module Level 1: https://www.w3.org/TR/css-masking/\n 'mask': ['-image', '-mode', '-position', '-size', '-repeat', '-origin', '-clip'],\n 'mask-border': ['-source', '-slice', '-width', '-outset', '-repeat', '-mode'],\n\n // CSS Multi-column Layout Module: https://www.w3.org/TR/css3-multicol/\n 'columns': ['column-width', 'column-count'],\n 'column-rule': ['-width', '-style', '-color'],\n\n // CSS Scroll Snap Module Level 1: https://www.w3.org/TR/css-scroll-snap-1/\n 'scroll-padding': ['-top', '-right', '-bottom', '-left'],\n 'scroll-padding-block': ['-start', '-end'],\n 'scroll-padding-inline': ['-start', '-end'],\n 'scroll-snap-margin': ['-top', '-right', '-bottom', '-left'],\n 'scroll-snap-margin-block': ['-start', '-end'],\n 'scroll-snap-margin-inline': ['-start', '-end'],\n\n // CSS Speech Module: https://www.w3.org/TR/css3-speech/\n 'cue': ['-before', '-after'],\n 'pause': ['-before', '-after'],\n 'rest': ['-before', '-after'],\n\n // CSS Text Decoration Module Level 3: https://www.w3.org/TR/css-text-decor-3/\n 'text-decoration': ['-line', '-style', '-color'],\n 'text-emphasis': ['-style', '-color'],\n\n // CSS Animations (WD): https://www.w3.org/TR/css3-animations\n 'animation': ['-name', '-duration', '-timing-function', '-delay', '-iteration-count', '-direction', '-fill-mode', '-play-state'],\n\n // CSS Transitions (WD): https://www.w3.org/TR/css3-transitions/\n 'transition': ['-property', '-duration', '-timing-function', '-delay'],\n };\n\n /**\n * Check if a CSS property is a shorthand value\n * @param {string} property CSS property name\n * @return {boolean} True if the property is a shorthand value\n */\n exports.isShorthand = function (property) {\n return props.hasOwnProperty(property);\n };\n\n /**\n * Expand a shorthand property into an array of longhand properties\n * @param {string} property CSS property name\n * @param {boolean} recurse Expand sub-properties, when applicable - default false\n * @return {array} List of longhand properties, or the original property if it's not a shorthand\n */\n exports.expand = function (property, recurse) {\n if (!props.hasOwnProperty(property)) {\n return [property];\n }\n return props[property].map(function (p) {\n var longhand = p.substr(0, 1) === '-' ? property + p : p;\n return recurse ? exports.expand(longhand, recurse) : longhand;\n });\n };\n})((function (root) {\n // CommonJS\n if (typeof module !== 'undefined' && module.exports !== undefined) return module.exports;\n // Global `cssShorthandProps`\n return (root.cssShorthandProps = {});\n})(this));\n","var ASSERT = require('assert');\nvar list = require('./list');\nvar props = require('css-shorthand-properties').shorthandProperties;\n\nexports.isShorthand = isShorthand;\nexports.expand = expand;\n\n/**\n * Expand a property to an array of parts or property and value to object\n *\n * @param {string} property\n * @param {?string} value\n * @param {?boolean} recurse\n * @returns {Array|Object}\n */\nfunction expand(property, value, recurse) {\n ASSERT(arguments.length, 'property argument is required');\n\n if (arguments.length < 3) {\n if (typeof value === 'boolean') {\n recurse = value;\n value = undefined;\n } else {\n recurse = true;\n }\n }\n\n var undefvalue = typeof value === 'undefined';\n\n return undefvalue?\n expandAsArray(property, recurse)\n : expandAsObject(property, value, recurse);\n}\n\nfunction expandAsArray(property, recurse) {\n if (!props.hasOwnProperty(property)) {\n return [property];\n }\n\n return props[property]\n .map(function (p) {\n var longhand = p.substr(0, 1) === '-' ? property + p : p;\n return recurse ? expand(longhand, recurse) : longhand;\n })\n .reduce(function (res, cur) {\n return res.concat(cur);\n }, []);\n}\n\n/**\n * expandAsObject\n *\n * @param {string} property - Source property name\n * @param {string|string[]} value - Source property value\n * @param {boolean} recurse - Flag to expand recursively\n * @return {Object} - Resulting object\n */\nfunction expandAsObject(property, value, recurse) {\n var res = {};\n if (!props.hasOwnProperty(property)) {\n res[property] = value;\n return res;\n }\n\n var subs = expandAsArray(property, false);\n if (typeof value === 'string') {\n value = list.space(value);\n }\n\n for (var i = 0, j, l = subs.length, jl = value.length; i < l; i++) {\n j = i < jl ? i : (jl < 2 ? 0 : i % 2);\n\n if (recurse) {\n var recRes = expandAsObject(subs[i], value[j], recurse);\n var keys = Object.keys(recRes);\n for (var ri = 0, rl = keys.length; ri < rl; ri++) {\n res[keys[ri]] = recRes[keys[ri]];\n }\n } else {\n res[subs[i]] = value[j];\n }\n }\n\n return res;\n}\n\nfunction isShorthand(property) {\n if (props.hasOwnProperty(property)) {\n return true;\n }\n return false;\n}\n","var openParentheses = \"(\".charCodeAt(0);\nvar closeParentheses = \")\".charCodeAt(0);\nvar singleQuote = \"'\".charCodeAt(0);\nvar doubleQuote = '\"'.charCodeAt(0);\nvar backslash = \"\\\\\".charCodeAt(0);\nvar slash = \"/\".charCodeAt(0);\nvar comma = \",\".charCodeAt(0);\nvar colon = \":\".charCodeAt(0);\nvar star = \"*\".charCodeAt(0);\n\nmodule.exports = function(input) {\n var tokens = [];\n var value = input;\n\n var next, quote, prev, token, escape, escapePos, whitespacePos;\n var pos = 0;\n var code = value.charCodeAt(pos);\n var max = value.length;\n var stack = [{ nodes: tokens }];\n var balanced = 0;\n var parent;\n\n var name = \"\";\n var before = \"\";\n var after = \"\";\n\n while (pos < max) {\n // Whitespaces\n if (code <= 32) {\n next = pos;\n do {\n next += 1;\n code = value.charCodeAt(next);\n } while (code <= 32);\n token = value.slice(pos, next);\n\n prev = tokens[tokens.length - 1];\n if (code === closeParentheses && balanced) {\n after = token;\n } else if (prev && prev.type === \"div\") {\n prev.after = token;\n } else if (\n code === comma ||\n code === colon ||\n (code === slash && value.charCodeAt(next + 1) !== star)\n ) {\n before = token;\n } else {\n tokens.push({\n type: \"space\",\n sourceIndex: pos,\n value: token\n });\n }\n\n pos = next;\n\n // Quotes\n } else if (code === singleQuote || code === doubleQuote) {\n next = pos;\n quote = code === singleQuote ? \"'\" : '\"';\n token = {\n type: \"string\",\n sourceIndex: pos,\n quote: quote\n };\n do {\n escape = false;\n next = value.indexOf(quote, next + 1);\n if (~next) {\n escapePos = next;\n while (value.charCodeAt(escapePos - 1) === backslash) {\n escapePos -= 1;\n escape = !escape;\n }\n } else {\n value += quote;\n next = value.length - 1;\n token.unclosed = true;\n }\n } while (escape);\n token.value = value.slice(pos + 1, next);\n\n tokens.push(token);\n pos = next + 1;\n code = value.charCodeAt(pos);\n\n // Comments\n } else if (code === slash && value.charCodeAt(pos + 1) === star) {\n token = {\n type: \"comment\",\n sourceIndex: pos\n };\n\n next = value.indexOf(\"*/\", pos);\n if (next === -1) {\n token.unclosed = true;\n next = value.length;\n }\n\n token.value = value.slice(pos + 2, next);\n tokens.push(token);\n\n pos = next + 2;\n code = value.charCodeAt(pos);\n\n // Dividers\n } else if (code === slash || code === comma || code === colon) {\n token = value[pos];\n\n tokens.push({\n type: \"div\",\n sourceIndex: pos - before.length,\n value: token,\n before: before,\n after: \"\"\n });\n before = \"\";\n\n pos += 1;\n code = value.charCodeAt(pos);\n\n // Open parentheses\n } else if (openParentheses === code) {\n // Whitespaces after open parentheses\n next = pos;\n do {\n next += 1;\n code = value.charCodeAt(next);\n } while (code <= 32);\n token = {\n type: \"function\",\n sourceIndex: pos - name.length,\n value: name,\n before: value.slice(pos + 1, next)\n };\n pos = next;\n\n if (name === \"url\" && code !== singleQuote && code !== doubleQuote) {\n next -= 1;\n do {\n escape = false;\n next = value.indexOf(\")\", next + 1);\n if (~next) {\n escapePos = next;\n while (value.charCodeAt(escapePos - 1) === backslash) {\n escapePos -= 1;\n escape = !escape;\n }\n } else {\n value += \")\";\n next = value.length - 1;\n token.unclosed = true;\n }\n } while (escape);\n // Whitespaces before closed\n whitespacePos = next;\n do {\n whitespacePos -= 1;\n code = value.charCodeAt(whitespacePos);\n } while (code <= 32);\n if (pos !== whitespacePos + 1) {\n token.nodes = [\n {\n type: \"word\",\n sourceIndex: pos,\n value: value.slice(pos, whitespacePos + 1)\n }\n ];\n } else {\n token.nodes = [];\n }\n if (token.unclosed && whitespacePos + 1 !== next) {\n token.after = \"\";\n token.nodes.push({\n type: \"space\",\n sourceIndex: whitespacePos + 1,\n value: value.slice(whitespacePos + 1, next)\n });\n } else {\n token.after = value.slice(whitespacePos + 1, next);\n }\n pos = next + 1;\n code = value.charCodeAt(pos);\n tokens.push(token);\n } else {\n balanced += 1;\n token.after = \"\";\n tokens.push(token);\n stack.push(token);\n tokens = token.nodes = [];\n parent = token;\n }\n name = \"\";\n\n // Close parentheses\n } else if (closeParentheses === code && balanced) {\n pos += 1;\n code = value.charCodeAt(pos);\n\n parent.after = after;\n after = \"\";\n balanced -= 1;\n stack.pop();\n parent = stack[balanced];\n tokens = parent.nodes;\n\n // Words\n } else {\n next = pos;\n do {\n if (code === backslash) {\n next += 1;\n }\n next += 1;\n code = value.charCodeAt(next);\n } while (\n next < max &&\n !(\n code <= 32 ||\n code === singleQuote ||\n code === doubleQuote ||\n code === comma ||\n code === colon ||\n code === slash ||\n code === openParentheses ||\n (code === closeParentheses && balanced)\n )\n );\n token = value.slice(pos, next);\n\n if (openParentheses === code) {\n name = token;\n } else {\n tokens.push({\n type: \"word\",\n sourceIndex: pos,\n value: token\n });\n }\n\n pos = next;\n }\n }\n\n for (pos = stack.length - 1; pos; pos -= 1) {\n stack[pos].unclosed = true;\n }\n\n return stack[0].nodes;\n};\n","module.exports = function walk(nodes, cb, bubble) {\n var i, max, node, result;\n\n for (i = 0, max = nodes.length; i < max; i += 1) {\n node = nodes[i];\n if (!bubble) {\n result = cb(node, i, nodes);\n }\n\n if (\n result !== false &&\n node.type === \"function\" &&\n Array.isArray(node.nodes)\n ) {\n walk(node.nodes, cb, bubble);\n }\n\n if (bubble) {\n cb(node, i, nodes);\n }\n }\n};\n","function stringifyNode(node, custom) {\n var type = node.type;\n var value = node.value;\n var buf;\n var customResult;\n\n if (custom && (customResult = custom(node)) !== undefined) {\n return customResult;\n } else if (type === \"word\" || type === \"space\") {\n return value;\n } else if (type === \"string\") {\n buf = node.quote || \"\";\n return buf + value + (node.unclosed ? \"\" : buf);\n } else if (type === \"comment\") {\n return \"/*\" + value + (node.unclosed ? \"\" : \"*/\");\n } else if (type === \"div\") {\n return (node.before || \"\") + value + (node.after || \"\");\n } else if (Array.isArray(node.nodes)) {\n buf = stringify(node.nodes);\n if (type !== \"function\") {\n return buf;\n }\n return (\n value +\n \"(\" +\n (node.before || \"\") +\n buf +\n (node.after || \"\") +\n (node.unclosed ? \"\" : \")\")\n );\n }\n return value;\n}\n\nfunction stringify(nodes, custom) {\n var result, i;\n\n if (Array.isArray(nodes)) {\n result = \"\";\n for (i = nodes.length - 1; ~i; i -= 1) {\n result = stringifyNode(nodes[i], custom) + result;\n }\n return result;\n }\n return stringifyNode(nodes, custom);\n}\n\nmodule.exports = stringify;\n","var minus = \"-\".charCodeAt(0);\nvar plus = \"+\".charCodeAt(0);\nvar dot = \".\".charCodeAt(0);\nvar exp = \"e\".charCodeAt(0);\nvar EXP = \"E\".charCodeAt(0);\n\nmodule.exports = function(value) {\n var pos = 0;\n var length = value.length;\n var dotted = false;\n var sciPos = -1;\n var containsNumber = false;\n var code;\n\n while (pos < length) {\n code = value.charCodeAt(pos);\n\n if (code >= 48 && code <= 57) {\n containsNumber = true;\n } else if (code === exp || code === EXP) {\n if (sciPos > -1) {\n break;\n }\n sciPos = pos;\n } else if (code === dot) {\n if (dotted) {\n break;\n }\n dotted = true;\n } else if (code === plus || code === minus) {\n if (pos !== 0) {\n break;\n }\n } else {\n break;\n }\n\n pos += 1;\n }\n\n if (sciPos + 1 === pos) pos--;\n\n return containsNumber\n ? {\n number: value.slice(0, pos),\n unit: value.slice(pos)\n }\n : false;\n};\n","var parse = require(\"./parse\");\nvar walk = require(\"./walk\");\nvar stringify = require(\"./stringify\");\n\nfunction ValueParser(value) {\n if (this instanceof ValueParser) {\n this.nodes = parse(value);\n return this;\n }\n return new ValueParser(value);\n}\n\nValueParser.prototype.toString = function() {\n return Array.isArray(this.nodes) ? stringify(this.nodes) : \"\";\n};\n\nValueParser.prototype.walk = function(cb, bubble) {\n walk(this.nodes, cb, bubble);\n return this;\n};\n\nValueParser.unit = require(\"./unit\");\n\nValueParser.walk = walk;\n\nValueParser.stringify = stringify;\n\nmodule.exports = ValueParser;\n","'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _postcssValueParser = require('postcss-value-parser');\n\nvar _postcssValueParser2 = _interopRequireDefault(_postcssValueParser);\n\nvar _cssColorNames = require('css-color-names');\n\nvar _cssColorNames2 = _interopRequireDefault(_cssColorNames);\n\nvar _endsWith = require('ends-with');\n\nvar _endsWith2 = _interopRequireDefault(_endsWith);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction lowercase(value) {\n return value.toLowerCase();\n}\n\nfunction isKeyword(_ref, values) {\n var type = _ref.type;\n var value = _ref.value;\n\n if (type !== 'word') {\n return false;\n }\n if (Array.isArray(values)) {\n return ~values.map(lowercase).indexOf(lowercase(value));\n }\n return lowercase(value) === values;\n}\n\nfunction isFunction(node, values) {\n if (node.type !== 'function') {\n return false;\n }\n if (Array.isArray(values)) {\n return ~values.map(lowercase).indexOf(lowercase(node.value));\n }\n return lowercase(node.value) === values;\n}\n\nvar isVariable = function isVariable(node) {\n return isFunction(node, 'var');\n};\n\nfunction isKeywordFactory(keywords) {\n return function wrappedIsKeyword(parsed) {\n if (parsed.nodes.length === 1) {\n return isKeyword(parsed.nodes[0], keywords);\n }\n return false;\n };\n}\n\nvar isUrl = function isUrl(node) {\n return isFunction(node, 'url');\n};\n\nvar isInteger = function isInteger(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n if (type !== 'word') {\n return false;\n }\n var int = (0, _postcssValueParser.unit)(value);\n return int && !~value.indexOf('.') && !int.unit;\n};\n\nvar isComma = function isComma(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n return type === 'div' && value === ',';\n};\n\nvar isNumber = function isNumber(node) {\n var value = node.value;\n\n if (node.type !== 'word') {\n return false;\n }\n\n return !isNaN(value) && !(0, _endsWith2.default)(value, '.');\n};\n\nvar isPercentage = function isPercentage(_ref) {\n var value = _ref.value;\n\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && int.unit === '%';\n};\n\nvar namedColours = Object.keys(_cssColorNames2.default);\n\nfunction isRgb(node) {\n if (!isFunction(node, 'rgb')) {\n return;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && !isInteger(child) && !isPercentage(child) || !even && !isComma(child)) {\n valid = false;\n }\n return false;\n });\n\n return valid && node.nodes.length === 5;\n}\n\nfunction isRgba(node) {\n if (!isFunction(node, 'rgba')) {\n return;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && (index < 6 && !isInteger(child) && !isPercentage(child) || index > 5 && !isNumber(child)) || !even && !isComma(child)) {\n valid = false;\n }\n return false;\n });\n\n return valid && node.nodes.length === 7;\n}\n\nfunction isHsl(node) {\n if (!isFunction(node, 'hsl')) {\n return;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && (index < 1 && !isNumber(child) || index > 1 && !isPercentage(child)) || !even && !isComma(child)) {\n valid = false;\n }\n return false;\n });\n\n return valid && node.nodes.length === 5;\n}\n\nfunction isHsla(node) {\n if (!isFunction(node, 'hsla')) {\n return;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && ((index === 0 || index === 6) && !isNumber(child) || (index === 2 || index === 4) && !isPercentage(child)) || !even && !isComma(child)) {\n valid = false;\n }\n return false;\n });\n\n return valid && node.nodes.length === 7;\n}\n\nfunction isHex(node) {\n if (node.type !== 'word' || node.value[0] !== '#') {\n return false;\n }\n var range = node.value.slice(1);\n return ~[3, 4, 6, 8].indexOf(range.length) && !isNaN(parseInt(range, 16));\n}\n\nfunction isNamedColor(node) {\n return isKeyword(node, namedColours);\n}\n\nfunction isCurrentColor(node) {\n return isKeyword(node, 'currentcolor');\n}\n\nfunction isColor(node) {\n return isRgb(node) || isRgba(node) || isHsl(node) || isHsla(node) || isHex(node) || isNamedColor(node) || isCurrentColor(node);\n}\n\nvar brStyles = ['none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'];\n\nvar isBrStyle = function isBrStyle(node) {\n return isKeyword(node, brStyles);\n};\n\nvar isSpace = function isSpace(_ref) {\n var type = _ref.type;\n\n return type === 'space';\n};\n\nvar angles = ['deg', 'grad', 'rad', 'turn'];\n\nvar isAngle = function isAngle(_ref) {\n var value = _ref.value;\n\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && (int.number === '0' || ~angles.indexOf(int.unit));\n};\n\nvar units = ['s', 'ms'];\n\nvar isTime = function isTime(_ref) {\n var value = _ref.value;\n\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && ~units.indexOf(int.unit);\n};\n\nvar operators = ['+', '-', '*', '/'];\nvar operatorsRegExp = /[+\\-\\*\\/]/i;\n\nfunction isCalc(node) {\n if (!isFunction(node, 'calc') || !node.nodes || !node.nodes.length) {\n return false;\n }\n\n var valid = true;\n var lastNonSpaceValue = false;\n\n (0, _postcssValueParser.walk)(node.nodes, function (child) {\n var type = child.type;\n var value = child.value;\n // if an expression starts with operator\n\n if (!lastNonSpaceValue && ~operators.indexOf(value)) {\n valid = false;\n }\n // store last non space node\n if (type !== 'space') {\n lastNonSpaceValue = value;\n }\n // only variables and () functions are allowed\n if (!isVariable(child) && type === 'function') {\n if (value.length > 0) {\n valid = false;\n }\n if (!child.nodes.length || !child.nodes) {\n valid = false;\n }\n }\n // invalidate any invalid word node\n if (type === 'word' && !isAngle(child) && !isLength(child) && !isTime(child) && !isInteger(child) && !isNumber(child) && !isPercentage(child) && operators.indexOf(value) < 0) {\n // + and - must be surrounded by spaces\n if (value.indexOf('+') > 0 || value.indexOf('-') > 0) {\n valid = false;\n }\n // expression can't endwith operator\n if (~operators.indexOf(value[value.length - 1])) {\n valid = false;\n }\n // unknown word node w/o operators is invalid\n if (!operatorsRegExp.test(value)) {\n valid = false;\n }\n }\n });\n // if an expression ends with operator\n if (~operators.indexOf(lastNonSpaceValue)) {\n valid = false;\n }\n\n return valid;\n}\n\nvar lengths = ['em', 'ex', 'ch', 'rem', 'vh', 'vw', 'vmin', 'vmax', 'px', 'q', 'mm', 'cm', 'in', 'pt', 'pc'];\n\nvar isLength = function isLength(node) {\n if (isCalc(node)) {\n return true;\n }\n if (node.type !== 'word') {\n return false;\n }\n var int = (0, _postcssValueParser.unit)(node.value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && (int.number === '0' || ~lengths.indexOf(int.unit));\n};\n\nvar brWidths = ['thin', 'medium', 'thick'];\n\nvar isBrWidth = function isBrWidth(node) {\n return isLength(node) || isKeyword(node, brWidths);\n};\n\nvar attachments = ['scroll', 'fixed', 'local'];\n\nvar isAttachment = function isAttachment(node) {\n return isKeyword(node, attachments);\n};\n\nvar singleValues = ['repeat-x', 'repeat-y'];\n\nvar multipleValues = ['repeat', 'space', 'round', 'no-repeat'];\n\nvar isRepeatStyle = function isRepeatStyle(parsed) {\n var group = [];\n var valid = true;\n if (parsed.nodes[parsed.nodes.length - 1].type === 'div') {\n return false;\n }\n parsed.walk(function (node) {\n if (isKeyword(node, singleValues)) {\n if (group.length) {\n valid = false;\n return false;\n }\n group.push(node);\n } else if (isKeyword(node, multipleValues) || isVariable(node)) {\n if (group.some(function (n) {\n return isKeyword(n, singleValues);\n }) || group.length === 2) {\n valid = false;\n return false;\n }\n group.push(node);\n } else if (isComma(node)) {\n group = [];\n return false;\n } else if (!isSpace(node)) {\n valid = false;\n }\n return false;\n });\n return valid;\n};\n\nvar singleAnimationDirections = ['normal', 'reverse', 'alternate', 'alternate-reverse'];\n\nvar isSingleAnimationDirection = function isSingleAnimationDirection(node) {\n return isKeyword(node, singleAnimationDirections);\n};\n\nvar singleAnimationFillModes = ['none', 'forwards', 'backwards', 'both'];\n\nvar isSingleAnimationFillMode = function isSingleAnimationFillMode(node) {\n return isKeyword(node, singleAnimationFillModes);\n};\n\nvar value = ['infinite'];\n\nvar isSingleAnimationIterationCount = function isSingleAnimationIterationCount(node) {\n return isKeyword(node, value) || isNumber(node);\n};\n\nfunction isInvalid(value) {\n return (/[^a-z0-9_-]/ig.test(value)\n );\n}\n\nfunction isCodepoint(value) {\n return (/\\\\u[a-f0-9]{1,6}/ig.test(value) || /\\\\[a-f0-9]{1,6}/ig.test(value)\n );\n}\n\nfunction isValid(value) {\n return !isInvalid(value) || isCodepoint(value);\n}\n\nvar isCustomIdent = function isCustomIdent(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n if (type !== 'word') {\n return false;\n }\n if (value[0] === '-') {\n if (/[0-9]/.test(value[1])) {\n return false;\n }\n if (value[1] === '-' && value[2] !== '-') {\n return false;\n }\n return isValid(value);\n }\n return !/[0-9]/.test(value[0]) && isValid(value);\n};\n\nvar isSingleAnimationName = function isSingleAnimationName(node) {\n return isKeyword(node, 'none') || isCustomIdent(node);\n};\n\nvar singleAnimationPlayStates = ['running', 'paused'];\n\nvar isSingleAnimationPlayState = function isSingleAnimationPlayState(node) {\n return isKeyword(node, singleAnimationPlayStates);\n};\n\nvar keywords = ['ease', 'linear', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end'];\n\nvar stepsKeywords = ['start', 'end'];\n\nfunction isTimingKeyword(node) {\n return isKeyword(node, keywords);\n}\n\nfunction isSteps(node) {\n if (!isFunction(node, 'steps') || !isInteger(node.nodes[0])) {\n return false;\n }\n var one = node.nodes[1];\n var two = node.nodes[2];\n if (one && !isComma(one)) {\n return false;\n }\n if (two) {\n return isKeyword(two, stepsKeywords);\n }\n return true;\n}\n\nfunction isValidAbscissa(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n return type === 'word' && value >= 0 && value <= 1;\n}\n\nfunction isCubicBezier(node) {\n if (!isFunction(node, 'cubic-bezier')) {\n return false;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && ((index === 0 || index === 4) && !isValidAbscissa(child) || (index === 2 || index === 6) && !isNumber(child)) || !even && !isComma(child)) {\n valid = false;\n }\n return false;\n });\n\n return valid && node.nodes.length === 7;\n}\n\nvar isSingleTransitionTimingFunction = function isSingleTransitionTimingFunction(node) {\n return isTimingKeyword(node) || isSteps(node) || isCubicBezier(node);\n};\n\nvar numberPercentages = ['brightness', 'contrast', 'grayscale', 'invert', 'opacity', 'sepia', 'saturate'];\n\nfunction isNumberOrPercentage(node) {\n if (!isFunction(node, numberPercentages)) {\n return false;\n }\n var nodes = node.nodes;\n\n return nodes.length === 1 && (isNumber(nodes[0]) || isPercentage(nodes[0]));\n}\n\nfunction isBlur(node) {\n if (!isFunction(node, 'blur')) {\n return false;\n }\n var nodes = node.nodes;\n\n return nodes.length === 1 && isLength(nodes[0]);\n}\n\nfunction isDropShadow(node) {\n if (!isFunction(node, 'drop-shadow')) {\n return false;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n var even = index % 2 === 0;\n if (even && index <= 2 && !isLength(child)) {\n valid = false;\n return false;\n }\n if (even && index === 4 && !isLength(child) && !isColor(child)) {\n valid = false;\n return false;\n }\n if (even && index === 6 && !isColor(child)) {\n valid = false;\n return false;\n }\n if (!even && !isSpace(child)) {\n valid = false;\n return false;\n }\n });\n return valid && node.nodes.length <= 7;\n}\n\nfunction isHueRotate(node) {\n if (!isFunction(node, 'hue-rotate')) {\n return false;\n }\n var nodes = node.nodes;\n\n return nodes.length === 1 && isAngle(nodes[0]);\n}\n\nfunction isFilterFunction(node) {\n return isBlur(node) || isDropShadow(node) || isHueRotate(node) || isNumberOrPercentage(node);\n}\n\nfunction isFilterFunctionList(parsed) {\n var valid = true;\n parsed.walk(function (node, index) {\n var even = index % 2 === 0;\n if (even && !isFilterFunction(node) && !isVariable(node)) {\n valid = false;\n }\n if (!even && !isSpace(node)) {\n valid = false;\n }\n return false;\n });\n return valid;\n}\n\nvar blendValues = ['normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'];\n\nvar isBlendMode = function isBlendMode(node) {\n return isKeyword(node, blendValues);\n};\n\nvar boxes = ['border-box', 'padding-box', 'content-box'];\n\nvar isBox = function isBox(node) {\n return isKeyword(node, boxes);\n};\n\nfunction getArguments(node) {\n return node.nodes.reduce(function (list, child) {\n if (isComma(child)) {\n list.push([]);\n } else {\n list[list.length - 1].push(child);\n }\n return list;\n }, [[]]);\n}\n\nvar isLengthPercentage = function isLengthPercentage(node) {\n return isLength(node) || isPercentage(node);\n};\n\nvar left$1 = 'left';\nvar center = 'center';\nvar right$1 = 'right';\nvar top$1 = 'top';\nvar bottom$1 = 'bottom';\n\nvar horizontals$1 = [left$1, right$1, center];\nvar verticals$1 = [top$1, bottom$1, center];\n\nfunction isKeywordOrVar(node, keywords) {\n return isKeyword(node, keywords) || isVariable(node);\n}\n\nfunction isLengthPercentageOrVar(node) {\n return isLengthPercentage(node) || isVariable(node);\n}\n\nfunction validateGroup(group) {\n var length = group.length;\n\n if (length === 1) {\n if (!isKeywordOrVar(group[0], [left$1, center, right$1, top$1, bottom$1]) && !isLengthPercentage(group[0])) {\n return false;\n }\n }\n if (length === 3) {\n if (!isSpace(group[1])) {\n return false;\n }\n if (isKeywordOrVar(group[0], horizontals$1) && isKeywordOrVar(group[2], verticals$1) || isKeywordOrVar(group[0], verticals$1) && isKeywordOrVar(group[2], horizontals$1)) {\n return true;\n }\n if (!isKeywordOrVar(group[0], horizontals$1) && !isLengthPercentage(group[0])) {\n return false;\n }\n if (!isKeywordOrVar(group[2], verticals$1) && !isLengthPercentage(group[2])) {\n return false;\n }\n }\n if (length >= 5 && length <= 7) {\n if (isKeywordOrVar(group[0], [left$1, right$1]) && isSpace(group[1]) && isLengthPercentageOrVar(group[2]) && isSpace(group[3]) && isKeywordOrVar(group[4], verticals$1)) {\n if (group[6] && isSpace(group[5]) && (!isLengthPercentageOrVar(group[6]) || group[4].value === center)) {\n return false;\n }\n return true;\n }\n if (isKeywordOrVar(group[0], [top$1, bottom$1]) && isSpace(group[1]) && isLengthPercentageOrVar(group[2]) && isSpace(group[3]) && isKeywordOrVar(group[4], horizontals$1)) {\n if (group[6] && isSpace(group[5]) && (!isLengthPercentageOrVar(group[6]) || group[4].value === center)) {\n return false;\n }\n return true;\n }\n return false;\n }\n return length < 8;\n}\n\nfunction isPositionFactory(repeating) {\n return function isPosition(parsed) {\n if (repeating && parsed.nodes[parsed.nodes.length - 1].type === 'div') {\n return false;\n }\n\n return getArguments(parsed).every(validateGroup);\n };\n}\n\nvar resolutions = ['dpi', 'dpcm', 'dppx'];\n\nfunction isResolution(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n if (type !== 'word') {\n return false;\n }\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && ~resolutions.indexOf(int.unit);\n};\n\nvar isString = function isString(_ref) {\n var type = _ref.type;\n return type === 'string';\n};\n\nfunction isMultiplier(_ref) {\n var type = _ref.type;\n var value = _ref.value;\n\n if (type !== 'word') {\n return false;\n }\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && int.unit === 'x';\n};\n\nfunction isImageFunction(node) {\n if (!isFunction(node, 'image')) {\n return false;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n if (index === 0 && !isImage(child) && !isString(child) && !isColor(child)) {\n valid = false;\n }\n if (index === 1 && !isComma(child)) {\n valid = false;\n }\n if (index === 2 && (isColor(node.nodes[0]) || !isColor(child))) {\n valid = false;\n }\n return false;\n });\n return valid && node.nodes.length <= 3;\n}\n\nfunction validateImageSet(group) {\n if (!isImage(group[0]) && !isString(group[0]) || isFunction(group[0], 'image-set') || !group[2] || !isResolution(group[2]) && !isMultiplier(group[2])) {\n return false;\n }\n return group.length === 3;\n}\n\nfunction isImageSet(node) {\n if (!isFunction(node, 'image-set')) {\n return false;\n }\n return getArguments(node).every(validateImageSet);\n}\n\nfunction isElement(node) {\n if (!isFunction(node, 'element')) {\n return false;\n }\n if (node.nodes.length !== 1) {\n return false;\n }\n var _node$nodes$ = node.nodes[0];\n var type = _node$nodes$.type;\n var value = _node$nodes$.value;\n\n return value[0] === '#' && type === 'word';\n}\n\nfunction isCrossFade(node) {\n if (!isFunction(node, 'cross-fade')) {\n return false;\n }\n var valid = true;\n (0, _postcssValueParser.walk)(node.nodes, function (child, index) {\n if (index === 0 && !isPercentage(child) && !isImage(child)) {\n valid = false;\n }\n if (index === 2 && !isPercentage(child) && !isImage(child)) {\n valid = false;\n }\n if (index === 4 && !isImage(child) && !isColor(child)) {\n valid = false;\n }\n return false;\n });\n return valid;\n}\n\nfunction isColourStop(group) {\n var length = group.length;\n\n if (length === 1) {\n return isColor(group[0]);\n }\n if (length === 3) {\n return isColor(group[0]) && isLengthPercentage(group[2]);\n }\n return false;\n}\n\nvar top = 'top';\nvar right = 'right';\nvar bottom = 'bottom';\nvar left = 'left';\n\nvar verticals = [top, bottom];\nvar horizontals = [right, left];\nvar directions = [].concat(horizontals, verticals);\n\nfunction isLinearGradient(node) {\n if (!isFunction(node, ['linear-gradient', 'repeating-linear-gradient'])) {\n return false;\n }\n var colours = 0;\n var valid = getArguments(node).every(function (group, index) {\n if (index === 0) {\n var length = group.length;\n\n if (length === 1 && isAngle(group[0])) {\n return true;\n }\n if (length > 1 && group[0].value === 'to' && length <= 5) {\n return !group[4] && isKeyword(group[2], directions) || isKeyword(group[2], horizontals) && isKeyword(group[4], verticals) || isKeyword(group[2], verticals) && isKeyword(group[4], horizontals);\n }\n }\n var colour = isColourStop(group);\n if (colour) {\n colours++;\n }\n return colour;\n });\n return valid && colours > 1;\n}\n\nvar at = 'at';\nvar circle = 'circle';\nvar ellipse = 'ellipse';\nvar endingShapes = [circle, ellipse];\n\nvar extentKeywords = ['closest-corner', 'closest-side', 'farthest-corner', 'farthest-side'];\n\nvar isRadialGradientPosition = isPositionFactory(false);\n\nfunction isAt(_ref2) {\n var value = _ref2.value;\n\n return value === at;\n}\n\nfunction isRadialGradient(node) {\n if (!isFunction(node, ['radial-gradient', 'repeating-radial-gradient'])) {\n return false;\n }\n var colours = 0;\n var valid = getArguments(node).every(function (group, index) {\n if (index === 0) {\n var length = group.length;\n\n var firstIsEndingShape = isKeyword(group[0], endingShapes);\n var firstIsLength = isLength(group[0]);\n var firstIsExtent = isKeyword(group[0], extentKeywords);\n if (length === 1 && (firstIsEndingShape || firstIsLength || firstIsExtent)) {\n return true;\n }\n var position2 = isRadialGradientPosition({ nodes: group.slice(2) });\n if (isAt(group[0]) && position2) {\n return true;\n }\n var firstIsCircle = group[0].value === circle;\n var secondIsExtent = group[2] && isKeyword(group[2], extentKeywords);\n var secondIsEndingShape = group[2] && isKeyword(group[2], endingShapes);\n if (length === 3 && (firstIsCircle && isLength(group[2]) || firstIsLength && group[2].value === circle || firstIsExtent && secondIsEndingShape || firstIsEndingShape && secondIsExtent)) {\n return true;\n }\n var firstIsEllipse = group[0].value === ellipse;\n var firstIsLP = isLengthPercentage(group[0]);\n var secondIsLP = group[2] && isLengthPercentage(group[2]);\n var thirdIsLP = group[4] && isLengthPercentage(group[4]);\n var position4 = isRadialGradientPosition({ nodes: group.slice(4) });\n var position6 = isRadialGradientPosition({ nodes: group.slice(6) });\n var position8 = isRadialGradientPosition({ nodes: group.slice(8) });\n if (length === 5 && (firstIsEllipse && secondIsLP && thirdIsLP || firstIsLP && secondIsLP && group[4].value === ellipse)) {\n return true;\n }\n if (length > 3 && (firstIsEndingShape && isAt(group[2]) && position4 || firstIsExtent && isAt(group[2]) && position4 || firstIsLength && isAt(group[2]) && position4 || firstIsLP && secondIsLP && isAt(group[4]) && position6 || firstIsCircle && isLength(group[2]) && isAt(group[4]) && position6 || firstIsEndingShape && secondIsExtent && isAt(group[4]) && position6 || firstIsExtent && secondIsEndingShape && isAt(group[4]) && position6 || firstIsEllipse && secondIsLP && thirdIsLP && isAt(group[6]) && position8 || firstIsLP && secondIsLP && group[4].value === ellipse && isAt(group[6]) && position8)) {\n return true;\n }\n }\n var colour = isColourStop(group);\n if (colour) {\n colours++;\n }\n return colour;\n });\n return valid && colours > 1;\n}\n\nfunction isGradient(node) {\n return isLinearGradient(node) || isRadialGradient(node);\n}\n\nfunction isImage(node) {\n return isUrl(node) || isImageFunction(node) || isImageSet(node) || isElement(node) || isCrossFade(node) || isGradient(node);\n}\n\nfunction isBgImage(node) {\n return isImage(node) || isKeyword(node, 'none');\n}\n\nvar sizeKeywords = ['cover', 'contain'];\n\nvar auto = 'auto';\n\nfunction validateNode(node) {\n return isKeyword(node, auto) || isLengthPercentage(node) || isVariable(node);\n}\n\nfunction validateGroup$1(group) {\n var length = group.length;\n\n if (length && length < 4) {\n if (!validateNode(group[0])) {\n return false;\n }\n if (group[2] && !validateNode(group[2])) {\n return false;\n }\n return true;\n }\n return false;\n}\n\nfunction isBgSize(parsed) {\n if (parsed.nodes.length === 1 && isKeyword(parsed.nodes[0], sizeKeywords)) {\n return true;\n }\n\n return getArguments(parsed).every(validateGroup$1);\n}\n\nvar absoluteSizes = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];\n\nvar isAbsoluteSize = function isAbsoluteSize(node) {\n return isKeyword(node, absoluteSizes);\n};\n\nvar relativeSizes = ['larger', 'smaller'];\n\nvar isRelativeSize = function isRelativeSize(node) {\n return isKeyword(node, relativeSizes);\n};\n\nvar isNegative = function isNegative(num) {\n return num < 0;\n};\n\nvar isFlex = function isFlex(_ref) {\n var value = _ref.value;\n\n var int = (0, _postcssValueParser.unit)(value);\n return int && !(0, _endsWith2.default)(int.number, '.') && !~int.unit.indexOf('.') && int.unit === 'fr' && !isNegative(int.number);\n};\n\nvar isMinMax = function isMinMax(node) {\n if (isFunction(node, 'minmax') && node.nodes.length === 3) {\n\n var firstChild = node.nodes[0];\n var secondChild = node.nodes[1];\n var thirdChild = node.nodes[2];\n\n if (!isKeyword(firstChild, keywords$1) && !isLengthPercentage(firstChild)) {\n return false;\n }\n\n if (!isComma(secondChild)) {\n return false;\n }\n\n if (!isKeyword(thirdChild, keywords$1) && !isLengthPercentage(thirdChild) && !isFlex(thirdChild)) {\n return false;\n }\n\n return true;\n }\n\n return false;\n};\n\nvar keywords$1 = ['min-content', 'max-content', 'auto'];\n\nvar isTrackSize = function isTrackSize(node) {\n return isMinMax(node) || isFlex(node) || isLengthPercentage(node) || isKeyword(node, keywords$1);\n};\n\nvar standard = ['disc', 'circle', 'square', 'decimal', 'cjk-decimal', 'decimal-leading-zero', 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', 'upper-alpha', 'upper-latin', 'arabic-indic', '-moz-arabic-indic', 'armenian', 'bengali', '-moz-bengali', 'cambodian', 'cjk-earthly-branch', '-moz-cjk-earthly-branch', 'cjk-heavenly-stem', '-moz-cjk-heavenly-stem', 'cjk-ideographic', 'devanagari', '-moz-devanagari', 'ethiopic-numeric', 'georgian', 'gujarati', '-moz-gujarati', 'gurmukhi', '-moz-gurmukhi', 'hebrew', 'hiragana', 'hiragana-iroha', 'japanese-formal', 'japanese-informal', 'kannada', '-moz-kannada', 'katakana', 'katakana-iroha', 'khmer', '-moz-khmer', 'korean-hangul-formal', 'korean-hanja-formal', 'korean-hanja-informal', 'lao', '-moz-lao', 'lower-armenian', 'malayalam', '-moz-malayalam', 'mongolian', 'myanmar', '-moz-myanmar', 'oriya', '-moz-oriya', 'persian', '-moz-persian', 'simp-chinese-formal', 'simp-chinese-informal', 'tamil', '-moz-tamil', 'telugu', '-moz-telugu', 'thai', '-moz-thai', 'tibetan', 'trad-chinese-formal', 'trad-chinese-informal', 'upper-armenian', 'disclosure-open', 'disclosure-closed'];\n\nvar nonStandard = ['-moz-ethiopic-halehame', '-moz-ethiopic-halehame-am', 'ethiopic-halehame-ti-er', '-moz-ethiopic-halehame-ti-er', 'ethiopic-halehame-ti-et', '-moz-ethiopic-hale