/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define("@angular/compiler/src/template_parser/template_parser", ["require", "exports", "tslib", "@angular/compiler/src/expression_parser/ast", "@angular/compiler/src/identifiers", "@angular/compiler/src/ml_parser/ast", "@angular/compiler/src/ml_parser/html_parser", "@angular/compiler/src/ml_parser/html_whitespaces", "@angular/compiler/src/ml_parser/icu_ast_expander", "@angular/compiler/src/ml_parser/interpolation_config", "@angular/compiler/src/ml_parser/tags", "@angular/compiler/src/parse_util", "@angular/compiler/src/provider_analyzer", "@angular/compiler/src/selector", "@angular/compiler/src/style_url_resolver", "@angular/compiler/src/util", "@angular/compiler/src/template_parser/binding_parser", "@angular/compiler/src/template_parser/template_ast", "@angular/compiler/src/template_parser/template_preparser"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isEmptyExpression = exports.removeSummaryDuplicates = exports.createElementCssSelector = exports.splitClasses = exports.TemplateParser = exports.TemplateParseResult = exports.TemplateParseError = void 0; var tslib_1 = require("tslib"); var ast_1 = require("@angular/compiler/src/expression_parser/ast"); var identifiers_1 = require("@angular/compiler/src/identifiers"); var html = require("@angular/compiler/src/ml_parser/ast"); var html_parser_1 = require("@angular/compiler/src/ml_parser/html_parser"); var html_whitespaces_1 = require("@angular/compiler/src/ml_parser/html_whitespaces"); var icu_ast_expander_1 = require("@angular/compiler/src/ml_parser/icu_ast_expander"); var interpolation_config_1 = require("@angular/compiler/src/ml_parser/interpolation_config"); var tags_1 = require("@angular/compiler/src/ml_parser/tags"); var parse_util_1 = require("@angular/compiler/src/parse_util"); var provider_analyzer_1 = require("@angular/compiler/src/provider_analyzer"); var selector_1 = require("@angular/compiler/src/selector"); var style_url_resolver_1 = require("@angular/compiler/src/style_url_resolver"); var util_1 = require("@angular/compiler/src/util"); var binding_parser_1 = require("@angular/compiler/src/template_parser/binding_parser"); var t = require("@angular/compiler/src/template_parser/template_ast"); var template_preparser_1 = require("@angular/compiler/src/template_parser/template_preparser"); 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 = '*'; var CLASS_ATTR = 'class'; var _TEXT_CSS_SELECTOR; function TEXT_CSS_SELECTOR() { if (!_TEXT_CSS_SELECTOR) { _TEXT_CSS_SELECTOR = selector_1.CssSelector.parse('*')[0]; } return _TEXT_CSS_SELECTOR; } var TemplateParseError = /** @class */ (function (_super) { tslib_1.__extends(TemplateParseError, _super); function TemplateParseError(message, span, level) { return _super.call(this, span, message, level) || this; } return TemplateParseError; }(parse_util_1.ParseError)); exports.TemplateParseError = TemplateParseError; var TemplateParseResult = /** @class */ (function () { function TemplateParseResult(templateAst, usedPipes, errors) { this.templateAst = templateAst; this.usedPipes = usedPipes; this.errors = errors; } return TemplateParseResult; }()); exports.TemplateParseResult = TemplateParseResult; var TemplateParser = /** @class */ (function () { function TemplateParser(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) { this._config = _config; this._reflector = _reflector; this._exprParser = _exprParser; this._schemaRegistry = _schemaRegistry; this._htmlParser = _htmlParser; this._console = _console; this.transforms = transforms; } Object.defineProperty(TemplateParser.prototype, "expressionParser", { get: function () { return this._exprParser; }, enumerable: false, configurable: true }); TemplateParser.prototype.parse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) { var _a; var result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces); var warnings = result.errors.filter(function (error) { return error.level === parse_util_1.ParseErrorLevel.WARNING; }); var errors = result.errors.filter(function (error) { return error.level === parse_util_1.ParseErrorLevel.ERROR; }); if (warnings.length > 0) { (_a = this._console) === null || _a === void 0 ? void 0 : _a.warn("Template parse warnings:\n" + warnings.join('\n')); } if (errors.length > 0) { var errorString = errors.join('\n'); throw parse_util_1.syntaxError("Template parse errors:\n" + errorString, errors); } return { template: result.templateAst, pipes: result.usedPipes }; }; TemplateParser.prototype.tryParse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) { var htmlParseResult = typeof template === 'string' ? this._htmlParser.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig: this.getInterpolationConfig(component) }) : template; if (!preserveWhitespaces) { htmlParseResult = html_whitespaces_1.removeWhitespaces(htmlParseResult); } return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas); }; TemplateParser.prototype.tryParseHtml = function (htmlAstWithErrors, component, directives, pipes, schemas) { var result; var errors = htmlAstWithErrors.errors; var usedPipes = []; if (htmlAstWithErrors.rootNodes.length > 0) { var uniqDirectives = removeSummaryDuplicates(directives); var uniqPipes = removeSummaryDuplicates(pipes); var providerViewContext = new provider_analyzer_1.ProviderViewContext(this._reflector, component); var interpolationConfig = undefined; if (component.template && component.template.interpolation) { interpolationConfig = { start: component.template.interpolation[0], end: component.template.interpolation[1] }; } var bindingParser = new binding_parser_1.BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors); var parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors); result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT); errors.push.apply(errors, tslib_1.__spreadArray([], tslib_1.__read(providerViewContext.errors))); usedPipes.push.apply(usedPipes, tslib_1.__spreadArray([], tslib_1.__read(bindingParser.getUsedPipes()))); } else { result = []; } this._assertNoReferenceDuplicationOnTemplate(result, errors); if (errors.length > 0) { return new TemplateParseResult(result, usedPipes, errors); } if (this.transforms) { this.transforms.forEach(function (transform) { result = t.templateVisitAll(transform, result); }); } return new TemplateParseResult(result, usedPipes, errors); }; TemplateParser.prototype.expandHtml = function (htmlAstWithErrors, forced) { if (forced === void 0) { forced = false; } var errors = htmlAstWithErrors.errors; if (errors.length == 0 || forced) { // Transform ICU messages to angular directives var expandedHtmlAst = icu_ast_expander_1.expandNodes(htmlAstWithErrors.rootNodes); errors.push.apply(errors, tslib_1.__spreadArray([], tslib_1.__read(expandedHtmlAst.errors))); htmlAstWithErrors = new html_parser_1.ParseTreeResult(expandedHtmlAst.nodes, errors); } return htmlAstWithErrors; }; TemplateParser.prototype.getInterpolationConfig = function (component) { if (component.template) { return interpolation_config_1.InterpolationConfig.fromArray(component.template.interpolation); } return undefined; }; /** @internal */ TemplateParser.prototype._assertNoReferenceDuplicationOnTemplate = function (result, errors) { var existingReferences = []; result.filter(function (element) { return !!element.references; }) .forEach(function (element) { return element.references.forEach(function (reference) { var name = reference.name; if (existingReferences.indexOf(name) < 0) { existingReferences.push(name); } else { var error = new TemplateParseError("Reference \"#" + name + "\" is defined several times", reference.sourceSpan, parse_util_1.ParseErrorLevel.ERROR); errors.push(error); } }); }); }; return TemplateParser; }()); exports.TemplateParser = TemplateParser; var TemplateParseVisitor = /** @class */ (function () { function TemplateParseVisitor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) { var _this = this; this.reflector = reflector; this.config = config; this.providerViewContext = providerViewContext; this._bindingParser = _bindingParser; this._schemaRegistry = _schemaRegistry; this._schemas = _schemas; this._targetErrors = _targetErrors; this.selectorMatcher = new selector_1.SelectorMatcher(); this.directivesIndex = new Map(); this.ngContentCount = 0; // Note: queries start with id 1 so we can use the number in a Bloom filter! this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1; directives.forEach(function (directive, index) { var selector = selector_1.CssSelector.parse(directive.selector); _this.selectorMatcher.addSelectables(selector, directive); _this.directivesIndex.set(directive, index); }); } TemplateParseVisitor.prototype.visitExpansion = function (expansion, context) { return null; }; TemplateParseVisitor.prototype.visitExpansionCase = function (expansionCase, context) { return null; }; TemplateParseVisitor.prototype.visitText = function (text, parent) { var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()); var valueNoNgsp = html_whitespaces_1.replaceNgsp(text.value); var expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan); return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan) : new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan); }; TemplateParseVisitor.prototype.visitAttribute = function (attribute, context) { return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan); }; TemplateParseVisitor.prototype.visitComment = function (comment, context) { return null; }; TemplateParseVisitor.prototype.visitElement = function (element, parent) { var _this = this; var queryStartIndex = this.contentQueryStartId; var elName = element.name; var preparsedElement = template_preparser_1.preparseElement(element); if (preparsedElement.type === template_preparser_1.PreparsedElementType.SCRIPT || preparsedElement.type === template_preparser_1.PreparsedElementType.STYLE) { // Skipping