@angular/compiler
Version:
Angular - the compiler library
755 lines • 116 kB
JavaScript
/**
* @license
* Copyright Google LLC 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, CssStylesBlockAst, CssStyleSheetAst, CssStyleValueAst, 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3NzX3BhcnNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy9jc3NfcGFyc2VyL2Nzc19wYXJzZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxLQUFLLEtBQUssTUFBTSxVQUFVLENBQUM7QUFDbEMsT0FBTyxFQUFDLFVBQVUsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUUxRixPQUFPLEVBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxxQkFBcUIsRUFBRSxXQUFXLEVBQUUseUJBQXlCLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLHdCQUF3QixFQUFFLGtCQUFrQixFQUFFLG9CQUFvQixFQUFFLG9CQUFvQixFQUFjLGNBQWMsRUFBRSxrQkFBa0IsRUFBRSxvQkFBb0IsRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxzQkFBc0IsRUFBRSxXQUFXLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDL2EsT0FBTyxFQUFDLFFBQVEsRUFBRSxZQUFZLEVBQWMsUUFBUSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBRXZJLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQztBQUUzQixPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFFcEMsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDO0FBQzVCLE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQztBQUN6QixNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQztBQUNyQyxNQUFNLGlCQUFpQixHQUFHLFFBQVEsQ0FBQztBQUVuQyxN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