diff --git a/vendor-overwrites/csslint/parserlib.js b/vendor-overwrites/csslint/parserlib.js index b8a631fd..34a9af64 100644 --- a/vendor-overwrites/csslint/parserlib.js +++ b/vendor-overwrites/csslint/parserlib.js @@ -725,9 +725,11 @@ self.parserlib = (() => { }, '': part => part.type === 'angle', + '': p => p.type === 'angle' || p.text === '0', '': part => part.units && lowerCmp(part.units, 'ar'), + '': p => p.type === 'function' && lowerCmp(p.name, 'attr'), '': part => !/\battr\(/i.test(part.text), '': 'scroll | fixed | local', @@ -1153,7 +1155,7 @@ self.parserlib = (() => { 'contrast': '', 'drop-shadow': '{2,3} && ?', 'grayscale': '', - 'hue-rotate': ' | ', + 'hue-rotate': '', 'invert': '', 'opacity': '', 'saturate': '', @@ -1172,17 +1174,17 @@ self.parserlib = (() => { 'scale': ' [ , ]?', 'scaleX': '', 'scaleY': '', - 'rotate': '[ | ]', - 'skew': '[ | ] [ , [ | ] ]?', - 'skewX': '[ | ]', - 'skewY': '[ | ]', + 'rotate': '', + 'skew': ' [ , ]?', + 'skewX': '', + 'skewY': '', 'matrix3d': '#{16}', 'translate3d': '#{2} , ', 'translateZ': '', 'scale3d': '#{3}', 'scaleZ': '', - 'rotate3d': '#{3} , [ | ]', + 'rotate3d': '#{3} , ', }, functionsMayBeEmpty: new Set([ @@ -2728,18 +2730,18 @@ self.parserlib = (() => { }, /** - * @param {PropertyValueIterator} expression + * @param {PropertyValueIterator} expr * @param {string} type * @return {?boolean} */ - isType(expression, type) { - const part = expression.peek(); + isType(expr, type) { + const part = expr.peek(); let result, m; if (this.simple[''](part)) { - if (expression._i < expression._parts.length - 1) { - expression.mark().next(); - expression.popMark(ValidationTypes.isType(expression, type)); + if (expr._i < expr._parts.length - 1) { + expr.mark().next(); + expr.popMark(ValidationTypes.isType(expr, type)); } result = true; @@ -2752,14 +2754,14 @@ self.parserlib = (() => { } else { m = this.complex[type]; return m instanceof Matcher ? - m.match(expression) : - m.call(this.complex, expression); + m.match(expr) : + m.call(this.complex, expr); } - if (!result && part.type === 'function' && lowerCmp(part.name, 'attr')) { + if (!result && expr.tryAttr && part.type === 'function' && lowerCmp(part.name, 'attr')) { result = ValidationTypes.isFunction('attr', part); } - if (result) expression.next(); + if (result) expr.next(); return result; }, @@ -2823,21 +2825,30 @@ self.parserlib = (() => { if (!spec) throw new ValidationError(`Unknown property '${property}'.`, property); // Property-specific validation. - const expression = new PropertyValueIterator(value); - const result = Matcher.parse(spec).match(expression); - - const hasNext = expression.hasNext(); - if (result) { - if (hasNext) throwEndExpected(expression.next()); - - } else { - if (hasNext && expression._i) { - throwEndExpected(expression.peek()); - } else { - const {text} = expression.value; - throw new ValidationError(`Expected '${ValidationTypes.describe(spec)}' but found '${text}'.`, - expression.value); + const expr = new PropertyValueIterator(value); + const tryAttr = /\battr\(/i.test(value.text); + const m = Matcher.parse(spec); + let result = m.match(expr); + if (tryAttr) { + if (!result) { + expr.tryAttr = true; + expr._i = 0; + result = m.match(expr); } + while (expr.hasNext() && + ValidationTypes.simple[''](expr.peek()) && + ValidationTypes.isFunction('attr', expr.peek())) { + expr.next(); + } + } + if (result) { + if (expr.hasNext()) throwEndExpected(expr.next()); + } else if (expr.hasNext() && expr._i) { + throwEndExpected(expr.peek()); + } else { + const {text} = expr.value; + throw new ValidationError(`Expected '${ValidationTypes.describe(spec)}' but found '${text}'.`, + expr.value); } if (!known) validationCache.set(prop, (known = new Set()));