` implies
* that `width=0` and `height=1`)
*/
this._stylesIndex = new Map();
/**
* Represents the location of each class binding in the template
* (e.g. `
` implies
* that `big=0` and `hidden=1`)
*/
this._classesIndex = new Map();
this._initialStyleValues = [];
this._initialClassValues = [];
// certain style properties ALWAYS need sanitization
// this is checked each time new styles are encountered
this._useDefaultSanitizer = false;
}
StylingBuilder.prototype.hasBindingsOrInitialValues = function () { return this._hasBindings || this._hasInitialValues; };
/**
* Registers a given input to the styling builder to be later used when producing AOT code.
*
* The code below will only accept the input if it is somehow tied to styling (whether it be
* style/class bindings or static style/class attributes).
*/
StylingBuilder.prototype.registerBoundInput = function (input) {
// [attr.style] or [attr.class] are skipped in the code below,
// they should not be treated as styling-based bindings since
// they are intended to be written directly to the attr and
// will therefore skip all style/class resolution that is present
// with style="", [style]="" and [style.prop]="", class="",
// [class.prop]="". [class]="" assignments
var name = input.name;
var binding = null;
switch (input.type) {
case 0 /* Property */:
if (name == 'style') {
binding = this.registerStyleInput(null, input.value, '', input.sourceSpan);
}
else if (isClassBinding(input.name)) {
binding = this.registerClassInput(null, input.value, input.sourceSpan);
}
break;
case 3 /* Style */:
binding = this.registerStyleInput(input.name, input.value, input.unit, input.sourceSpan);
break;
case 2 /* Class */:
binding = this.registerClassInput(input.name, input.value, input.sourceSpan);
break;
}
return binding ? true : false;
};
StylingBuilder.prototype.registerStyleInput = function (propertyName, value, unit, sourceSpan) {
var entry = { name: propertyName, unit: unit, value: value, sourceSpan: sourceSpan };
if (propertyName) {
(this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
this._useDefaultSanitizer = this._useDefaultSanitizer || isStyleSanitizable(propertyName);
registerIntoMap(this._stylesIndex, propertyName);
}
else {
this._useDefaultSanitizer = true;
this._styleMapInput = entry;
}
this._lastStylingInput = entry;
this._hasBindings = true;
return entry;
};
StylingBuilder.prototype.registerClassInput = function (className, value, sourceSpan) {
var entry = { name: className, value: value, sourceSpan: sourceSpan };
if (className) {
(this._singleClassInputs = this._singleClassInputs || []).push(entry);
registerIntoMap(this._classesIndex, className);
}
else {
this._classMapInput = entry;
}
this._lastStylingInput = entry;
this._hasBindings = true;
return entry;
};
/**
* Registers the element's static style string value to the builder.
*
* @param value the style string (e.g. `width:100px; height:200px;`)
*/
StylingBuilder.prototype.registerStyleAttr = function (value) {
this._initialStyleValues = parse(value);
this._hasInitialValues = true;
};
/**
* Registers the element's static class string value to the builder.
*
* @param value the className string (e.g. `disabled gold zoom`)
*/
StylingBuilder.prototype.registerClassAttr = function (value) {
this._initialClassValues = value.trim().split(/\s+/g);
this._hasInitialValues = true;
};
/**
* Appends all styling-related expressions to the provided attrs array.
*
* @param attrs an existing array where each of the styling expressions
* will be inserted into.
*/
StylingBuilder.prototype.populateInitialStylingAttrs = function (attrs) {
// [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
if (this._initialClassValues.length) {
attrs.push(literal(1 /* Classes */));
for (var i = 0; i < this._initialClassValues.length; i++) {
attrs.push(literal(this._initialClassValues[i]));
}
}
// [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
if (this._initialStyleValues.length) {
attrs.push(literal(2 /* Styles */));
for (var i = 0; i < this._initialStyleValues.length; i += 2) {
attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
}
}
};
/**
* Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
*
* The instruction generation code below is used for producing the AOT statement code which is
* responsible for registering initial styles (within a directive hostBindings' creation block)
* to the directive host element.
*/
StylingBuilder.prototype.buildDirectiveHostAttrsInstruction = function (sourceSpan, constantPool) {
var _this = this;
if (this._hasInitialValues && this._directiveExpr) {
return {
sourceSpan: sourceSpan,
reference: Identifiers$1.elementHostAttrs,
buildParams: function () {
var attrs = [];
_this.populateInitialStylingAttrs(attrs);
return [_this._directiveExpr, getConstantLiteralFromArray(constantPool, attrs)];
}
};
}
return null;
};
/**
* Builds an instruction with all the expressions and parameters for `elementStyling`.
*
* The instruction generation code below is used for producing the AOT statement code which is
* responsible for registering style/class bindings to an element.
*/
StylingBuilder.prototype.buildElementStylingInstruction = function (sourceSpan, constantPool) {
var _this = this;
if (this._hasBindings) {
return {
sourceSpan: sourceSpan,
reference: Identifiers$1.elementStyling,
buildParams: function () {
// a string array of every style-based binding
var styleBindingProps = _this._singleStyleInputs ? _this._singleStyleInputs.map(function (i) { return literal(i.name); }) : [];
// a string array of every class-based binding
var classBindingNames = _this._singleClassInputs ? _this._singleClassInputs.map(function (i) { return literal(i.name); }) : [];
// to salvage space in the AOT generated code, there is no point in passing
// in `null` into a param if any follow-up params are not used. Therefore,
// only when a trailing param is used then it will be filled with nulls in between
// (otherwise a shorter amount of params will be filled). The code below helps
// determine how many params are required in the expression code.
//
// min params => elementStyling()
// max params => elementStyling(classBindings, styleBindings, sanitizer, directive)
var expectedNumberOfArgs = 0;
if (_this._directiveExpr) {
expectedNumberOfArgs = 4;
}
else if (_this._useDefaultSanitizer) {
expectedNumberOfArgs = 3;
}
else if (styleBindingProps.length) {
expectedNumberOfArgs = 2;
}
else if (classBindingNames.length) {
expectedNumberOfArgs = 1;
}
var params = [];
addParam(params, classBindingNames.length > 0, getConstantLiteralFromArray(constantPool, classBindingNames), 1, expectedNumberOfArgs);
addParam(params, styleBindingProps.length > 0, getConstantLiteralFromArray(constantPool, styleBindingProps), 2, expectedNumberOfArgs);
addParam(params, _this._useDefaultSanitizer, importExpr(Identifiers$1.defaultStyleSanitizer), 3, expectedNumberOfArgs);
if (_this._directiveExpr) {
params.push(_this._directiveExpr);
}
return params;
}
};
}
return null;
};
/**
* Builds an instruction with all the expressions and parameters for `elementStylingMap`.
*
* The instruction data will contain all expressions for `elementStylingMap` to function
* which include the `[style]` and `[class]` expression params (if they exist) as well as
* the sanitizer and directive reference expression.
*/
StylingBuilder.prototype.buildElementStylingMapInstruction = function (valueConverter) {
var _this = this;
if (this._classMapInput || this._styleMapInput) {
var stylingInput = this._classMapInput || this._styleMapInput;
// these values must be outside of the update block so that they can
// be evaluted (the AST visit call) during creation time so that any
// pipes can be picked up in time before the template is built
var mapBasedClassValue_1 = this._classMapInput ? this._classMapInput.value.visit(valueConverter) : null;
var mapBasedStyleValue_1 = this._styleMapInput ? this._styleMapInput.value.visit(valueConverter) : null;
return {
sourceSpan: stylingInput.sourceSpan,
reference: Identifiers$1.elementStylingMap,
buildParams: function (convertFn) {
var params = [_this._elementIndexExpr];
if (mapBasedClassValue_1) {
params.push(convertFn(mapBasedClassValue_1));
}
else if (_this._styleMapInput) {
params.push(NULL_EXPR);
}
if (mapBasedStyleValue_1) {
params.push(convertFn(mapBasedStyleValue_1));
}
else if (_this._directiveExpr) {
params.push(NULL_EXPR);
}
if (_this._directiveExpr) {
params.push(_this._directiveExpr);
}
return params;
}
};
}
return null;
};
StylingBuilder.prototype._buildSingleInputs = function (reference, inputs, mapIndex, allowUnits, valueConverter) {
var _this = this;
return inputs.map(function (input) {
var bindingIndex = mapIndex.get(input.name);
var value = input.value.visit(valueConverter);
return {
sourceSpan: input.sourceSpan,
reference: reference,
buildParams: function (convertFn) {
var params = [_this._elementIndexExpr, literal(bindingIndex), convertFn(value)];
if (allowUnits) {
if (input.unit) {
params.push(literal(input.unit));
}
else if (_this._directiveExpr) {
params.push(NULL_EXPR);
}
}
if (_this._directiveExpr) {
params.push(_this._directiveExpr);
}
return params;
}
};
});
};
StylingBuilder.prototype._buildClassInputs = function (valueConverter) {
if (this._singleClassInputs) {
return this._buildSingleInputs(Identifiers$1.elementClassProp, this._singleClassInputs, this._classesIndex, false, valueConverter);
}
return [];
};
StylingBuilder.prototype._buildStyleInputs = function (valueConverter) {
if (this._singleStyleInputs) {
return this._buildSingleInputs(Identifiers$1.elementStyleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter);
}
return [];
};
StylingBuilder.prototype._buildApplyFn = function () {
var _this = this;
return {
sourceSpan: this._lastStylingInput ? this._lastStylingInput.sourceSpan : null,
reference: Identifiers$1.elementStylingApply,
buildParams: function () {
var params = [_this._elementIndexExpr];
if (_this._directiveExpr) {
params.push(_this._directiveExpr);
}
return params;
}
};
};
/**
* Constructs all instructions which contain the expressions that will be placed
* into the update block of a template function or a directive hostBindings function.
*/
StylingBuilder.prototype.buildUpdateLevelInstructions = function (valueConverter) {
var instructions = [];
if (this._hasBindings) {
var mapInstruction = this.buildElementStylingMapInstruction(valueConverter);
if (mapInstruction) {
instructions.push(mapInstruction);
}
instructions.push.apply(instructions, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(this._buildStyleInputs(valueConverter)));
instructions.push.apply(instructions, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(this._buildClassInputs(valueConverter)));
instructions.push(this._buildApplyFn());
}
return instructions;
};
return StylingBuilder;
}());
function isClassBinding(name) {
return name == 'className' || name == 'class';
}
function registerIntoMap(map, key) {
if (!map.has(key)) {
map.set(key, map.size);
}
}
function isStyleSanitizable(prop) {
return prop === 'background-image' || prop === 'background' || prop === 'border-image' ||
prop === 'filter' || prop === 'list-style' || prop === 'list-style-image';
}
/**
* Simple helper function to either provide the constant literal that will house the value
* here or a null value if the provided values are empty.
*/
function getConstantLiteralFromArray(constantPool, values) {
return values.length ? constantPool.getConstLiteral(literalArr(values), true) : NULL_EXPR;
}
/**
* Simple helper function that adds a parameter or does nothing at all depending on the provided
* predicate and totalExpectedArgs values
*/
function addParam(params, predicate, value, argNumber, totalExpectedArgs) {
if (predicate) {
params.push(value);
}
else if (argNumber < totalExpectedArgs) {
params.push(NULL_EXPR);
}
}
/**
* @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
*/
var TokenType;
(function (TokenType) {
TokenType[TokenType["Character"] = 0] = "Character";
TokenType[TokenType["Identifier"] = 1] = "Identifier";
TokenType[TokenType["Keyword"] = 2] = "Keyword";
TokenType[TokenType["String"] = 3] = "String";
TokenType[TokenType["Operator"] = 4] = "Operator";
TokenType[TokenType["Number"] = 5] = "Number";
TokenType[TokenType["Error"] = 6] = "Error";
})(TokenType || (TokenType = {}));
var KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
var Lexer = /** @class */ (function () {
function Lexer() {
}
Lexer.prototype.tokenize = function (text) {
var scanner = new _Scanner(text);
var tokens = [];
var token = scanner.scanToken();
while (token != null) {
tokens.push(token);
token = scanner.scanToken();
}
return tokens;
};
return Lexer;
}());
var Token = /** @class */ (function () {
function Token(index, type, numValue, strValue) {
this.index = index;
this.type = type;
this.numValue = numValue;
this.strValue = strValue;
}
Token.prototype.isCharacter = function (code) {
return this.type == TokenType.Character && this.numValue == code;
};
Token.prototype.isNumber = function () { return this.type == TokenType.Number; };
Token.prototype.isString = function () { return this.type == TokenType.String; };
Token.prototype.isOperator = function (operator) {
return this.type == TokenType.Operator && this.strValue == operator;
};
Token.prototype.isIdentifier = function () { return this.type == TokenType.Identifier; };
Token.prototype.isKeyword = function () { return this.type == TokenType.Keyword; };
Token.prototype.isKeywordLet = function () { return this.type == TokenType.Keyword && this.strValue == 'let'; };
Token.prototype.isKeywordAs = function () { return this.type == TokenType.Keyword && this.strValue == 'as'; };
Token.prototype.isKeywordNull = function () { return this.type == TokenType.Keyword && this.strValue == 'null'; };
Token.prototype.isKeywordUndefined = function () {
return this.type == TokenType.Keyword && this.strValue == 'undefined';
};
Token.prototype.isKeywordTrue = function () { return this.type == TokenType.Keyword && this.strValue == 'true'; };
Token.prototype.isKeywordFalse = function () { return this.type == TokenType.Keyword && this.strValue == 'false'; };
Token.prototype.isKeywordThis = function () { return this.type == TokenType.Keyword && this.strValue == 'this'; };
Token.prototype.isError = function () { return this.type == TokenType.Error; };
Token.prototype.toNumber = function () { return this.type == TokenType.Number ? this.numValue : -1; };
Token.prototype.toString = function () {
switch (this.type) {
case TokenType.Character:
case TokenType.Identifier:
case TokenType.Keyword:
case TokenType.Operator:
case TokenType.String:
case TokenType.Error:
return this.strValue;
case TokenType.Number:
return this.numValue.toString();
default:
return null;
}
};
return Token;
}());
function newCharacterToken(index, code) {
return new Token(index, TokenType.Character, code, String.fromCharCode(code));
}
function newIdentifierToken(index, text) {
return new Token(index, TokenType.Identifier, 0, text);
}
function newKeywordToken(index, text) {
return new Token(index, TokenType.Keyword, 0, text);
}
function newOperatorToken(index, text) {
return new Token(index, TokenType.Operator, 0, text);
}
function newStringToken(index, text) {
return new Token(index, TokenType.String, 0, text);
}
function newNumberToken(index, n) {
return new Token(index, TokenType.Number, n, '');
}
function newErrorToken(index, message) {
return new Token(index, TokenType.Error, 0, message);
}
var EOF = new Token(-1, TokenType.Character, 0, '');
var _Scanner = /** @class */ (function () {
function _Scanner(input) {
this.input = input;
this.peek = 0;
this.index = -1;
this.length = input.length;
this.advance();
}
_Scanner.prototype.advance = function () {
this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
};
_Scanner.prototype.scanToken = function () {
var input = this.input, length = this.length;
var peek = this.peek, index = this.index;
// Skip whitespace.
while (peek <= $SPACE) {
if (++index >= length) {
peek = $EOF;
break;
}
else {
peek = input.charCodeAt(index);
}
}
this.peek = peek;
this.index = index;
if (index >= length) {
return null;
}
// Handle identifiers and numbers.
if (isIdentifierStart(peek))
return this.scanIdentifier();
if (isDigit(peek))
return this.scanNumber(index);
var start = index;
switch (peek) {
case $PERIOD:
this.advance();
return isDigit(this.peek) ? this.scanNumber(start) :
newCharacterToken(start, $PERIOD);
case $LPAREN:
case $RPAREN:
case $LBRACE:
case $RBRACE:
case $LBRACKET:
case $RBRACKET:
case $COMMA:
case $COLON:
case $SEMICOLON:
return this.scanCharacter(start, peek);
case $SQ:
case $DQ:
return this.scanString();
case $HASH:
case $PLUS:
case $MINUS:
case $STAR:
case $SLASH:
case $PERCENT:
case $CARET:
return this.scanOperator(start, String.fromCharCode(peek));
case $QUESTION:
return this.scanComplexOperator(start, '?', $PERIOD, '.');
case $LT:
case $GT:
return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
case $BANG:
case $EQ:
return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
case $AMPERSAND:
return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
case $BAR:
return this.scanComplexOperator(start, '|', $BAR, '|');
case $NBSP:
while (isWhitespace(this.peek))
this.advance();
return this.scanToken();
}
this.advance();
return this.error("Unexpected character [" + String.fromCharCode(peek) + "]", 0);
};
_Scanner.prototype.scanCharacter = function (start, code) {
this.advance();
return newCharacterToken(start, code);
};
_Scanner.prototype.scanOperator = function (start, str) {
this.advance();
return newOperatorToken(start, str);
};
/**
* Tokenize a 2/3 char long operator
*
* @param start start index in the expression
* @param one first symbol (always part of the operator)
* @param twoCode code point for the second symbol
* @param two second symbol (part of the operator when the second code point matches)
* @param threeCode code point for the third symbol
* @param three third symbol (part of the operator when provided and matches source expression)
*/
_Scanner.prototype.scanComplexOperator = function (start, one, twoCode, two, threeCode, three) {
this.advance();
var str = one;
if (this.peek == twoCode) {
this.advance();
str += two;
}
if (threeCode != null && this.peek == threeCode) {
this.advance();
str += three;
}
return newOperatorToken(start, str);
};
_Scanner.prototype.scanIdentifier = function () {
var start = this.index;
this.advance();
while (isIdentifierPart(this.peek))
this.advance();
var str = this.input.substring(start, this.index);
return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, str) :
newIdentifierToken(start, str);
};
_Scanner.prototype.scanNumber = function (start) {
var simple = (this.index === start);
this.advance(); // Skip initial digit.
while (true) {
if (isDigit(this.peek)) ;
else if (this.peek == $PERIOD) {
simple = false;
}
else if (isExponentStart(this.peek)) {
this.advance();
if (isExponentSign(this.peek))
this.advance();
if (!isDigit(this.peek))
return this.error('Invalid exponent', -1);
simple = false;
}
else {
break;
}
this.advance();
}
var str = this.input.substring(start, this.index);
var value = simple ? parseIntAutoRadix(str) : parseFloat(str);
return newNumberToken(start, value);
};
_Scanner.prototype.scanString = function () {
var start = this.index;
var quote = this.peek;
this.advance(); // Skip initial quote.
var buffer = '';
var marker = this.index;
var input = this.input;
while (this.peek != quote) {
if (this.peek == $BACKSLASH) {
buffer += input.substring(marker, this.index);
this.advance();
var unescapedCode = void 0;
// Workaround for TS2.1-introduced type strictness
this.peek = this.peek;
if (this.peek == $u) {
// 4 character hex code for unicode character.
var hex = input.substring(this.index + 1, this.index + 5);
if (/^[0-9a-f]+$/i.test(hex)) {
unescapedCode = parseInt(hex, 16);
}
else {
return this.error("Invalid unicode escape [\\u" + hex + "]", 0);
}
for (var i = 0; i < 5; i++) {
this.advance();
}
}
else {
unescapedCode = unescape(this.peek);
this.advance();
}
buffer += String.fromCharCode(unescapedCode);
marker = this.index;
}
else if (this.peek == $EOF) {
return this.error('Unterminated quote', 0);
}
else {
this.advance();
}
}
var last = input.substring(marker, this.index);
this.advance(); // Skip terminating quote.
return newStringToken(start, buffer + last);
};
_Scanner.prototype.error = function (message, offset) {
var position = this.index + offset;
return newErrorToken(position, "Lexer Error: " + message + " at column " + position + " in expression [" + this.input + "]");
};
return _Scanner;
}());
function isIdentifierStart(code) {
return ($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
(code == $_) || (code == $$);
}
function isIdentifier(input) {
if (input.length == 0)
return false;
var scanner = new _Scanner(input);
if (!isIdentifierStart(scanner.peek))
return false;
scanner.advance();
while (scanner.peek !== $EOF) {
if (!isIdentifierPart(scanner.peek))
return false;
scanner.advance();
}
return true;
}
function isIdentifierPart(code) {
return isAsciiLetter(code) || isDigit(code) || (code == $_) ||
(code == $$);
}
function isExponentStart(code) {
return code == $e || code == $E;
}
function isExponentSign(code) {
return code == $MINUS || code == $PLUS;
}
function isQuote(code) {
return code === $SQ || code === $DQ || code === $BT;
}
function unescape(code) {
switch (code) {
case $n:
return $LF;
case $f:
return $FF;
case $r:
return $CR;
case $t:
return $TAB;
case $v:
return $VTAB;
default:
return code;
}
}
function parseIntAutoRadix(text) {
var result = parseInt(text);
if (isNaN(result)) {
throw new Error('Invalid integer literal when parsing ' + text);
}
return result;
}
/**
* @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
*/
var SplitInterpolation = /** @class */ (function () {
function SplitInterpolation(strings, expressions, offsets) {
this.strings = strings;
this.expressions = expressions;
this.offsets = offsets;
}
return SplitInterpolation;
}());
var TemplateBindingParseResult = /** @class */ (function () {
function TemplateBindingParseResult(templateBindings, warnings, errors) {
this.templateBindings = templateBindings;
this.warnings = warnings;
this.errors = errors;
}
return TemplateBindingParseResult;
}());
function _createInterpolateRegExp(config) {
var pattern = escapeRegExp(config.start) + '([\\s\\S]*?)' + escapeRegExp(config.end);
return new RegExp(pattern, 'g');
}
var Parser = /** @class */ (function () {
function Parser(_lexer) {
this._lexer = _lexer;
this.errors = [];
}
Parser.prototype.parseAction = function (input, location, interpolationConfig) {
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
this._checkNoInterpolation(input, location, interpolationConfig);
var sourceToLex = this._stripComments(input);
var tokens = this._lexer.tokenize(this._stripComments(input));
var ast = new _ParseAST(input, location, tokens, sourceToLex.length, true, this.errors, input.length - sourceToLex.length)
.parseChain();
return new ASTWithSource(ast, input, location, this.errors);
};
Parser.prototype.parseBinding = function (input, location, interpolationConfig) {
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
var ast = this._parseBindingAst(input, location, interpolationConfig);
return new ASTWithSource(ast, input, location, this.errors);
};
Parser.prototype.parseSimpleBinding = function (input, location, interpolationConfig) {
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
var ast = this._parseBindingAst(input, location, interpolationConfig);
var errors = SimpleExpressionChecker.check(ast);
if (errors.length > 0) {
this._reportError("Host binding expression cannot contain " + errors.join(' '), input, location);
}
return new ASTWithSource(ast, input, location, this.errors);
};
Parser.prototype._reportError = function (message, input, errLocation, ctxLocation) {
this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
};
Parser.prototype._parseBindingAst = function (input, location, interpolationConfig) {
// Quotes expressions use 3rd-party expression language. We don't want to use
// our lexer or parser for that, so we check for that ahead of time.
var quote = this._parseQuote(input, location);
if (quote != null) {
return quote;
}
this._checkNoInterpolation(input, location, interpolationConfig);
var sourceToLex = this._stripComments(input);
var tokens = this._lexer.tokenize(sourceToLex);
return new _ParseAST(input, location, tokens, sourceToLex.length, false, this.errors, input.length - sourceToLex.length)
.parseChain();
};
Parser.prototype._parseQuote = function (input, location) {
if (input == null)
return null;
var prefixSeparatorIndex = input.indexOf(':');
if (prefixSeparatorIndex == -1)
return null;
var prefix = input.substring(0, prefixSeparatorIndex).trim();
if (!isIdentifier(prefix))
return null;
var uninterpretedExpression = input.substring(prefixSeparatorIndex + 1);
return new Quote(new ParseSpan(0, input.length), prefix, uninterpretedExpression, location);
};
Parser.prototype.parseTemplateBindings = function (tplKey, tplValue, location) {
var tokens = this._lexer.tokenize(tplValue);
return new _ParseAST(tplValue, location, tokens, tplValue.length, false, this.errors, 0)
.parseTemplateBindings(tplKey);
};
Parser.prototype.parseInterpolation = function (input, location, interpolationConfig) {
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
var split = this.splitInterpolation(input, location, interpolationConfig);
if (split == null)
return null;
var expressions = [];
for (var i = 0; i < split.expressions.length; ++i) {
var expressionText = split.expressions[i];
var sourceToLex = this._stripComments(expressionText);
var tokens = this._lexer.tokenize(sourceToLex);
var ast = new _ParseAST(input, location, tokens, sourceToLex.length, false, this.errors, split.offsets[i] + (expressionText.length - sourceToLex.length))
.parseChain();
expressions.push(ast);
}
return new ASTWithSource(new Interpolation(new ParseSpan(0, input == null ? 0 : input.length), split.strings, expressions), input, location, this.errors);
};
Parser.prototype.splitInterpolation = function (input, location, interpolationConfig) {
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
var regexp = _createInterpolateRegExp(interpolationConfig);
var parts = input.split(regexp);
if (parts.length <= 1) {
return null;
}
var strings = [];
var expressions = [];
var offsets = [];
var offset = 0;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (i % 2 === 0) {
// fixed string
strings.push(part);
offset += part.length;
}
else if (part.trim().length > 0) {
offset += interpolationConfig.start.length;
expressions.push(part);
offsets.push(offset);
offset += part.length + interpolationConfig.end.length;
}
else {
this._reportError('Blank expressions are not allowed in interpolated strings', input, "at column " + this._findInterpolationErrorColumn(parts, i, interpolationConfig) + " in", location);
expressions.push('$implict');
offsets.push(offset);
}
}
return new SplitInterpolation(strings, expressions, offsets);
};
Parser.prototype.wrapLiteralPrimitive = function (input, location) {
return new ASTWithSource(new LiteralPrimitive(new ParseSpan(0, input == null ? 0 : input.length), input), input, location, this.errors);
};
Parser.prototype._stripComments = function (input) {
var i = this._commentStart(input);
return i != null ? input.substring(0, i).trim() : input;
};
Parser.prototype._commentStart = function (input) {
var outerQuote = null;
for (var i = 0; i < input.length - 1; i++) {
var char = input.charCodeAt(i);
var nextChar = input.charCodeAt(i + 1);
if (char === $SLASH && nextChar == $SLASH && outerQuote == null)
return i;
if (outerQuote === char) {
outerQuote = null;
}
else if (outerQuote == null && isQuote(char)) {
outerQuote = char;
}
}
return null;
};
Parser.prototype._checkNoInterpolation = function (input, location, interpolationConfig) {
var regexp = _createInterpolateRegExp(interpolationConfig);
var parts = input.split(regexp);
if (parts.length > 1) {
this._reportError("Got interpolation (" + interpolationConfig.start + interpolationConfig.end + ") where expression was expected", input, "at column " + this._findInterpolationErrorColumn(parts, 1, interpolationConfig) + " in", location);
}
};
Parser.prototype._findInterpolationErrorColumn = function (parts, partInErrIdx, interpolationConfig) {
var errLocation = '';
for (var j = 0; j < partInErrIdx; j++) {
errLocation += j % 2 === 0 ?
parts[j] :
"" + interpolationConfig.start + parts[j] + interpolationConfig.end;
}
return errLocation.length;
};
return Parser;
}());
var _ParseAST = /** @class */ (function () {
function _ParseAST(input, location, tokens, inputLength, parseAction, errors, offset) {
this.input = input;
this.location = location;
this.tokens = tokens;
this.inputLength = inputLength;
this.parseAction = parseAction;
this.errors = errors;
this.offset = offset;
this.rparensExpected = 0;
this.rbracketsExpected = 0;
this.rbracesExpected = 0;
this.index = 0;
}
_ParseAST.prototype.peek = function (offset) {
var i = this.index + offset;
return i < this.tokens.length ? this.tokens[i] : EOF;
};
Object.defineProperty(_ParseAST.prototype, "next", {
get: function () { return this.peek(0); },
enumerable: true,
configurable: true
});
Object.defineProperty(_ParseAST.prototype, "inputIndex", {
get: function () {
return (this.index < this.tokens.length) ? this.next.index + this.offset :
this.inputLength + this.offset;
},
enumerable: true,
configurable: true
});
_ParseAST.prototype.span = function (start) { return new ParseSpan(start, this.inputIndex); };
_ParseAST.prototype.advance = function () { this.index++; };
_ParseAST.prototype.optionalCharacter = function (code) {
if (this.next.isCharacter(code)) {
this.advance();
return true;
}
else {
return false;
}
};
_ParseAST.prototype.peekKeywordLet = function () { return this.next.isKeywordLet(); };
_ParseAST.prototype.peekKeywordAs = function () { return this.next.isKeywordAs(); };
_ParseAST.prototype.expectCharacter = function (code) {
if (this.optionalCharacter(code))
return;
this.error("Missing expected " + String.fromCharCode(code));
};
_ParseAST.prototype.optionalOperator = function (op) {
if (this.next.isOperator(op)) {
this.advance();
return true;
}
else {
return false;
}
};
_ParseAST.prototype.expectOperator = function (operator) {
if (this.optionalOperator(operator))
return;
this.error("Missing expected operator " + operator);
};
_ParseAST.prototype.expectIdentifierOrKeyword = function () {
var n = this.next;
if (!n.isIdentifier() && !n.isKeyword()) {
this.error("Unexpected token " + n + ", expected identifier or keyword");
return '';
}
this.advance();
return n.toString();
};
_ParseAST.prototype.expectIdentifierOrKeywordOrString = function () {
var n = this.next;
if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
this.error("Unexpected token " + n + ", expected identifier, keyword, or string");
return '';
}
this.advance();
return n.toString();
};
_ParseAST.prototype.parseChain = function () {
var exprs = [];
var start = this.inputIndex;
while (this.index < this.tokens.length) {
var expr = this.parsePipe();
exprs.push(expr);
if (this.optionalCharacter($SEMICOLON)) {
if (!this.parseAction) {
this.error('Binding expression cannot contain chained expression');
}
while (this.optionalCharacter($SEMICOLON)) {
} // read all semicolons
}
else if (this.index < this.tokens.length) {
this.error("Unexpected token '" + this.next + "'");
}
}
if (exprs.length == 0)
return new EmptyExpr(this.span(start));
if (exprs.length == 1)
return exprs[0];
return new Chain(this.span(start), exprs);
};
_ParseAST.prototype.parsePipe = function () {
var result = this.parseExpression();
if (this.optionalOperator('|')) {
if (this.parseAction) {
this.error('Cannot have a pipe in an action expression');
}
do {
var name_1 = this.expectIdentifierOrKeyword();
var args = [];
while (this.optionalCharacter($COLON)) {
args.push(this.parseExpression());
}
result = new BindingPipe(this.span(result.span.start), result, name_1, args);
} while (this.optionalOperator('|'));
}
return result;
};
_ParseAST.prototype.parseExpression = function () { return this.parseConditional(); };
_ParseAST.prototype.parseConditional = function () {
var start = this.inputIndex;
var result = this.parseLogicalOr();
if (this.optionalOperator('?')) {
var yes = this.parsePipe();
var no = void 0;
if (!this.optionalCharacter($COLON)) {
var end = this.inputIndex;
var expression = this.input.substring(start, end);
this.error("Conditional expression " + expression + " requires all 3 expressions");
no = new EmptyExpr(this.span(start));
}
else {
no = this.parsePipe();
}
return new Conditional(this.span(start), result, yes, no);
}
else {
return result;
}
};
_ParseAST.prototype.parseLogicalOr = function () {
// '||'
var result = this.parseLogicalAnd();
while (this.optionalOperator('||')) {
var right = this.parseLogicalAnd();
result = new Binary(this.span(result.span.start), '||', result, right);
}
return result;
};
_ParseAST.prototype.parseLogicalAnd = function () {
// '&&'
var result = this.parseEquality();
while (this.optionalOperator('&&')) {
var right = this.parseEquality();
result = new Binary(this.span(result.span.start), '&&', result, right);
}
return result;
};
_ParseAST.prototype.parseEquality = function () {
// '==','!=','===','!=='
var result = this.parseRelational();
while (this.next.type == TokenType.Operator) {
var operator = this.next.strValue;
switch (operator) {
case '==':
case '===':
case '!=':
case '!==':
this.advance();
var right = this.parseRelational();
result = new Binary(this.span(result.span.start), operator, result, right);
continue;
}
break;
}
return result;
};
_ParseAST.prototype.parseRelational = function () {
// '<', '>', '<=', '>='
var result = this.parseAdditive();
while (this.next.type == TokenType.Operator) {
var operator = this.next.strValue;
switch (operator) {
case '<':
case '>':
case '<=':
case '>=':
this.advance();
var right = this.parseAdditive();
result = new Binary(this.span(result.span.start), operator, result, right);
continue;
}
break;
}
return result;
};
_ParseAST.prototype.parseAdditive = function () {
// '+', '-'
var result = this.parseMultiplicative();
while (this.next.type == TokenType.Operator) {
var operator = this.next.strValue;
switch (operator) {
case '+':
case '-':
this.advance();
var right = this.parseMultiplicative();
result = new Binary(this.span(result.span.start), operator, result, right);
continue;
}
break;
}
return result;
};
_ParseAST.prototype.parseMultiplicative = function () {
// '*', '%', '/'
var result = this.parsePrefix();
while (this.next.type == TokenType.Operator) {
var operator = this.next.strValue;
switch (operator) {
case '*':
case '%':
case '/':
this.advance();
var right = this.parsePrefix();
result = new Binary(this.span(result.span.start), operator, result, right);
continue;
}
break;
}
return result;
};
_ParseAST.prototype.parsePrefix = function () {
if (this.next.type == TokenType.Operator) {
var start = this.inputIndex;
var operator = this.next.strValue;
var result = void 0;
switch (operator) {
case '+':
this.advance();
result = this.parsePrefix();
return new Binary(this.span(start), '-', result, new LiteralPrimitive(new ParseSpan(start, start), 0));
case '-':
this.advance();
result = this.parsePrefix();
return new Binary(this.span(start), operator, new LiteralPrimitive(new ParseSpan(start, start), 0), result);
case '!':
this.advance();
result = this.parsePrefix();
return new PrefixNot(this.span(start), result);
}
}
return this.parseCallChain();
};
_ParseAST.prototype.parseCallChain = function () {
var result = this.parsePrimary();
while (true) {
if (this.optionalCharacter($PERIOD)) {
result = this.parseAccessMemberOrMethodCall(result, false);
}
else if (this.optionalOperator('?.')) {
result = this.parseAccessMemberOrMethodCall(result, true);
}
else if (this.optionalCharacter($LBRACKET)) {
this.rbracketsExpected++;
var key = this.parsePipe();
this.rbracketsExpected--;
this.expectCharacter($RBRACKET);
if (this.optionalOperator('=')) {
var value = this.parseConditional();
result = new KeyedWrite(this.span(result.span.start), result, key, value);
}
else {
result = new KeyedRead(this.span(result.span.start), result, key);
}
}
else if (this.optionalCharacter($LPAREN)) {
this.rparensExpected++;
var args = this.parseCallArguments();
this.rparensExpected--;
this.expectCharacter($RPAREN);
result = new FunctionCall(this.span(result.span.start), result, args);
}
else if (this.optionalOperator('!')) {
result = new NonNullAssert(this.span(result.span.start), result);
}
else {
return result;
}
}
};
_ParseAST.prototype.parsePrimary = function () {
var start = this.inputIndex;
if (this.optionalCharacter($LPAREN)) {
this.rparensExpected++;
var result = this.parsePipe();
this.rparensExpected--;
this.expectCharacter($RPAREN);
return result;
}
else if (this.next.isKeywordNull()) {
this.advance();
return new LiteralPrimitive(this.span(start), null);
}
else if (this.next.isKeywordUndefined()) {
this.advance();
return new LiteralPrimitive(this.span(start), void 0);
}
else if (this.next.isKeywordTrue()) {
this.advance();
return new LiteralPrimitive(this.span(start), true);
}
else if (this.next.isKeywordFalse()) {
this.advance();
return new LiteralPrimitive(this.span(start), false);
}
else if (this.next.isKeywordThis()) {
this.advance();
return new ImplicitReceiver(this.span(start));
}
else if (this.optionalCharacter($LBRACKET)) {
this.rbracketsExpected++;
var elements = this.parseExpressionList($RBRACKET);
this.rbracketsExpected--;
this.expectCharacter($RBRACKET);
return new LiteralArray(this.span(start), elements);
}
else if (this.next.isCharacter($LBRACE)) {
return this.parseLiteralMap();
}
else if (this.next.isIdentifier()) {
return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start)), false);
}
else if (this.next.isNumber()) {
var value = this.next.toNumber();
this.advance();
return new LiteralPrimitive(this.span(start), value);
}
else if (this.next.isString()) {
var literalValue = this.next.toString();
this.advance();
return new LiteralPrimitive(this.span(start), literalValue);
}
else if (this.index >= this.tokens.length) {
this.error("Unexpected end of expression: " + this.input);
return new EmptyExpr(this.span(start));
}
else {
this.error("Unexpected token " + this.next);
return new EmptyExpr(this.span(start));
}
};
_ParseAST.prototype.parseExpressionList = function (terminator) {
var result = [];
if (!this.next.isCharacter(terminator)) {
do {
result.push(this.parsePipe());
} while (this.optionalCharacter($COMMA));
}
return result;
};
_ParseAST.prototype.parseLiteralMap = function () {
var keys = [];
var values = [];
var start = this.inputIndex;
this.expectCharacter($LBRACE);
if (!this.optionalCharacter($RBRACE)) {
this.rbracesExpected++;
do {
var quoted = this.next.isString();
var key = this.expectIdentifierOrKeywordOrString();
keys.push({ key: key, quoted: quoted });
this.expectCharacter($COLON);
values.push(this.parsePipe());
} while (this.optionalCharacter($COMMA));
this.rbracesExpected--;
this.expectCharacter($RBRACE);
}
return new LiteralMap(this.span(start), keys, values);
};
_ParseAST.prototype.parseAccessMemberOrMethodCall = function (receiver, isSafe) {
if (isSafe === void 0) { isSafe = false; }
var start = receiver.span.start;
var id = this.expectIdentifierOrKeyword();
if (this.optionalCharacter($LPAREN)) {
this.rparensExpected++;
var args = this.parseCallArguments();
this.expectCharacter($RPAREN);
this.rparensExpected--;
var span = this.span(start);
return isSafe ? new SafeMethodCall(span, receiver, id, args) :
new MethodCall(span, receiver, id, args);
}
else {
if (isSafe) {
if (this.optionalOperator('=')) {
this.error('The \'?.\' operator cannot be used in the assignment');
return new EmptyExpr(this.span(start));
}
else {
return new SafePropertyRead(this.span(start), receiver, id);
}
}
else {
if (this.optionalOperator('=')) {
if (!this.parseAction) {
this.error('Bindings cannot contain assignments');
return new EmptyExpr(this.span(start));
}
var value = this.parseConditional();
return new PropertyWrite(this.span(start), receiver, id, value);
}
else {
return new PropertyRead(this.span(start), receiver, id);
}
}
}
};
_ParseAST.prototype.parseCallArguments = function () {
if (this.next.isCharacter($RPAREN))
return [];
var positionals = [];
do {
positionals.push(this.parsePipe());
} while (this.optionalCharacter($COMMA));
return positionals;
};
/**
* An identifier, a keyword, a string with an optional `-` in between.
*/
_ParseAST.prototype.expectTemplateBindingKey = function () {
var result = '';
var operatorFound = false;
do {
result += this.expectIdentifierOrKeywordOrString();
operatorFound = this.optionalOperator('-');
if (operatorFound) {
result += '-';
}
} while (operatorFound);
return result.toString();
};
// Parses the AST for ``
_ParseAST.prototype.parseTemplateBindings = function (tplKey) {
var firstBinding = true;
var bindings = [];
var warnings = [];
do {
var start = this.inputIndex;
var rawKey = void 0;
var key = void 0;
var isVar = false;
if (firstBinding) {
rawKey = key = tplKey;
firstBinding = false;
}
else {
isVar = this.peekKeywordLet();
if (isVar)
this.advance();
rawKey = this.expectTemplateBindingKey();
key = isVar ? rawKey : tplKey + rawKey[0].toUpperCase() + rawKey.substring(1);
this.optionalCharacter($COLON);
}
var name_2 = null;
var expression = null;
if (isVar) {
if (this.optionalOperator('=')) {
name_2 = this.expectTemplateBindingKey();
}
else {
name_2 = '\$implicit';
}
}
else if (this.peekKeywordAs()) {
this.advance(); // consume `as`
name_2 = rawKey;
key = this.expectTemplateBindingKey(); // read local var name
isVar = true;
}
else if (this.next !== EOF && !this.peekKeywordLet()) {
var start_1 = this.inputIndex;
var ast = this.parsePipe();
var source = this.input.substring(start_1 - this.offset, this.inputIndex - this.offset);
expression = new ASTWithSource(ast, source, this.location, this.errors);
}
bindings.push(new TemplateBinding(this.span(start), key, isVar, name_2, expression));
if (this.peekKeywordAs() && !isVar) {
var letStart = this.inputIndex;
this.advance(); // consume `as`
var letName = this.expectTemplateBindingKey(); // read local var name
bindings.push(new TemplateBinding(this.span(letStart), letName, true, key, null));
}
if (!this.optionalCharacter($SEMICOLON)) {
this.optionalCharacter($COMMA);
}
} while (this.index < this.tokens.length);
return new TemplateBindingParseResult(bindings, warnings, this.errors);
};
_ParseAST.prototype.error = function (message, index) {
if (index === void 0) { index = null; }
this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
this.skip();
};
_ParseAST.prototype.locationText = function (index) {
if (index === void 0) { index = null; }
if (index == null)
index = this.index;
return (index < this.tokens.length) ? "at column " + (this.tokens[index].index + 1) + " in" :
"at the end of the expression";
};
// Error recovery should skip tokens until it encounters a recovery point. skip() treats
// the end of input and a ';' as unconditionally a recovery point. It also treats ')',
// '}' and ']' as conditional recovery points if one of calling productions is expecting
// one of these symbols. This allows skip() to recover from errors such as '(a.) + 1' allowing
// more of the AST to be retained (it doesn't skip any tokens as the ')' is retained because
// of the '(' begins an '(' ')' production). The recovery points of grouping symbols
// must be conditional as they must be skipped if none of the calling productions are not
// expecting the closing token else we will never make progress in the case of an
// extraneous group closing symbol (such as a stray ')'). This is not the case for ';' because
// parseChain() is always the root production and it expects a ';'.
// If a production expects one of these token it increments the corresponding nesting count,
// and then decrements it just prior to checking if the token is in the input.
_ParseAST.prototype.skip = function () {
var n = this.next;
while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) &&
(this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) &&
(this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) &&
(this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET))) {
if (this.next.isError()) {
this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
}
this.advance();
n = this.next;
}
};
return _ParseAST;
}());
var SimpleExpressionChecker = /** @class */ (function () {
function SimpleExpressionChecker() {
this.errors = [];
}
SimpleExpressionChecker.check = function (ast) {
var s = new SimpleExpressionChecker();
ast.visit(s);
return s.errors;
};
SimpleExpressionChecker.prototype.visitImplicitReceiver = function (ast, context) { };
SimpleExpressionChecker.prototype.visitInterpolation = function (ast, context) { };
SimpleExpressionChecker.prototype.visitLiteralPrimitive = function (ast, context) { };
SimpleExpressionChecker.prototype.visitPropertyRead = function (ast, context) { };
SimpleExpressionChecker.prototype.visitPropertyWrite = function (ast, context) { };
SimpleExpressionChecker.prototype.visitSafePropertyRead = function (ast, context) { };
SimpleExpressionChecker.prototype.visitMethodCall = function (ast, context) { };
SimpleExpressionChecker.prototype.visitSafeMethodCall = function (ast, context) { };
SimpleExpressionChecker.prototype.visitFunctionCall = function (ast, context) { };
SimpleExpressionChecker.prototype.visitLiteralArray = function (ast, context) { this.visitAll(ast.expressions); };
SimpleExpressionChecker.prototype.visitLiteralMap = function (ast, context) { this.visitAll(ast.values); };
SimpleExpressionChecker.prototype.visitBinary = function (ast, context) { };
SimpleExpressionChecker.prototype.visitPrefixNot = function (ast, context) { };
SimpleExpressionChecker.prototype.visitNonNullAssert = function (ast, context) { };
SimpleExpressionChecker.prototype.visitConditional = function (ast, context) { };
SimpleExpressionChecker.prototype.visitPipe = function (ast, context) { this.errors.push('pipes'); };
SimpleExpressionChecker.prototype.visitKeyedRead = function (ast, context) { };
SimpleExpressionChecker.prototype.visitKeyedWrite = function (ast, context) { };
SimpleExpressionChecker.prototype.visitAll = function (asts) {
var _this = this;
return asts.map(function (node) { return node.visit(_this); });
};
SimpleExpressionChecker.prototype.visitChain = function (ast, context) { };
SimpleExpressionChecker.prototype.visitQuote = function (ast, context) { };
return SimpleExpressionChecker;
}());
/**
* @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
*/
/**
* A path is an ordered set of elements. Typically a path is to a
* particular offset in a source file. The head of the list is the top
* most node. The tail is the node that contains the offset directly.
*
* For example, the expression `a + b + c` might have an ast that looks
* like:
* +
* / \
* a +
* / \
* b c
*
* The path to the node at offset 9 would be `['+' at 1-10, '+' at 7-10,
* 'c' at 9-10]` and the path the node at offset 1 would be
* `['+' at 1-10, 'a' at 1-2]`.
*/
var AstPath = /** @class */ (function () {
function AstPath(path, position) {
if (position === void 0) { position = -1; }
this.path = path;
this.position = position;
}
Object.defineProperty(AstPath.prototype, "empty", {
get: function () { return !this.path || !this.path.length; },
enumerable: true,
configurable: true
});
Object.defineProperty(AstPath.prototype, "head", {
get: function () { return this.path[0]; },
enumerable: true,
configurable: true
});
Object.defineProperty(AstPath.prototype, "tail", {
get: function () { return this.path[this.path.length - 1]; },
enumerable: true,
configurable: true
});
AstPath.prototype.parentOf = function (node) {
return node && this.path[this.path.indexOf(node) - 1];
};
AstPath.prototype.childOf = function (node) { return this.path[this.path.indexOf(node) + 1]; };
AstPath.prototype.first = function (ctor) {
for (var i = this.path.length - 1; i >= 0; i--) {
var item = this.path[i];
if (item instanceof ctor)
return item;
}
};
AstPath.prototype.push = function (node) { this.path.push(node); };
AstPath.prototype.pop = function () { return this.path.pop(); };
return AstPath;
}());
/**
* @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
*/
var Text$2 = /** @class */ (function () {
function Text(value, sourceSpan, i18n) {
this.value = value;
this.sourceSpan = sourceSpan;
this.i18n = i18n;
}
Text.prototype.visit = function (visitor, context) { return visitor.visitText(this, context); };
return Text;
}());
var Expansion = /** @class */ (function () {
function Expansion(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
this.switchValue = switchValue;
this.type = type;
this.cases = cases;
this.sourceSpan = sourceSpan;
this.switchValueSourceSpan = switchValueSourceSpan;
this.i18n = i18n;
}
Expansion.prototype.visit = function (visitor, context) { return visitor.visitExpansion(this, context); };
return Expansion;
}());
var ExpansionCase = /** @class */ (function () {
function ExpansionCase(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
this.value = value;
this.expression = expression;
this.sourceSpan = sourceSpan;
this.valueSourceSpan = valueSourceSpan;
this.expSourceSpan = expSourceSpan;
}
ExpansionCase.prototype.visit = function (visitor, context) { return visitor.visitExpansionCase(this, context); };
return ExpansionCase;
}());
var Attribute = /** @class */ (function () {
function Attribute(name, value, sourceSpan, valueSpan, i18n) {
this.name = name;
this.value = value;
this.sourceSpan = sourceSpan;
this.valueSpan = valueSpan;
this.i18n = i18n;
}
Attribute.prototype.visit = function (visitor, context) { return visitor.visitAttribute(this, context); };
return Attribute;
}());
var Element = /** @class */ (function () {
function Element(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
if (startSourceSpan === void 0) { startSourceSpan = null; }
if (endSourceSpan === void 0) { endSourceSpan = null; }
this.name = name;
this.attrs = attrs;
this.children = children;
this.sourceSpan = sourceSpan;
this.startSourceSpan = startSourceSpan;
this.endSourceSpan = endSourceSpan;
this.i18n = i18n;
}
Element.prototype.visit = function (visitor, context) { return visitor.visitElement(this, context); };
return Element;
}());
var Comment = /** @class */ (function () {
function Comment(value, sourceSpan) {
this.value = value;
this.sourceSpan = sourceSpan;
}
Comment.prototype.visit = function (visitor, context) { return visitor.visitComment(this, context); };
return Comment;
}());
function visitAll(visitor, nodes, context) {
if (context === void 0) { context = null; }
var result = [];
var visit = visitor.visit ?
function (ast) { return visitor.visit(ast, context) || ast.visit(visitor, context); } :
function (ast) { return ast.visit(visitor, context); };
nodes.forEach(function (ast) {
var astResult = visit(ast);
if (astResult) {
result.push(astResult);
}
});
return result;
}
var RecursiveVisitor = /** @class */ (function () {
function RecursiveVisitor() {
}
RecursiveVisitor.prototype.visitElement = function (ast, context) {
this.visitChildren(context, function (visit) {
visit(ast.attrs);
visit(ast.children);
});
};
RecursiveVisitor.prototype.visitAttribute = function (ast, context) { };
RecursiveVisitor.prototype.visitText = function (ast, context) { };
RecursiveVisitor.prototype.visitComment = function (ast, context) { };
RecursiveVisitor.prototype.visitExpansion = function (ast, context) {
return this.visitChildren(context, function (visit) { visit(ast.cases); });
};
RecursiveVisitor.prototype.visitExpansionCase = function (ast, context) { };
RecursiveVisitor.prototype.visitChildren = function (context, cb) {
var results = [];
var t = this;
function visit(children) {
if (children)
results.push(visitAll(t, children, context));
}
cb(visit);
return [].concat.apply([], results);
};
return RecursiveVisitor;
}());
function spanOf(ast) {
var start = ast.sourceSpan.start.offset;
var end = ast.sourceSpan.end.offset;
if (ast instanceof Element) {
if (ast.endSourceSpan) {
end = ast.endSourceSpan.end.offset;
}
else if (ast.children && ast.children.length) {
end = spanOf(ast.children[ast.children.length - 1]).end;
}
}
return { start: start, end: end };
}
function findNode(nodes, position) {
var path = [];
var visitor = new /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(class_1, _super);
function class_1() {
return _super !== null && _super.apply(this, arguments) || this;
}
class_1.prototype.visit = function (ast, context) {
var span = spanOf(ast);
if (span.start <= position && position < span.end) {
path.push(ast);
}
else {
// Returning a value here will result in the children being skipped.
return true;
}
};
return class_1;
}(RecursiveVisitor));
visitAll(visitor, nodes);
return new AstPath(path, position);
}
/**
* @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
*/
var TokenType$1;
(function (TokenType) {
TokenType[TokenType["TAG_OPEN_START"] = 0] = "TAG_OPEN_START";
TokenType[TokenType["TAG_OPEN_END"] = 1] = "TAG_OPEN_END";
TokenType[TokenType["TAG_OPEN_END_VOID"] = 2] = "TAG_OPEN_END_VOID";
TokenType[TokenType["TAG_CLOSE"] = 3] = "TAG_CLOSE";
TokenType[TokenType["TEXT"] = 4] = "TEXT";
TokenType[TokenType["ESCAPABLE_RAW_TEXT"] = 5] = "ESCAPABLE_RAW_TEXT";
TokenType[TokenType["RAW_TEXT"] = 6] = "RAW_TEXT";
TokenType[TokenType["COMMENT_START"] = 7] = "COMMENT_START";
TokenType[TokenType["COMMENT_END"] = 8] = "COMMENT_END";
TokenType[TokenType["CDATA_START"] = 9] = "CDATA_START";
TokenType[TokenType["CDATA_END"] = 10] = "CDATA_END";
TokenType[TokenType["ATTR_NAME"] = 11] = "ATTR_NAME";
TokenType[TokenType["ATTR_VALUE"] = 12] = "ATTR_VALUE";
TokenType[TokenType["DOC_TYPE"] = 13] = "DOC_TYPE";
TokenType[TokenType["EXPANSION_FORM_START"] = 14] = "EXPANSION_FORM_START";
TokenType[TokenType["EXPANSION_CASE_VALUE"] = 15] = "EXPANSION_CASE_VALUE";
TokenType[TokenType["EXPANSION_CASE_EXP_START"] = 16] = "EXPANSION_CASE_EXP_START";
TokenType[TokenType["EXPANSION_CASE_EXP_END"] = 17] = "EXPANSION_CASE_EXP_END";
TokenType[TokenType["EXPANSION_FORM_END"] = 18] = "EXPANSION_FORM_END";
TokenType[TokenType["EOF"] = 19] = "EOF";
})(TokenType$1 || (TokenType$1 = {}));
var Token$1 = /** @class */ (function () {
function Token(type, parts, sourceSpan) {
this.type = type;
this.parts = parts;
this.sourceSpan = sourceSpan;
}
return Token;
}());
var TokenError = /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TokenError, _super);
function TokenError(errorMsg, tokenType, span) {
var _this = _super.call(this, span, errorMsg) || this;
_this.tokenType = tokenType;
return _this;
}
return TokenError;
}(ParseError));
var TokenizeResult = /** @class */ (function () {
function TokenizeResult(tokens, errors) {
this.tokens = tokens;
this.errors = errors;
}
return TokenizeResult;
}());
function tokenize(source, url, getTagDefinition, tokenizeExpansionForms, interpolationConfig) {
if (tokenizeExpansionForms === void 0) { tokenizeExpansionForms = false; }
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
return new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, tokenizeExpansionForms, interpolationConfig)
.tokenize();
}
var _CR_OR_CRLF_REGEXP = /\r\n?/g;
function _unexpectedCharacterErrorMsg(charCode) {
var char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
return "Unexpected character \"" + char + "\"";
}
function _unknownEntityErrorMsg(entitySrc) {
return "Unknown entity \"" + entitySrc + "\" - use the \";\" or \";\" syntax";
}
var _ControlFlowError = /** @class */ (function () {
function _ControlFlowError(error) {
this.error = error;
}
return _ControlFlowError;
}());
// See http://www.w3.org/TR/html51/syntax.html#writing
var _Tokenizer = /** @class */ (function () {
/**
* @param _file The html source
* @param _getTagDefinition
* @param _tokenizeIcu Whether to tokenize ICU messages (considered as text nodes when false)
* @param _interpolationConfig
*/
function _Tokenizer(_file, _getTagDefinition, _tokenizeIcu, _interpolationConfig) {
if (_interpolationConfig === void 0) { _interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
this._file = _file;
this._getTagDefinition = _getTagDefinition;
this._tokenizeIcu = _tokenizeIcu;
this._interpolationConfig = _interpolationConfig;
// Note: this is always lowercase!
this._peek = -1;
this._nextPeek = -1;
this._index = -1;
this._line = 0;
this._column = -1;
this._expansionCaseStack = [];
this._inInterpolation = false;
this.tokens = [];
this.errors = [];
this._input = _file.content;
this._length = _file.content.length;
this._advance();
}
_Tokenizer.prototype._processCarriageReturns = function (content) {
// http://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream
// In order to keep the original position in the source, we can not
// pre-process it.
// Instead CRs are processed right before instantiating the tokens.
return content.replace(_CR_OR_CRLF_REGEXP, '\n');
};
_Tokenizer.prototype.tokenize = function () {
while (this._peek !== $EOF) {
var start = this._getLocation();
try {
if (this._attemptCharCode($LT)) {
if (this._attemptCharCode($BANG)) {
if (this._attemptCharCode($LBRACKET)) {
this._consumeCdata(start);
}
else if (this._attemptCharCode($MINUS)) {
this._consumeComment(start);
}
else {
this._consumeDocType(start);
}
}
else if (this._attemptCharCode($SLASH)) {
this._consumeTagClose(start);
}
else {
this._consumeTagOpen(start);
}
}
else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
this._consumeText();
}
}
catch (e) {
if (e instanceof _ControlFlowError) {
this.errors.push(e.error);
}
else {
throw e;
}
}
}
this._beginToken(TokenType$1.EOF);
this._endToken([]);
return new TokenizeResult(mergeTextTokens(this.tokens), this.errors);
};
/**
* @returns whether an ICU token has been created
* @internal
*/
_Tokenizer.prototype._tokenizeExpansionForm = function () {
if (isExpansionFormStart(this._input, this._index, this._interpolationConfig)) {
this._consumeExpansionFormStart();
return true;
}
if (isExpansionCaseStart(this._peek) && this._isInExpansionForm()) {
this._consumeExpansionCaseStart();
return true;
}
if (this._peek === $RBRACE) {
if (this._isInExpansionCase()) {
this._consumeExpansionCaseEnd();
return true;
}
if (this._isInExpansionForm()) {
this._consumeExpansionFormEnd();
return true;
}
}
return false;
};
_Tokenizer.prototype._getLocation = function () {
return new ParseLocation(this._file, this._index, this._line, this._column);
};
_Tokenizer.prototype._getSpan = function (start, end) {
if (start === void 0) { start = this._getLocation(); }
if (end === void 0) { end = this._getLocation(); }
return new ParseSourceSpan(start, end);
};
_Tokenizer.prototype._beginToken = function (type, start) {
if (start === void 0) { start = this._getLocation(); }
this._currentTokenStart = start;
this._currentTokenType = type;
};
_Tokenizer.prototype._endToken = function (parts, end) {
if (end === void 0) { end = this._getLocation(); }
var token = new Token$1(this._currentTokenType, parts, new ParseSourceSpan(this._currentTokenStart, end));
this.tokens.push(token);
this._currentTokenStart = null;
this._currentTokenType = null;
return token;
};
_Tokenizer.prototype._createError = function (msg, span) {
if (this._isInExpansionForm()) {
msg += " (Do you have an unescaped \"{\" in your template? Use \"{{ '{' }}\") to escape it.)";
}
var error = new TokenError(msg, this._currentTokenType, span);
this._currentTokenStart = null;
this._currentTokenType = null;
return new _ControlFlowError(error);
};
_Tokenizer.prototype._advance = function () {
if (this._index >= this._length) {
throw this._createError(_unexpectedCharacterErrorMsg($EOF), this._getSpan());
}
if (this._peek === $LF) {
this._line++;
this._column = 0;
}
else if (this._peek !== $LF && this._peek !== $CR) {
this._column++;
}
this._index++;
this._peek = this._index >= this._length ? $EOF : this._input.charCodeAt(this._index);
this._nextPeek =
this._index + 1 >= this._length ? $EOF : this._input.charCodeAt(this._index + 1);
};
_Tokenizer.prototype._attemptCharCode = function (charCode) {
if (this._peek === charCode) {
this._advance();
return true;
}
return false;
};
_Tokenizer.prototype._attemptCharCodeCaseInsensitive = function (charCode) {
if (compareCharCodeCaseInsensitive(this._peek, charCode)) {
this._advance();
return true;
}
return false;
};
_Tokenizer.prototype._requireCharCode = function (charCode) {
var location = this._getLocation();
if (!this._attemptCharCode(charCode)) {
throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan(location, location));
}
};
_Tokenizer.prototype._attemptStr = function (chars) {
var len = chars.length;
if (this._index + len > this._length) {
return false;
}
var initialPosition = this._savePosition();
for (var i = 0; i < len; i++) {
if (!this._attemptCharCode(chars.charCodeAt(i))) {
// If attempting to parse the string fails, we want to reset the parser
// to where it was before the attempt
this._restorePosition(initialPosition);
return false;
}
}
return true;
};
_Tokenizer.prototype._attemptStrCaseInsensitive = function (chars) {
for (var i = 0; i < chars.length; i++) {
if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
return false;
}
}
return true;
};
_Tokenizer.prototype._requireStr = function (chars) {
var location = this._getLocation();
if (!this._attemptStr(chars)) {
throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan(location));
}
};
_Tokenizer.prototype._attemptCharCodeUntilFn = function (predicate) {
while (!predicate(this._peek)) {
this._advance();
}
};
_Tokenizer.prototype._requireCharCodeUntilFn = function (predicate, len) {
var start = this._getLocation();
this._attemptCharCodeUntilFn(predicate);
if (this._index - start.offset < len) {
throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan(start, start));
}
};
_Tokenizer.prototype._attemptUntilChar = function (char) {
while (this._peek !== char) {
this._advance();
}
};
_Tokenizer.prototype._readChar = function (decodeEntities) {
if (decodeEntities && this._peek === $AMPERSAND) {
return this._decodeEntity();
}
else {
var index = this._index;
this._advance();
return this._input[index];
}
};
_Tokenizer.prototype._decodeEntity = function () {
var start = this._getLocation();
this._advance();
if (this._attemptCharCode($HASH)) {
var isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
var numberStart = this._getLocation().offset;
this._attemptCharCodeUntilFn(isDigitEntityEnd);
if (this._peek != $SEMICOLON) {
throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan());
}
this._advance();
var strNum = this._input.substring(numberStart, this._index - 1);
try {
var charCode = parseInt(strNum, isHex ? 16 : 10);
return String.fromCharCode(charCode);
}
catch (_a) {
var entity = this._input.substring(start.offset + 1, this._index - 1);
throw this._createError(_unknownEntityErrorMsg(entity), this._getSpan(start));
}
}
else {
var startPosition = this._savePosition();
this._attemptCharCodeUntilFn(isNamedEntityEnd);
if (this._peek != $SEMICOLON) {
this._restorePosition(startPosition);
return '&';
}
this._advance();
var name_1 = this._input.substring(start.offset + 1, this._index - 1);
var char = NAMED_ENTITIES[name_1];
if (!char) {
throw this._createError(_unknownEntityErrorMsg(name_1), this._getSpan(start));
}
return char;
}
};
_Tokenizer.prototype._consumeRawText = function (decodeEntities, firstCharOfEnd, attemptEndRest) {
var tagCloseStart;
var textStart = this._getLocation();
this._beginToken(decodeEntities ? TokenType$1.ESCAPABLE_RAW_TEXT : TokenType$1.RAW_TEXT, textStart);
var parts = [];
while (true) {
tagCloseStart = this._getLocation();
if (this._attemptCharCode(firstCharOfEnd) && attemptEndRest()) {
break;
}
if (this._index > tagCloseStart.offset) {
// add the characters consumed by the previous if statement to the output
parts.push(this._input.substring(tagCloseStart.offset, this._index));
}
while (this._peek !== firstCharOfEnd) {
parts.push(this._readChar(decodeEntities));
}
}
return this._endToken([this._processCarriageReturns(parts.join(''))], tagCloseStart);
};
_Tokenizer.prototype._consumeComment = function (start) {
var _this = this;
this._beginToken(TokenType$1.COMMENT_START, start);
this._requireCharCode($MINUS);
this._endToken([]);
var textToken = this._consumeRawText(false, $MINUS, function () { return _this._attemptStr('->'); });
this._beginToken(TokenType$1.COMMENT_END, textToken.sourceSpan.end);
this._endToken([]);
};
_Tokenizer.prototype._consumeCdata = function (start) {
var _this = this;
this._beginToken(TokenType$1.CDATA_START, start);
this._requireStr('CDATA[');
this._endToken([]);
var textToken = this._consumeRawText(false, $RBRACKET, function () { return _this._attemptStr(']>'); });
this._beginToken(TokenType$1.CDATA_END, textToken.sourceSpan.end);
this._endToken([]);
};
_Tokenizer.prototype._consumeDocType = function (start) {
this._beginToken(TokenType$1.DOC_TYPE, start);
this._attemptUntilChar($GT);
this._advance();
this._endToken([this._input.substring(start.offset + 2, this._index - 1)]);
};
_Tokenizer.prototype._consumePrefixAndName = function () {
var nameOrPrefixStart = this._index;
var prefix = null;
while (this._peek !== $COLON && !isPrefixEnd(this._peek)) {
this._advance();
}
var nameStart;
if (this._peek === $COLON) {
this._advance();
prefix = this._input.substring(nameOrPrefixStart, this._index - 1);
nameStart = this._index;
}
else {
nameStart = nameOrPrefixStart;
}
this._requireCharCodeUntilFn(isNameEnd, this._index === nameStart ? 1 : 0);
var name = this._input.substring(nameStart, this._index);
return [prefix, name];
};
_Tokenizer.prototype._consumeTagOpen = function (start) {
var savedPos = this._savePosition();
var tagName;
var lowercaseTagName;
try {
if (!isAsciiLetter(this._peek)) {
throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan());
}
var nameStart = this._index;
this._consumeTagOpenStart(start);
tagName = this._input.substring(nameStart, this._index);
lowercaseTagName = tagName.toLowerCase();
this._attemptCharCodeUntilFn(isNotWhitespace);
while (this._peek !== $SLASH && this._peek !== $GT) {
this._consumeAttributeName();
this._attemptCharCodeUntilFn(isNotWhitespace);
if (this._attemptCharCode($EQ)) {
this._attemptCharCodeUntilFn(isNotWhitespace);
this._consumeAttributeValue();
}
this._attemptCharCodeUntilFn(isNotWhitespace);
}
this._consumeTagOpenEnd();
}
catch (e) {
if (e instanceof _ControlFlowError) {
// When the start tag is invalid, assume we want a "<"
this._restorePosition(savedPos);
// Back to back text tokens are merged at the end
this._beginToken(TokenType$1.TEXT, start);
this._endToken(['<']);
return;
}
throw e;
}
var contentTokenType = this._getTagDefinition(tagName).contentType;
if (contentTokenType === TagContentType.RAW_TEXT) {
this._consumeRawTextWithTagClose(lowercaseTagName, false);
}
else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
this._consumeRawTextWithTagClose(lowercaseTagName, true);
}
};
_Tokenizer.prototype._consumeRawTextWithTagClose = function (lowercaseTagName, decodeEntities) {
var _this = this;
var textToken = this._consumeRawText(decodeEntities, $LT, function () {
if (!_this._attemptCharCode($SLASH))
return false;
_this._attemptCharCodeUntilFn(isNotWhitespace);
if (!_this._attemptStrCaseInsensitive(lowercaseTagName))
return false;
_this._attemptCharCodeUntilFn(isNotWhitespace);
return _this._attemptCharCode($GT);
});
this._beginToken(TokenType$1.TAG_CLOSE, textToken.sourceSpan.end);
this._endToken([null, lowercaseTagName]);
};
_Tokenizer.prototype._consumeTagOpenStart = function (start) {
this._beginToken(TokenType$1.TAG_OPEN_START, start);
var parts = this._consumePrefixAndName();
this._endToken(parts);
};
_Tokenizer.prototype._consumeAttributeName = function () {
this._beginToken(TokenType$1.ATTR_NAME);
var prefixAndName = this._consumePrefixAndName();
this._endToken(prefixAndName);
};
_Tokenizer.prototype._consumeAttributeValue = function () {
this._beginToken(TokenType$1.ATTR_VALUE);
var value;
if (this._peek === $SQ || this._peek === $DQ) {
var quoteChar = this._peek;
this._advance();
var parts = [];
while (this._peek !== quoteChar) {
parts.push(this._readChar(true));
}
value = parts.join('');
this._advance();
}
else {
var valueStart = this._index;
this._requireCharCodeUntilFn(isNameEnd, 1);
value = this._input.substring(valueStart, this._index);
}
this._endToken([this._processCarriageReturns(value)]);
};
_Tokenizer.prototype._consumeTagOpenEnd = function () {
var tokenType = this._attemptCharCode($SLASH) ? TokenType$1.TAG_OPEN_END_VOID : TokenType$1.TAG_OPEN_END;
this._beginToken(tokenType);
this._requireCharCode($GT);
this._endToken([]);
};
_Tokenizer.prototype._consumeTagClose = function (start) {
this._beginToken(TokenType$1.TAG_CLOSE, start);
this._attemptCharCodeUntilFn(isNotWhitespace);
var prefixAndName = this._consumePrefixAndName();
this._attemptCharCodeUntilFn(isNotWhitespace);
this._requireCharCode($GT);
this._endToken(prefixAndName);
};
_Tokenizer.prototype._consumeExpansionFormStart = function () {
this._beginToken(TokenType$1.EXPANSION_FORM_START, this._getLocation());
this._requireCharCode($LBRACE);
this._endToken([]);
this._expansionCaseStack.push(TokenType$1.EXPANSION_FORM_START);
this._beginToken(TokenType$1.RAW_TEXT, this._getLocation());
var condition = this._readUntil($COMMA);
this._endToken([condition], this._getLocation());
this._requireCharCode($COMMA);
this._attemptCharCodeUntilFn(isNotWhitespace);
this._beginToken(TokenType$1.RAW_TEXT, this._getLocation());
var type = this._readUntil($COMMA);
this._endToken([type], this._getLocation());
this._requireCharCode($COMMA);
this._attemptCharCodeUntilFn(isNotWhitespace);
};
_Tokenizer.prototype._consumeExpansionCaseStart = function () {
this._beginToken(TokenType$1.EXPANSION_CASE_VALUE, this._getLocation());
var value = this._readUntil($LBRACE).trim();
this._endToken([value], this._getLocation());
this._attemptCharCodeUntilFn(isNotWhitespace);
this._beginToken(TokenType$1.EXPANSION_CASE_EXP_START, this._getLocation());
this._requireCharCode($LBRACE);
this._endToken([], this._getLocation());
this._attemptCharCodeUntilFn(isNotWhitespace);
this._expansionCaseStack.push(TokenType$1.EXPANSION_CASE_EXP_START);
};
_Tokenizer.prototype._consumeExpansionCaseEnd = function () {
this._beginToken(TokenType$1.EXPANSION_CASE_EXP_END, this._getLocation());
this._requireCharCode($RBRACE);
this._endToken([], this._getLocation());
this._attemptCharCodeUntilFn(isNotWhitespace);
this._expansionCaseStack.pop();
};
_Tokenizer.prototype._consumeExpansionFormEnd = function () {
this._beginToken(TokenType$1.EXPANSION_FORM_END, this._getLocation());
this._requireCharCode($RBRACE);
this._endToken([]);
this._expansionCaseStack.pop();
};
_Tokenizer.prototype._consumeText = function () {
var start = this._getLocation();
this._beginToken(TokenType$1.TEXT, start);
var parts = [];
do {
if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
parts.push(this._interpolationConfig.start);
this._inInterpolation = true;
}
else if (this._interpolationConfig && this._inInterpolation &&
this._attemptStr(this._interpolationConfig.end)) {
parts.push(this._interpolationConfig.end);
this._inInterpolation = false;
}
else {
parts.push(this._readChar(true));
}
} while (!this._isTextEnd());
this._endToken([this._processCarriageReturns(parts.join(''))]);
};
_Tokenizer.prototype._isTextEnd = function () {
if (this._peek === $LT || this._peek === $EOF) {
return true;
}
if (this._tokenizeIcu && !this._inInterpolation) {
if (isExpansionFormStart(this._input, this._index, this._interpolationConfig)) {
// start of an expansion form
return true;
}
if (this._peek === $RBRACE && this._isInExpansionCase()) {
// end of and expansion case
return true;
}
}
return false;
};
_Tokenizer.prototype._savePosition = function () {
return [this._peek, this._index, this._column, this._line, this.tokens.length];
};
_Tokenizer.prototype._readUntil = function (char) {
var start = this._index;
this._attemptUntilChar(char);
return this._input.substring(start, this._index);
};
_Tokenizer.prototype._restorePosition = function (position) {
this._peek = position[0];
this._index = position[1];
this._column = position[2];
this._line = position[3];
var nbTokens = position[4];
if (nbTokens < this.tokens.length) {
// remove any extra tokens
this.tokens = this.tokens.slice(0, nbTokens);
}
};
_Tokenizer.prototype._isInExpansionCase = function () {
return this._expansionCaseStack.length > 0 &&
this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
TokenType$1.EXPANSION_CASE_EXP_START;
};
_Tokenizer.prototype._isInExpansionForm = function () {
return this._expansionCaseStack.length > 0 &&
this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
TokenType$1.EXPANSION_FORM_START;
};
return _Tokenizer;
}());
function isNotWhitespace(code) {
return !isWhitespace(code) || code === $EOF;
}
function isNameEnd(code) {
return isWhitespace(code) || code === $GT || code === $SLASH ||
code === $SQ || code === $DQ || code === $EQ;
}
function isPrefixEnd(code) {
return (code < $a || $z < code) && (code < $A || $Z < code) &&
(code < $0 || code > $9);
}
function isDigitEntityEnd(code) {
return code == $SEMICOLON || code == $EOF || !isAsciiHexDigit(code);
}
function isNamedEntityEnd(code) {
return code == $SEMICOLON || code == $EOF || !isAsciiLetter(code);
}
function isExpansionFormStart(input, offset, interpolationConfig) {
var isInterpolationStart = interpolationConfig ? input.indexOf(interpolationConfig.start, offset) == offset : false;
return input.charCodeAt(offset) == $LBRACE && !isInterpolationStart;
}
function isExpansionCaseStart(peek) {
return peek === $EQ || isAsciiLetter(peek) || isDigit(peek);
}
function compareCharCodeCaseInsensitive(code1, code2) {
return toUpperCaseCharCode(code1) == toUpperCaseCharCode(code2);
}
function toUpperCaseCharCode(code) {
return code >= $a && code <= $z ? code - $a + $A : code;
}
function mergeTextTokens(srcTokens) {
var dstTokens = [];
var lastDstToken = undefined;
for (var i = 0; i < srcTokens.length; i++) {
var token = srcTokens[i];
if (lastDstToken && lastDstToken.type == TokenType$1.TEXT && token.type == TokenType$1.TEXT) {
lastDstToken.parts[0] += token.parts[0];
lastDstToken.sourceSpan.end = token.sourceSpan.end;
}
else {
lastDstToken = token;
dstTokens.push(lastDstToken);
}
}
return dstTokens;
}
/**
* @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
*/
var TreeError = /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TreeError, _super);
function TreeError(elementName, span, msg) {
var _this = _super.call(this, span, msg) || this;
_this.elementName = elementName;
return _this;
}
TreeError.create = function (elementName, span, msg) {
return new TreeError(elementName, span, msg);
};
return TreeError;
}(ParseError));
var ParseTreeResult = /** @class */ (function () {
function ParseTreeResult(rootNodes, errors) {
this.rootNodes = rootNodes;
this.errors = errors;
}
return ParseTreeResult;
}());
var Parser$1 = /** @class */ (function () {
function Parser(getTagDefinition) {
this.getTagDefinition = getTagDefinition;
}
Parser.prototype.parse = function (source, url, parseExpansionForms, interpolationConfig) {
if (parseExpansionForms === void 0) { parseExpansionForms = false; }
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
var tokensAndErrors = tokenize(source, url, this.getTagDefinition, parseExpansionForms, interpolationConfig);
var treeAndErrors = new _TreeBuilder(tokensAndErrors.tokens, this.getTagDefinition).build();
return new ParseTreeResult(treeAndErrors.rootNodes, tokensAndErrors.errors.concat(treeAndErrors.errors));
};
return Parser;
}());
var _TreeBuilder = /** @class */ (function () {
function _TreeBuilder(tokens, getTagDefinition) {
this.tokens = tokens;
this.getTagDefinition = getTagDefinition;
this._index = -1;
this._rootNodes = [];
this._errors = [];
this._elementStack = [];
this._advance();
}
_TreeBuilder.prototype.build = function () {
while (this._peek.type !== TokenType$1.EOF) {
if (this._peek.type === TokenType$1.TAG_OPEN_START) {
this._consumeStartTag(this._advance());
}
else if (this._peek.type === TokenType$1.TAG_CLOSE) {
this._consumeEndTag(this._advance());
}
else if (this._peek.type === TokenType$1.CDATA_START) {
this._closeVoidElement();
this._consumeCdata(this._advance());
}
else if (this._peek.type === TokenType$1.COMMENT_START) {
this._closeVoidElement();
this._consumeComment(this._advance());
}
else if (this._peek.type === TokenType$1.TEXT || this._peek.type === TokenType$1.RAW_TEXT ||
this._peek.type === TokenType$1.ESCAPABLE_RAW_TEXT) {
this._closeVoidElement();
this._consumeText(this._advance());
}
else if (this._peek.type === TokenType$1.EXPANSION_FORM_START) {
this._consumeExpansion(this._advance());
}
else {
// Skip all other tokens...
this._advance();
}
}
return new ParseTreeResult(this._rootNodes, this._errors);
};
_TreeBuilder.prototype._advance = function () {
var prev = this._peek;
if (this._index < this.tokens.length - 1) {
// Note: there is always an EOF token at the end
this._index++;
}
this._peek = this.tokens[this._index];
return prev;
};
_TreeBuilder.prototype._advanceIf = function (type) {
if (this._peek.type === type) {
return this._advance();
}
return null;
};
_TreeBuilder.prototype._consumeCdata = function (startToken) {
this._consumeText(this._advance());
this._advanceIf(TokenType$1.CDATA_END);
};
_TreeBuilder.prototype._consumeComment = function (token) {
var text = this._advanceIf(TokenType$1.RAW_TEXT);
this._advanceIf(TokenType$1.COMMENT_END);
var value = text != null ? text.parts[0].trim() : null;
this._addToParent(new Comment(value, token.sourceSpan));
};
_TreeBuilder.prototype._consumeExpansion = function (token) {
var switchValue = this._advance();
var type = this._advance();
var cases = [];
// read =
while (this._peek.type === TokenType$1.EXPANSION_CASE_VALUE) {
var expCase = this._parseExpansionCase();
if (!expCase)
return; // error
cases.push(expCase);
}
// read the final }
if (this._peek.type !== TokenType$1.EXPANSION_FORM_END) {
this._errors.push(TreeError.create(null, this._peek.sourceSpan, "Invalid ICU message. Missing '}'."));
return;
}
var sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end);
this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
this._advance();
};
_TreeBuilder.prototype._parseExpansionCase = function () {
var value = this._advance();
// read {
if (this._peek.type !== TokenType$1.EXPANSION_CASE_EXP_START) {
this._errors.push(TreeError.create(null, this._peek.sourceSpan, "Invalid ICU message. Missing '{'."));
return null;
}
// read until }
var start = this._advance();
var exp = this._collectExpansionExpTokens(start);
if (!exp)
return null;
var end = this._advance();
exp.push(new Token$1(TokenType$1.EOF, [], end.sourceSpan));
// parse everything in between { and }
var parsedExp = new _TreeBuilder(exp, this.getTagDefinition).build();
if (parsedExp.errors.length > 0) {
this._errors = this._errors.concat(parsedExp.errors);
return null;
}
var sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end);
var expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end);
return new ExpansionCase(value.parts[0], parsedExp.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
};
_TreeBuilder.prototype._collectExpansionExpTokens = function (start) {
var exp = [];
var expansionFormStack = [TokenType$1.EXPANSION_CASE_EXP_START];
while (true) {
if (this._peek.type === TokenType$1.EXPANSION_FORM_START ||
this._peek.type === TokenType$1.EXPANSION_CASE_EXP_START) {
expansionFormStack.push(this._peek.type);
}
if (this._peek.type === TokenType$1.EXPANSION_CASE_EXP_END) {
if (lastOnStack(expansionFormStack, TokenType$1.EXPANSION_CASE_EXP_START)) {
expansionFormStack.pop();
if (expansionFormStack.length == 0)
return exp;
}
else {
this._errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
return null;
}
}
if (this._peek.type === TokenType$1.EXPANSION_FORM_END) {
if (lastOnStack(expansionFormStack, TokenType$1.EXPANSION_FORM_START)) {
expansionFormStack.pop();
}
else {
this._errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
return null;
}
}
if (this._peek.type === TokenType$1.EOF) {
this._errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
return null;
}
exp.push(this._advance());
}
};
_TreeBuilder.prototype._consumeText = function (token) {
var text = token.parts[0];
if (text.length > 0 && text[0] == '\n') {
var parent_1 = this._getParentElement();
if (parent_1 != null && parent_1.children.length == 0 &&
this.getTagDefinition(parent_1.name).ignoreFirstLf) {
text = text.substring(1);
}
}
if (text.length > 0) {
this._addToParent(new Text$2(text, token.sourceSpan));
}
};
_TreeBuilder.prototype._closeVoidElement = function () {
var el = this._getParentElement();
if (el && this.getTagDefinition(el.name).isVoid) {
this._elementStack.pop();
}
};
_TreeBuilder.prototype._consumeStartTag = function (startTagToken) {
var prefix = startTagToken.parts[0];
var name = startTagToken.parts[1];
var attrs = [];
while (this._peek.type === TokenType$1.ATTR_NAME) {
attrs.push(this._consumeAttr(this._advance()));
}
var fullName = this._getElementFullName(prefix, name, this._getParentElement());
var selfClosing = false;
// Note: There could have been a tokenizer error
// so that we don't get a token for the end tag...
if (this._peek.type === TokenType$1.TAG_OPEN_END_VOID) {
this._advance();
selfClosing = true;
var tagDef = this.getTagDefinition(fullName);
if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
this._errors.push(TreeError.create(fullName, startTagToken.sourceSpan, "Only void and foreign elements can be self closed \"" + startTagToken.parts[1] + "\""));
}
}
else if (this._peek.type === TokenType$1.TAG_OPEN_END) {
this._advance();
selfClosing = false;
}
var end = this._peek.sourceSpan.start;
var span = new ParseSourceSpan(startTagToken.sourceSpan.start, end);
var el = new Element(fullName, attrs, [], span, span, undefined);
this._pushElement(el);
if (selfClosing) {
this._popElement(fullName);
el.endSourceSpan = span;
}
};
_TreeBuilder.prototype._pushElement = function (el) {
var parentEl = this._getParentElement();
if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
this._elementStack.pop();
}
var tagDef = this.getTagDefinition(el.name);
var _a = this._getParentElementSkippingContainers(), parent = _a.parent, container = _a.container;
if (parent && tagDef.requireExtraParent(parent.name)) {
var newParent = new Element(tagDef.parentToAdd, [], [], el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
this._insertBeforeContainer(parent, container, newParent);
}
this._addToParent(el);
this._elementStack.push(el);
};
_TreeBuilder.prototype._consumeEndTag = function (endTagToken) {
var fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
if (this._getParentElement()) {
this._getParentElement().endSourceSpan = endTagToken.sourceSpan;
}
if (this.getTagDefinition(fullName).isVoid) {
this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, "Void elements do not have end tags \"" + endTagToken.parts[1] + "\""));
}
else if (!this._popElement(fullName)) {
var errMsg = "Unexpected closing tag \"" + fullName + "\". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags";
this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
}
};
_TreeBuilder.prototype._popElement = function (fullName) {
for (var stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
var el = this._elementStack[stackIndex];
if (el.name == fullName) {
this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
return true;
}
if (!this.getTagDefinition(el.name).closedByParent) {
return false;
}
}
return false;
};
_TreeBuilder.prototype._consumeAttr = function (attrName) {
var fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
var end = attrName.sourceSpan.end;
var value = '';
var valueSpan = undefined;
if (this._peek.type === TokenType$1.ATTR_VALUE) {
var valueToken = this._advance();
value = valueToken.parts[0];
end = valueToken.sourceSpan.end;
valueSpan = valueToken.sourceSpan;
}
return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end), valueSpan);
};
_TreeBuilder.prototype._getParentElement = function () {
return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
};
/**
* Returns the parent in the DOM and the container.
*
* `` elements are skipped as they are not rendered as DOM element.
*/
_TreeBuilder.prototype._getParentElementSkippingContainers = function () {
var container = null;
for (var i = this._elementStack.length - 1; i >= 0; i--) {
if (!isNgContainer(this._elementStack[i].name)) {
return { parent: this._elementStack[i], container: container };
}
container = this._elementStack[i];
}
return { parent: null, container: container };
};
_TreeBuilder.prototype._addToParent = function (node) {
var parent = this._getParentElement();
if (parent != null) {
parent.children.push(node);
}
else {
this._rootNodes.push(node);
}
};
/**
* Insert a node between the parent and the container.
* When no container is given, the node is appended as a child of the parent.
* Also updates the element stack accordingly.
*
* @internal
*/
_TreeBuilder.prototype._insertBeforeContainer = function (parent, container, node) {
if (!container) {
this._addToParent(node);
this._elementStack.push(node);
}
else {
if (parent) {
// replace the container with the new node in the children
var index = parent.children.indexOf(container);
parent.children[index] = node;
}
else {
this._rootNodes.push(node);
}
node.children.push(container);
this._elementStack.splice(this._elementStack.indexOf(container), 0, node);
}
};
_TreeBuilder.prototype._getElementFullName = function (prefix, localName, parentElement) {
if (prefix == null) {
prefix = this.getTagDefinition(localName).implicitNamespacePrefix;
if (prefix == null && parentElement != null) {
prefix = getNsPrefix(parentElement.name);
}
}
return mergeNsAndName(prefix, localName);
};
return _TreeBuilder;
}());
function lastOnStack(stack, element) {
return stack.length > 0 && stack[stack.length - 1] === element;
}
/**
* @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
*/
var HtmlParser = /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(HtmlParser, _super);
function HtmlParser() {
return _super.call(this, getHtmlTagDefinition) || this;
}
HtmlParser.prototype.parse = function (source, url, parseExpansionForms, interpolationConfig) {
if (parseExpansionForms === void 0) { parseExpansionForms = false; }
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
return _super.prototype.parse.call(this, source, url, parseExpansionForms, interpolationConfig);
};
return HtmlParser;
}(Parser$1));
/**
* @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
*/
var PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
var SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
// Equivalent to \s with \u00a0 (non-breaking space) excluded.
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
var WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
var NO_WS_REGEXP = new RegExp("[^" + WS_CHARS + "]");
var WS_REPLACE_REGEXP = new RegExp("[" + WS_CHARS + "]{2,}", 'g');
function hasPreserveWhitespacesAttr(attrs) {
return attrs.some(function (attr) { return attr.name === PRESERVE_WS_ATTR_NAME; });
}
/**
* Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
* https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
* In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
* and later on replaced by a space. We are re-implementing the same idea here.
*/
function replaceNgsp(value) {
// lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
}
/**
* This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
* - consider spaces, tabs and new lines as whitespace characters;
* - drop text nodes consisting of whitespace characters only;
* - for all other text nodes replace consecutive whitespace characters with one space;
* - convert &ngsp; pseudo-entity to a single space;
*
* Removal and trimming of whitespaces have positive performance impact (less code to generate
* while compiling templates, faster view creation). At the same time it can be "destructive"
* in some cases (whitespaces can influence layout). Because of the potential of breaking layout
* this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
* whitespace removal. The default option for whitespace removal will be revisited in Angular 6
* and might be changed to "on" by default.
*/
var WhitespaceVisitor = /** @class */ (function () {
function WhitespaceVisitor() {
}
WhitespaceVisitor.prototype.visitElement = function (element, context) {
if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
// don't descent into elements where we need to preserve whitespaces
// but still visit all attributes to eliminate one used as a market to preserve WS
return new Element(element.name, visitAll(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
}
return new Element(element.name, element.attrs, visitAll(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
};
WhitespaceVisitor.prototype.visitAttribute = function (attribute, context) {
return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
};
WhitespaceVisitor.prototype.visitText = function (text, context) {
var isNotBlank = text.value.match(NO_WS_REGEXP);
if (isNotBlank) {
return new Text$2(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n);
}
return null;
};
WhitespaceVisitor.prototype.visitComment = function (comment, context) { return comment; };
WhitespaceVisitor.prototype.visitExpansion = function (expansion, context) { return expansion; };
WhitespaceVisitor.prototype.visitExpansionCase = function (expansionCase, context) { return expansionCase; };
return WhitespaceVisitor;
}());
function removeWhitespaces(htmlAstWithErrors) {
return new ParseTreeResult(visitAll(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
}
/**
* @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
*/
// =================================================================================================
// =================================================================================================
// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
// =================================================================================================
// =================================================================================================
//
// DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
// Reach out to mprobst for details.
//
// =================================================================================================
/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
var _SECURITY_SCHEMA;
function SECURITY_SCHEMA() {
if (!_SECURITY_SCHEMA) {
_SECURITY_SCHEMA = {};
// Case is insignificant below, all element and attribute names are lower-cased for lookup.
registerContext(SecurityContext.HTML, [
'iframe|srcdoc',
'*|innerHTML',
'*|outerHTML',
]);
registerContext(SecurityContext.STYLE, ['*|style']);
// NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
registerContext(SecurityContext.URL, [
'*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
]);
registerContext(SecurityContext.RESOURCE_URL, [
'applet|code',
'applet|codebase',
'base|href',
'embed|src',
'frame|src',
'head|profile',
'html|manifest',
'iframe|src',
'link|href',
'media|src',
'object|codebase',
'object|data',
'script|src',
]);
}
return _SECURITY_SCHEMA;
}
function registerContext(ctx, specs) {
var e_1, _a;
try {
for (var specs_1 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__values"])(specs), specs_1_1 = specs_1.next(); !specs_1_1.done; specs_1_1 = specs_1.next()) {
var spec = specs_1_1.value;
_SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (specs_1_1 && !specs_1_1.done && (_a = specs_1.return)) _a.call(specs_1);
}
finally { if (e_1) throw e_1.error; }
}
}
/**
* @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
*/
var ElementSchemaRegistry = /** @class */ (function () {
function ElementSchemaRegistry() {
}
return ElementSchemaRegistry;
}());
/**
* @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
*/
var BOOLEAN = 'boolean';
var NUMBER = 'number';
var STRING = 'string';
var OBJECT = 'object';
/**
* This array represents the DOM schema. It encodes inheritance, properties, and events.
*
* ## Overview
*
* Each line represents one kind of element. The `element_inheritance` and properties are joined
* using `element_inheritance|properties` syntax.
*
* ## Element Inheritance
*
* The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
* Here the individual elements are separated by `,` (commas). Every element in the list
* has identical properties.
*
* An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
* specified then `""` (blank) element is assumed.
*
* NOTE: The blank element inherits from root `[Element]` element, the super element of all
* elements.
*
* NOTE an element prefix such as `:svg:` has no special meaning to the schema.
*
* ## Properties
*
* Each element has a set of properties separated by `,` (commas). Each property can be prefixed
* by a special character designating its type:
*
* - (no prefix): property is a string.
* - `*`: property represents an event.
* - `!`: property is a boolean.
* - `#`: property is a number.
* - `%`: property is an object.
*
* ## Query
*
* The class creates an internal squas representation which allows to easily answer the query of
* if a given property exist on a given element.
*
* NOTE: We don't yet support querying for types or events.
* NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
* see dom_element_schema_registry_spec.ts
*/
// =================================================================================================
// =================================================================================================
// =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
// =================================================================================================
// =================================================================================================
//
// DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW!
//
// Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
// dom_security_schema.ts. Reach out to mprobst & rjamet for details.
//
// =================================================================================================
var SCHEMA = [
'[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
/* added manually to avoid breaking changes */
',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
'[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
':svg:^[HTMLElement]|*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex',
':svg:graphics^:svg:|',
':svg:animation^:svg:|*begin,*end,*repeat',
':svg:geometry^:svg:|',
':svg:componentTransferFunction^:svg:|',
':svg:gradient^:svg:|',
':svg:textContent^:svg:graphics|',
':svg:textPositioning^:svg:textContent|',
'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,rev,search,shape,target,text,type,username',
'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
'audio^media|',
'br^[HTMLElement]|clear',
'base^[HTMLElement]|href,target',
'body^[HTMLElement]|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink',
'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
'canvas^[HTMLElement]|#height,#width',
'content^[HTMLElement]|select',
'dl^[HTMLElement]|!compact',
'datalist^[HTMLElement]|',
'details^[HTMLElement]|!open',
'dialog^[HTMLElement]|!open,returnValue',
'dir^[HTMLElement]|!compact',
'div^[HTMLElement]|align',
'embed^[HTMLElement]|align,height,name,src,type,width',
'fieldset^[HTMLElement]|!disabled,name',
'font^[HTMLElement]|color,face,size',
'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
'hr^[HTMLElement]|align,color,!noShade,size,width',
'head^[HTMLElement]|',
'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
'html^[HTMLElement]|version',
'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
'input^[HTMLElement]|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width',
'li^[HTMLElement]|type,#value',
'label^[HTMLElement]|htmlFor',
'legend^[HTMLElement]|align',
'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
'map^[HTMLElement]|name',
'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
'menu^[HTMLElement]|!compact',
'meta^[HTMLElement]|content,httpEquiv,name,scheme',
'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
'ins,del^[HTMLElement]|cite,dateTime',
'ol^[HTMLElement]|!compact,!reversed,#start,type',
'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
'optgroup^[HTMLElement]|!disabled,label',
'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
'p^[HTMLElement]|align',
'param^[HTMLElement]|name,type,value,valueType',
'picture^[HTMLElement]|',
'pre^[HTMLElement]|#width',
'progress^[HTMLElement]|#max,#value',
'q,blockquote,cite^[HTMLElement]|',
'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
'select^[HTMLElement]|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
'shadow^[HTMLElement]|',
'slot^[HTMLElement]|name',
'source^[HTMLElement]|media,sizes,src,srcset,type',
'span^[HTMLElement]|',
'style^[HTMLElement]|!disabled,media,type',
'caption^[HTMLElement]|align',
'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
'template^[HTMLElement]|',
'textarea^[HTMLElement]|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
'title^[HTMLElement]|text',
'track^[HTMLElement]|!default,kind,label,src,srclang',
'ul^[HTMLElement]|!compact,type',
'unknown^[HTMLElement]|',
'video^media|#height,poster,#width',
':svg:a^:svg:graphics|',
':svg:animate^:svg:animation|',
':svg:animateMotion^:svg:animation|',
':svg:animateTransform^:svg:animation|',
':svg:circle^:svg:geometry|',
':svg:clipPath^:svg:graphics|',
':svg:defs^:svg:graphics|',
':svg:desc^:svg:|',
':svg:discard^:svg:|',
':svg:ellipse^:svg:geometry|',
':svg:feBlend^:svg:|',
':svg:feColorMatrix^:svg:|',
':svg:feComponentTransfer^:svg:|',
':svg:feComposite^:svg:|',
':svg:feConvolveMatrix^:svg:|',
':svg:feDiffuseLighting^:svg:|',
':svg:feDisplacementMap^:svg:|',
':svg:feDistantLight^:svg:|',
':svg:feDropShadow^:svg:|',
':svg:feFlood^:svg:|',
':svg:feFuncA^:svg:componentTransferFunction|',
':svg:feFuncB^:svg:componentTransferFunction|',
':svg:feFuncG^:svg:componentTransferFunction|',
':svg:feFuncR^:svg:componentTransferFunction|',
':svg:feGaussianBlur^:svg:|',
':svg:feImage^:svg:|',
':svg:feMerge^:svg:|',
':svg:feMergeNode^:svg:|',
':svg:feMorphology^:svg:|',
':svg:feOffset^:svg:|',
':svg:fePointLight^:svg:|',
':svg:feSpecularLighting^:svg:|',
':svg:feSpotLight^:svg:|',
':svg:feTile^:svg:|',
':svg:feTurbulence^:svg:|',
':svg:filter^:svg:|',
':svg:foreignObject^:svg:graphics|',
':svg:g^:svg:graphics|',
':svg:image^:svg:graphics|',
':svg:line^:svg:geometry|',
':svg:linearGradient^:svg:gradient|',
':svg:mpath^:svg:|',
':svg:marker^:svg:|',
':svg:mask^:svg:|',
':svg:metadata^:svg:|',
':svg:path^:svg:geometry|',
':svg:pattern^:svg:|',
':svg:polygon^:svg:geometry|',
':svg:polyline^:svg:geometry|',
':svg:radialGradient^:svg:gradient|',
':svg:rect^:svg:geometry|',
':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
':svg:script^:svg:|type',
':svg:set^:svg:animation|',
':svg:stop^:svg:|',
':svg:style^:svg:|!disabled,media,title,type',
':svg:switch^:svg:graphics|',
':svg:symbol^:svg:|',
':svg:tspan^:svg:textPositioning|',
':svg:text^:svg:textPositioning|',
':svg:textPath^:svg:textContent|',
':svg:title^:svg:|',
':svg:use^:svg:graphics|',
':svg:view^:svg:|#zoomAndPan',
'data^[HTMLElement]|value',
'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
'summary^[HTMLElement]|',
'time^[HTMLElement]|dateTime',
':svg:cursor^:svg:|',
];
var _ATTR_TO_PROP = {
'class': 'className',
'for': 'htmlFor',
'formaction': 'formAction',
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
var DomElementSchemaRegistry = /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(DomElementSchemaRegistry, _super);
function DomElementSchemaRegistry() {
var _this = _super.call(this) || this;
_this._schema = {};
SCHEMA.forEach(function (encodedType) {
var type = {};
var _a = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__read"])(encodedType.split('|'), 2), strType = _a[0], strProperties = _a[1];
var properties = strProperties.split(',');
var _b = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__read"])(strType.split('^'), 2), typeNames = _b[0], superName = _b[1];
typeNames.split(',').forEach(function (tag) { return _this._schema[tag.toLowerCase()] = type; });
var superType = superName && _this._schema[superName.toLowerCase()];
if (superType) {
Object.keys(superType).forEach(function (prop) { type[prop] = superType[prop]; });
}
properties.forEach(function (property) {
if (property.length > 0) {
switch (property[0]) {
case '*':
// We don't yet support events.
// If ever allowing to bind to events, GO THROUGH A SECURITY REVIEW, allowing events
// will
// almost certainly introduce bad XSS vulnerabilities.
// type[property.substring(1)] = EVENT;
break;
case '!':
type[property.substring(1)] = BOOLEAN;
break;
case '#':
type[property.substring(1)] = NUMBER;
break;
case '%':
type[property.substring(1)] = OBJECT;
break;
default:
type[property] = STRING;
}
}
});
});
return _this;
}
DomElementSchemaRegistry.prototype.hasProperty = function (tagName, propName, schemaMetas) {
if (schemaMetas.some(function (schema) { return schema.name === NO_ERRORS_SCHEMA.name; })) {
return true;
}
if (tagName.indexOf('-') > -1) {
if (isNgContainer(tagName) || isNgContent(tagName)) {
return false;
}
if (schemaMetas.some(function (schema) { return schema.name === CUSTOM_ELEMENTS_SCHEMA.name; })) {
// Can't tell now as we don't know which properties a custom element will get
// once it is instantiated
return true;
}
}
var elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
return !!elementProperties[propName];
};
DomElementSchemaRegistry.prototype.hasElement = function (tagName, schemaMetas) {
if (schemaMetas.some(function (schema) { return schema.name === NO_ERRORS_SCHEMA.name; })) {
return true;
}
if (tagName.indexOf('-') > -1) {
if (isNgContainer(tagName) || isNgContent(tagName)) {
return true;
}
if (schemaMetas.some(function (schema) { return schema.name === CUSTOM_ELEMENTS_SCHEMA.name; })) {
// Allow any custom elements
return true;
}
}
return !!this._schema[tagName.toLowerCase()];
};
/**
* securityContext returns the security context for the given property on the given DOM tag.
*
* Tag and property name are statically known and cannot change at runtime, i.e. it is not
* possible to bind a value into a changing attribute or tag name.
*
* The filtering is white list based. All attributes in the schema above are assumed to have the
* 'NONE' security context, i.e. that they are safe inert string values. Only specific well known
* attack vectors are assigned their appropriate context.
*/
DomElementSchemaRegistry.prototype.securityContext = function (tagName, propName, isAttribute) {
if (isAttribute) {
// NB: For security purposes, use the mapped property name, not the attribute name.
propName = this.getMappedPropName(propName);
}
// Make sure comparisons are case insensitive, so that case differences between attribute and
// property names do not have a security impact.
tagName = tagName.toLowerCase();
propName = propName.toLowerCase();
var ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
if (ctx) {
return ctx;
}
ctx = SECURITY_SCHEMA()['*|' + propName];
return ctx ? ctx : SecurityContext.NONE;
};
DomElementSchemaRegistry.prototype.getMappedPropName = function (propName) { return _ATTR_TO_PROP[propName] || propName; };
DomElementSchemaRegistry.prototype.getDefaultComponentElementName = function () { return 'ng-component'; };
DomElementSchemaRegistry.prototype.validateProperty = function (name) {
if (name.toLowerCase().startsWith('on')) {
var msg = "Binding to event property '" + name + "' is disallowed for security reasons, " +
("please use (" + name.slice(2) + ")=...") +
("\nIf '" + name + "' is a directive input, make sure the directive is imported by the") +
" current module.";
return { error: true, msg: msg };
}
else {
return { error: false };
}
};
DomElementSchemaRegistry.prototype.validateAttribute = function (name) {
if (name.toLowerCase().startsWith('on')) {
var msg = "Binding to event attribute '" + name + "' is disallowed for security reasons, " +
("please use (" + name.slice(2) + ")=...");
return { error: true, msg: msg };
}
else {
return { error: false };
}
};
DomElementSchemaRegistry.prototype.allKnownElementNames = function () { return Object.keys(this._schema); };
DomElementSchemaRegistry.prototype.normalizeAnimationStyleProperty = function (propName) {
return dashCaseToCamelCase(propName);
};
DomElementSchemaRegistry.prototype.normalizeAnimationStyleValue = function (camelCaseProp, userProvidedProp, val) {
var unit = '';
var strVal = val.toString().trim();
var errorMsg = null;
if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
if (typeof val === 'number') {
unit = 'px';
}
else {
var valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
errorMsg = "Please provide a CSS unit value for " + userProvidedProp + ":" + val;
}
}
}
return { error: errorMsg, value: strVal + unit };
};
return DomElementSchemaRegistry;
}(ElementSchemaRegistry));
function _isPixelDimensionStyle(prop) {
switch (prop) {
case 'width':
case 'height':
case 'minWidth':
case 'minHeight':
case 'maxWidth':
case 'maxHeight':
case 'left':
case 'top':
case 'bottom':
case 'right':
case 'fontSize':
case 'outlineWidth':
case 'outlineOffset':
case 'paddingTop':
case 'paddingLeft':
case 'paddingBottom':
case 'paddingRight':
case 'marginTop':
case 'marginLeft':
case 'marginBottom':
case 'marginRight':
case 'borderRadius':
case 'borderWidth':
case 'borderTopWidth':
case 'borderLeftWidth':
case 'borderRightWidth':
case 'borderBottomWidth':
case 'textIndent':
return true;
default:
return false;
}
}
/**
* @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
*/
var PROPERTY_PARTS_SEPARATOR = '.';
var ATTRIBUTE_PREFIX = 'attr';
var CLASS_PREFIX = 'class';
var STYLE_PREFIX = 'style';
var ANIMATE_PROP_PREFIX = 'animate-';
/**
* Parses bindings in templates and in the directive host area.
*/
var BindingParser = /** @class */ (function () {
function BindingParser(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) {
this._exprParser = _exprParser;
this._interpolationConfig = _interpolationConfig;
this._schemaRegistry = _schemaRegistry;
this.errors = errors;
this.pipesByName = null;
this._usedPipes = new Map();
// When the `pipes` parameter is `null`, do not check for used pipes
// This is used in IVY when we might not know the available pipes at compile time
if (pipes) {
var pipesByName_1 = new Map();
pipes.forEach(function (pipe) { return pipesByName_1.set(pipe.name, pipe); });
this.pipesByName = pipesByName_1;
}
}
Object.defineProperty(BindingParser.prototype, "interpolationConfig", {
get: function () { return this._interpolationConfig; },
enumerable: true,
configurable: true
});
BindingParser.prototype.getUsedPipes = function () { return Array.from(this._usedPipes.values()); };
BindingParser.prototype.createBoundHostProperties = function (dirMeta, sourceSpan) {
var _this = this;
if (dirMeta.hostProperties) {
var boundProps_1 = [];
Object.keys(dirMeta.hostProperties).forEach(function (propName) {
var expression = dirMeta.hostProperties[propName];
if (typeof expression === 'string') {
_this.parsePropertyBinding(propName, expression, true, sourceSpan, [], boundProps_1);
}
else {
_this._reportError("Value of the host property binding \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan);
}
});
return boundProps_1;
}
return null;
};
BindingParser.prototype.createDirectiveHostPropertyAsts = function (dirMeta, elementSelector, sourceSpan) {
var _this = this;
var boundProps = this.createBoundHostProperties(dirMeta, sourceSpan);
return boundProps &&
boundProps.map(function (prop) { return _this.createBoundElementProperty(elementSelector, prop); });
};
BindingParser.prototype.createDirectiveHostEventAsts = function (dirMeta, sourceSpan) {
var _this = this;
if (dirMeta.hostListeners) {
var targetEvents_1 = [];
Object.keys(dirMeta.hostListeners).forEach(function (propName) {
var expression = dirMeta.hostListeners[propName];
if (typeof expression === 'string') {
_this.parseEvent(propName, expression, sourceSpan, [], targetEvents_1);
}
else {
_this._reportError("Value of the host listener \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan);
}
});
return targetEvents_1;
}
return null;
};
BindingParser.prototype.parseInterpolation = function (value, sourceSpan) {
var sourceInfo = sourceSpan.start.toString();
try {
var ast = this._exprParser.parseInterpolation(value, sourceInfo, this._interpolationConfig);
if (ast)
this._reportExpressionParserErrors(ast.errors, sourceSpan);
this._checkPipes(ast, sourceSpan);
return ast;
}
catch (e) {
this._reportError("" + e, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
};
// Parse an inline template binding. ie `">`
BindingParser.prototype.parseInlineTemplateBinding = function (tplKey, tplValue, sourceSpan, targetMatchableAttrs, targetProps, targetVars) {
var bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan);
for (var i = 0; i < bindings.length; i++) {
var binding = bindings[i];
if (binding.keyIsVar) {
targetVars.push(new ParsedVariable(binding.key, binding.name, sourceSpan));
}
else if (binding.expression) {
this._parsePropertyAst(binding.key, binding.expression, sourceSpan, targetMatchableAttrs, targetProps);
}
else {
targetMatchableAttrs.push([binding.key, '']);
this.parseLiteralAttr(binding.key, null, sourceSpan, targetMatchableAttrs, targetProps);
}
}
};
BindingParser.prototype._parseTemplateBindings = function (tplKey, tplValue, sourceSpan) {
var _this = this;
var sourceInfo = sourceSpan.start.toString();
try {
var bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo);
this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
bindingsResult.templateBindings.forEach(function (binding) {
if (binding.expression) {
_this._checkPipes(binding.expression, sourceSpan);
}
});
bindingsResult.warnings.forEach(function (warning) { _this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
return bindingsResult.templateBindings;
}
catch (e) {
this._reportError("" + e, sourceSpan);
return [];
}
};
BindingParser.prototype.parseLiteralAttr = function (name, value, sourceSpan, targetMatchableAttrs, targetProps) {
if (isAnimationLabel(name)) {
name = name.substring(1);
if (value) {
this._reportError("Assigning animation triggers via @prop=\"exp\" attributes with an expression is invalid." +
" Use property bindings (e.g. [@prop]=\"exp\") or use an attribute without a value (e.g. @prop) instead.", sourceSpan, ParseErrorLevel.ERROR);
}
this._parseAnimation(name, value, sourceSpan, targetMatchableAttrs, targetProps);
}
else {
targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, ''), ParsedPropertyType.LITERAL_ATTR, sourceSpan));
}
};
BindingParser.prototype.parsePropertyBinding = function (name, expression, isHost, sourceSpan, targetMatchableAttrs, targetProps) {
var isAnimationProp = false;
if (name.startsWith(ANIMATE_PROP_PREFIX)) {
isAnimationProp = true;
name = name.substring(ANIMATE_PROP_PREFIX.length);
}
else if (isAnimationLabel(name)) {
isAnimationProp = true;
name = name.substring(1);
}
if (isAnimationProp) {
this._parseAnimation(name, expression, sourceSpan, targetMatchableAttrs, targetProps);
}
else {
this._parsePropertyAst(name, this._parseBinding(expression, isHost, sourceSpan), sourceSpan, targetMatchableAttrs, targetProps);
}
};
BindingParser.prototype.parsePropertyInterpolation = function (name, value, sourceSpan, targetMatchableAttrs, targetProps) {
var expr = this.parseInterpolation(value, sourceSpan);
if (expr) {
this._parsePropertyAst(name, expr, sourceSpan, targetMatchableAttrs, targetProps);
return true;
}
return false;
};
BindingParser.prototype._parsePropertyAst = function (name, ast, sourceSpan, targetMatchableAttrs, targetProps) {
targetMatchableAttrs.push([name, ast.source]);
targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan));
};
BindingParser.prototype._parseAnimation = function (name, expression, sourceSpan, targetMatchableAttrs, targetProps) {
// This will occur when a @trigger is not paired with an expression.
// For animations it is valid to not have an expression since */void
// states will be applied by angular when the element is attached/detached
var ast = this._parseBinding(expression || 'undefined', false, sourceSpan);
targetMatchableAttrs.push([name, ast.source]);
targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan));
};
BindingParser.prototype._parseBinding = function (value, isHostBinding, sourceSpan) {
var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
try {
var ast = isHostBinding ?
this._exprParser.parseSimpleBinding(value, sourceInfo, this._interpolationConfig) :
this._exprParser.parseBinding(value, sourceInfo, this._interpolationConfig);
if (ast)
this._reportExpressionParserErrors(ast.errors, sourceSpan);
this._checkPipes(ast, sourceSpan);
return ast;
}
catch (e) {
this._reportError("" + e, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
};
BindingParser.prototype.createBoundElementProperty = function (elementSelector, boundProp) {
if (boundProp.isAnimation) {
return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan);
}
var unit = null;
var bindingType = undefined;
var boundPropertyName = null;
var parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
var securityContexts = undefined;
// Check check for special cases (prefix style, attr, class)
if (parts.length > 1) {
if (parts[0] == ATTRIBUTE_PREFIX) {
boundPropertyName = parts[1];
this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
var nsSeparatorIdx = boundPropertyName.indexOf(':');
if (nsSeparatorIdx > -1) {
var ns = boundPropertyName.substring(0, nsSeparatorIdx);
var name_1 = boundPropertyName.substring(nsSeparatorIdx + 1);
boundPropertyName = mergeNsAndName(ns, name_1);
}
bindingType = 1 /* Attribute */;
}
else if (parts[0] == CLASS_PREFIX) {
boundPropertyName = parts[1];
bindingType = 2 /* Class */;
securityContexts = [SecurityContext.NONE];
}
else if (parts[0] == STYLE_PREFIX) {
unit = parts.length > 2 ? parts[2] : null;
boundPropertyName = parts[1];
bindingType = 3 /* Style */;
securityContexts = [SecurityContext.STYLE];
}
}
// If not a special case, use the full property name
if (boundPropertyName === null) {
boundPropertyName = this._schemaRegistry.getMappedPropName(boundProp.name);
securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, false);
bindingType = 0 /* Property */;
this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, false);
}
return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan);
};
BindingParser.prototype.parseEvent = function (name, expression, sourceSpan, targetMatchableAttrs, targetEvents) {
if (isAnimationLabel(name)) {
name = name.substr(1);
this._parseAnimationEvent(name, expression, sourceSpan, targetEvents);
}
else {
this._parseRegularEvent(name, expression, sourceSpan, targetMatchableAttrs, targetEvents);
}
};
BindingParser.prototype._parseAnimationEvent = function (name, expression, sourceSpan, targetEvents) {
var matches = splitAtPeriod(name, [name, '']);
var eventName = matches[0];
var phase = matches[1].toLowerCase();
if (phase) {
switch (phase) {
case 'start':
case 'done':
var ast = this._parseAction(expression, sourceSpan);
targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan));
break;
default:
this._reportError("The provided animation output phase value \"" + phase + "\" for \"@" + eventName + "\" is not supported (use start or done)", sourceSpan);
break;
}
}
else {
this._reportError("The animation trigger output event (@" + eventName + ") is missing its phase value name (start or done are currently supported)", sourceSpan);
}
};
BindingParser.prototype._parseRegularEvent = function (name, expression, sourceSpan, targetMatchableAttrs, targetEvents) {
// long format: 'target: eventName'
var _a = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__read"])(splitAtColon(name, [null, name]), 2), target = _a[0], eventName = _a[1];
var ast = this._parseAction(expression, sourceSpan);
targetMatchableAttrs.push([name, ast.source]);
targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan));
// Don't detect directives for event names for now,
// so don't add the event name to the matchableAttrs
};
BindingParser.prototype._parseAction = function (value, sourceSpan) {
var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
try {
var ast = this._exprParser.parseAction(value, sourceInfo, this._interpolationConfig);
if (ast) {
this._reportExpressionParserErrors(ast.errors, sourceSpan);
}
if (!ast || ast.ast instanceof EmptyExpr) {
this._reportError("Empty expressions are not allowed", sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
this._checkPipes(ast, sourceSpan);
return ast;
}
catch (e) {
this._reportError("" + e, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
};
BindingParser.prototype._reportError = function (message, sourceSpan, level) {
if (level === void 0) { level = ParseErrorLevel.ERROR; }
this.errors.push(new ParseError(sourceSpan, message, level));
};
BindingParser.prototype._reportExpressionParserErrors = function (errors, sourceSpan) {
var e_1, _a;
try {
for (var errors_1 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__values"])(errors), errors_1_1 = errors_1.next(); !errors_1_1.done; errors_1_1 = errors_1.next()) {
var error$$1 = errors_1_1.value;
this._reportError(error$$1.message, sourceSpan);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (errors_1_1 && !errors_1_1.done && (_a = errors_1.return)) _a.call(errors_1);
}
finally { if (e_1) throw e_1.error; }
}
};
// Make sure all the used pipes are known in `this.pipesByName`
BindingParser.prototype._checkPipes = function (ast, sourceSpan) {
var _this = this;
if (ast && this.pipesByName) {
var collector = new PipeCollector();
ast.visit(collector);
collector.pipes.forEach(function (ast, pipeName) {
var pipeMeta = _this.pipesByName.get(pipeName);
if (!pipeMeta) {
_this._reportError("The pipe '" + pipeName + "' could not be found", new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
}
else {
_this._usedPipes.set(pipeName, pipeMeta);
}
});
}
};
/**
* @param propName the name of the property / attribute
* @param sourceSpan
* @param isAttr true when binding to an attribute
*/
BindingParser.prototype._validatePropertyOrAttributeName = function (propName, sourceSpan, isAttr) {
var report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
this._schemaRegistry.validateProperty(propName);
if (report.error) {
this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
}
};
return BindingParser;
}());
var PipeCollector = /** @class */ (function (_super) {
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(PipeCollector, _super);
function PipeCollector() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.pipes = new Map();
return _this;
}
PipeCollector.prototype.visitPipe = function (ast, context) {
this.pipes.set(ast.name, ast);
ast.exp.visit(this);
this.visitAll(ast.args, context);
return null;
};
return PipeCollector;
}(RecursiveAstVisitor$1));
function isAnimationLabel(name) {
return name[0] == '@';
}
function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
var ctxs = [];
CssSelector.parse(selector).forEach(function (selector) {
var elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
var notElementNames = new Set(selector.notSelectors.filter(function (selector) { return selector.isElementSelector(); })
.map(function (selector) { return selector.element; }));
var possibleElementNames = elementNames.filter(function (elementName) { return !notElementNames.has(elementName); });
ctxs.push.apply(ctxs, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(possibleElementNames.map(function (elementName) { return registry.securityContext(elementName, propName, isAttribute); })));
});
return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
}
/**
* @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
*/
var Text$3 = /** @class */ (function () {
function Text(value, sourceSpan) {
this.value = value;
this.sourceSpan = sourceSpan;
}
Text.prototype.visit = function (visitor) { return visitor.visitText(this); };
return Text;
}());
var BoundText = /** @class */ (function () {
function BoundText(value, sourceSpan, i18n) {
this.value = value;
this.sourceSpan = sourceSpan;
this.i18n = i18n;
}
BoundText.prototype.visit = function (visitor) { return visitor.visitBoundText(this); };
return BoundText;
}());
var TextAttribute = /** @class */ (function () {
function TextAttribute(name, value, sourceSpan, valueSpan, i18n) {
this.name = name;
this.value = value;
this.sourceSpan = sourceSpan;
this.valueSpan = valueSpan;
this.i18n = i18n;
}
TextAttribute.prototype.visit = function (visitor) { return visitor.visitTextAttribute(this); };
return TextAttribute;
}());
var BoundAttribute = /** @class */ (function () {
function BoundAttribute(name, type, securityContext, value, unit, sourceSpan, i18n) {
this.name = name;
this.type = type;
this.securityContext = securityContext;
this.value = value;
this.unit = unit;
this.sourceSpan = sourceSpan;
this.i18n = i18n;
}
BoundAttribute.fromBoundElementProperty = function (prop, i18n) {
return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, i18n);
};
BoundAttribute.prototype.visit = function (visitor) { return visitor.visitBoundAttribute(this); };
return BoundAttribute;
}());
var BoundEvent = /** @class */ (function () {
function BoundEvent(name, type, handler, target, phase, sourceSpan) {
this.name = name;
this.type = type;
this.handler = handler;
this.target = target;
this.phase = phase;
this.sourceSpan = sourceSpan;
}
BoundEvent.fromParsedEvent = function (event) {
var target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
var phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan);
};
BoundEvent.prototype.visit = function (visitor) { return visitor.visitBoundEvent(this); };
return BoundEvent;
}());
var Element$1 = /** @class */ (function () {
function Element(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
this.name = name;
this.attributes = attributes;
this.inputs = inputs;
this.outputs = outputs;
this.children = children;
this.references = references;
this.sourceSpan = sourceSpan;
this.startSourceSpan = startSourceSpan;
this.endSourceSpan = endSourceSpan;
this.i18n = i18n;
}
Element.prototype.visit = function (visitor) { return visitor.visitElement(this); };
return Element;
}());
var Template = /** @class */ (function () {
function Template(tagName, attributes, inputs, outputs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
this.tagName = tagName;
this.attributes = attributes;
this.inputs = inputs;
this.outputs = outputs;
this.children = children;
this.references = references;
this.variables = variables;
this.sourceSpan = sourceSpan;
this.startSourceSpan = startSourceSpan;
this.endSourceSpan = endSourceSpan;
this.i18n = i18n;
}
Template.prototype.visit = function (visitor) { return visitor.visitTemplate(this); };
return Template;
}());
var Content = /** @class */ (function () {
function Content(selector, attributes, sourceSpan, i18n) {
this.selector = selector;
this.attributes = attributes;
this.sourceSpan = sourceSpan;
this.i18n = i18n;
}
Content.prototype.visit = function (visitor) { return visitor.visitContent(this); };
return Content;
}());
var Variable = /** @class */ (function () {
function Variable(name, value, sourceSpan) {
this.name = name;
this.value = value;
this.sourceSpan = sourceSpan;
}
Variable.prototype.visit = function (visitor) { return visitor.visitVariable(this); };
return Variable;
}());
var Reference = /** @class */ (function () {
function Reference(name, value, sourceSpan) {
this.name = name;
this.value = value;
this.sourceSpan = sourceSpan;
}
Reference.prototype.visit = function (visitor) { return visitor.visitReference(this); };
return Reference;
}());
var Icu$1 = /** @class */ (function () {
function Icu(vars, placeholders, sourceSpan, i18n) {
this.vars = vars;
this.placeholders = placeholders;
this.sourceSpan = sourceSpan;
this.i18n = i18n;
}
Icu.prototype.visit = function (visitor) { return visitor.visitIcu(this); };
return Icu;
}());
function visitAll$1(visitor, nodes) {
var e_1, _a, e_2, _b;
var result = [];
if (visitor.visit) {
try {
for (var nodes_1 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__values"])(nodes), nodes_1_1 = nodes_1.next(); !nodes_1_1.done; nodes_1_1 = nodes_1.next()) {
var node = nodes_1_1.value;
var newNode = visitor.visit(node) || node.visit(visitor);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (nodes_1_1 && !nodes_1_1.done && (_a = nodes_1.return)) _a.call(nodes_1);
}
finally { if (e_1) throw e_1.error; }
}
}
else {
try {
for (var nodes_2 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__values"])(nodes), nodes_2_1 = nodes_2.next(); !nodes_2_1.done; nodes_2_1 = nodes_2.next()) {
var node = nodes_2_1.value;
var newNode = node.visit(visitor);
if (newNode) {
result.push(newNode);
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (nodes_2_1 && !nodes_2_1.done && (_b = nodes_2.return)) _b.call(nodes_2);
}
finally { if (e_2) throw e_2.error; }
}
}
return result;
}
/**
* @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
*/
var StyleWithImports = /** @class */ (function () {
function StyleWithImports(style, styleUrls) {
this.style = style;
this.styleUrls = styleUrls;
}
return StyleWithImports;
}());
function isStyleUrlResolvable(url) {
if (url == null || url.length === 0 || url[0] == '/')
return false;
var schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
}
/**
* Rewrites stylesheets by resolving and removing the @import urls that
* are either relative or don't have a `package:` scheme
*/
function extractStyleUrls(resolver, baseUrl, cssText) {
var foundUrls = [];
var modifiedCssText = cssText.replace(CSS_STRIPPABLE_COMMENT_REGEXP, '')
.replace(CSS_IMPORT_REGEXP, function () {
var m = [];
for (var _i = 0; _i < arguments.length; _i++) {
m[_i] = arguments[_i];
}
var url = m[1] || m[2];
if (!isStyleUrlResolvable(url)) {
// Do not attempt to resolve non-package absolute URLs with URI
// scheme
return m[0];
}
foundUrls.push(resolver.resolve(baseUrl, url));
return '';
});
return new StyleWithImports(modifiedCssText, foundUrls);
}
var CSS_IMPORT_REGEXP = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g;
var CSS_STRIPPABLE_COMMENT_REGEXP = /\/\*(?!#\s*(?:sourceURL|sourceMappingURL)=)[\s\S]+?\*\//g;
var URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
/**
* @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
*/
var NG_CONTENT_SELECT_ATTR = 'select';
var LINK_ELEMENT = 'link';
var LINK_STYLE_REL_ATTR = 'rel';
var LINK_STYLE_HREF_ATTR = 'href';
var LINK_STYLE_REL_VALUE = 'stylesheet';
var STYLE_ELEMENT = 'style';
var SCRIPT_ELEMENT = 'script';
var NG_NON_BINDABLE_ATTR = 'ngNonBindable';
var NG_PROJECT_AS = 'ngProjectAs';
function preparseElement(ast) {
var selectAttr = null;
var hrefAttr = null;
var relAttr = null;
var nonBindable = false;
var projectAs = '';
ast.attrs.forEach(function (attr) {
var lcAttrName = attr.name.toLowerCase();
if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
selectAttr = attr.value;
}
else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
hrefAttr = attr.value;
}
else if (lcAttrName == LINK_STYLE_REL_ATTR) {
relAttr = attr.value;
}
else if (attr.name == NG_NON_BINDABLE_ATTR) {
nonBindable = true;
}
else if (attr.name == NG_PROJECT_AS) {
if (attr.value.length > 0) {
projectAs = attr.value;
}
}
});
selectAttr = normalizeNgContentSelect(selectAttr);
var nodeName = ast.name.toLowerCase();
var type = PreparsedElementType.OTHER;
if (isNgContent(nodeName)) {
type = PreparsedElementType.NG_CONTENT;
}
else if (nodeName == STYLE_ELEMENT) {
type = PreparsedElementType.STYLE;
}
else if (nodeName == SCRIPT_ELEMENT) {
type = PreparsedElementType.SCRIPT;
}
else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
type = PreparsedElementType.STYLESHEET;
}
return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
}
var PreparsedElementType;
(function (PreparsedElementType) {
PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
})(PreparsedElementType || (PreparsedElementType = {}));
var PreparsedElement = /** @class */ (function () {
function PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs) {
this.type = type;
this.selectAttr = selectAttr;
this.hrefAttr = hrefAttr;
this.nonBindable = nonBindable;
this.projectAs = projectAs;
}
return PreparsedElement;
}());
function normalizeNgContentSelect(selectAttr) {
if (selectAttr === null || selectAttr.length === 0) {
return '*';
}
return selectAttr;
}
/**
* @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
*/
var BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
// Group 1 = "bind-"
var KW_BIND_IDX = 1;
// Group 2 = "let-"
var KW_LET_IDX = 2;
// Group 3 = "ref-/#"
var KW_REF_IDX = 3;
// Group 4 = "on-"
var KW_ON_IDX = 4;
// Group 5 = "bindon-"
var KW_BINDON_IDX = 5;
// Group 6 = "@"
var KW_AT_IDX = 6;
// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
var IDENT_KW_IDX = 7;
// Group 8 = identifier inside [()]
var IDENT_BANANA_BOX_IDX = 8;
// Group 9 = identifier inside []
var IDENT_PROPERTY_IDX = 9;
// Group 10 = identifier inside ()
var IDENT_EVENT_IDX = 10;
var TEMPLATE_ATTR_PREFIX = '*';
function htmlAstToRender3Ast(htmlNodes, bindingParser) {
var transformer = new HtmlAstToIvyAst(bindingParser);
var ivyNodes = visitAll(transformer, htmlNodes);
// Errors might originate in either the binding parser or the html to ivy transformer
var allErrors = bindingParser.errors.concat(transformer.errors);
var errors = allErrors.filter(function (e) { return e.level === ParseErrorLevel.ERROR; });
if (errors.length > 0) {
var errorString = errors.join('\n');
throw syntaxError("Template parse errors:\n" + errorString, errors);
}
return {
nodes: ivyNodes,
errors: allErrors,
};
}
var HtmlAstToIvyAst = /** @class */ (function () {
function HtmlAstToIvyAst(bindingParser) {
this.bindingParser = bindingParser;
this.errors = [];
}
// HTML visitor
HtmlAstToIvyAst.prototype.visitElement = function (element) {
var _this = this;
var e_1, _a;
var preparsedElement = preparseElement(element);
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
preparsedElement.type === PreparsedElementType.STYLE) {
// Skipping