CSSLint: parse CSS4 :matches(), the future of :any()

This commit is contained in:
tophf 2018-03-01 21:04:39 +03:00
parent e4c399a1c0
commit 3a68c4e636

View File

@ -1346,6 +1346,7 @@ self.parserlib = (() => {
// modifier // modifier
{name: 'NOT'}, {name: 'NOT'},
{name: 'ANY', text: ['any', '-webkit-any', '-moz-any']}, {name: 'ANY', text: ['any', '-webkit-any', '-moz-any']},
{name: 'MATCHES'},
/* /*
* Defined in CSS3 Paged Media * Defined in CSS3 Paged Media
@ -2954,7 +2955,7 @@ self.parserlib = (() => {
* - CHAR * - CHAR
*/ */
case ':': case ':':
return this.notOrAnyToken(c, pos); return this.notOrAnyOrMatchesToken(c, pos);
/* /*
* Potential tokens: * Potential tokens:
@ -3163,12 +3164,15 @@ self.parserlib = (() => {
// NOT // NOT
// ANY // ANY
// MATCHES
// CHAR // CHAR
notOrAnyToken(first, pos) { notOrAnyOrMatchesToken(first, pos) {
const reader = this._reader; const reader = this._reader;
const func = reader.readMatch(/not\(|(-(moz|webkit)-)?any\(/iy); const func = reader.readMatch(/(not|(-(moz|webkit)-)?any|matches)\(/iy);
if (func) { if (func) {
const type = func.startsWith('n') || func.startsWith('N') ? Tokens.NOT : Tokens.ANY; const type =
func.startsWith('n') || func.startsWith('N') ? Tokens.NOT :
func.startsWith('m') || func.startsWith('M') ? Tokens.MATCHES : Tokens.ANY;
return this.createToken(type, first + func, pos); return this.createToken(type, first + func, pos);
} }
return this.charToken(first, pos); return this.charToken(first, pos);
@ -4474,17 +4478,11 @@ self.parserlib = (() => {
} }
while (true) { while (true) {
const next = stream.peek(); const action = Parser.ACTIONS.simpleSelectorSequence.get(stream.peek());
const component = const component = action && action.call(this);
next === Tokens.HASH && this._hash() ||
next === Tokens.DOT && this._class() ||
next === Tokens.LBRACKET && this._attrib() ||
next === Tokens.COLON && this._pseudo() ||
next === Tokens.ANY && this._any() ||
next === Tokens.NOT && this._negation();
if (!component) break; if (!component) break;
modifiers.push(component); modifiers.push(component);
text += component.toString(); text += component;
} }
return text && new SelectorPart(elementName, modifiers, text, start); return text && new SelectorPart(elementName, modifiers, text, start);
@ -4658,21 +4656,23 @@ self.parserlib = (() => {
return value.length ? value : null; return value.length ? value : null;
} }
_any() { _anyOrMatches() {
const stream = this._tokenStream; const stream = this._tokenStream;
if (!stream.match(Tokens.ANY)) return null; if (!stream.match([Tokens.ANY, Tokens.MATCHES])) return null;
let arg;
const start = stream._token; const start = stream._token;
let value = stream._token.value + this._ws(); const type = start.type === Tokens.ANY ? 'any' : 'matches';
const value =
start.value +
this._ws() +
((arg = this._selectorsGroup())) +
this._ws() +
')';
stream.mustMatch(Tokens.RPAREN);
const arg = this._selectorsGroup(); const subpart = new SelectorSubPart(value, type, start);
value += arg + this._ws(); subpart.args = arg;
stream.match(Tokens.RPAREN);
value += stream._token.value;
const subpart = new SelectorSubPart(value, 'any', start);
subpart.args.push(arg);
return subpart; return subpart;
} }
@ -5311,6 +5311,17 @@ self.parserlib = (() => {
Object.assign(Parser, TYPES); Object.assign(Parser, TYPES);
Object.assign(Parser.prototype, TYPES); Object.assign(Parser.prototype, TYPES);
Parser.prototype._readWhitespace = Parser.prototype._ws; Parser.prototype._readWhitespace = Parser.prototype._ws;
Parser.ACTIONS = {
simpleSelectorSequence: new Map([
[Tokens.HASH, Parser.prototype._hash],
[Tokens.DOT, Parser.prototype._class],
[Tokens.LBRACKET, Parser.prototype._attrib],
[Tokens.COLON, Parser.prototype._pseudo],
[Tokens.ANY, Parser.prototype._anyOrMatches],
[Tokens.MATCHES, Parser.prototype._anyOrMatches],
[Tokens.NOT, Parser.prototype._negation],
]),
};
//endregion //endregion
//region Helper functions //region Helper functions