parserlib: consume unknown @-rules per CSS grammar
This commit is contained in:
		
							parent
							
								
									07ba44cc2c
								
							
						
					
					
						commit
						aa43507478
					
				|  | @ -2722,6 +2722,10 @@ self.parserlib = (() => { | |||
| 
 | ||||
|     constructor(input) { | ||||
|       this._reader = new StringReader(input ? input.toString() : ''); | ||||
|       this.resetLT(); | ||||
|     } | ||||
| 
 | ||||
|     resetLT() { | ||||
|       // Token object for the last consumed token.
 | ||||
|       this._token = null; | ||||
|       // Lookahead token buffer.
 | ||||
|  | @ -3148,8 +3152,7 @@ self.parserlib = (() => { | |||
|      */ | ||||
|     atRuleToken(first, pos) { | ||||
|       this._reader.mark(); | ||||
|       const ident = this.readName(); | ||||
|       let rule = first + ident; | ||||
|       let rule = first + this.readName(); | ||||
|       let tt = Tokens.type(lower(rule)); | ||||
|       // if it's not valid, use the first character only and reset the reader
 | ||||
|       if (tt === Tokens.CHAR || tt === Tokens.UNKNOWN) { | ||||
|  | @ -5296,19 +5299,62 @@ self.parserlib = (() => { | |||
|         throw new SyntaxError('Unknown @ rule.', lt0); | ||||
|       } | ||||
| 
 | ||||
|       this.fire({ | ||||
|         type: 'error', | ||||
|         error: null, | ||||
|         message: 'Unknown @ rule: ' + lt0.value + '.', | ||||
|       }, lt0); | ||||
|       this._ws(); | ||||
|       const simpleValue = | ||||
|         stream.match([Tokens.IDENT, Tokens.CUSTOM_PROP]) && SyntaxUnit.fromToken(stream._token) || | ||||
|         stream.peek() === Tokens.FUNCTION && this._function({asText: true}) || | ||||
|         this._unknownBlock([Tokens.LBRACKET, Tokens.LPAREN]); | ||||
| 
 | ||||
|       // skip {} block
 | ||||
|       let count = 0; | ||||
|       do { | ||||
|         const brace = stream.advance([Tokens.LBRACE, Tokens.RBRACE]); | ||||
|         count += brace === Tokens.LBRACE ? 1 : -1; | ||||
|       } while (count > 0 && !stream._reader.eof()); | ||||
|       if (count < 0) stream.unget(); | ||||
|       this._ws(); | ||||
|       const blockValue = this._unknownBlock(); | ||||
|       if (!blockValue) { | ||||
|         stream.match(Tokens.SEMICOLON); | ||||
|       } | ||||
| 
 | ||||
|       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) { | ||||
|  | @ -5406,18 +5452,28 @@ self.parserlib = (() => { | |||
|   Object.assign(Parser.prototype, TYPES); | ||||
|   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 = { | ||||
| 
 | ||||
|     stylesheet: new Map([ | ||||
|       [Tokens.MEDIA_SYM, Parser.prototype._media], | ||||
|       [Tokens.DOCUMENT_SYM, Parser.prototype._document], | ||||
|       [Tokens.SUPPORTS_SYM, Parser.prototype._supports], | ||||
|       [Tokens.PAGE_SYM, Parser.prototype._page], | ||||
|       [Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], | ||||
|       [Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], | ||||
|       [Tokens.VIEWPORT_SYM, Parser.prototype._viewport], | ||||
|       symMedia, | ||||
|       symDocument, | ||||
|       symSupports, | ||||
|       symPage, | ||||
|       symFontFace, | ||||
|       symKeyframes, | ||||
|       symViewport, | ||||
|       symUnknown, | ||||
|       [Tokens.S, Parser.prototype._ws], | ||||
|       [Tokens.UNKNOWN_SYM, Parser.prototype._unknownSym], | ||||
|     ]), | ||||
| 
 | ||||
|     stylesheetMisplaced: new Map([ | ||||
|  | @ -5427,31 +5483,34 @@ self.parserlib = (() => { | |||
|     ]), | ||||
| 
 | ||||
|     document: new Map([ | ||||
|       [Tokens.MEDIA_SYM, Parser.prototype._media], | ||||
|       [Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], | ||||
|       [Tokens.SUPPORTS_SYM, Parser.prototype._supports], | ||||
|       [Tokens.PAGE_SYM, Parser.prototype._page], | ||||
|       [Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], | ||||
|       [Tokens.VIEWPORT_SYM, Parser.prototype._viewport], | ||||
|       [Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], | ||||
|       symMedia, | ||||
|       symDocMisplaced, | ||||
|       symSupports, | ||||
|       symPage, | ||||
|       symFontFace, | ||||
|       symViewport, | ||||
|       symKeyframes, | ||||
|       symUnknown, | ||||
|     ]), | ||||
| 
 | ||||
|     supports: new Map([ | ||||
|       [Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], | ||||
|       [Tokens.MEDIA_SYM, Parser.prototype._media], | ||||
|       [Tokens.SUPPORTS_SYM, Parser.prototype._supports], | ||||
|       [Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], | ||||
|       [Tokens.VIEWPORT_SYM, Parser.prototype._viewport], | ||||
|       symKeyframes, | ||||
|       symMedia, | ||||
|       symSupports, | ||||
|       symDocMisplaced, | ||||
|       symViewport, | ||||
|       symUnknown, | ||||
|     ]), | ||||
| 
 | ||||
|     media: new Map([ | ||||
|       [Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes], | ||||
|       [Tokens.MEDIA_SYM, Parser.prototype._media], | ||||
|       [Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced], | ||||
|       [Tokens.SUPPORTS_SYM, Parser.prototype._supports], | ||||
|       [Tokens.PAGE_SYM, Parser.prototype._page], | ||||
|       [Tokens.FONT_FACE_SYM, Parser.prototype._fontFace], | ||||
|       [Tokens.VIEWPORT_SYM, Parser.prototype._viewport], | ||||
|       symKeyframes, | ||||
|       symMedia, | ||||
|       symDocMisplaced, | ||||
|       symSupports, | ||||
|       symPage, | ||||
|       symFontFace, | ||||
|       symViewport, | ||||
|       symUnknown, | ||||
|     ]), | ||||
| 
 | ||||
|     simpleSelectorSequence: new Map([ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user