@angular/compiler
Version:
Angular - the compiler library
849 lines • 164 kB
JavaScript
/**
* @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