UNPKG

@angular/compiler

Version:

Angular - the compiler library

849 lines 164 kB
/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ (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/render3/view/template", ["require", "exports", "tslib", "@angular/compiler/src/compile_metadata", "@angular/compiler/src/compiler_util/expression_converter", "@angular/compiler/src/core", "@angular/compiler/src/expression_parser/ast", "@angular/compiler/src/expression_parser/lexer", "@angular/compiler/src/expression_parser/parser", "@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/interpolation_config", "@angular/compiler/src/ml_parser/tags", "@angular/compiler/src/output/output_ast", "@angular/compiler/src/schema/dom_element_schema_registry", "@angular/compiler/src/selector", "@angular/compiler/src/template_parser/binding_parser", "@angular/compiler/src/util", "@angular/compiler/src/render3/r3_ast", "@angular/compiler/src/render3/r3_identifiers", "@angular/compiler/src/render3/r3_template_transform", "@angular/compiler/src/render3/view/styling", "@angular/compiler/src/render3/view/util"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var compile_metadata_1 = require("@angular/compiler/src/compile_metadata"); var expression_converter_1 = require("@angular/compiler/src/compiler_util/expression_converter"); var core = require("@angular/compiler/src/core"); var ast_1 = require("@angular/compiler/src/expression_parser/ast"); var lexer_1 = require("@angular/compiler/src/expression_parser/lexer"); var parser_1 = require("@angular/compiler/src/expression_parser/parser"); 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 interpolation_config_1 = require("@angular/compiler/src/ml_parser/interpolation_config"); var tags_1 = require("@angular/compiler/src/ml_parser/tags"); var o = require("@angular/compiler/src/output/output_ast"); var dom_element_schema_registry_1 = require("@angular/compiler/src/schema/dom_element_schema_registry"); var selector_1 = require("@angular/compiler/src/selector"); var binding_parser_1 = require("@angular/compiler/src/template_parser/binding_parser"); var util_1 = require("@angular/compiler/src/util"); var t = require("@angular/compiler/src/render3/r3_ast"); var r3_identifiers_1 = require("@angular/compiler/src/render3/r3_identifiers"); var r3_template_transform_1 = require("@angular/compiler/src/render3/r3_template_transform"); var styling_1 = require("@angular/compiler/src/render3/view/styling"); var util_2 = require("@angular/compiler/src/render3/view/util"); function mapBindingToInstruction(type) { switch (type) { case 0 /* Property */: return r3_identifiers_1.Identifiers.elementProperty; case 1 /* Attribute */: return r3_identifiers_1.Identifiers.elementAttribute; case 2 /* Class */: return r3_identifiers_1.Identifiers.elementClassProp; default: return undefined; } } // if (rf & flags) { .. } function renderFlagCheckIfStmt(flags, statements) { return o.ifStmt(o.variable(util_2.RENDER_FLAGS).bitwiseAnd(o.literal(flags), null, false), statements); } exports.renderFlagCheckIfStmt = renderFlagCheckIfStmt; var TemplateDefinitionBuilder = /** @class */ (function () { function TemplateDefinitionBuilder(constantPool, contextParameter, parentBindingScope, level, contextName, templateName, viewQueries, directiveMatcher, directives, pipeTypeByName, pipes, _namespace) { if (level === void 0) { level = 0; } var _this = this; this.constantPool = constantPool; this.contextParameter = contextParameter; this.level = level; this.contextName = contextName; this.templateName = templateName; this.viewQueries = viewQueries; this.directiveMatcher = directiveMatcher; this.directives = directives; this.pipeTypeByName = pipeTypeByName; this.pipes = pipes; this._namespace = _namespace; this._dataIndex = 0; this._bindingContext = 0; this._prefixCode = []; this._creationCode = []; this._variableCode = []; this._bindingCode = []; this._postfixCode = []; this._unsupported = util_2.unsupported; // Whether we are inside a translatable element (`<p i18n>... somewhere here ... </p>) this._inI18nSection = false; this._i18nSectionIndex = -1; // Maps of placeholder to node indexes for each of the i18n section this._phToNodeIdxes = [{}]; // Number of slots to reserve for pureFunctions this._pureFunctionSlots = 0; // These should be handled in the template or element directly. this.visitReference = util_2.invalid; this.visitVariable = util_2.invalid; this.visitTextAttribute = util_2.invalid; this.visitBoundAttribute = util_2.invalid; this.visitBoundEvent = util_2.invalid; // view queries can take up space in data and allocation happens earlier (in the "viewQuery" // function) this._dataIndex = viewQueries.length; this._bindingScope = parentBindingScope.nestedScope(function (lhsVar, expression) { _this._bindingCode.push(lhsVar.set(expression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); }); this._valueConverter = new ValueConverter(constantPool, function () { return _this.allocateDataSlot(); }, function (numSlots) { return _this._pureFunctionSlots += numSlots; }, function (name, localName, slot, value) { var pipeType = pipeTypeByName.get(name); if (pipeType) { _this.pipes.add(pipeType); } _this._bindingScope.set(localName, value); _this._creationCode.push(o.importExpr(r3_identifiers_1.Identifiers.pipe).callFn([o.literal(slot), o.literal(name)]).toStmt()); }); } TemplateDefinitionBuilder.prototype.buildTemplateFunction = function (nodes, variables, hasNgContent, ngContentSelectors) { if (hasNgContent === void 0) { hasNgContent = false; } if (ngContentSelectors === void 0) { ngContentSelectors = []; } var e_1, _a, e_2, _b; if (this._namespace !== r3_identifiers_1.Identifiers.namespaceHTML) { this.instruction(this._creationCode, null, this._namespace); } try { // Create variable bindings for (var variables_1 = tslib_1.__values(variables), variables_1_1 = variables_1.next(); !variables_1_1.done; variables_1_1 = variables_1.next()) { var variable = variables_1_1.value; var variableName = variable.name; var expression = o.variable(this.contextParameter).prop(variable.value || util_2.IMPLICIT_REFERENCE); var scopedName = this._bindingScope.freshReferenceName(); // Add the reference to the local scope. this._bindingScope.set(variableName, o.variable(variableName + scopedName), expression); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (variables_1_1 && !variables_1_1.done && (_a = variables_1.return)) _a.call(variables_1); } finally { if (e_1) throw e_1.error; } } // Output a `ProjectionDef` instruction when some `<ng-content>` are present if (hasNgContent) { var parameters = []; // Only selectors with a non-default value are generated if (ngContentSelectors.length > 1) { var r3Selectors = ngContentSelectors.map(function (s) { return core.parseSelectorToR3Selector(s); }); // `projectionDef` needs both the parsed and raw value of the selectors var parsed = this.constantPool.getConstLiteral(util_2.asLiteral(r3Selectors), true); var unParsed = this.constantPool.getConstLiteral(util_2.asLiteral(ngContentSelectors), true); parameters.push(parsed, unParsed); } this.instruction.apply(this, tslib_1.__spread([this._creationCode, null, r3_identifiers_1.Identifiers.projectionDef], parameters)); } t.visitAll(this, nodes); if (this._pureFunctionSlots > 0) { this.instruction(this._creationCode, null, r3_identifiers_1.Identifiers.reserveSlots, o.literal(this._pureFunctionSlots)); } var creationCode = this._creationCode.length > 0 ? [renderFlagCheckIfStmt(1 /* Create */, this._creationCode)] : []; var updateCode = this._bindingCode.length > 0 ? [renderFlagCheckIfStmt(2 /* Update */, this._bindingCode)] : []; try { // Generate maps of placeholder name to node indexes // TODO(vicb): This is a WIP, not fully supported yet for (var _c = tslib_1.__values(this._phToNodeIdxes), _d = _c.next(); !_d.done; _d = _c.next()) { var phToNodeIdx = _d.value; if (Object.keys(phToNodeIdx).length > 0) { var scopedName = this._bindingScope.freshReferenceName(); var phMap = o.variable(scopedName) .set(util_2.mapToExpression(phToNodeIdx, true)) .toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]); this._prefixCode.push(phMap); } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_d && !_d.done && (_b = _c.return)) _b.call(_c); } finally { if (e_2) throw e_2.error; } } return o.fn([new o.FnParam(util_2.RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(this.contextParameter, null)], tslib_1.__spread(this._prefixCode, creationCode, this._variableCode, updateCode, this._postfixCode), o.INFERRED_TYPE, null, this.templateName); }; // LocalResolver TemplateDefinitionBuilder.prototype.getLocal = function (name) { return this._bindingScope.get(name); }; TemplateDefinitionBuilder.prototype.visitContent = function (ngContent) { var slot = this.allocateDataSlot(); var selectorIndex = ngContent.selectorIndex; var parameters = [o.literal(slot)]; var attributeAsList = []; ngContent.attributes.forEach(function (attribute) { var name = attribute.name; if (name !== 'select') { attributeAsList.push(name, attribute.value); } }); if (attributeAsList.length > 0) { parameters.push(o.literal(selectorIndex), util_2.asLiteral(attributeAsList)); } else if (selectorIndex !== 0) { parameters.push(o.literal(selectorIndex)); } this.instruction.apply(this, tslib_1.__spread([this._creationCode, ngContent.sourceSpan, r3_identifiers_1.Identifiers.projection], parameters)); }; TemplateDefinitionBuilder.prototype.getNamespaceInstruction = function (namespaceKey) { switch (namespaceKey) { case 'math': return r3_identifiers_1.Identifiers.namespaceMathML; case 'svg': return r3_identifiers_1.Identifiers.namespaceSVG; default: return r3_identifiers_1.Identifiers.namespaceHTML; } }; TemplateDefinitionBuilder.prototype.addNamespaceInstruction = function (nsInstruction, element) { this._namespace = nsInstruction; this.instruction(this._creationCode, element.sourceSpan, nsInstruction); }; TemplateDefinitionBuilder.prototype.visitElement = function (element) { var _this = this; var e_3, _a, _b, _c; var elementIndex = this.allocateDataSlot(); var referenceDataSlots = new Map(); var wasInI18nSection = this._inI18nSection; var outputAttrs = {}; var attrI18nMetas = {}; var i18nMeta = ''; var _d = tslib_1.__read(tags_1.splitNsName(element.name), 2), namespaceKey = _d[0], elementName = _d[1]; // Elements inside i18n sections are replaced with placeholders // TODO(vicb): nested elements are a WIP in this phase if (this._inI18nSection) { var phName = element.name.toLowerCase(); if (!this._phToNodeIdxes[this._i18nSectionIndex][phName]) { this._phToNodeIdxes[this._i18nSectionIndex][phName] = []; } this._phToNodeIdxes[this._i18nSectionIndex][phName].push(elementIndex); } try { // Handle i18n attributes for (var _e = tslib_1.__values(element.attributes), _f = _e.next(); !_f.done; _f = _e.next()) { var attr = _f.value; var name_1 = attr.name; var value = attr.value; if (name_1 === util_2.I18N_ATTR) { if (this._inI18nSection) { throw new Error("Could not mark an element as translatable inside of a translatable section"); } this._inI18nSection = true; this._i18nSectionIndex++; this._phToNodeIdxes[this._i18nSectionIndex] = {}; i18nMeta = value; } else if (name_1.startsWith(util_2.I18N_ATTR_PREFIX)) { attrI18nMetas[name_1.slice(util_2.I18N_ATTR_PREFIX.length)] = value; } else { outputAttrs[name_1] = value; } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_f && !_f.done && (_a = _e.return)) _a.call(_e); } finally { if (e_3) throw e_3.error; } } // Match directives on non i18n attributes if (this.directiveMatcher) { var selector = createCssSelector(element.name, outputAttrs); this.directiveMatcher.match(selector, function (sel, staticType) { _this.directives.add(staticType); }); } // Element creation mode var parameters = [ o.literal(elementIndex), o.literal(elementName), ]; // Add the attributes var i18nMessages = []; var attributes = []; var initialStyleDeclarations = []; var initialClassDeclarations = []; var styleInputs = []; var classInputs = []; var allOtherInputs = []; element.inputs.forEach(function (input) { switch (input.type) { // [attr.style] or [attr.class] should not be treated as styling-based // bindings since they are intended to be written directly to the attr // and therefore will skip all style/class resolution that is present // with style="", [style]="" and [style.prop]="", class="", // [class.prop]="". [class]="" assignments case 0 /* Property */: if (input.name == 'style') { // this should always go first in the compilation (for [style]) styleInputs.splice(0, 0, input); } else if (isClassBinding(input)) { // this should always go first in the compilation (for [class]) classInputs.splice(0, 0, input); } else { allOtherInputs.push(input); } break; case 3 /* Style */: styleInputs.push(input); break; case 2 /* Class */: classInputs.push(input); break; default: allOtherInputs.push(input); break; } }); var currStyleIndex = 0; var currClassIndex = 0; var staticStylesMap = null; var staticClassesMap = null; var stylesIndexMap = {}; var classesIndexMap = {}; Object.getOwnPropertyNames(outputAttrs).forEach(function (name) { var value = outputAttrs[name]; if (name == 'style') { staticStylesMap = styling_1.parseStyle(value); Object.keys(staticStylesMap).forEach(function (prop) { stylesIndexMap[prop] = currStyleIndex++; }); } else if (name == 'class') { staticClassesMap = {}; value.split(/\s+/g).forEach(function (className) { classesIndexMap[className] = currClassIndex++; staticClassesMap[className] = true; }); } else { attributes.push(o.literal(name)); if (attrI18nMetas.hasOwnProperty(name)) { var meta = parseI18nMeta(attrI18nMetas[name]); var variable = _this.constantPool.getTranslation(value, meta); attributes.push(variable); } else { attributes.push(o.literal(value)); } } }); var hasMapBasedStyling = false; for (var i = 0; i < styleInputs.length; i++) { var input = styleInputs[i]; var isMapBasedStyleBinding = i === 0 && input.name === 'style'; if (isMapBasedStyleBinding) { hasMapBasedStyling = true; } else if (!stylesIndexMap.hasOwnProperty(input.name)) { stylesIndexMap[input.name] = currStyleIndex++; } } for (var i = 0; i < classInputs.length; i++) { var input = classInputs[i]; var isMapBasedClassBinding = i === 0 && isClassBinding(input); if (!isMapBasedClassBinding && !stylesIndexMap.hasOwnProperty(input.name)) { classesIndexMap[input.name] = currClassIndex++; } } // in the event that a [style] binding is used then sanitization will // always be imported because it is not possible to know ahead of time // whether style bindings will use or not use any sanitizable properties // that isStyleSanitizable() will detect var useDefaultStyleSanitizer = hasMapBasedStyling; // this will build the instructions so that they fall into the following syntax // => [prop1, prop2, prop3, 0, prop1, value1, prop2, value2] Object.keys(stylesIndexMap).forEach(function (prop) { useDefaultStyleSanitizer = useDefaultStyleSanitizer || isStyleSanitizable(prop); initialStyleDeclarations.push(o.literal(prop)); }); if (staticStylesMap) { initialStyleDeclarations.push(o.literal(1 /* VALUES_MODE */)); Object.keys(staticStylesMap).forEach(function (prop) { initialStyleDeclarations.push(o.literal(prop)); var value = staticStylesMap[prop]; initialStyleDeclarations.push(o.literal(value)); }); } Object.keys(classesIndexMap).forEach(function (prop) { initialClassDeclarations.push(o.literal(prop)); }); if (staticClassesMap) { initialClassDeclarations.push(o.literal(1 /* VALUES_MODE */)); Object.keys(staticClassesMap).forEach(function (className) { initialClassDeclarations.push(o.literal(className)); initialClassDeclarations.push(o.literal(true)); }); } var hasStylingInstructions = initialStyleDeclarations.length || styleInputs.length || initialClassDeclarations.length || classInputs.length; var attrArg = attributes.length > 0 ? this.constantPool.getConstLiteral(o.literalArr(attributes), true) : o.TYPED_NULL_EXPR; parameters.push(attrArg); if (element.references && element.references.length > 0) { var references = compile_metadata_1.flatten(element.references.map(function (reference) { var slot = _this.allocateDataSlot(); referenceDataSlots.set(reference.name, slot); // Generate the update temporary. var variableName = _this._bindingScope.freshReferenceName(); _this._variableCode.push(o.variable(variableName, o.INFERRED_TYPE) .set(o.importExpr(r3_identifiers_1.Identifiers.load).callFn([o.literal(slot)])) .toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); _this._bindingScope.set(reference.name, o.variable(variableName)); return [reference.name, reference.value]; })); parameters.push(this.constantPool.getConstLiteral(util_2.asLiteral(references), true)); } else { parameters.push(o.TYPED_NULL_EXPR); } // Generate the instruction create element instruction if (i18nMessages.length > 0) { (_b = this._creationCode).push.apply(_b, tslib_1.__spread(i18nMessages)); } var wasInNamespace = this._namespace; var currentNamespace = this.getNamespaceInstruction(namespaceKey); // If the namespace is changing now, include an instruction to change it // during element creation. if (currentNamespace !== wasInNamespace) { this.addNamespaceInstruction(currentNamespace, element); } var implicit = o.variable(util_2.CONTEXT_NAME); var createSelfClosingInstruction = !hasStylingInstructions && element.children.length === 0 && element.outputs.length === 0; if (createSelfClosingInstruction) { this.instruction.apply(this, tslib_1.__spread([this._creationCode, element.sourceSpan, r3_identifiers_1.Identifiers.element], util_2.trimTrailingNulls(parameters))); } else { // Generate the instruction create element instruction if (i18nMessages.length > 0) { (_c = this._creationCode).push.apply(_c, tslib_1.__spread(i18nMessages)); } this.instruction.apply(this, tslib_1.__spread([this._creationCode, element.sourceSpan, r3_identifiers_1.Identifiers.elementStart], util_2.trimTrailingNulls(parameters))); // initial styling for static style="..." attributes if (hasStylingInstructions) { var paramsList = []; if (initialClassDeclarations.length) { // the template compiler handles initial class styling (e.g. class="foo") values // in a special command called `elementClass` so that the initial class // can be processed during runtime. These initial class values are bound to // a constant because the inital class values do not change (since they're static). paramsList.push(this.constantPool.getConstLiteral(o.literalArr(initialClassDeclarations), true)); } else if (initialStyleDeclarations.length || useDefaultStyleSanitizer) { // no point in having an extra `null` value unless there are follow-up params paramsList.push(o.NULL_EXPR); } if (initialStyleDeclarations.length) { // the template compiler handles initial style (e.g. style="foo") values // in a special command called `elementStyle` so that the initial styles // can be processed during runtime. These initial styles values are bound to // a constant because the inital style values do not change (since they're static). paramsList.push(this.constantPool.getConstLiteral(o.literalArr(initialStyleDeclarations), true)); } else if (useDefaultStyleSanitizer) { // no point in having an extra `null` value unless there are follow-up params paramsList.push(o.NULL_EXPR); } if (useDefaultStyleSanitizer) { paramsList.push(o.importExpr(r3_identifiers_1.Identifiers.defaultStyleSanitizer)); } this._creationCode.push(o.importExpr(r3_identifiers_1.Identifiers.elementStyling).callFn(paramsList).toStmt()); } // Generate Listeners (outputs) element.outputs.forEach(function (outputAst) { var elName = compile_metadata_1.sanitizeIdentifier(element.name); var evName = compile_metadata_1.sanitizeIdentifier(outputAst.name); var functionName = _this.templateName + "_" + elName + "_" + evName + "_listener"; var localVars = []; var bindingScope = _this._bindingScope.nestedScope(function (lhsVar, rhsExpression) { localVars.push(lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); }); var bindingExpr = expression_converter_1.convertActionBinding(bindingScope, implicit, outputAst.handler, 'b', function () { return util_1.error('Unexpected interpolation'); }); var handler = o.fn([new o.FnParam('$event', o.DYNAMIC_TYPE)], tslib_1.__spread(localVars, bindingExpr.render3Stmts), o.INFERRED_TYPE, null, functionName); _this.instruction(_this._creationCode, outputAst.sourceSpan, r3_identifiers_1.Identifiers.listener, o.literal(outputAst.name), handler); }); } if ((styleInputs.length || classInputs.length) && hasStylingInstructions) { var indexLiteral = o.literal(elementIndex); var firstStyle = styleInputs[0]; var mapBasedStyleInput = firstStyle && firstStyle.name == 'style' ? firstStyle : null; var firstClass = classInputs[0]; var mapBasedClassInput = firstClass && isClassBinding(firstClass) ? firstClass : null; var stylingInput = mapBasedStyleInput || mapBasedClassInput; if (stylingInput) { var params = []; if (mapBasedClassInput) { params.push(this.convertPropertyBinding(implicit, mapBasedClassInput.value, true)); } else if (mapBasedStyleInput) { params.push(o.NULL_EXPR); } if (mapBasedStyleInput) { params.push(this.convertPropertyBinding(implicit, mapBasedStyleInput.value, true)); } this.instruction.apply(this, tslib_1.__spread([this._bindingCode, stylingInput.sourceSpan, r3_identifiers_1.Identifiers.elementStylingMap, indexLiteral], params)); } var lastInputCommand = null; if (styleInputs.length) { var i = mapBasedStyleInput ? 1 : 0; for (i; i < styleInputs.length; i++) { var input = styleInputs[i]; var convertedBinding = this.convertPropertyBinding(implicit, input.value, true); var params = [convertedBinding]; var sanitizationRef = resolveSanitizationFn(input, input.securityContext); if (sanitizationRef) { params.push(sanitizationRef); } var key = input.name; var styleIndex = stylesIndexMap[key]; this.instruction.apply(this, tslib_1.__spread([this._bindingCode, input.sourceSpan, r3_identifiers_1.Identifiers.elementStyleProp, indexLiteral, o.literal(styleIndex)], params)); } lastInputCommand = styleInputs[styleInputs.length - 1]; } if (classInputs.length) { var i = mapBasedClassInput ? 1 : 0; for (i; i < classInputs.length; i++) { var input = classInputs[i]; var convertedBinding = this.convertPropertyBinding(implicit, input.value, true); var params = [convertedBinding]; var sanitizationRef = resolveSanitizationFn(input, input.securityContext); if (sanitizationRef) { params.push(sanitizationRef); } var key = input.name; var classIndex = classesIndexMap[key]; this.instruction.apply(this, tslib_1.__spread([this._bindingCode, input.sourceSpan, r3_identifiers_1.Identifiers.elementClassProp, indexLiteral, o.literal(classIndex)], params)); } lastInputCommand = classInputs[classInputs.length - 1]; } this.instruction(this._bindingCode, lastInputCommand.sourceSpan, r3_identifiers_1.Identifiers.elementStylingApply, indexLiteral); } // Generate element input bindings allOtherInputs.forEach(function (input) { if (input.type === 4 /* Animation */) { console.error('warning: animation bindings not yet supported'); return; } var convertedBinding = _this.convertPropertyBinding(implicit, input.value); var instruction = mapBindingToInstruction(input.type); if (instruction) { var params = [convertedBinding]; var sanitizationRef = resolveSanitizationFn(input, input.securityContext); if (sanitizationRef) { params.push(sanitizationRef); } // TODO(chuckj): runtime: security context? _this.instruction.apply(_this, tslib_1.__spread([_this._bindingCode, input.sourceSpan, instruction, o.literal(elementIndex), o.literal(input.name)], params)); } else { _this._unsupported("binding type " + input.type); } }); // Traverse element child nodes if (this._inI18nSection && element.children.length == 1 && element.children[0] instanceof t.Text) { var text = element.children[0]; this.visitSingleI18nTextChild(text, i18nMeta); } else { t.visitAll(this, element.children); } if (!createSelfClosingInstruction) { // Finish element construction mode. this.instruction(this._creationCode, element.endSourceSpan || element.sourceSpan, r3_identifiers_1.Identifiers.elementEnd); } // Restore the state before exiting this node this._inI18nSection = wasInI18nSection; }; TemplateDefinitionBuilder.prototype.visitTemplate = function (template) { var _this = this; var templateIndex = this.allocateDataSlot(); var elName = ''; if (template.children.length === 1 && template.children[0] instanceof t.Element) { // When the template as a single child, derive the context name from the tag elName = compile_metadata_1.sanitizeIdentifier(template.children[0].name); } var contextName = elName ? this.contextName + "_" + elName : ''; var templateName = contextName ? contextName + "_Template_" + templateIndex : "Template_" + templateIndex; var templateContext = "ctx" + this.level; var parameters = [ o.literal(templateIndex), o.variable(templateName), o.TYPED_NULL_EXPR, ]; var attributeNames = []; var attributeMap = {}; template.attributes.forEach(function (a) { attributeNames.push(util_2.asLiteral(a.name), util_2.asLiteral('')); attributeMap[a.name] = a.value; }); // Match directives on template attributes if (this.directiveMatcher) { var selector = createCssSelector('ng-template', attributeMap); this.directiveMatcher.match(selector, function (cssSelector, staticType) { _this.directives.add(staticType); }); } if (attributeNames.length) { parameters.push(this.constantPool.getConstLiteral(o.literalArr(attributeNames), true)); } // e.g. C(1, C1Template) this.instruction.apply(this, tslib_1.__spread([this._creationCode, template.sourceSpan, r3_identifiers_1.Identifiers.containerCreate], util_2.trimTrailingNulls(parameters))); // e.g. p(1, 'forOf', ɵb(ctx.items)); var context = o.variable(util_2.CONTEXT_NAME); template.inputs.forEach(function (input) { var convertedBinding = _this.convertPropertyBinding(context, input.value); _this.instruction(_this._bindingCode, template.sourceSpan, r3_identifiers_1.Identifiers.elementProperty, o.literal(templateIndex), o.literal(input.name), convertedBinding); }); // Create the template function var templateVisitor = new TemplateDefinitionBuilder(this.constantPool, templateContext, this._bindingScope, this.level + 1, contextName, templateName, [], this.directiveMatcher, this.directives, this.pipeTypeByName, this.pipes, this._namespace); var templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables); this._postfixCode.push(templateFunctionExpr.toDeclStmt(templateName, null)); }; TemplateDefinitionBuilder.prototype.visitBoundText = function (text) { var nodeIndex = this.allocateDataSlot(); this.instruction(this._creationCode, text.sourceSpan, r3_identifiers_1.Identifiers.text, o.literal(nodeIndex)); this.instruction(this._bindingCode, text.sourceSpan, r3_identifiers_1.Identifiers.textBinding, o.literal(nodeIndex), this.convertPropertyBinding(o.variable(util_2.CONTEXT_NAME), text.value)); }; TemplateDefinitionBuilder.prototype.visitText = function (text) { this.instruction(this._creationCode, text.sourceSpan, r3_identifiers_1.Identifiers.text, o.literal(this.allocateDataSlot()), o.literal(text.value)); }; // When the content of the element is a single text node the translation can be inlined: // // `<p i18n="desc|mean">some content</p>` // compiles to // ``` // /** // * @desc desc // * @meaning mean // */ // const MSG_XYZ = goog.getMsg('some content'); // i0.ɵT(1, MSG_XYZ); // ``` TemplateDefinitionBuilder.prototype.visitSingleI18nTextChild = function (text, i18nMeta) { var meta = parseI18nMeta(i18nMeta); var variable = this.constantPool.getTranslation(text.value, meta); this.instruction(this._creationCode, text.sourceSpan, r3_identifiers_1.Identifiers.text, o.literal(this.allocateDataSlot()), variable); }; TemplateDefinitionBuilder.prototype.allocateDataSlot = function () { return this._dataIndex++; }; TemplateDefinitionBuilder.prototype.bindingContext = function () { return "" + this._bindingContext++; }; TemplateDefinitionBuilder.prototype.instruction = function (statements, span, reference) { var params = []; for (var _i = 3; _i < arguments.length; _i++) { params[_i - 3] = arguments[_i]; } statements.push(o.importExpr(reference, null, span).callFn(params, span).toStmt()); }; TemplateDefinitionBuilder.prototype.convertPropertyBinding = function (implicit, value, skipBindFn) { var _a, _b; var pipesConvertedValue = value.visit(this._valueConverter); if (pipesConvertedValue instanceof ast_1.Interpolation) { var convertedPropertyBinding = expression_converter_1.convertPropertyBinding(this, implicit, pipesConvertedValue, this.bindingContext(), expression_converter_1.BindingForm.TrySimple, interpolate); (_a = this._bindingCode).push.apply(_a, tslib_1.__spread(convertedPropertyBinding.stmts)); return convertedPropertyBinding.currValExpr; } else { var convertedPropertyBinding = expression_converter_1.convertPropertyBinding(this, implicit, pipesConvertedValue, this.bindingContext(), expression_converter_1.BindingForm.TrySimple, function () { return util_1.error('Unexpected interpolation'); }); (_b = this._bindingCode).push.apply(_b, tslib_1.__spread(convertedPropertyBinding.stmts)); var valExpr = convertedPropertyBinding.currValExpr; return skipBindFn ? valExpr : o.importExpr(r3_identifiers_1.Identifiers.bind).callFn([valExpr]); } }; return TemplateDefinitionBuilder; }()); exports.TemplateDefinitionBuilder = TemplateDefinitionBuilder; var ValueConverter = /** @class */ (function (_super) { tslib_1.__extends(ValueConverter, _super); function ValueConverter(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) { var _this = _super.call(this) || this; _this.constantPool = constantPool; _this.allocateSlot = allocateSlot; _this.allocatePureFunctionSlots = allocatePureFunctionSlots; _this.definePipe = definePipe; return _this; } // AstMemoryEfficientTransformer ValueConverter.prototype.visitPipe = function (pipe, context) { // Allocate a slot to create the pipe var slot = this.allocateSlot(); var slotPseudoLocal = "PIPE:" + slot; // Allocate one slot for the result plus one slot per pipe argument var pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length); var target = new ast_1.PropertyRead(pipe.span, new ast_1.ImplicitReceiver(pipe.span), slotPseudoLocal); var _a = pipeBindingCallInfo(pipe.args), identifier = _a.identifier, isVarLength = _a.isVarLength; this.definePipe(pipe.name, slotPseudoLocal, slot, o.importExpr(identifier)); var args = tslib_1.__spread([pipe.exp], pipe.args); var convertedArgs = isVarLength ? this.visitAll([new ast_1.LiteralArray(pipe.span, args)]) : this.visitAll(args); return new ast_1.FunctionCall(pipe.span, target, tslib_1.__spread([ new ast_1.LiteralPrimitive(pipe.span, slot), new ast_1.LiteralPrimitive(pipe.span, pureFunctionSlot) ], convertedArgs)); }; ValueConverter.prototype.visitLiteralArray = function (array, context) { var _this = this; return new expression_converter_1.BuiltinFunctionCall(array.span, this.visitAll(array.expressions), function (values) { // If the literal has calculated (non-literal) elements transform it into // calls to literal factories that compose the literal and will cache intermediate // values. Otherwise, just return an literal array that contains the values. var literal = o.literalArr(values); return values.every(function (a) { return a.isConstant(); }) ? _this.constantPool.getConstLiteral(literal, true) : getLiteralFactory(_this.constantPool, literal, _this.allocatePureFunctionSlots); }); }; ValueConverter.prototype.visitLiteralMap = function (map, context) { var _this = this; return new expression_converter_1.BuiltinFunctionCall(map.span, this.visitAll(map.values), function (values) { // If the literal has calculated (non-literal) elements transform it into // calls to literal factories that compose the literal and will cache intermediate // values. Otherwise, just return an literal array that contains the values. var literal = o.literalMap(values.map(function (value, index) { return ({ key: map.keys[index].key, value: value, quoted: map.keys[index].quoted }); })); return values.every(function (a) { return a.isConstant(); }) ? _this.constantPool.getConstLiteral(literal, true) : getLiteralFactory(_this.constantPool, literal, _this.allocatePureFunctionSlots); }); }; return ValueConverter; }(ast_1.AstMemoryEfficientTransformer)); // Pipes always have at least one parameter, the value they operate on var pipeBindingIdentifiers = [r3_identifiers_1.Identifiers.pipeBind1, r3_identifiers_1.Identifiers.pipeBind2, r3_identifiers_1.Identifiers.pipeBind3, r3_identifiers_1.Identifiers.pipeBind4]; function pipeBindingCallInfo(args) { var identifier = pipeBindingIdentifiers[args.length]; return { identifier: identifier || r3_identifiers_1.Identifiers.pipeBindV, isVarLength: !identifier, }; } var pureFunctionIdentifiers = [ r3_identifiers_1.Identifiers.pureFunction0, r3_identifiers_1.Identifiers.pureFunction1, r3_identifiers_1.Identifiers.pureFunction2, r3_identifiers_1.Identifiers.pureFunction3, r3_identifiers_1.Identifiers.pureFunction4, r3_identifiers_1.Identifiers.pureFunction5, r3_identifiers_1.Identifiers.pureFunction6, r3_identifiers_1.Identifiers.pureFunction7, r3_identifiers_1.Identifiers.pureFunction8 ]; function pureFunctionCallInfo(args) { var identifier = pureFunctionIdentifiers[args.length]; return { identifier: identifier || r3_identifiers_1.Identifiers.pureFunctionV, isVarLength: !identifier, }; } function getLiteralFactory(constantPool, literal, allocateSlots) { var _a = constantPool.getLiteralFactory(literal), literalFactory = _a.literalFactory, literalFactoryArguments = _a.literalFactoryArguments; // Allocate 1 slot for the result plus 1 per argument var startSlot = allocateSlots(1 + literalFactoryArguments.length); literalFactoryArguments.length > 0 || util_1.error("Expected arguments to a literal factory function"); var _b = pureFunctionCallInfo(literalFactoryArguments), identifier = _b.identifier, isVarLength = _b.isVarLength; // Literal factories are pure functions that only need to be re-invoked when the parameters // change. var args = [ o.literal(startSlot), literalFactory, ]; if (isVarLength) { args.push(o.literalArr(literalFactoryArguments)); } else { args.push.apply(args, tslib_1.__spread(literalFactoryArguments)); } return o.importExpr(identifier).callFn(args); } var BindingScope = /** @class */ (function () { function BindingScope(parent, declareLocalVarCallback) { if (parent === void 0) { parent = null; } if (declareLocalVarCallback === void 0) { declareLocalVarCallback = util_2.noop; } this.parent = parent; this.declareLocalVarCallback = declareLocalVarCallback; /** * Keeps a map from local variables to their expressions. * * This is used when one refers to variable such as: 'let abc = a.b.c`. * - key to the map is the string literal `"abc"`. * - value `lhs` is the left hand side which is an AST representing `abc`. * - value `rhs` is the right hand side which is an AST representing `a.b.c`. * - value `declared` is true if the `declareLocalVarCallback` has been called for this scope * already. */ this.map = new Map(); this.referenceNameIndex = 0; } Object.defineProperty(BindingScope, "ROOT_SCOPE", { get: function () { if (!BindingScope._ROOT_SCOPE) { BindingScope._ROOT_SCOPE = new BindingScope().set('$event', o.variable('$event')); } return BindingScope._ROOT_SCOPE; }, enumerable: true, configurable: true }); BindingScope.prototype.get = function (name) { var current = this; while (current) { var value = current.map.get(name); if (value != null) { if (current !== this) { // make a local copy and reset the `declared` state. value = { lhs: value.lhs, rhs: value.rhs, declared: false }; // Cache the value locally. this.map.set(name, value); } if (value.rhs && !value.declared) { // if it is first time we are referencing the variable in the scope // than invoke the callback to insert variable declaration. this.declareLocalVarCallback(value.lhs, value.rhs); value.declared = true; } return value.lhs; } current = current.parent; } return null; }; /** * Create a local variable for later reference. * * @param name Name of the variable. * @param lhs AST representing the left hand side of the `let lhs = rhs;`. * @param rhs AST representing the right hand side of the `let lhs = rhs;`. The `rhs` can be * `undefined` for variable that are ambient such as `$event` and which don't have `rhs` * declaration. */ BindingScope.prototype.set = function (name, lhs, rhs) { !this.map.has(name) || util_1.error("The name " + name + " is already defined in scope to be " + this.map.get(name)); this.map.set(name, { lhs: lhs, rhs: rhs, declared: false }); return this; }; BindingScope.prototype.getLocal = function (name) { return this.get(name); }; BindingScope.prototype.nestedScope = function (declareCallback) { return new BindingScope(this, declareCallback); }; BindingScope.prototype.freshReferenceName = function () { var current = this; // Find the top scope as it maintains the global reference count while (current.parent) current = current.parent; var ref = "" + util_2.REFERENCE_PREFIX + current.referenceNameIndex++; return ref; }; return BindingScope; }()); exports.BindingScope = BindingScope; /** * Creates a `CssSelector` given a tag name and a map of attributes */ function create