update CSSLint

* fix missing <zero>
* retry/consume attr()
* code cosmetics
This commit is contained in:
tophf 2020-11-02 22:08:14 +03:00
parent 32728b023b
commit a997ecbe24

View File

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