parserlib: consume unknown @-rules per CSS grammar

This commit is contained in:
tophf 2020-08-27 22:39:49 +03:00
parent 07ba44cc2c
commit aa43507478

View File

@ -2722,6 +2722,10 @@ self.parserlib = (() => {
constructor(input) { constructor(input) {
this._reader = new StringReader(input ? input.toString() : ''); this._reader = new StringReader(input ? input.toString() : '');
this.resetLT();
}
resetLT() {
// Token object for the last consumed token. // Token object for the last consumed token.
this._token = null; this._token = null;
// Lookahead token buffer. // Lookahead token buffer.
@ -3148,8 +3152,7 @@ self.parserlib = (() => {
*/ */
atRuleToken(first, pos) { atRuleToken(first, pos) {
this._reader.mark(); this._reader.mark();
const ident = this.readName(); let rule = first + this.readName();
let rule = first + ident;
let tt = Tokens.type(lower(rule)); let tt = Tokens.type(lower(rule));
// if it's not valid, use the first character only and reset the reader // if it's not valid, use the first character only and reset the reader
if (tt === Tokens.CHAR || tt === Tokens.UNKNOWN) { if (tt === Tokens.CHAR || tt === Tokens.UNKNOWN) {
@ -5296,19 +5299,62 @@ self.parserlib = (() => {
throw new SyntaxError('Unknown @ rule.', lt0); throw new SyntaxError('Unknown @ rule.', lt0);
} }
this.fire({ this._ws();
type: 'error', const simpleValue =
error: null, stream.match([Tokens.IDENT, Tokens.CUSTOM_PROP]) && SyntaxUnit.fromToken(stream._token) ||
message: 'Unknown @ rule: ' + lt0.value + '.', stream.peek() === Tokens.FUNCTION && this._function({asText: true}) ||
}, lt0); this._unknownBlock([Tokens.LBRACKET, Tokens.LPAREN]);
// skip {} block this._ws();
let count = 0; const blockValue = this._unknownBlock();
do { if (!blockValue) {
const brace = stream.advance([Tokens.LBRACE, Tokens.RBRACE]); stream.match(Tokens.SEMICOLON);
count += brace === Tokens.LBRACE ? 1 : -1; }
} while (count > 0 && !stream._reader.eof());
if (count < 0) stream.unget(); this.fire({
type: 'unknown-at-rule',
name: lt0.value,
simpleValue,
blockValue,
}, lt0);
this._ws();
}
_unknownBlock(canStartWith = [Tokens.LBRACE]) {
const stream = this._tokenStream;
if (!canStartWith.includes(stream.peek())) {
return null;
}
stream.get();
const start = stream._token;
const reader = stream._reader;
reader.mark();
reader._cursor = start.offset;
reader._line = start.startLine;
reader._col = start.startCol;
const value = [];
const endings = [];
let blockEnd;
while (!reader.eof()) {
const chunk = reader.readMatch(/[^{}()[\]]*[{}()[\]]?/y);
const c = chunk.slice(-1);
value.push(chunk);
if (c === '{' || c === '(' || c === '[') {
endings.push(blockEnd);
blockEnd = c === '{' ? '}' : c === '(' ? ')' : ']';
} else if (c === '}' || c === ')' || c === ']') {
if (c !== blockEnd) {
break;
}
blockEnd = endings.pop();
if (!blockEnd) {
stream.resetLT();
return new SyntaxUnit(value.join(''), start);
}
}
}
reader.reset();
return null;
} }
_unexpectedToken(token) { _unexpectedToken(token) {
@ -5406,18 +5452,28 @@ self.parserlib = (() => {
Object.assign(Parser.prototype, TYPES); Object.assign(Parser.prototype, TYPES);
Parser.prototype._readWhitespace = Parser.prototype._ws; Parser.prototype._readWhitespace = Parser.prototype._ws;
const symDocument = [Tokens.DOCUMENT_SYM, Parser.prototype._document];
const symDocMisplaced = [Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced];
const symFontFace = [Tokens.FONT_FACE_SYM, Parser.prototype._fontFace];
const symKeyframes = [Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes];
const symMedia = [Tokens.MEDIA_SYM, Parser.prototype._media];
const symPage = [Tokens.PAGE_SYM, Parser.prototype._page];
const symSupports = [Tokens.SUPPORTS_SYM, Parser.prototype._supports];
const symUnknown = [Tokens.UNKNOWN_SYM, Parser.prototype._unknownSym];
const symViewport = [Tokens.VIEWPORT_SYM, Parser.prototype._viewport];
Parser.ACTIONS = { Parser.ACTIONS = {
stylesheet: new Map([ stylesheet: new Map([
[Tokens.MEDIA_SYM, Parser.prototype._media], symMedia,
[Tokens.DOCUMENT_SYM, Parser.prototype._document], symDocument,
[Tokens.SUPPORTS_SYM, Parser.prototype._supports], symSupports,
[Tokens.PAGE_SYM, Parser.prototype._page], symPage,
[Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], symFontFace,
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], symKeyframes,
[Tokens.VIEWPORT_SYM, Parser.prototype._viewport], symViewport,
symUnknown,
[Tokens.S, Parser.prototype._ws], [Tokens.S, Parser.prototype._ws],
[Tokens.UNKNOWN_SYM, Parser.prototype._unknownSym],
]), ]),
stylesheetMisplaced: new Map([ stylesheetMisplaced: new Map([
@ -5427,31 +5483,34 @@ self.parserlib = (() => {
]), ]),
document: new Map([ document: new Map([
[Tokens.MEDIA_SYM, Parser.prototype._media], symMedia,
[Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], symDocMisplaced,
[Tokens.SUPPORTS_SYM, Parser.prototype._supports], symSupports,
[Tokens.PAGE_SYM, Parser.prototype._page], symPage,
[Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], symFontFace,
[Tokens.VIEWPORT_SYM, Parser.prototype._viewport], symViewport,
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], symKeyframes,
symUnknown,
]), ]),
supports: new Map([ supports: new Map([
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], symKeyframes,
[Tokens.MEDIA_SYM, Parser.prototype._media], symMedia,
[Tokens.SUPPORTS_SYM, Parser.prototype._supports], symSupports,
[Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], symDocMisplaced,
[Tokens.VIEWPORT_SYM, Parser.prototype._viewport], symViewport,
symUnknown,
]), ]),
media: new Map([ media: new Map([
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], symKeyframes,
[Tokens.MEDIA_SYM, Parser.prototype._media], symMedia,
[Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], symDocMisplaced,
[Tokens.SUPPORTS_SYM, Parser.prototype._supports], symSupports,
[Tokens.PAGE_SYM, Parser.prototype._page], symPage,
[Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], symFontFace,
[Tokens.VIEWPORT_SYM, Parser.prototype._viewport], symViewport,
symUnknown,
]), ]),
simpleSelectorSequence: new Map([ simpleSelectorSequence: new Map([