CSSLint: parse CSS4 :matches(), the future of :any()
This commit is contained in:
parent
e4c399a1c0
commit
3a68c4e636
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user