| /*--------------------------------------------------------------------------------------------- |
| * Copyright (c) Microsoft Corporation. All rights reserved. |
| * Licensed under the MIT License. See License.txt in the project root for license information. |
| *--------------------------------------------------------------------------------------------*/ |
| 'use strict'; |
| var __extends = (this && this.__extends) || (function () { |
| var extendStatics = function (d, b) { |
| extendStatics = Object.setPrototypeOf || |
| ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
| function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; |
| return extendStatics(d, b); |
| }; |
| return function (d, b) { |
| extendStatics(d, b); |
| function __() { this.constructor = d; } |
| d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
| }; |
| })(); |
| import * as scssScanner from './scssScanner'; |
| import { TokenType } from './cssScanner'; |
| import * as cssParser from './cssParser'; |
| import * as nodes from './cssNodes'; |
| import { SCSSParseError } from './scssErrors'; |
| import { ParseError } from './cssErrors'; |
| /// <summary> |
| /// A parser for scss |
| /// http://sass-lang.com/documentation/file.SASS_REFERENCE.html |
| /// </summary> |
| var SCSSParser = /** @class */ (function (_super) { |
| __extends(SCSSParser, _super); |
| function SCSSParser() { |
| return _super.call(this, new scssScanner.SCSSScanner()) || this; |
| } |
| SCSSParser.prototype._parseStylesheetStatement = function (isNested) { |
| if (isNested === void 0) { isNested = false; } |
| if (this.peek(TokenType.AtKeyword)) { |
| return this._parseWarnAndDebug() // @warn, @debug and @error statements |
| || this._parseControlStatement() // @if, @while, @for, @each |
| || this._parseMixinDeclaration() // @mixin |
| || this._parseMixinContent() // @content |
| || this._parseMixinReference() // @include |
| || this._parseFunctionDeclaration() // @function |
| || this._parseForward() // @forward |
| || this._parseUse() // @use |
| || this._parseRuleset(isNested) // @at-rule |
| || _super.prototype._parseStylesheetAtStatement.call(this, isNested); |
| } |
| return this._parseRuleset(true) || this._parseVariableDeclaration(); |
| }; |
| SCSSParser.prototype._parseImport = function () { |
| if (!this.peekKeyword('@import')) { |
| return null; |
| } |
| var node = this.create(nodes.Import); |
| this.consumeToken(); |
| if (!node.addChild(this._parseURILiteral()) && !node.addChild(this._parseStringLiteral())) { |
| return this.finish(node, ParseError.URIOrStringExpected); |
| } |
| while (this.accept(TokenType.Comma)) { |
| if (!node.addChild(this._parseURILiteral()) && !node.addChild(this._parseStringLiteral())) { |
| return this.finish(node, ParseError.URIOrStringExpected); |
| } |
| } |
| if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) { |
| node.setMedialist(this._parseMediaQueryList()); |
| } |
| return this.finish(node); |
| }; |
| // scss variables: $font-size: 12px; |
| SCSSParser.prototype._parseVariableDeclaration = function (panic) { |
| if (panic === void 0) { panic = []; } |
| if (!this.peek(scssScanner.VariableName)) { |
| return null; |
| } |
| var node = this.create(nodes.VariableDeclaration); |
| if (!node.setVariable(this._parseVariable())) { |
| return null; |
| } |
| if (!this.accept(TokenType.Colon)) { |
| return this.finish(node, ParseError.ColonExpected); |
| } |
| if (this.prevToken) { |
| node.colonPosition = this.prevToken.offset; |
| } |
| if (!node.setValue(this._parseExpr())) { |
| return this.finish(node, ParseError.VariableValueExpected, [], panic); |
| } |
| while (this.peek(TokenType.Exclamation)) { |
| if (node.addChild(this._tryParsePrio())) { |
| // !important |
| } |
| else { |
| this.consumeToken(); |
| if (!this.peekRegExp(TokenType.Ident, /^(default|global)$/)) { |
| return this.finish(node, ParseError.UnknownKeyword); |
| } |
| this.consumeToken(); |
| } |
| } |
| if (this.peek(TokenType.SemiColon)) { |
| node.semicolonPosition = this.token.offset; // not part of the declaration, but useful information for code assist |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMediaContentStart = function () { |
| return this._parseInterpolation(); |
| }; |
| SCSSParser.prototype._parseMediaFeatureName = function () { |
| return this._parseModuleMember() |
| || this._parseFunction() // function before ident |
| || this._parseIdent() |
| || this._parseVariable(); |
| }; |
| SCSSParser.prototype._parseKeyframeSelector = function () { |
| return this._tryParseKeyframeSelector() |
| || this._parseControlStatement(this._parseKeyframeSelector.bind(this)) |
| || this._parseVariableDeclaration() |
| || this._parseMixinContent(); |
| }; |
| SCSSParser.prototype._parseVariable = function () { |
| if (!this.peek(scssScanner.VariableName)) { |
| return null; |
| } |
| var node = this.create(nodes.Variable); |
| this.consumeToken(); |
| return node; |
| }; |
| SCSSParser.prototype._parseModuleMember = function () { |
| var pos = this.mark(); |
| var node = this.create(nodes.Module); |
| if (!node.setIdentifier(this._parseIdent([nodes.ReferenceType.Module]))) { |
| return null; |
| } |
| if (this.hasWhitespace() |
| || !this.acceptDelim('.') |
| || this.hasWhitespace()) { |
| this.restoreAtMark(pos); |
| return null; |
| } |
| if (!node.addChild(this._parseVariable() || this._parseFunction())) { |
| return this.finish(node, ParseError.IdentifierOrVariableExpected); |
| } |
| return node; |
| }; |
| SCSSParser.prototype._parseIdent = function (referenceTypes) { |
| var _this = this; |
| if (!this.peek(TokenType.Ident) && !this.peek(scssScanner.InterpolationFunction) && !this.peekDelim('-')) { |
| return null; |
| } |
| var node = this.create(nodes.Identifier); |
| node.referenceTypes = referenceTypes; |
| node.isCustomProperty = this.peekRegExp(TokenType.Ident, /^--/); |
| var hasContent = false; |
| var indentInterpolation = function () { |
| var pos = _this.mark(); |
| if (_this.acceptDelim('-')) { |
| if (!_this.hasWhitespace()) { |
| _this.acceptDelim('-'); |
| } |
| if (_this.hasWhitespace()) { |
| _this.restoreAtMark(pos); |
| return null; |
| } |
| } |
| return _this._parseInterpolation(); |
| }; |
| while (this.accept(TokenType.Ident) || node.addChild(indentInterpolation()) || (hasContent && this.acceptRegexp(/[\w-]/))) { |
| hasContent = true; |
| if (this.hasWhitespace()) { |
| break; |
| } |
| } |
| return hasContent ? this.finish(node) : null; |
| }; |
| SCSSParser.prototype._parseTermExpression = function () { |
| return this._parseModuleMember() || |
| this._parseVariable() || |
| this._parseSelectorCombinator() || |
| //this._tryParsePrio() || |
| _super.prototype._parseTermExpression.call(this); |
| }; |
| SCSSParser.prototype._parseInterpolation = function () { |
| if (this.peek(scssScanner.InterpolationFunction)) { |
| var node = this.create(nodes.Interpolation); |
| this.consumeToken(); |
| if (!node.addChild(this._parseExpr()) && !this._parseSelectorCombinator()) { |
| if (this.accept(TokenType.CurlyR)) { |
| return this.finish(node); |
| } |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| if (!this.accept(TokenType.CurlyR)) { |
| return this.finish(node, ParseError.RightCurlyExpected); |
| } |
| return this.finish(node); |
| } |
| return null; |
| }; |
| SCSSParser.prototype._parseOperator = function () { |
| if (this.peek(scssScanner.EqualsOperator) || this.peek(scssScanner.NotEqualsOperator) |
| || this.peek(scssScanner.GreaterEqualsOperator) || this.peek(scssScanner.SmallerEqualsOperator) |
| || this.peekDelim('>') || this.peekDelim('<') |
| || this.peekIdent('and') || this.peekIdent('or') |
| || this.peekDelim('%')) { |
| var node = this.createNode(nodes.NodeType.Operator); |
| this.consumeToken(); |
| return this.finish(node); |
| } |
| return _super.prototype._parseOperator.call(this); |
| }; |
| SCSSParser.prototype._parseUnaryOperator = function () { |
| if (this.peekIdent('not')) { |
| var node = this.create(nodes.Node); |
| this.consumeToken(); |
| return this.finish(node); |
| } |
| return _super.prototype._parseUnaryOperator.call(this); |
| }; |
| SCSSParser.prototype._parseRuleSetDeclaration = function () { |
| if (this.peek(TokenType.AtKeyword)) { |
| return this._parseKeyframe() // nested @keyframe |
| || this._parseImport() // nested @import |
| || this._parseMedia(true) // nested @media |
| || this._parseFontFace() // nested @font-face |
| || this._parseWarnAndDebug() // @warn, @debug and @error statements |
| || this._parseControlStatement() // @if, @while, @for, @each |
| || this._parseFunctionDeclaration() // @function |
| || this._parseExtends() // @extends |
| || this._parseMixinReference() // @include |
| || this._parseMixinContent() // @content |
| || this._parseMixinDeclaration() // nested @mixin |
| || this._parseRuleset(true) // @at-rule |
| || this._parseSupports(true) // @supports |
| || _super.prototype._parseRuleSetDeclarationAtStatement.call(this); |
| } |
| return this._parseVariableDeclaration() // variable declaration |
| || this._tryParseRuleset(true) // nested ruleset |
| || _super.prototype._parseRuleSetDeclaration.call(this); // try css ruleset declaration as last so in the error case, the ast will contain a declaration |
| }; |
| SCSSParser.prototype._parseDeclaration = function (resyncStopTokens) { |
| var node = this.create(nodes.Declaration); |
| if (!node.setProperty(this._parseProperty())) { |
| return null; |
| } |
| if (!this.accept(TokenType.Colon)) { |
| return this.finish(node, ParseError.ColonExpected, [TokenType.Colon], resyncStopTokens); |
| } |
| if (this.prevToken) { |
| node.colonPosition = this.prevToken.offset; |
| } |
| var hasContent = false; |
| if (node.setValue(this._parseExpr())) { |
| hasContent = true; |
| node.addChild(this._parsePrio()); |
| } |
| if (this.peek(TokenType.CurlyL)) { |
| node.setNestedProperties(this._parseNestedProperties()); |
| } |
| else { |
| if (!hasContent) { |
| return this.finish(node, ParseError.PropertyValueExpected); |
| } |
| } |
| if (this.peek(TokenType.SemiColon)) { |
| node.semicolonPosition = this.token.offset; // not part of the declaration, but useful information for code assist |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseNestedProperties = function () { |
| var node = this.create(nodes.NestedProperties); |
| return this._parseBody(node, this._parseDeclaration.bind(this)); |
| }; |
| SCSSParser.prototype._parseExtends = function () { |
| if (this.peekKeyword('@extend')) { |
| var node = this.create(nodes.ExtendsReference); |
| this.consumeToken(); |
| if (!node.getSelectors().addChild(this._parseSimpleSelector())) { |
| return this.finish(node, ParseError.SelectorExpected); |
| } |
| while (this.accept(TokenType.Comma)) { |
| node.getSelectors().addChild(this._parseSimpleSelector()); |
| } |
| if (this.accept(TokenType.Exclamation)) { |
| if (!this.acceptIdent('optional')) { |
| return this.finish(node, ParseError.UnknownKeyword); |
| } |
| } |
| return this.finish(node); |
| } |
| return null; |
| }; |
| SCSSParser.prototype._parseSimpleSelectorBody = function () { |
| return this._parseSelectorCombinator() || this._parseSelectorPlaceholder() || _super.prototype._parseSimpleSelectorBody.call(this); |
| }; |
| SCSSParser.prototype._parseSelectorCombinator = function () { |
| if (this.peekDelim('&')) { |
| var node = this.createNode(nodes.NodeType.SelectorCombinator); |
| this.consumeToken(); |
| while (!this.hasWhitespace() && (this.acceptDelim('-') || this.accept(TokenType.Num) || this.accept(TokenType.Dimension) || node.addChild(this._parseIdent()) || this.acceptDelim('&'))) { |
| // support &-foo-1 |
| } |
| return this.finish(node); |
| } |
| return null; |
| }; |
| SCSSParser.prototype._parseSelectorPlaceholder = function () { |
| if (this.peekDelim('%')) { |
| var node = this.createNode(nodes.NodeType.SelectorPlaceholder); |
| this.consumeToken(); |
| this._parseIdent(); |
| return this.finish(node); |
| } |
| else if (this.peekKeyword('@at-root')) { |
| var node = this.createNode(nodes.NodeType.SelectorPlaceholder); |
| this.consumeToken(); |
| return this.finish(node); |
| } |
| return null; |
| }; |
| SCSSParser.prototype._parseElementName = function () { |
| var pos = this.mark(); |
| var node = _super.prototype._parseElementName.call(this); |
| if (node && !this.hasWhitespace() && this.peek(TokenType.ParenthesisL)) { // for #49589 |
| this.restoreAtMark(pos); |
| return null; |
| } |
| return node; |
| }; |
| SCSSParser.prototype._tryParsePseudoIdentifier = function () { |
| return this._parseInterpolation() || _super.prototype._tryParsePseudoIdentifier.call(this); // for #49589 |
| }; |
| SCSSParser.prototype._parseWarnAndDebug = function () { |
| if (!this.peekKeyword('@debug') |
| && !this.peekKeyword('@warn') |
| && !this.peekKeyword('@error')) { |
| return null; |
| } |
| var node = this.createNode(nodes.NodeType.Debug); |
| this.consumeToken(); // @debug, @warn or @error |
| node.addChild(this._parseExpr()); // optional |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseControlStatement = function (parseStatement) { |
| if (parseStatement === void 0) { parseStatement = this._parseRuleSetDeclaration.bind(this); } |
| if (!this.peek(TokenType.AtKeyword)) { |
| return null; |
| } |
| return this._parseIfStatement(parseStatement) || this._parseForStatement(parseStatement) |
| || this._parseEachStatement(parseStatement) || this._parseWhileStatement(parseStatement); |
| }; |
| SCSSParser.prototype._parseIfStatement = function (parseStatement) { |
| if (!this.peekKeyword('@if')) { |
| return null; |
| } |
| return this._internalParseIfStatement(parseStatement); |
| }; |
| SCSSParser.prototype._internalParseIfStatement = function (parseStatement) { |
| var node = this.create(nodes.IfStatement); |
| this.consumeToken(); // @if or if |
| if (!node.setExpression(this._parseExpr(true))) { |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| this._parseBody(node, parseStatement); |
| if (this.acceptKeyword('@else')) { |
| if (this.peekIdent('if')) { |
| node.setElseClause(this._internalParseIfStatement(parseStatement)); |
| } |
| else if (this.peek(TokenType.CurlyL)) { |
| var elseNode = this.create(nodes.ElseStatement); |
| this._parseBody(elseNode, parseStatement); |
| node.setElseClause(elseNode); |
| } |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseForStatement = function (parseStatement) { |
| if (!this.peekKeyword('@for')) { |
| return null; |
| } |
| var node = this.create(nodes.ForStatement); |
| this.consumeToken(); // @for |
| if (!node.setVariable(this._parseVariable())) { |
| return this.finish(node, ParseError.VariableNameExpected, [TokenType.CurlyR]); |
| } |
| if (!this.acceptIdent('from')) { |
| return this.finish(node, SCSSParseError.FromExpected, [TokenType.CurlyR]); |
| } |
| if (!node.addChild(this._parseBinaryExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected, [TokenType.CurlyR]); |
| } |
| if (!this.acceptIdent('to') && !this.acceptIdent('through')) { |
| return this.finish(node, SCSSParseError.ThroughOrToExpected, [TokenType.CurlyR]); |
| } |
| if (!node.addChild(this._parseBinaryExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected, [TokenType.CurlyR]); |
| } |
| return this._parseBody(node, parseStatement); |
| }; |
| SCSSParser.prototype._parseEachStatement = function (parseStatement) { |
| if (!this.peekKeyword('@each')) { |
| return null; |
| } |
| var node = this.create(nodes.EachStatement); |
| this.consumeToken(); // @each |
| var variables = node.getVariables(); |
| if (!variables.addChild(this._parseVariable())) { |
| return this.finish(node, ParseError.VariableNameExpected, [TokenType.CurlyR]); |
| } |
| while (this.accept(TokenType.Comma)) { |
| if (!variables.addChild(this._parseVariable())) { |
| return this.finish(node, ParseError.VariableNameExpected, [TokenType.CurlyR]); |
| } |
| } |
| this.finish(variables); |
| if (!this.acceptIdent('in')) { |
| return this.finish(node, SCSSParseError.InExpected, [TokenType.CurlyR]); |
| } |
| if (!node.addChild(this._parseExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected, [TokenType.CurlyR]); |
| } |
| return this._parseBody(node, parseStatement); |
| }; |
| SCSSParser.prototype._parseWhileStatement = function (parseStatement) { |
| if (!this.peekKeyword('@while')) { |
| return null; |
| } |
| var node = this.create(nodes.WhileStatement); |
| this.consumeToken(); // @while |
| if (!node.addChild(this._parseBinaryExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected, [TokenType.CurlyR]); |
| } |
| return this._parseBody(node, parseStatement); |
| }; |
| SCSSParser.prototype._parseFunctionBodyDeclaration = function () { |
| return this._parseVariableDeclaration() || this._parseReturnStatement() || this._parseWarnAndDebug() |
| || this._parseControlStatement(this._parseFunctionBodyDeclaration.bind(this)); |
| }; |
| SCSSParser.prototype._parseFunctionDeclaration = function () { |
| if (!this.peekKeyword('@function')) { |
| return null; |
| } |
| var node = this.create(nodes.FunctionDeclaration); |
| this.consumeToken(); // @function |
| if (!node.setIdentifier(this._parseIdent([nodes.ReferenceType.Function]))) { |
| return this.finish(node, ParseError.IdentifierExpected, [TokenType.CurlyR]); |
| } |
| if (!this.accept(TokenType.ParenthesisL)) { |
| return this.finish(node, ParseError.LeftParenthesisExpected, [TokenType.CurlyR]); |
| } |
| if (node.getParameters().addChild(this._parseParameterDeclaration())) { |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getParameters().addChild(this._parseParameterDeclaration())) { |
| return this.finish(node, ParseError.VariableNameExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected, [TokenType.CurlyR]); |
| } |
| return this._parseBody(node, this._parseFunctionBodyDeclaration.bind(this)); |
| }; |
| SCSSParser.prototype._parseReturnStatement = function () { |
| if (!this.peekKeyword('@return')) { |
| return null; |
| } |
| var node = this.createNode(nodes.NodeType.ReturnStatement); |
| this.consumeToken(); // @function |
| if (!node.addChild(this._parseExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMixinDeclaration = function () { |
| if (!this.peekKeyword('@mixin')) { |
| return null; |
| } |
| var node = this.create(nodes.MixinDeclaration); |
| this.consumeToken(); |
| if (!node.setIdentifier(this._parseIdent([nodes.ReferenceType.Mixin]))) { |
| return this.finish(node, ParseError.IdentifierExpected, [TokenType.CurlyR]); |
| } |
| if (this.accept(TokenType.ParenthesisL)) { |
| if (node.getParameters().addChild(this._parseParameterDeclaration())) { |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getParameters().addChild(this._parseParameterDeclaration())) { |
| return this.finish(node, ParseError.VariableNameExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected, [TokenType.CurlyR]); |
| } |
| } |
| return this._parseBody(node, this._parseRuleSetDeclaration.bind(this)); |
| }; |
| SCSSParser.prototype._parseParameterDeclaration = function () { |
| var node = this.create(nodes.FunctionParameter); |
| if (!node.setIdentifier(this._parseVariable())) { |
| return null; |
| } |
| if (this.accept(scssScanner.Ellipsis)) { |
| // ok |
| } |
| if (this.accept(TokenType.Colon)) { |
| if (!node.setDefaultValue(this._parseExpr(true))) { |
| return this.finish(node, ParseError.VariableValueExpected, [], [TokenType.Comma, TokenType.ParenthesisR]); |
| } |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMixinContent = function () { |
| if (!this.peekKeyword('@content')) { |
| return null; |
| } |
| var node = this.create(nodes.MixinContentReference); |
| this.consumeToken(); |
| if (this.accept(TokenType.ParenthesisL)) { |
| if (node.getArguments().addChild(this._parseFunctionArgument())) { |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getArguments().addChild(this._parseFunctionArgument())) { |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected); |
| } |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMixinReference = function () { |
| if (!this.peekKeyword('@include')) { |
| return null; |
| } |
| var node = this.create(nodes.MixinReference); |
| this.consumeToken(); |
| // Could be module or mixin identifier, set as mixin as default. |
| var firstIdent = this._parseIdent([nodes.ReferenceType.Mixin]); |
| if (!node.setIdentifier(firstIdent)) { |
| return this.finish(node, ParseError.IdentifierExpected, [TokenType.CurlyR]); |
| } |
| // Is a module accessor. |
| if (!this.hasWhitespace() && this.acceptDelim('.') && !this.hasWhitespace()) { |
| var secondIdent = this._parseIdent([nodes.ReferenceType.Mixin]); |
| if (!secondIdent) { |
| return this.finish(node, ParseError.IdentifierExpected, [TokenType.CurlyR]); |
| } |
| var moduleToken = this.create(nodes.Module); |
| // Re-purpose first matched ident as identifier for module token. |
| firstIdent.referenceTypes = [nodes.ReferenceType.Module]; |
| moduleToken.setIdentifier(firstIdent); |
| // Override identifier with second ident. |
| node.setIdentifier(secondIdent); |
| node.addChild(moduleToken); |
| } |
| if (this.accept(TokenType.ParenthesisL)) { |
| if (node.getArguments().addChild(this._parseFunctionArgument())) { |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getArguments().addChild(this._parseFunctionArgument())) { |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected); |
| } |
| } |
| if (this.peekIdent('using') || this.peek(TokenType.CurlyL)) { |
| node.setContent(this._parseMixinContentDeclaration()); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMixinContentDeclaration = function () { |
| var node = this.create(nodes.MixinContentDeclaration); |
| if (this.acceptIdent('using')) { |
| if (!this.accept(TokenType.ParenthesisL)) { |
| return this.finish(node, ParseError.LeftParenthesisExpected, [TokenType.CurlyL]); |
| } |
| if (node.getParameters().addChild(this._parseParameterDeclaration())) { |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getParameters().addChild(this._parseParameterDeclaration())) { |
| return this.finish(node, ParseError.VariableNameExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected, [TokenType.CurlyL]); |
| } |
| } |
| if (this.peek(TokenType.CurlyL)) { |
| this._parseBody(node, this._parseMixinReferenceBodyStatement.bind(this)); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseMixinReferenceBodyStatement = function () { |
| return this._tryParseKeyframeSelector() || this._parseRuleSetDeclaration(); |
| }; |
| SCSSParser.prototype._parseFunctionArgument = function () { |
| // [variableName ':'] expression | variableName '...' |
| var node = this.create(nodes.FunctionArgument); |
| var pos = this.mark(); |
| var argument = this._parseVariable(); |
| if (argument) { |
| if (!this.accept(TokenType.Colon)) { |
| if (this.accept(scssScanner.Ellipsis)) { // optional |
| node.setValue(argument); |
| return this.finish(node); |
| } |
| else { |
| this.restoreAtMark(pos); |
| } |
| } |
| else { |
| node.setIdentifier(argument); |
| } |
| } |
| if (node.setValue(this._parseExpr(true))) { |
| this.accept(scssScanner.Ellipsis); // #43746 |
| node.addChild(this._parsePrio()); // #9859 |
| return this.finish(node); |
| } |
| else if (node.setValue(this._tryParsePrio())) { |
| return this.finish(node); |
| } |
| return null; |
| }; |
| SCSSParser.prototype._parseURLArgument = function () { |
| var pos = this.mark(); |
| var node = _super.prototype._parseURLArgument.call(this); |
| if (!node || !this.peek(TokenType.ParenthesisR)) { |
| this.restoreAtMark(pos); |
| var node_1 = this.create(nodes.Node); |
| node_1.addChild(this._parseBinaryExpr()); |
| return this.finish(node_1); |
| } |
| return node; |
| }; |
| SCSSParser.prototype._parseOperation = function () { |
| if (!this.peek(TokenType.ParenthesisL)) { |
| return null; |
| } |
| var node = this.create(nodes.Node); |
| this.consumeToken(); |
| while (node.addChild(this._parseListElement())) { |
| this.accept(TokenType.Comma); // optional |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseListElement = function () { |
| var node = this.create(nodes.ListEntry); |
| var child = this._parseBinaryExpr(); |
| if (!child) { |
| return null; |
| } |
| if (this.accept(TokenType.Colon)) { |
| node.setKey(child); |
| if (!node.setValue(this._parseBinaryExpr())) { |
| return this.finish(node, ParseError.ExpressionExpected); |
| } |
| } |
| else { |
| node.setValue(child); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseUse = function () { |
| if (!this.peekKeyword('@use')) { |
| return null; |
| } |
| var node = this.create(nodes.Use); |
| this.consumeToken(); // @use |
| if (!node.addChild(this._parseStringLiteral())) { |
| return this.finish(node, ParseError.StringLiteralExpected); |
| } |
| if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) { |
| if (!this.peekRegExp(TokenType.Ident, /as|with/)) { |
| return this.finish(node, ParseError.UnknownKeyword); |
| } |
| if (this.acceptIdent('as') && |
| (!node.setIdentifier(this._parseIdent([nodes.ReferenceType.Module])) && !this.acceptDelim('*'))) { |
| return this.finish(node, ParseError.IdentifierOrWildcardExpected); |
| } |
| if (this.acceptIdent('with')) { |
| if (!this.accept(TokenType.ParenthesisL)) { |
| return this.finish(node, ParseError.LeftParenthesisExpected, [TokenType.ParenthesisR]); |
| } |
| // First variable statement, no comma. |
| if (!node.getParameters().addChild(this._parseModuleConfigDeclaration())) { |
| return this.finish(node, ParseError.VariableNameExpected); |
| } |
| while (this.accept(TokenType.Comma)) { |
| if (this.peek(TokenType.ParenthesisR)) { |
| break; |
| } |
| if (!node.getParameters().addChild(this._parseModuleConfigDeclaration())) { |
| return this.finish(node, ParseError.VariableNameExpected); |
| } |
| } |
| if (!this.accept(TokenType.ParenthesisR)) { |
| return this.finish(node, ParseError.RightParenthesisExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { |
| return this.finish(node, ParseError.SemiColonExpected); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseModuleConfigDeclaration = function () { |
| var node = this.create(nodes.ModuleConfiguration); |
| if (!node.setIdentifier(this._parseVariable())) { |
| return null; |
| } |
| if (!this.accept(TokenType.Colon) || !node.setValue(this._parseExpr(true))) { |
| return this.finish(node, ParseError.VariableValueExpected, [], [TokenType.Comma, TokenType.ParenthesisR]); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseForward = function () { |
| if (!this.peekKeyword('@forward')) { |
| return null; |
| } |
| var node = this.create(nodes.Forward); |
| this.consumeToken(); |
| if (!node.addChild(this._parseStringLiteral())) { |
| return this.finish(node, ParseError.StringLiteralExpected); |
| } |
| if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) { |
| if (!this.peekRegExp(TokenType.Ident, /as|hide|show/)) { |
| return this.finish(node, ParseError.UnknownKeyword); |
| } |
| if (this.acceptIdent('as')) { |
| var identifier = this._parseIdent([nodes.ReferenceType.Forward]); |
| if (!node.setIdentifier(identifier)) { |
| return this.finish(node, ParseError.IdentifierExpected); |
| } |
| // Wildcard must be the next character after the identifier string. |
| if (this.hasWhitespace() || !this.acceptDelim('*')) { |
| return this.finish(node, ParseError.WildcardExpected); |
| } |
| } |
| if (this.peekIdent('hide') || this.peekIdent('show')) { |
| if (!node.addChild(this._parseForwardVisibility())) { |
| return this.finish(node, ParseError.IdentifierOrVariableExpected); |
| } |
| } |
| } |
| if (!this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { |
| return this.finish(node, ParseError.SemiColonExpected); |
| } |
| return this.finish(node); |
| }; |
| SCSSParser.prototype._parseForwardVisibility = function () { |
| var node = this.create(nodes.ForwardVisibility); |
| // Assume to be "hide" or "show". |
| node.setIdentifier(this._parseIdent()); |
| while (node.addChild(this._parseVariable() || this._parseIdent())) { |
| // Consume all variables and idents ahead. |
| } |
| // More than just identifier |
| return node.getChildren().length > 1 ? node : null; |
| }; |
| SCSSParser.prototype._parseSupportsCondition = function () { |
| return this._parseInterpolation() || _super.prototype._parseSupportsCondition.call(this); |
| }; |
| return SCSSParser; |
| }(cssParser.Parser)); |
| export { SCSSParser }; |