UNPKG

@angular/compiler

Version:

Angular - the compiler library

741 lines • 116 kB
/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import * as chars from '../chars'; import { ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan } from '../parse_util'; import { BlockType, CssAst, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst, mergeTokens } from './css_ast'; import { CssLexer, CssLexerMode, CssToken, CssTokenType, generateErrorMessage, getRawMessage, isNewline } from './css_lexer'; const SPACE_OPERATOR = ' '; export { CssToken } from './css_lexer'; export { BlockType } from './css_ast'; const SLASH_CHARACTER = '/'; const GT_CHARACTER = '>'; const TRIPLE_GT_OPERATOR_STR = '>>>'; const DEEP_OPERATOR_STR = '/deep/'; const EOF_DELIM_FLAG = 1; const RBRACE_DELIM_FLAG = 2; const LBRACE_DELIM_FLAG = 4; const COMMA_DELIM_FLAG = 8; const COLON_DELIM_FLAG = 16; const SEMICOLON_DELIM_FLAG = 32; const NEWLINE_DELIM_FLAG = 64; const RPAREN_DELIM_FLAG = 128; const LPAREN_DELIM_FLAG = 256; const SPACE_DELIM_FLAG = 512; function _pseudoSelectorSupportsInnerSelectors(name) { return ['not', 'host', 'host-context'].indexOf(name) >= 0; } function isSelectorOperatorCharacter(code) { switch (code) { case chars.$SLASH: case chars.$TILDA: case chars.$PLUS: case chars.$GT: return true; default: return chars.isWhitespace(code); } } function getDelimFromCharacter(code) { switch (code) { case chars.$EOF: return EOF_DELIM_FLAG; case chars.$COMMA: return COMMA_DELIM_FLAG; case chars.$COLON: return COLON_DELIM_FLAG; case chars.$SEMICOLON: return SEMICOLON_DELIM_FLAG; case chars.$RBRACE: return RBRACE_DELIM_FLAG; case chars.$LBRACE: return LBRACE_DELIM_FLAG; case chars.$RPAREN: return RPAREN_DELIM_FLAG; case chars.$SPACE: case chars.$TAB: return SPACE_DELIM_FLAG; default: return isNewline(code) ? NEWLINE_DELIM_FLAG : 0; } } function characterContainsDelimiter(code, delimiters) { return (getDelimFromCharacter(code) & delimiters) > 0; } export class ParsedCssResult { constructor(errors, ast) { this.errors = errors; this.ast = ast; } } export class CssParser { constructor() { this._errors = []; } /** * @param css the CSS code that will be parsed * @param url the name of the CSS file containing the CSS source code */ parse(css, url) { const lexer = new CssLexer(); this._file = new ParseSourceFile(css, url); this._scanner = lexer.scan(css, false); const ast = this._parseStyleSheet(EOF_DELIM_FLAG); const errors = this._errors; this._errors = []; const result = new ParsedCssResult(errors, ast); this._file = null; this._scanner = null; return result; } /** @internal */ _parseStyleSheet(delimiters) { const results = []; this._scanner.consumeEmptyStatements(); while (this._scanner.peek != chars.$EOF) { this._scanner.setMode(CssLexerMode.BLOCK); results.push(this._parseRule(delimiters)); } let span = null; if (results.length > 0) { const firstRule = results[0]; // we collect the last token like so incase there was an // EOF token that was emitted sometime during the lexing span = this._generateSourceSpan(firstRule, this._lastToken); } return new CssStyleSheetAst(span, results); } /** @internal */ _getSourceContent() { return this._scanner != null ? this._scanner.input : ''; } /** @internal */ _extractSourceContent(start, end) { return this._getSourceContent().substring(start, end + 1); } /** @internal */ _generateSourceSpan(start, end = null) { let startLoc; if (start instanceof CssAst) { startLoc = start.location.start; } else { let token = start; if (token == null) { // the data here is invalid, however, if and when this does // occur, any other errors associated with this will be collected token = this._lastToken; } startLoc = new ParseLocation(this._file, token.index, token.line, token.column); } if (end == null) { end = this._lastToken; } let endLine = -1; let endColumn = -1; let endIndex = -1; if (end instanceof CssAst) { endLine = end.location.end.line; endColumn = end.location.end.col; endIndex = end.location.end.offset; } else if (end instanceof CssToken) { endLine = end.line; endColumn = end.column; endIndex = end.index; } const endLoc = new ParseLocation(this._file, endIndex, endLine, endColumn); return new ParseSourceSpan(startLoc, endLoc); } /** @internal */ _resolveBlockType(token) { switch (token.strValue) { case '@-o-keyframes': case '@-moz-keyframes': case '@-webkit-keyframes': case '@keyframes': return BlockType.Keyframes; case '@charset': return BlockType.Charset; case '@import': return BlockType.Import; case '@namespace': return BlockType.Namespace; case '@page': return BlockType.Page; case '@document': return BlockType.Document; case '@media': return BlockType.MediaQuery; case '@font-face': return BlockType.FontFace; case '@viewport': return BlockType.Viewport; case '@supports': return BlockType.Supports; default: return BlockType.Unsupported; } } /** @internal */ _parseRule(delimiters) { if (this._scanner.peek == chars.$AT) { return this._parseAtRule(delimiters); } return this._parseSelectorRule(delimiters); } /** @internal */ _parseAtRule(delimiters) { const start = this._getScannerIndex(); this._scanner.setMode(CssLexerMode.BLOCK); const token = this._scan(); const startToken = token; this._assertCondition(token.type == CssTokenType.AtKeyword, `The CSS Rule ${token.strValue} is not a valid [@] rule.`, token); let block; const type = this._resolveBlockType(token); let span; let tokens; let endToken; let end; let strValue; let query; switch (type) { case BlockType.Charset: case BlockType.Namespace: case BlockType.Import: let value = this._parseValue(delimiters); this._scanner.setMode(CssLexerMode.BLOCK); this._scanner.consumeEmptyStatements(); span = this._generateSourceSpan(startToken, value); return new CssInlineRuleAst(span, type, value); case BlockType.Viewport: case BlockType.FontFace: block = this._parseStyleBlock(delimiters); span = this._generateSourceSpan(startToken, block); return new CssBlockRuleAst(span, type, block); case BlockType.Keyframes: tokens = this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG); // keyframes only have one identifier name let name = tokens[0]; block = this._parseKeyframeBlock(delimiters); span = this._generateSourceSpan(startToken, block); return new CssKeyframeRuleAst(span, name, block); case BlockType.MediaQuery: this._scanner.setMode(CssLexerMode.MEDIA_QUERY); tokens = this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG); endToken = tokens[tokens.length - 1]; // we do not track the whitespace after the mediaQuery predicate ends // so we have to calculate the end string value on our own end = endToken.index + endToken.strValue.length - 1; strValue = this._extractSourceContent(start, end); span = this._generateSourceSpan(startToken, endToken); query = new CssAtRulePredicateAst(span, strValue, tokens); block = this._parseBlock(delimiters); strValue = this._extractSourceContent(start, this._getScannerIndex() - 1); span = this._generateSourceSpan(startToken, block); return new CssMediaQueryRuleAst(span, strValue, query, block); case BlockType.Document: case BlockType.Supports: case BlockType.Page: this._scanner.setMode(CssLexerMode.AT_RULE_QUERY); tokens = this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG); endToken = tokens[tokens.length - 1]; // we do not track the whitespace after this block rule predicate ends // so we have to calculate the end string value on our own end = endToken.index + endToken.strValue.length - 1; strValue = this._extractSourceContent(start, end); span = this._generateSourceSpan(startToken, tokens[tokens.length - 1]); query = new CssAtRulePredicateAst(span, strValue, tokens); block = this._parseBlock(delimiters); strValue = this._extractSourceContent(start, block.end.offset); span = this._generateSourceSpan(startToken, block); return new CssBlockDefinitionRuleAst(span, strValue, type, query, block); // if a custom @rule { ... } is used it should still tokenize the insides default: let listOfTokens = []; let tokenName = token.strValue; this._scanner.setMode(CssLexerMode.ALL); this._error(generateErrorMessage(this._getSourceContent(), `The CSS "at" rule "${tokenName}" is not allowed to used here`, token.strValue, token.index, token.line, token.column), token); this._collectUntilDelim(delimiters | LBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG) .forEach((token) => { listOfTokens.push(token); }); if (this._scanner.peek == chars.$LBRACE) { listOfTokens.push(this._consume(CssTokenType.Character, '{')); this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG) .forEach((token) => { listOfTokens.push(token); }); listOfTokens.push(this._consume(CssTokenType.Character, '}')); } endToken = listOfTokens[listOfTokens.length - 1]; span = this._generateSourceSpan(startToken, endToken); return new CssUnknownRuleAst(span, tokenName, listOfTokens); } } /** @internal */ _parseSelectorRule(delimiters) { const start = this._getScannerIndex(); const selectors = this._parseSelectors(delimiters); const block = this._parseStyleBlock(delimiters); let ruleAst; let span; const startSelector = selectors[0]; if (block != null) { span = this._generateSourceSpan(startSelector, block); ruleAst = new CssSelectorRuleAst(span, selectors, block); } else { const name = this._extractSourceContent(start, this._getScannerIndex() - 1); const innerTokens = []; selectors.forEach((selector) => { selector.selectorParts.forEach((part) => { part.tokens.forEach((token) => { innerTokens.push(token); }); }); }); const endToken = innerTokens[innerTokens.length - 1]; span = this._generateSourceSpan(startSelector, endToken); ruleAst = new CssUnknownTokenListAst(span, name, innerTokens); } this._scanner.setMode(CssLexerMode.BLOCK); this._scanner.consumeEmptyStatements(); return ruleAst; } /** @internal */ _parseSelectors(delimiters) { delimiters |= LBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG; const selectors = []; let isParsingSelectors = true; while (isParsingSelectors) { selectors.push(this._parseSelector(delimiters)); isParsingSelectors = !characterContainsDelimiter(this._scanner.peek, delimiters); if (isParsingSelectors) { this._consume(CssTokenType.Character, ','); isParsingSelectors = !characterContainsDelimiter(this._scanner.peek, delimiters); if (isParsingSelectors) { this._scanner.consumeWhitespace(); } } } return selectors; } /** @internal */ _scan() { const output = this._scanner.scan(); const token = output.token; const error = output.error; if (error != null) { this._error(getRawMessage(error), token); } this._lastToken = token; return token; } /** @internal */ _getScannerIndex() { return this._scanner.index; } /** @internal */ _consume(type, value = null) { const output = this._scanner.consume(type, value); const token = output.token; const error = output.error; if (error != null) { this._error(getRawMessage(error), token); } this._lastToken = token; return token; } /** @internal */ _parseKeyframeBlock(delimiters) { delimiters |= RBRACE_DELIM_FLAG; this._scanner.setMode(CssLexerMode.KEYFRAME_BLOCK); const startToken = this._consume(CssTokenType.Character, '{'); const definitions = []; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { definitions.push(this._parseKeyframeDefinition(delimiters)); } const endToken = this._consume(CssTokenType.Character, '}'); const span = this._generateSourceSpan(startToken, endToken); return new CssBlockAst(span, definitions); } /** @internal */ _parseKeyframeDefinition(delimiters) { const start = this._getScannerIndex(); const stepTokens = []; delimiters |= LBRACE_DELIM_FLAG; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { stepTokens.push(this._parseKeyframeLabel(delimiters | COMMA_DELIM_FLAG)); if (this._scanner.peek != chars.$LBRACE) { this._consume(CssTokenType.Character, ','); } } const stylesBlock = this._parseStyleBlock(delimiters | RBRACE_DELIM_FLAG); const span = this._generateSourceSpan(stepTokens[0], stylesBlock); const ast = new CssKeyframeDefinitionAst(span, stepTokens, stylesBlock); this._scanner.setMode(CssLexerMode.BLOCK); return ast; } /** @internal */ _parseKeyframeLabel(delimiters) { this._scanner.setMode(CssLexerMode.KEYFRAME_BLOCK); return mergeTokens(this._collectUntilDelim(delimiters)); } /** @internal */ _parsePseudoSelector(delimiters) { const start = this._getScannerIndex(); delimiters &= ~COMMA_DELIM_FLAG; // we keep the original value since we may use it to recurse when :not, :host are used const startingDelims = delimiters; const startToken = this._consume(CssTokenType.Character, ':'); const tokens = [startToken]; if (this._scanner.peek == chars.$COLON) { // ::something tokens.push(this._consume(CssTokenType.Character, ':')); } const innerSelectors = []; this._scanner.setMode(CssLexerMode.PSEUDO_SELECTOR); // host, host-context, lang, not, nth-child are all identifiers const pseudoSelectorToken = this._consume(CssTokenType.Identifier); const pseudoSelectorName = pseudoSelectorToken.strValue; tokens.push(pseudoSelectorToken); // host(), lang(), nth-child(), etc... if (this._scanner.peek == chars.$LPAREN) { this._scanner.setMode(CssLexerMode.PSEUDO_SELECTOR_WITH_ARGUMENTS); const openParenToken = this._consume(CssTokenType.Character, '('); tokens.push(openParenToken); // :host(innerSelector(s)), :not(selector), etc... if (_pseudoSelectorSupportsInnerSelectors(pseudoSelectorName)) { let innerDelims = startingDelims | LPAREN_DELIM_FLAG | RPAREN_DELIM_FLAG; if (pseudoSelectorName == 'not') { // the inner selector inside of :not(...) can only be one // CSS selector (no commas allowed) ... This is according // to the CSS specification innerDelims |= COMMA_DELIM_FLAG; } // :host(a, b, c) { this._parseSelectors(innerDelims).forEach((selector, index) => { innerSelectors.push(selector); }); } else { // this branch is for things like "en-us, 2k + 1, etc..." // which all end up in pseudoSelectors like :lang, :nth-child, etc.. const innerValueDelims = delimiters | LBRACE_DELIM_FLAG | COLON_DELIM_FLAG | RPAREN_DELIM_FLAG | LPAREN_DELIM_FLAG; while (!characterContainsDelimiter(this._scanner.peek, innerValueDelims)) { const token = this._scan(); tokens.push(token); } } const closeParenToken = this._consume(CssTokenType.Character, ')'); tokens.push(closeParenToken); } const end = this._getScannerIndex() - 1; const strValue = this._extractSourceContent(start, end); const endToken = tokens[tokens.length - 1]; const span = this._generateSourceSpan(startToken, endToken); return new CssPseudoSelectorAst(span, strValue, pseudoSelectorName, tokens, innerSelectors); } /** @internal */ _parseSimpleSelector(delimiters) { const start = this._getScannerIndex(); delimiters |= COMMA_DELIM_FLAG; this._scanner.setMode(CssLexerMode.SELECTOR); const selectorCssTokens = []; const pseudoSelectors = []; let previousToken = undefined; const selectorPartDelimiters = delimiters | SPACE_DELIM_FLAG; let loopOverSelector = !characterContainsDelimiter(this._scanner.peek, selectorPartDelimiters); let hasAttributeError = false; while (loopOverSelector) { const peek = this._scanner.peek; switch (peek) { case chars.$COLON: let innerPseudo = this._parsePseudoSelector(delimiters); pseudoSelectors.push(innerPseudo); this._scanner.setMode(CssLexerMode.SELECTOR); break; case chars.$LBRACKET: // we set the mode after the scan because attribute mode does not // allow attribute [] values. And this also will catch any errors // if an extra "[" is used inside. selectorCssTokens.push(this._scan()); this._scanner.setMode(CssLexerMode.ATTRIBUTE_SELECTOR); break; case chars.$RBRACKET: if (this._scanner.getMode() != CssLexerMode.ATTRIBUTE_SELECTOR) { hasAttributeError = true; } // we set the mode early because attribute mode does not // allow attribute [] values this._scanner.setMode(CssLexerMode.SELECTOR); selectorCssTokens.push(this._scan()); break; default: if (isSelectorOperatorCharacter(peek)) { loopOverSelector = false; continue; } let token = this._scan(); previousToken = token; selectorCssTokens.push(token); break; } loopOverSelector = !characterContainsDelimiter(this._scanner.peek, selectorPartDelimiters); } hasAttributeError = hasAttributeError || this._scanner.getMode() == CssLexerMode.ATTRIBUTE_SELECTOR; if (hasAttributeError) { this._error(`Unbalanced CSS attribute selector at column ${previousToken.line}:${previousToken.column}`, previousToken); } let end = this._getScannerIndex() - 1; // this happens if the selector is not directly followed by // a comma or curly brace without a space in between let operator = null; let operatorScanCount = 0; let lastOperatorToken = null; if (!characterContainsDelimiter(this._scanner.peek, delimiters)) { while (operator == null && !characterContainsDelimiter(this._scanner.peek, delimiters) && isSelectorOperatorCharacter(this._scanner.peek)) { let token = this._scan(); const tokenOperator = token.strValue; operatorScanCount++; lastOperatorToken = token; if (tokenOperator != SPACE_OPERATOR) { switch (tokenOperator) { case SLASH_CHARACTER: // /deep/ operator let deepToken = this._consume(CssTokenType.Identifier); let deepSlash = this._consume(CssTokenType.Character); let index = lastOperatorToken.index; let line = lastOperatorToken.line; let column = lastOperatorToken.column; if (deepToken != null && deepToken.strValue.toLowerCase() == 'deep' && deepSlash.strValue == SLASH_CHARACTER) { token = new CssToken(lastOperatorToken.index, lastOperatorToken.column, lastOperatorToken.line, CssTokenType.Identifier, DEEP_OPERATOR_STR); } else { const text = SLASH_CHARACTER + deepToken.strValue + deepSlash.strValue; this._error(generateErrorMessage(this._getSourceContent(), `${text} is an invalid CSS operator`, text, index, line, column), lastOperatorToken); token = new CssToken(index, column, line, CssTokenType.Invalid, text); } break; case GT_CHARACTER: // >>> operator if (this._scanner.peek == chars.$GT && this._scanner.peekPeek == chars.$GT) { this._consume(CssTokenType.Character, GT_CHARACTER); this._consume(CssTokenType.Character, GT_CHARACTER); token = new CssToken(lastOperatorToken.index, lastOperatorToken.column, lastOperatorToken.line, CssTokenType.Identifier, TRIPLE_GT_OPERATOR_STR); } break; } operator = token; } } // so long as there is an operator then we can have an // ending value that is beyond the selector value ... // otherwise it's just a bunch of trailing whitespace if (operator != null) { end = operator.index; } } this._scanner.consumeWhitespace(); const strValue = this._extractSourceContent(start, end); // if we do come across one or more spaces inside of // the operators loop then an empty space is still a // valid operator to use if something else was not found if (operator == null && operatorScanCount > 0 && this._scanner.peek != chars.$LBRACE) { operator = lastOperatorToken; } // please note that `endToken` is reassigned multiple times below // so please do not optimize the if statements into if/elseif let startTokenOrAst = null; let endTokenOrAst = null; if (selectorCssTokens.length > 0) { startTokenOrAst = startTokenOrAst || selectorCssTokens[0]; endTokenOrAst = selectorCssTokens[selectorCssTokens.length - 1]; } if (pseudoSelectors.length > 0) { startTokenOrAst = startTokenOrAst || pseudoSelectors[0]; endTokenOrAst = pseudoSelectors[pseudoSelectors.length - 1]; } if (operator != null) { startTokenOrAst = startTokenOrAst || operator; endTokenOrAst = operator; } const span = this._generateSourceSpan(startTokenOrAst, endTokenOrAst); return new CssSimpleSelectorAst(span, selectorCssTokens, strValue, pseudoSelectors, operator); } /** @internal */ _parseSelector(delimiters) { delimiters |= COMMA_DELIM_FLAG; this._scanner.setMode(CssLexerMode.SELECTOR); const simpleSelectors = []; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { simpleSelectors.push(this._parseSimpleSelector(delimiters)); this._scanner.consumeWhitespace(); } const firstSelector = simpleSelectors[0]; const lastSelector = simpleSelectors[simpleSelectors.length - 1]; const span = this._generateSourceSpan(firstSelector, lastSelector); return new CssSelectorAst(span, simpleSelectors); } /** @internal */ _parseValue(delimiters) { delimiters |= RBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG | NEWLINE_DELIM_FLAG; this._scanner.setMode(CssLexerMode.STYLE_VALUE); const start = this._getScannerIndex(); const tokens = []; let wsStr = ''; let previous = undefined; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { let token; if (previous != null && previous.type == CssTokenType.Identifier && this._scanner.peek == chars.$LPAREN) { token = this._consume(CssTokenType.Character, '('); tokens.push(token); this._scanner.setMode(CssLexerMode.STYLE_VALUE_FUNCTION); token = this._scan(); tokens.push(token); this._scanner.setMode(CssLexerMode.STYLE_VALUE); token = this._consume(CssTokenType.Character, ')'); tokens.push(token); } else { token = this._scan(); if (token.type == CssTokenType.Whitespace) { wsStr += token.strValue; } else { wsStr = ''; tokens.push(token); } } previous = token; } const end = this._getScannerIndex() - 1; this._scanner.consumeWhitespace(); const code = this._scanner.peek; if (code == chars.$SEMICOLON) { this._consume(CssTokenType.Character, ';'); } else if (code != chars.$RBRACE) { this._error(generateErrorMessage(this._getSourceContent(), `The CSS key/value definition did not end with a semicolon`, previous.strValue, previous.index, previous.line, previous.column), previous); } const strValue = this._extractSourceContent(start, end); const startToken = tokens[0]; const endToken = tokens[tokens.length - 1]; const span = this._generateSourceSpan(startToken, endToken); return new CssStyleValueAst(span, tokens, strValue); } /** @internal */ _collectUntilDelim(delimiters, assertType = null) { const tokens = []; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { const val = assertType != null ? this._consume(assertType) : this._scan(); tokens.push(val); } return tokens; } /** @internal */ _parseBlock(delimiters) { delimiters |= RBRACE_DELIM_FLAG; this._scanner.setMode(CssLexerMode.BLOCK); const startToken = this._consume(CssTokenType.Character, '{'); this._scanner.consumeEmptyStatements(); const results = []; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { results.push(this._parseRule(delimiters)); } const endToken = this._consume(CssTokenType.Character, '}'); this._scanner.setMode(CssLexerMode.BLOCK); this._scanner.consumeEmptyStatements(); const span = this._generateSourceSpan(startToken, endToken); return new CssBlockAst(span, results); } /** @internal */ _parseStyleBlock(delimiters) { delimiters |= RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG; this._scanner.setMode(CssLexerMode.STYLE_BLOCK); const startToken = this._consume(CssTokenType.Character, '{'); if (startToken.numValue != chars.$LBRACE) { return null; } const definitions = []; this._scanner.consumeEmptyStatements(); while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { definitions.push(this._parseDefinition(delimiters)); this._scanner.consumeEmptyStatements(); } const endToken = this._consume(CssTokenType.Character, '}'); this._scanner.setMode(CssLexerMode.STYLE_BLOCK); this._scanner.consumeEmptyStatements(); const span = this._generateSourceSpan(startToken, endToken); return new CssStylesBlockAst(span, definitions); } /** @internal */ _parseDefinition(delimiters) { this._scanner.setMode(CssLexerMode.STYLE_BLOCK); let prop = this._consume(CssTokenType.Identifier); let parseValue = false; let value = null; let endToken = prop; // the colon value separates the prop from the style. // there are a few cases as to what could happen if it // is missing switch (this._scanner.peek) { case chars.$SEMICOLON: case chars.$RBRACE: case chars.$EOF: parseValue = false; break; default: let propStr = [prop.strValue]; if (this._scanner.peek != chars.$COLON) { // this will throw the error const nextValue = this._consume(CssTokenType.Character, ':'); propStr.push(nextValue.strValue); const remainingTokens = this._collectUntilDelim(delimiters | COLON_DELIM_FLAG | SEMICOLON_DELIM_FLAG, CssTokenType.Identifier); if (remainingTokens.length > 0) { remainingTokens.forEach((token) => { propStr.push(token.strValue); }); } endToken = prop = new CssToken(prop.index, prop.column, prop.line, prop.type, propStr.join(' ')); } // this means we've reached the end of the definition and/or block if (this._scanner.peek == chars.$COLON) { this._consume(CssTokenType.Character, ':'); parseValue = true; } break; } if (parseValue) { value = this._parseValue(delimiters); endToken = value; } else { this._error(generateErrorMessage(this._getSourceContent(), `The CSS property was not paired with a style value`, prop.strValue, prop.index, prop.line, prop.column), prop); } const span = this._generateSourceSpan(prop, endToken); return new CssDefinitionAst(span, prop, value); } /** @internal */ _assertCondition(status, errorMessage, problemToken) { if (!status) { this._error(errorMessage, problemToken); return true; } return false; } /** @internal */ _error(message, problemToken) { const length = problemToken.strValue.length; const error = CssParseError.create(this._file, 0, problemToken.line, problemToken.column, length, message); this._errors.push(error); } } export class CssParseError extends ParseError { static create(file, offset, line, col, length, errMsg) { const start = new ParseLocation(file, offset, line, col); const end = new ParseLocation(file, offset, line, col + length); const span = new ParseSourceSpan(start, end); return new CssParseError(span, 'CSS Parse Error: ' + errMsg); } constructor(span, message) { super(span, message); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3NzX3BhcnNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy9jc3NfcGFyc2VyL2Nzc19wYXJzZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxLQUFLLEtBQUssTUFBTSxVQUFVLENBQUM7QUFDbEMsT0FBTyxFQUFDLFVBQVUsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUUxRixPQUFPLEVBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxxQkFBcUIsRUFBRSxXQUFXLEVBQUUseUJBQXlCLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLHdCQUF3QixFQUFFLGtCQUFrQixFQUFFLG9CQUFvQixFQUFFLG9CQUFvQixFQUFjLGNBQWMsRUFBRSxrQkFBa0IsRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxzQkFBc0IsRUFBRSxXQUFXLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDL2EsT0FBTyxFQUFDLFFBQVEsRUFBRSxZQUFZLEVBQWMsUUFBUSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBRXZJLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQztBQUUzQixPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFFcEMsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDO0FBQzVCLE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQztBQUN6QixNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQztBQUNyQyxNQUFNLGlCQUFpQixHQUFHLFFBQVEsQ0FBQztBQUVuQyxN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