parserlib: consume unknown @-rules per CSS grammar
This commit is contained in:
		
							parent
							
								
									07ba44cc2c
								
							
						
					
					
						commit
						aa43507478
					
				| 
						 | 
					@ -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([
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user