| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, flatten, identifierName, rendererTypeName, sanitizeIdentifier, tokenReference, viewClassName} from '../compile_metadata'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import {CompileReflector} from '../compile_reflector'; | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  | import {BindingForm, BuiltinConverter, BuiltinFunctionCall, ConvertPropertyBindingResult, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import {ConstantPool, DefinitionKind} from '../constant_pool'; | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  | import {AST, AstMemoryEfficientTransformer, AstTransformer, BindingPipe, FunctionCall, ImplicitReceiver, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PropertyRead} from '../expression_parser/ast'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import {Identifiers} from '../identifiers'; | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  | import {LifecycleHooks} from '../lifecycle_reflector'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import * as o from '../output/output_ast'; | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | import {ParseSourceSpan, typeSourceSpan} from '../parse_util'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import {CssSelector} from '../selector'; | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | import {BindingParser} from '../template_parser/binding_parser'; | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  | import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | import {OutputContext, error} from '../util'; | 
					
						
							|  |  |  | import {Identifiers as R3} from './r3_identifiers'; | 
					
						
							| 
									
										
										
										
											2018-02-28 14:56:41 -08:00
										 |  |  | import {BUILD_OPTIMIZER_COLOCATE, OutputMode} from './r3_types'; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | /** Name of the context parameter passed into a template function */ | 
					
						
							|  |  |  | const CONTEXT_NAME = 'ctx'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Name of the creation mode flag passed into a template function */ | 
					
						
							|  |  |  | const CREATION_MODE_FLAG = 'cm'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Name of the temporary to use during data binding */ | 
					
						
							|  |  |  | const TEMPORARY_NAME = '_t'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | /** The prefix reference variables */ | 
					
						
							|  |  |  | const REFERENCE_PREFIX = '_r'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  | /** The name of the implicit context reference */ | 
					
						
							|  |  |  | const IMPLICIT_REFERENCE = '$implicit'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  | /** Name of the i18n attributes **/ | 
					
						
							|  |  |  | const I18N_ATTR = 'i18n'; | 
					
						
							|  |  |  | const I18N_ATTR_PREFIX = 'i18n-'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** I18n separators for metadata **/ | 
					
						
							|  |  |  | const MEANING_SEPARATOR = '|'; | 
					
						
							|  |  |  | const ID_SEPARATOR = '@@'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | export function compileDirective( | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |     outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector, | 
					
						
							| 
									
										
										
										
											2018-02-28 14:56:41 -08:00
										 |  |  |     bindingParser: BindingParser, mode: OutputMode) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   const field = (key: string, value: o.Expression | null) => { | 
					
						
							|  |  |  |     if (value) { | 
					
						
							|  |  |  |       definitionMapValues.push({key, value, quoted: false}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-25 13:20:42 -08:00
										 |  |  |   // e.g. 'type: MyDirective`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('type', outputCtx.importExpr(directive.type.reference)); | 
					
						
							| 
									
										
										
										
											2018-01-25 13:20:42 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 21:32:39 -07:00
										 |  |  |   // e.g. `selector: [[[null, 'someDir', ''], null]]`
 | 
					
						
							|  |  |  |   field('selector', createDirectiveSelector(directive.selector !)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   // e.g. `factory: () => new MyApp(injectElementRef())`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('factory', createFactory(directive.type, outputCtx, reflector, directive.queries)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // e.g. `hostBindings: (dirIndex, elIndex) => { ... }
 | 
					
						
							|  |  |  |   field('hostBindings', createHostBindingsFunction(directive, outputCtx, bindingParser)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // e.g. `attributes: ['role', 'listbox']`
 | 
					
						
							|  |  |  |   field('attributes', createHostAttributesArray(directive, outputCtx)); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |   // e.g 'inputs: {a: 'a'}`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('inputs', createInputsObject(directive, outputCtx)); | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   const className = identifierName(directive.type) !; | 
					
						
							|  |  |  |   className || error(`Cannot resolver the name of ${directive.type}`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 14:56:41 -08:00
										 |  |  |   const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Directive); | 
					
						
							|  |  |  |   const definitionFunction = | 
					
						
							|  |  |  |       o.importExpr(R3.defineDirective).callFn([o.literalMap(definitionMapValues)]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mode === OutputMode.PartialClass) { | 
					
						
							|  |  |  |     // Create the partial class to be merged with the actual class.
 | 
					
						
							|  |  |  |     outputCtx.statements.push(new o.ClassStmt( | 
					
						
							|  |  |  |         /* name */ className, | 
					
						
							|  |  |  |         /* parent */ null, | 
					
						
							|  |  |  |         /* fields */[new o.ClassField( | 
					
						
							|  |  |  |             /* name */ definitionField, | 
					
						
							|  |  |  |             /* type */ o.INFERRED_TYPE, | 
					
						
							|  |  |  |             /* modifiers */[o.StmtModifier.Static], | 
					
						
							|  |  |  |             /* initializer */ definitionFunction)], | 
					
						
							|  |  |  |         /* getters */[], | 
					
						
							|  |  |  |         /* constructorMethod */ new o.ClassMethod(null, [], []), | 
					
						
							|  |  |  |         /* methods */[])); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     // Create back-patch definition.
 | 
					
						
							|  |  |  |     const classReference = outputCtx.importExpr(directive.type.reference); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create the back-patch statement
 | 
					
						
							|  |  |  |     outputCtx.statements.push(new o.CommentStmt(BUILD_OPTIMIZER_COLOCATE)); | 
					
						
							|  |  |  |     outputCtx.statements.push( | 
					
						
							|  |  |  |         classReference.prop(definitionField).set(definitionFunction).toStmt()); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | export function compileComponent( | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |     outputCtx: OutputContext, component: CompileDirectiveMetadata, pipes: CompilePipeSummary[], | 
					
						
							| 
									
										
										
										
											2018-02-28 14:56:41 -08:00
										 |  |  |     template: TemplateAst[], reflector: CompileReflector, bindingParser: BindingParser, | 
					
						
							|  |  |  |     mode: OutputMode) { | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   const field = (key: string, value: o.Expression | null) => { | 
					
						
							|  |  |  |     if (value) { | 
					
						
							|  |  |  |       definitionMapValues.push({key, value, quoted: false}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-25 13:20:42 -08:00
										 |  |  |   // e.g. `type: MyApp`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('type', outputCtx.importExpr(component.type.reference)); | 
					
						
							| 
									
										
										
										
											2018-01-25 13:20:42 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 21:32:39 -07:00
										 |  |  |   // e.g. `selector: [[['my-app'], null]]`
 | 
					
						
							|  |  |  |   field('selector', createDirectiveSelector(component.selector !)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   const selector = component.selector && CssSelector.parse(component.selector); | 
					
						
							|  |  |  |   const firstSelector = selector && selector[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // e.g. `attr: ["class", ".my.app"]
 | 
					
						
							|  |  |  |   // This is optional an only included if the first selector of a component specifies attributes.
 | 
					
						
							|  |  |  |   if (firstSelector) { | 
					
						
							|  |  |  |     const selectorAttributes = firstSelector.getAttrs(); | 
					
						
							|  |  |  |     if (selectorAttributes.length) { | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |       field( | 
					
						
							|  |  |  |           'attrs', outputCtx.constantPool.getConstLiteral( | 
					
						
							|  |  |  |                        o.literalArr(selectorAttributes.map( | 
					
						
							|  |  |  |                            value => value != null ? o.literal(value) : o.literal(undefined))), | 
					
						
							|  |  |  |                        /* forceShared */ true)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |   // e.g. `factory: function MyApp_Factory() { return new MyApp(injectElementRef()); }`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('factory', createFactory(component.type, outputCtx, reflector, component.queries)); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |   // e.g `hostBindings: function MyApp_HostBindings { ... }
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('hostBindings', createHostBindingsFunction(component, outputCtx, bindingParser)); | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |   // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
 | 
					
						
							|  |  |  |   const templateTypeName = component.type.reference.name; | 
					
						
							|  |  |  |   const templateName = templateTypeName ? `${templateTypeName}_Template` : null; | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   const pipeMap = new Map(pipes.map<[string, CompilePipeSummary]>(pipe => [pipe.name, pipe])); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   const templateFunctionExpression = | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |       new TemplateDefinitionBuilder( | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |           outputCtx, outputCtx.constantPool, reflector, CONTEXT_NAME, ROOT_SCOPE.nestedScope(), 0, | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |           component.template !.ngContentSelectors, templateTypeName, templateName, pipeMap, | 
					
						
							|  |  |  |           component.viewQueries) | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  |           .buildTemplateFunction(template, []); | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   field('template', templateFunctionExpression); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |   // e.g `inputs: {a: 'a'}`
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   field('inputs', createInputsObject(component, outputCtx)); | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // e.g. `features: [NgOnChangesFeature(MyComponent)]`
 | 
					
						
							|  |  |  |   const features: o.Expression[] = []; | 
					
						
							|  |  |  |   if (component.type.lifecycleHooks.some(lifecycle => lifecycle == LifecycleHooks.OnChanges)) { | 
					
						
							|  |  |  |     features.push(o.importExpr(R3.NgOnChangesFeature, null, null).callFn([outputCtx.importExpr( | 
					
						
							|  |  |  |         component.type.reference)])); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (features.length) { | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |     field('features', o.literalArr(features)); | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 14:56:41 -08:00
										 |  |  |   const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Component); | 
					
						
							|  |  |  |   const definitionFunction = | 
					
						
							|  |  |  |       o.importExpr(R3.defineComponent).callFn([o.literalMap(definitionMapValues)]); | 
					
						
							|  |  |  |   if (mode === OutputMode.PartialClass) { | 
					
						
							|  |  |  |     const className = identifierName(component.type) !; | 
					
						
							|  |  |  |     className || error(`Cannot resolver the name of ${component.type}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create the partial class to be merged with the actual class.
 | 
					
						
							|  |  |  |     outputCtx.statements.push(new o.ClassStmt( | 
					
						
							|  |  |  |         /* name */ className, | 
					
						
							|  |  |  |         /* parent */ null, | 
					
						
							|  |  |  |         /* fields */[new o.ClassField( | 
					
						
							|  |  |  |             /* name */ definitionField, | 
					
						
							|  |  |  |             /* type */ o.INFERRED_TYPE, | 
					
						
							|  |  |  |             /* modifiers */[o.StmtModifier.Static], | 
					
						
							|  |  |  |             /* initializer */ definitionFunction)], | 
					
						
							|  |  |  |         /* getters */[], | 
					
						
							|  |  |  |         /* constructorMethod */ new o.ClassMethod(null, [], []), | 
					
						
							|  |  |  |         /* methods */[])); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     const classReference = outputCtx.importExpr(component.type.reference); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create the back-patch statement
 | 
					
						
							|  |  |  |     outputCtx.statements.push( | 
					
						
							|  |  |  |         new o.CommentStmt(BUILD_OPTIMIZER_COLOCATE), | 
					
						
							|  |  |  |         classReference.prop(definitionField).set(definitionFunction).toStmt()); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO: Remove these when the things are fully supported
 | 
					
						
							|  |  |  | function unknown<T>(arg: o.Expression | o.Statement | TemplateAst): never { | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |   throw new Error( | 
					
						
							|  |  |  |       `Builder ${this.constructor.name} is unable to handle ${arg.constructor.name} yet`); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | function unsupported(feature: string): never { | 
					
						
							|  |  |  |   if (this) { | 
					
						
							|  |  |  |     throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-25 15:38:39 -08:00
										 |  |  |   throw new Error(`Feature ${feature} is not supported yet`); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const BINDING_INSTRUCTION_MAP: {[index: number]: o.ExternalReference | undefined} = { | 
					
						
							|  |  |  |   [PropertyBindingType.Property]: R3.elementProperty, | 
					
						
							|  |  |  |   [PropertyBindingType.Attribute]: R3.elementAttribute, | 
					
						
							| 
									
										
										
										
											2018-03-07 16:25:18 -08:00
										 |  |  |   [PropertyBindingType.Class]: R3.elementClassNamed, | 
					
						
							|  |  |  |   [PropertyBindingType.Style]: R3.elementStyleNamed | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function interpolate(args: o.Expression[]): o.Expression { | 
					
						
							|  |  |  |   args = args.slice(1);  // Ignore the length prefix added for render2
 | 
					
						
							|  |  |  |   switch (args.length) { | 
					
						
							|  |  |  |     case 3: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation1).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 5: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation2).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 7: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation3).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 9: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation4).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 11: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation5).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 13: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation6).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 15: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation7).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     case 17: | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |       return o.importExpr(R3.interpolation8).callFn(args); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-31 13:11:07 -08:00
										 |  |  |   (args.length >= 19 && args.length % 2 == 1) || | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       error(`Invalid interpolation argument length ${args.length}`); | 
					
						
							| 
									
										
										
										
											2018-02-14 11:22:14 -08:00
										 |  |  |   return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  | function pipeBinding(args: o.Expression[]): o.ExternalReference { | 
					
						
							|  |  |  |   switch (args.length) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       // The first parameter to pipeBind is always the value to be transformed followed
 | 
					
						
							|  |  |  |       // by arg.length arguments so the total number of arguments to pipeBind are
 | 
					
						
							|  |  |  |       // arg.length + 1.
 | 
					
						
							|  |  |  |       return R3.pipeBind1; | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       return R3.pipeBind2; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       return R3.pipeBind3; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return R3.pipeBindV; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  | const pureFunctionIdentifiers = [ | 
					
						
							|  |  |  |   R3.pureFunction0, R3.pureFunction1, R3.pureFunction2, R3.pureFunction3, R3.pureFunction4, | 
					
						
							|  |  |  |   R3.pureFunction5, R3.pureFunction6, R3.pureFunction7, R3.pureFunction8 | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | function getLiteralFactory( | 
					
						
							|  |  |  |     outputContext: OutputContext, literal: o.LiteralArrayExpr | o.LiteralMapExpr): o.Expression { | 
					
						
							|  |  |  |   const {literalFactory, literalFactoryArguments} = | 
					
						
							|  |  |  |       outputContext.constantPool.getLiteralFactory(literal); | 
					
						
							|  |  |  |   literalFactoryArguments.length > 0 || error(`Expected arguments to a literal factory function`); | 
					
						
							|  |  |  |   let pureFunctionIdent = | 
					
						
							|  |  |  |       pureFunctionIdentifiers[literalFactoryArguments.length] || R3.pureFunctionV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Literal factories are pure functions that only need to be re-invoked when the parameters
 | 
					
						
							|  |  |  |   // change.
 | 
					
						
							|  |  |  |   return o.importExpr(pureFunctionIdent).callFn([literalFactory, ...literalFactoryArguments]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | class BindingScope { | 
					
						
							|  |  |  |   private map = new Map<string, o.Expression>(); | 
					
						
							|  |  |  |   private referenceNameIndex = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(private parent: BindingScope|null) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   get(name: string): o.Expression|null { | 
					
						
							|  |  |  |     let current: BindingScope|null = this; | 
					
						
							|  |  |  |     while (current) { | 
					
						
							|  |  |  |       const value = current.map.get(name); | 
					
						
							|  |  |  |       if (value != null) { | 
					
						
							|  |  |  |         // Cache the value locally.
 | 
					
						
							|  |  |  |         this.map.set(name, value); | 
					
						
							|  |  |  |         return value; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       current = current.parent; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   set(name: string, value: o.Expression): BindingScope { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     !this.map.has(name) || | 
					
						
							|  |  |  |         error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`); | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |     this.map.set(name, value); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     return this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   nestedScope(): BindingScope { return new BindingScope(this); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   freshReferenceName(): string { | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     let current: BindingScope = this; | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     // Find the top scope as it maintains the global reference count
 | 
					
						
							|  |  |  |     while (current.parent) current = current.parent; | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`; | 
					
						
							|  |  |  |     return ref; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  | const ROOT_SCOPE = new BindingScope(null).set('$event', o.variable('$event')); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver { | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   private _dataIndex = 0; | 
					
						
							|  |  |  |   private _bindingContext = 0; | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   private _referenceIndex = 0; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   private _temporaryAllocated = false; | 
					
						
							|  |  |  |   private _prefix: o.Statement[] = []; | 
					
						
							|  |  |  |   private _creationMode: o.Statement[] = []; | 
					
						
							|  |  |  |   private _bindingMode: o.Statement[] = []; | 
					
						
							|  |  |  |   private _hostMode: o.Statement[] = []; | 
					
						
							|  |  |  |   private _refreshMode: o.Statement[] = []; | 
					
						
							|  |  |  |   private _postfix: o.Statement[] = []; | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |   private _contentProjections: Map<NgContentAst, NgContentInfo>; | 
					
						
							|  |  |  |   private _projectionDefinitionIndex = 0; | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  |   private _valueConverter: ValueConverter; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   private unsupported = unsupported; | 
					
						
							|  |  |  |   private invalid = invalid; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |   // Whether we are inside a translatable element (`<p i18n>... somewhere here ... </p>)
 | 
					
						
							|  |  |  |   private _inI18nSection: boolean = false; | 
					
						
							|  |  |  |   private _i18nSectionIndex = -1; | 
					
						
							|  |  |  |   // Maps of placeholder to node indexes for each of the i18n section
 | 
					
						
							|  |  |  |   private _phToNodeIdxes: {[phName: string]: number[]}[] = [{}]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   constructor( | 
					
						
							|  |  |  |       private outputCtx: OutputContext, private constantPool: ConstantPool, | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |       private reflector: CompileReflector, private contextParameter: string, | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |       private bindingScope: BindingScope, private level = 0, private ngContentSelectors: string[], | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |       private contextName: string|null, private templateName: string|null, | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |       private pipes: Map<string, CompilePipeSummary>, private viewQueries: CompileQueryMetadata[]) { | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  |     this._valueConverter = new ValueConverter( | 
					
						
							|  |  |  |         outputCtx, () => this.allocateDataSlot(), (name, localName, slot, value) => { | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |           bindingScope.set(localName, value); | 
					
						
							|  |  |  |           const pipe = pipes.get(name) !; | 
					
						
							|  |  |  |           pipe || error(`Could not find pipe ${name}`); | 
					
						
							|  |  |  |           const pipeDefinition = constantPool.getDefinition( | 
					
						
							|  |  |  |               pipe.type.reference, DefinitionKind.Pipe, outputCtx, /* forceShared */ true); | 
					
						
							|  |  |  |           this._creationMode.push( | 
					
						
							|  |  |  |               o.importExpr(R3.pipe) | 
					
						
							|  |  |  |                   .callFn([ | 
					
						
							|  |  |  |                     o.literal(slot), pipeDefinition, pipeDefinition.callMethod(R3.NEW_METHOD, []) | 
					
						
							|  |  |  |                   ]) | 
					
						
							|  |  |  |                   .toStmt()); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  |   buildTemplateFunction(asts: TemplateAst[], variables: VariableAst[]): o.FunctionExpr { | 
					
						
							|  |  |  |     // Create variable bindings
 | 
					
						
							|  |  |  |     for (const variable of variables) { | 
					
						
							|  |  |  |       const variableName = variable.name; | 
					
						
							|  |  |  |       const expression = | 
					
						
							|  |  |  |           o.variable(this.contextParameter).prop(variable.value || IMPLICIT_REFERENCE); | 
					
						
							|  |  |  |       const scopedName = this.bindingScope.freshReferenceName(); | 
					
						
							|  |  |  |       const declaration = o.variable(scopedName).set(expression).toDeclStmt(o.INFERRED_TYPE, [ | 
					
						
							|  |  |  |         o.StmtModifier.Final | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Add the reference to the local scope.
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |       this.bindingScope.set(variableName, o.variable(scopedName)); | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Declare the local variable in binding mode
 | 
					
						
							|  |  |  |       this._bindingMode.push(declaration); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |     // Collect content projections
 | 
					
						
							|  |  |  |     if (this.ngContentSelectors && this.ngContentSelectors.length > 0) { | 
					
						
							|  |  |  |       const contentProjections = getContentProjection(asts, this.ngContentSelectors); | 
					
						
							|  |  |  |       this._contentProjections = contentProjections; | 
					
						
							|  |  |  |       if (contentProjections.size > 0) { | 
					
						
							|  |  |  |         const infos: R3CssSelector[] = []; | 
					
						
							|  |  |  |         Array.from(contentProjections.values()).forEach(info => { | 
					
						
							|  |  |  |           if (info.selector) { | 
					
						
							|  |  |  |             infos[info.index - 1] = info.selector; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         const projectionIndex = this._projectionDefinitionIndex = this.allocateDataSlot(); | 
					
						
							|  |  |  |         const parameters: o.Expression[] = [o.literal(projectionIndex)]; | 
					
						
							|  |  |  |         !infos.some(value => !value) || error(`content project information skipped an index`); | 
					
						
							|  |  |  |         if (infos.length > 1) { | 
					
						
							|  |  |  |           parameters.push(this.outputCtx.constantPool.getConstLiteral( | 
					
						
							|  |  |  |               asLiteral(infos), /* forceShared */ true)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this.instruction(this._creationMode, null, R3.projectionDef, ...parameters); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |     // Define and update any view queries
 | 
					
						
							|  |  |  |     for (let query of this.viewQueries) { | 
					
						
							|  |  |  |       // e.g. r3.Q(0, SomeDirective, true);
 | 
					
						
							|  |  |  |       const querySlot = this.allocateDataSlot(); | 
					
						
							|  |  |  |       const predicate = getQueryPredicate(query, this.outputCtx); | 
					
						
							|  |  |  |       const args = [ | 
					
						
							|  |  |  |         /* memoryIndex */ o.literal(querySlot, o.INFERRED_TYPE), | 
					
						
							|  |  |  |         /* predicate */ predicate, | 
					
						
							|  |  |  |         /* descend */ o.literal(query.descendants, o.INFERRED_TYPE) | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (query.read) { | 
					
						
							|  |  |  |         args.push(this.outputCtx.importExpr(query.read.identifier !.reference)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.instruction(this._creationMode, null, R3.query, ...args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // (r3.qR(tmp = r3.ɵld(0)) && (ctx.someDir = tmp));
 | 
					
						
							|  |  |  |       const temporary = this.temp(); | 
					
						
							|  |  |  |       const getQueryList = o.importExpr(R3.load).callFn([o.literal(querySlot)]); | 
					
						
							|  |  |  |       const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]); | 
					
						
							|  |  |  |       const updateDirective = o.variable(CONTEXT_NAME) | 
					
						
							|  |  |  |                                   .prop(query.propertyName) | 
					
						
							|  |  |  |                                   .set(query.first ? temporary.prop('first') : temporary); | 
					
						
							|  |  |  |       this._bindingMode.push(refresh.and(updateDirective).toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     templateVisitAll(this, asts); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |     const creationMode = this._creationMode.length > 0 ? | 
					
						
							|  |  |  |         [o.ifStmt(o.variable(CREATION_MODE_FLAG), this._creationMode)] : | 
					
						
							|  |  |  |         []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     // Generate maps of placeholder name to node indexes
 | 
					
						
							|  |  |  |     // TODO(vicb): This is a WIP, not fully supported yet
 | 
					
						
							|  |  |  |     for (const phToNodeIdx of this._phToNodeIdxes) { | 
					
						
							|  |  |  |       if (Object.keys(phToNodeIdx).length > 0) { | 
					
						
							|  |  |  |         const scopedName = this.bindingScope.freshReferenceName(); | 
					
						
							|  |  |  |         const phMap = o.variable(scopedName) | 
					
						
							|  |  |  |                           .set(mapToExpression(phToNodeIdx, true)) | 
					
						
							|  |  |  |                           .toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this._prefix.push(phMap); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     return o.fn( | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |           new o.FnParam(this.contextParameter, null), new o.FnParam(CREATION_MODE_FLAG, o.BOOL_TYPE) | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |           // Temporary variable declarations (i.e. let _t: any;)
 | 
					
						
							|  |  |  |           ...this._prefix, | 
					
						
							|  |  |  |           // Creating mode (i.e. if (cm) { ... })
 | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |           ...creationMode, | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |           // Binding mode (i.e. ɵp(...))
 | 
					
						
							|  |  |  |           ...this._bindingMode, | 
					
						
							|  |  |  |           // Host mode (i.e. Comp.h(...))
 | 
					
						
							|  |  |  |           ...this._hostMode, | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |           // Refresh mode (i.e. Comp.r(...))
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |           ...this._refreshMode, | 
					
						
							|  |  |  |           // Nested templates (i.e. function CompTemplate() {})
 | 
					
						
							|  |  |  |           ...this._postfix | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |         o.INFERRED_TYPE, null, this.templateName); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // LocalResolver
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   getLocal(name: string): o.Expression|null { return this.bindingScope.get(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // TemplateAstVisitor
 | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |   visitNgContent(ast: NgContentAst) { | 
					
						
							|  |  |  |     const info = this._contentProjections.get(ast) !; | 
					
						
							|  |  |  |     info || error(`Expected ${ast.sourceSpan} to be included in content projection collection`); | 
					
						
							|  |  |  |     const slot = this.allocateDataSlot(); | 
					
						
							|  |  |  |     const parameters = [o.literal(slot), o.literal(this._projectionDefinitionIndex)]; | 
					
						
							|  |  |  |     if (info.index !== 0) { | 
					
						
							|  |  |  |       parameters.push(o.literal(info.index)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.instruction(this._creationMode, ast.sourceSpan, R3.projection, ...parameters); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   private _computeDirectivesArray(directives: DirectiveAst[]) { | 
					
						
							|  |  |  |     const directiveIndexMap = new Map<any, number>(); | 
					
						
							|  |  |  |     const directiveExpressions: o.Expression[] = | 
					
						
							|  |  |  |         directives.filter(directive => !directive.directive.isComponent).map(directive => { | 
					
						
							|  |  |  |           directiveIndexMap.set(directive.directive.type.reference, this.allocateDataSlot()); | 
					
						
							|  |  |  |           return this.typeReference(directive.directive.type.reference); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       directivesArray: directiveExpressions.length ? | 
					
						
							|  |  |  |           this.constantPool.getConstLiteral( | 
					
						
							|  |  |  |               o.literalArr(directiveExpressions), /* forceShared */ true) : | 
					
						
							|  |  |  |           o.literal(null), | 
					
						
							|  |  |  |       directiveIndexMap | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // TemplateAstVisitor
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |   visitElement(element: ElementAst) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     const elementIndex = this.allocateDataSlot(); | 
					
						
							|  |  |  |     let componentIndex: number|undefined = undefined; | 
					
						
							|  |  |  |     const referenceDataSlots = new Map<string, number>(); | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     const wasInI18nSection = this._inI18nSection; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const outputAttrs: {[name: string]: string} = {}; | 
					
						
							|  |  |  |     const attrI18nMetas: {[name: string]: string} = {}; | 
					
						
							|  |  |  |     let i18nMeta: string = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Elements inside i18n sections are replaced with placeholders
 | 
					
						
							|  |  |  |     // TODO(vicb): nested elements are a WIP in this phase
 | 
					
						
							|  |  |  |     if (this._inI18nSection) { | 
					
						
							|  |  |  |       const phName = element.name.toLowerCase(); | 
					
						
							|  |  |  |       if (!this._phToNodeIdxes[this._i18nSectionIndex][phName]) { | 
					
						
							|  |  |  |         this._phToNodeIdxes[this._i18nSectionIndex][phName] = []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this._phToNodeIdxes[this._i18nSectionIndex][phName].push(elementIndex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Handle i18n attributes
 | 
					
						
							|  |  |  |     for (const attr of element.attrs) { | 
					
						
							|  |  |  |       const name = attr.name; | 
					
						
							|  |  |  |       const value = attr.value; | 
					
						
							|  |  |  |       if (name === 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.startsWith(I18N_ATTR_PREFIX)) { | 
					
						
							|  |  |  |         attrI18nMetas[name.slice(I18N_ATTR_PREFIX.length)] = value; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         outputAttrs[name] = value; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Element creation mode
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     const component = findComponent(element.directives); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     const nullNode = o.literal(null, o.INFERRED_TYPE); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     const parameters: o.Expression[] = [o.literal(elementIndex)]; | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Add component type or element tag
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     if (component) { | 
					
						
							|  |  |  |       parameters.push(this.typeReference(component.directive.type.reference)); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |       componentIndex = this.allocateDataSlot(); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |       parameters.push(o.literal(element.name)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     // Add the attributes
 | 
					
						
							|  |  |  |     const i18nMessages: o.Statement[] = []; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     const attributes: o.Expression[] = []; | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     let hasI18nAttr = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Object.getOwnPropertyNames(outputAttrs).forEach(name => { | 
					
						
							|  |  |  |       const value = outputAttrs[name]; | 
					
						
							|  |  |  |       attributes.push(o.literal(name)); | 
					
						
							|  |  |  |       if (attrI18nMetas.hasOwnProperty(name)) { | 
					
						
							|  |  |  |         hasI18nAttr = true; | 
					
						
							| 
									
										
										
										
											2018-03-22 15:03:06 -07:00
										 |  |  |         const meta = parseI18nMeta(attrI18nMetas[name]); | 
					
						
							|  |  |  |         const variable = this.constantPool.getTranslation(value, meta); | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |         attributes.push(variable); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         attributes.push(o.literal(value)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let attrArg: o.Expression = nullNode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (attributes.length > 0) { | 
					
						
							|  |  |  |       attrArg = hasI18nAttr ? getLiteralFactory(this.outputCtx, o.literalArr(attributes)) : | 
					
						
							|  |  |  |                               this.constantPool.getConstLiteral(o.literalArr(attributes), true); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     parameters.push(attrArg); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Add directives array
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     const {directivesArray, directiveIndexMap} = this._computeDirectivesArray(element.directives); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     parameters.push(directiveIndexMap.size > 0 ? directivesArray : nullNode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (component && componentIndex != null) { | 
					
						
							|  |  |  |       // Record the data slot for the component
 | 
					
						
							|  |  |  |       directiveIndexMap.set(component.directive.type.reference, componentIndex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     if (element.references && element.references.length > 0) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |       const references = | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |           flatten(element.references.map(reference => { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |             const slot = this.allocateDataSlot(); | 
					
						
							|  |  |  |             referenceDataSlots.set(reference.name, slot); | 
					
						
							|  |  |  |             // Generate the update temporary.
 | 
					
						
							|  |  |  |             const variableName = this.bindingScope.freshReferenceName(); | 
					
						
							|  |  |  |             this._bindingMode.push(o.variable(variableName, o.INFERRED_TYPE) | 
					
						
							| 
									
										
										
										
											2018-02-16 16:58:07 -08:00
										 |  |  |                                        .set(o.importExpr(R3.load).callFn([o.literal(slot)])) | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |                                        .toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |             this.bindingScope.set(reference.name, o.variable(variableName)); | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |             return [reference.name, reference.originalValue]; | 
					
						
							|  |  |  |           })).map(value => o.literal(value)); | 
					
						
							|  |  |  |       parameters.push( | 
					
						
							|  |  |  |           this.constantPool.getConstLiteral(o.literalArr(references), /* forceShared */ true)); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       parameters.push(nullNode); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     // Remove trailing null nodes as they are implied.
 | 
					
						
							|  |  |  |     while (parameters[parameters.length - 1] === nullNode) { | 
					
						
							|  |  |  |       parameters.pop(); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     // Generate the instruction create element instruction
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     if (i18nMessages.length > 0) { | 
					
						
							|  |  |  |       this._creationMode.push(...i18nMessages); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.instruction(this._creationMode, element.sourceSpan, R3.createElement, ...parameters); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const implicit = o.variable(this.contextParameter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Generate element input bindings
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     for (let input of element.inputs) { | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       if (input.isAnimation) { | 
					
						
							|  |  |  |         this.unsupported('animations'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |       const convertedBinding = this.convertPropertyBinding(implicit, input.value); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       const instruction = BINDING_INSTRUCTION_MAP[input.type]; | 
					
						
							|  |  |  |       if (instruction) { | 
					
						
							|  |  |  |         // TODO(chuckj): runtime: security context?
 | 
					
						
							|  |  |  |         this.instruction( | 
					
						
							|  |  |  |             this._bindingMode, input.sourceSpan, instruction, o.literal(elementIndex), | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |             o.literal(input.name), convertedBinding); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         this.unsupported(`binding ${PropertyBindingType[input.type]}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Generate directives input bindings
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     this._visitDirectives(element.directives, implicit, elementIndex, directiveIndexMap); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Traverse element child nodes
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     if (this._inI18nSection && element.children.length == 1 && | 
					
						
							|  |  |  |         element.children[0] instanceof TextAst) { | 
					
						
							|  |  |  |       const text = element.children[0] as TextAst; | 
					
						
							|  |  |  |       this.visitSingleI18nTextChild(text, i18nMeta); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       templateVisitAll(this, element.children); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Finish element construction mode.
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._creationMode, element.endSourceSpan || element.sourceSpan, R3.elementEnd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Restore the state before exiting this node
 | 
					
						
							|  |  |  |     this._inI18nSection = wasInI18nSection; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   private _visitDirectives( | 
					
						
							|  |  |  |       directives: DirectiveAst[], implicit: o.Expression, nodeIndex: number, | 
					
						
							|  |  |  |       directiveIndexMap: Map<any, number>) { | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     for (let directive of directives) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |       const directiveIndex = directiveIndexMap.get(directive.directive.type.reference); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Creation mode
 | 
					
						
							|  |  |  |       // e.g. D(0, TodoComponentDef.n(), TodoComponentDef);
 | 
					
						
							|  |  |  |       const directiveType = directive.directive.type.reference; | 
					
						
							|  |  |  |       const kind = | 
					
						
							|  |  |  |           directive.directive.isComponent ? DefinitionKind.Component : DefinitionKind.Directive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Note: *do not cache* calls to this.directiveOf() as the constant pool needs to know if the
 | 
					
						
							|  |  |  |       // node is referenced multiple times to know that it must generate the reference into a
 | 
					
						
							|  |  |  |       // temporary.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Bindings
 | 
					
						
							|  |  |  |       for (const input of directive.inputs) { | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |         const convertedBinding = this.convertPropertyBinding(implicit, input.value); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |         this.instruction( | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  |             this._bindingMode, directive.sourceSpan, R3.elementProperty, o.literal(nodeIndex), | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |             o.literal(input.templateName), o.importExpr(R3.bind).callFn([convertedBinding])); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  |       // e.g. MyDirective.ngDirectiveDef.h(0, 0);
 | 
					
						
							|  |  |  |       this._hostMode.push( | 
					
						
							|  |  |  |           this.definitionOf(directiveType, kind) | 
					
						
							|  |  |  |               .callMethod(R3.HOST_BINDING_METHOD, [o.literal(directiveIndex), o.literal(nodeIndex)]) | 
					
						
							|  |  |  |               .toStmt()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 09:11:04 -08:00
										 |  |  |       // e.g. r(0, 0);
 | 
					
						
							|  |  |  |       this.instruction( | 
					
						
							|  |  |  |           this._refreshMode, directive.sourceSpan, R3.refreshComponent, o.literal(directiveIndex), | 
					
						
							|  |  |  |           o.literal(nodeIndex)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // TemplateAstVisitor
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   visitEmbeddedTemplate(ast: EmbeddedTemplateAst) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     const templateIndex = this.allocateDataSlot(); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |     const templateRef = this.reflector.resolveExternalReference(Identifiers.TemplateRef); | 
					
						
							|  |  |  |     const templateDirective = ast.directives.find( | 
					
						
							|  |  |  |         directive => directive.directive.type.diDeps.some( | 
					
						
							|  |  |  |             dependency => | 
					
						
							|  |  |  |                 dependency.token != null && (tokenReference(dependency.token) == templateRef))); | 
					
						
							|  |  |  |     const contextName = | 
					
						
							|  |  |  |         this.contextName && templateDirective && templateDirective.directive.type.reference.name ? | 
					
						
							|  |  |  |         `${this.contextName}_${templateDirective.directive.type.reference.name}` : | 
					
						
							|  |  |  |         null; | 
					
						
							|  |  |  |     const templateName = | 
					
						
							|  |  |  |         contextName ? `${contextName}_Template_${templateIndex}` : `Template_${templateIndex}`; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     const templateContext = `ctx${this.level}`; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     const {directivesArray, directiveIndexMap} = this._computeDirectivesArray(ast.directives); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // e.g. C(1, C1Template)
 | 
					
						
							|  |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._creationMode, ast.sourceSpan, R3.containerCreate, o.literal(templateIndex), | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |         directivesArray, o.variable(templateName)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // e.g. Cr(1)
 | 
					
						
							|  |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._refreshMode, ast.sourceSpan, R3.containerRefreshStart, o.literal(templateIndex)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     // Generate directives
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     this._visitDirectives( | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |         ast.directives, o.variable(this.contextParameter), templateIndex, directiveIndexMap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // e.g. cr();
 | 
					
						
							|  |  |  |     this.instruction(this._refreshMode, ast.sourceSpan, R3.containerRefreshEnd); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Create the template function
 | 
					
						
							|  |  |  |     const templateVisitor = new TemplateDefinitionBuilder( | 
					
						
							| 
									
										
										
										
											2018-01-22 15:35:18 -08:00
										 |  |  |         this.outputCtx, this.constantPool, this.reflector, templateContext, | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |         this.bindingScope.nestedScope(), this.level + 1, this.ngContentSelectors, contextName, | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |         templateName, this.pipes, []); | 
					
						
							| 
									
										
										
										
											2018-01-24 11:19:39 -08:00
										 |  |  |     const templateFunctionExpr = templateVisitor.buildTemplateFunction(ast.children, ast.variables); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     this._postfix.push(templateFunctionExpr.toDeclStmt(templateName, null)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // These should be handled in the template or element directly.
 | 
					
						
							|  |  |  |   readonly visitReference = invalid; | 
					
						
							|  |  |  |   readonly visitVariable = invalid; | 
					
						
							|  |  |  |   readonly visitEvent = invalid; | 
					
						
							|  |  |  |   readonly visitElementProperty = invalid; | 
					
						
							|  |  |  |   readonly visitAttr = invalid; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // TemplateAstVisitor
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   visitBoundText(ast: BoundTextAst) { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     const nodeIndex = this.allocateDataSlot(); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Creation mode
 | 
					
						
							|  |  |  |     this.instruction(this._creationMode, ast.sourceSpan, R3.text, o.literal(nodeIndex)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Refresh mode
 | 
					
						
							|  |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._refreshMode, ast.sourceSpan, R3.textCreateBound, o.literal(nodeIndex), | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |         this.bind(o.variable(CONTEXT_NAME), ast.value, ast.sourceSpan)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   // TemplateAstVisitor
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   visitText(ast: TextAst) { | 
					
						
							|  |  |  |     // Text is defined in creation mode only.
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._creationMode, ast.sourceSpan, R3.text, o.literal(this.allocateDataSlot()), | 
					
						
							|  |  |  |         o.literal(ast.value)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |   // 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);
 | 
					
						
							|  |  |  |   // ```
 | 
					
						
							|  |  |  |   visitSingleI18nTextChild(text: TextAst, i18nMeta: string) { | 
					
						
							| 
									
										
										
										
											2018-03-22 15:03:06 -07:00
										 |  |  |     const meta = parseI18nMeta(i18nMeta); | 
					
						
							|  |  |  |     const variable = this.constantPool.getTranslation(text.value, meta); | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |     this.instruction( | 
					
						
							|  |  |  |         this._creationMode, text.sourceSpan, R3.text, o.literal(this.allocateDataSlot()), variable); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   // These should be handled in the template or element directly
 | 
					
						
							|  |  |  |   readonly visitDirective = invalid; | 
					
						
							|  |  |  |   readonly visitDirectiveProperty = invalid; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |   private allocateDataSlot() { return this._dataIndex++; } | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   private bindingContext() { return `${this._bindingContext++}`; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private instruction( | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  |       statements: o.Statement[], span: ParseSourceSpan|null, reference: o.ExternalReference, | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       ...params: o.Expression[]) { | 
					
						
							|  |  |  |     statements.push(o.importExpr(reference, null, span).callFn(params, span).toStmt()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private typeReference(type: any): o.Expression { return this.outputCtx.importExpr(type); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private definitionOf(type: any, kind: DefinitionKind): o.Expression { | 
					
						
							|  |  |  |     return this.constantPool.getDefinition(type, kind, this.outputCtx); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private temp(): o.ReadVarExpr { | 
					
						
							|  |  |  |     if (!this._temporaryAllocated) { | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |       this._prefix.push(new o.DeclareVarStmt(TEMPORARY_NAME, undefined, o.DYNAMIC_TYPE)); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       this._temporaryAllocated = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return o.variable(TEMPORARY_NAME); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private convertPropertyBinding(implicit: o.Expression, value: AST): o.Expression { | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  |     const pipesConvertedValue = value.visit(this._valueConverter); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     const convertedPropertyBinding = convertPropertyBinding( | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |         this, implicit, pipesConvertedValue, this.bindingContext(), BindingForm.TrySimple, | 
					
						
							|  |  |  |         interpolate); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |     this._refreshMode.push(...convertedPropertyBinding.stmts); | 
					
						
							|  |  |  |     return convertedPropertyBinding.currValExpr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private bind(implicit: o.Expression, value: AST, sourceSpan: ParseSourceSpan): o.Expression { | 
					
						
							| 
									
										
										
										
											2018-01-11 15:37:56 -08:00
										 |  |  |     return this.convertPropertyBinding(implicit, value); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  | function getQueryPredicate(query: CompileQueryMetadata, outputCtx: OutputContext): o.Expression { | 
					
						
							|  |  |  |   let predicate: o.Expression; | 
					
						
							|  |  |  |   if (query.selectors.length > 1 || (query.selectors.length == 1 && query.selectors[0].value)) { | 
					
						
							|  |  |  |     const selectors = query.selectors.map(value => value.value as string); | 
					
						
							|  |  |  |     selectors.some(value => !value) && error('Found a type among the string selectors expected'); | 
					
						
							|  |  |  |     predicate = outputCtx.constantPool.getConstLiteral( | 
					
						
							|  |  |  |         o.literalArr(selectors.map(value => o.literal(value)))); | 
					
						
							|  |  |  |   } else if (query.selectors.length == 1) { | 
					
						
							|  |  |  |     const first = query.selectors[0]; | 
					
						
							|  |  |  |     if (first.identifier) { | 
					
						
							|  |  |  |       predicate = outputCtx.importExpr(first.identifier.reference); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       error('Unexpected query form'); | 
					
						
							|  |  |  |       predicate = o.literal(null); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     error('Unexpected query form'); | 
					
						
							|  |  |  |     predicate = o.literal(null); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return predicate; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  | export function createFactory( | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |     type: CompileTypeMetadata, outputCtx: OutputContext, reflector: CompileReflector, | 
					
						
							|  |  |  |     queries: CompileQueryMetadata[]): o.Expression { | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   let args: o.Expression[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const elementRef = reflector.resolveExternalReference(Identifiers.ElementRef); | 
					
						
							|  |  |  |   const templateRef = reflector.resolveExternalReference(Identifiers.TemplateRef); | 
					
						
							|  |  |  |   const viewContainerRef = reflector.resolveExternalReference(Identifiers.ViewContainerRef); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (let dependency of type.diDeps) { | 
					
						
							|  |  |  |     if (dependency.isValue) { | 
					
						
							|  |  |  |       unsupported('value dependencies'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (dependency.isHost) { | 
					
						
							|  |  |  |       unsupported('host dependencies'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const token = dependency.token; | 
					
						
							|  |  |  |     if (token) { | 
					
						
							|  |  |  |       const tokenRef = tokenReference(token); | 
					
						
							|  |  |  |       if (tokenRef === elementRef) { | 
					
						
							|  |  |  |         args.push(o.importExpr(R3.injectElementRef).callFn([])); | 
					
						
							|  |  |  |       } else if (tokenRef === templateRef) { | 
					
						
							|  |  |  |         args.push(o.importExpr(R3.injectTemplateRef).callFn([])); | 
					
						
							|  |  |  |       } else if (tokenRef === viewContainerRef) { | 
					
						
							|  |  |  |         args.push(o.importExpr(R3.injectViewContainerRef).callFn([])); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2018-01-25 15:38:39 -08:00
										 |  |  |         const value = | 
					
						
							|  |  |  |             token.identifier != null ? outputCtx.importExpr(tokenRef) : o.literal(tokenRef); | 
					
						
							|  |  |  |         args.push(o.importExpr(R3.inject).callFn([value])); | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       unsupported('dependency without a token'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |   const queryDefinitions: o.Expression[] = []; | 
					
						
							|  |  |  |   for (let query of queries) { | 
					
						
							|  |  |  |     const predicate = getQueryPredicate(query, outputCtx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // e.g. r3.Q(null, SomeDirective, false) or r3.Q(null, ['div'], false)
 | 
					
						
							|  |  |  |     const parameters = [ | 
					
						
							|  |  |  |       /* memoryIndex */ o.literal(null, o.INFERRED_TYPE), | 
					
						
							|  |  |  |       /* predicate */ predicate, | 
					
						
							|  |  |  |       /* descend */ o.literal(query.descendants) | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (query.read) { | 
					
						
							|  |  |  |       parameters.push(outputCtx.importExpr(query.read.identifier !.reference)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     queryDefinitions.push(o.importExpr(R3.query).callFn(parameters)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const createInstance = new o.InstantiateExpr(outputCtx.importExpr(type.reference), args); | 
					
						
							|  |  |  |   const result = queryDefinitions.length > 0 ? o.literalArr([createInstance, ...queryDefinitions]) : | 
					
						
							|  |  |  |                                                createInstance; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  |   return o.fn( | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |       [], [new o.ReturnStatement(result)], o.INFERRED_TYPE, null, | 
					
						
							|  |  |  |       type.reference.name ? `${type.reference.name}_Factory` : null); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | type HostBindings = { | 
					
						
							|  |  |  |   [key: string]: string | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 21:32:39 -07:00
										 |  |  | // Turn a directive selector into an R3-compatible selector for directive def
 | 
					
						
							|  |  |  | function createDirectiveSelector(selector: string): o.Expression { | 
					
						
							|  |  |  |   return asLiteral(parseSelectorsToR3Selector(CssSelector.parse(selector))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | function createHostAttributesArray( | 
					
						
							|  |  |  |     directiveMetadata: CompileDirectiveMetadata, outputCtx: OutputContext): o.Expression|null { | 
					
						
							|  |  |  |   const values: o.Expression[] = []; | 
					
						
							|  |  |  |   const attributes = directiveMetadata.hostAttributes; | 
					
						
							|  |  |  |   for (let key of Object.getOwnPropertyNames(attributes)) { | 
					
						
							|  |  |  |     const value = attributes[key]; | 
					
						
							|  |  |  |     values.push(o.literal(key), o.literal(value)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (values.length > 0) { | 
					
						
							|  |  |  |     return outputCtx.constantPool.getConstLiteral(o.literalArr(values)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  | // Return a host binding function or null if one is not necessary.
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | function createHostBindingsFunction( | 
					
						
							|  |  |  |     directiveMetadata: CompileDirectiveMetadata, outputCtx: OutputContext, | 
					
						
							|  |  |  |     bindingParser: BindingParser): o.Expression|null { | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |   const statements: o.Statement[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const temporary = function() { | 
					
						
							|  |  |  |     let declared = false; | 
					
						
							|  |  |  |     return () => { | 
					
						
							|  |  |  |       if (!declared) { | 
					
						
							|  |  |  |         statements.push(new o.DeclareVarStmt(TEMPORARY_NAME, undefined, o.DYNAMIC_TYPE)); | 
					
						
							|  |  |  |         declared = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return o.variable(TEMPORARY_NAME); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   const hostBindingSourceSpan = typeSourceSpan( | 
					
						
							|  |  |  |       directiveMetadata.isComponent ? 'Component' : 'Directive', directiveMetadata.type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Calculate the queries
 | 
					
						
							|  |  |  |   for (let index = 0; index < directiveMetadata.queries.length; index++) { | 
					
						
							|  |  |  |     const query = directiveMetadata.queries[index]; | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // e.g. r3.qR(tmp = r3.ld(dirIndex)[1]) && (r3.ld(dirIndex)[0].someDir = tmp);
 | 
					
						
							|  |  |  |     const getDirectiveMemory = o.importExpr(R3.load).callFn([o.variable('dirIndex')]); | 
					
						
							|  |  |  |     // The query list is at the query index + 1 because the directive itself is in slot 0.
 | 
					
						
							|  |  |  |     const getQueryList = getDirectiveMemory.key(o.literal(index + 1)); | 
					
						
							|  |  |  |     const assignToTemporary = temporary().set(getQueryList); | 
					
						
							|  |  |  |     const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]); | 
					
						
							|  |  |  |     const updateDirective = getDirectiveMemory.key(o.literal(0, o.INFERRED_TYPE)) | 
					
						
							|  |  |  |                                 .prop(query.propertyName) | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |                                 .set(query.first ? temporary().prop('first') : temporary()); | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |     const andExpression = callQueryRefresh.and(updateDirective); | 
					
						
							|  |  |  |     statements.push(andExpression.toStmt()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |   const directiveSummary = directiveMetadata.toSummary(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Calculate the host property bindings
 | 
					
						
							|  |  |  |   const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan); | 
					
						
							|  |  |  |   const bindingContext = o.importExpr(R3.load).callFn([o.variable('dirIndex')]); | 
					
						
							|  |  |  |   if (bindings) { | 
					
						
							|  |  |  |     for (const binding of bindings) { | 
					
						
							|  |  |  |       const bindingExpr = convertPropertyBinding( | 
					
						
							|  |  |  |           null, bindingContext, binding.expression, 'b', BindingForm.TrySimple, | 
					
						
							|  |  |  |           () => error('Unexpected interpolation')); | 
					
						
							|  |  |  |       statements.push(...bindingExpr.stmts); | 
					
						
							|  |  |  |       statements.push(o.importExpr(R3.elementProperty) | 
					
						
							|  |  |  |                           .callFn([ | 
					
						
							|  |  |  |                             o.variable('elIndex'), o.literal(binding.name), | 
					
						
							|  |  |  |                             o.importExpr(R3.bind).callFn([bindingExpr.currValExpr]) | 
					
						
							|  |  |  |                           ]) | 
					
						
							|  |  |  |                           .toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Calculate host event bindings
 | 
					
						
							|  |  |  |   const eventBindings = | 
					
						
							|  |  |  |       bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan); | 
					
						
							|  |  |  |   if (eventBindings) { | 
					
						
							|  |  |  |     for (const binding of eventBindings) { | 
					
						
							|  |  |  |       const bindingExpr = convertActionBinding( | 
					
						
							|  |  |  |           null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation')); | 
					
						
							|  |  |  |       const bindingName = binding.name && sanitizeIdentifier(binding.name); | 
					
						
							|  |  |  |       const typeName = identifierName(directiveMetadata.type); | 
					
						
							|  |  |  |       const functionName = | 
					
						
							|  |  |  |           typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null; | 
					
						
							|  |  |  |       const handler = o.fn( | 
					
						
							|  |  |  |           [new o.FnParam('event', o.DYNAMIC_TYPE)], | 
					
						
							|  |  |  |           [...bindingExpr.stmts, new o.ReturnStatement(bindingExpr.allowDefault)], o.INFERRED_TYPE, | 
					
						
							|  |  |  |           null, functionName); | 
					
						
							|  |  |  |       statements.push( | 
					
						
							|  |  |  |           o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |   if (statements.length > 0) { | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |     const typeName = directiveMetadata.type.reference.name; | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |     return o.fn( | 
					
						
							|  |  |  |         [new o.FnParam('dirIndex', o.NUMBER_TYPE), new o.FnParam('elIndex', o.NUMBER_TYPE)], | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  |         statements, o.INFERRED_TYPE, null, typeName ? `${typeName}_HostBindings` : null); | 
					
						
							| 
									
										
										
										
											2018-02-13 10:48:22 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return null; | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 16:43:16 -08:00
										 |  |  | function createInputsObject( | 
					
						
							|  |  |  |     directive: CompileDirectiveMetadata, outputCtx: OutputContext): o.Expression|null { | 
					
						
							|  |  |  |   if (Object.getOwnPropertyNames(directive.inputs).length > 0) { | 
					
						
							|  |  |  |     return outputCtx.constantPool.getConstLiteral(mapToExpression(directive.inputs)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  | class ValueConverter extends AstMemoryEfficientTransformer { | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |   private pipeSlots = new Map<string, number>(); | 
					
						
							|  |  |  |   constructor( | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  |       private outputCtx: OutputContext, private allocateSlot: () => number, | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  |       private definePipe: | 
					
						
							|  |  |  |           (name: string, localName: string, slot: number, value: o.Expression) => void) { | 
					
						
							|  |  |  |     super(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // AstMemoryEfficientTransformer
 | 
					
						
							|  |  |  |   visitPipe(ast: BindingPipe, context: any): AST { | 
					
						
							|  |  |  |     // Allocate a slot to create the pipe
 | 
					
						
							|  |  |  |     let slot = this.pipeSlots.get(ast.name); | 
					
						
							|  |  |  |     if (slot == null) { | 
					
						
							|  |  |  |       slot = this.allocateSlot(); | 
					
						
							|  |  |  |       this.pipeSlots.set(ast.name, slot); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const slotPseudoLocal = `PIPE:${slot}`; | 
					
						
							|  |  |  |     const target = new PropertyRead(ast.span, new ImplicitReceiver(ast.span), slotPseudoLocal); | 
					
						
							|  |  |  |     const bindingId = pipeBinding(ast.args); | 
					
						
							|  |  |  |     this.definePipe(ast.name, slotPseudoLocal, slot, o.importExpr(bindingId)); | 
					
						
							|  |  |  |     const value = ast.exp.visit(this); | 
					
						
							|  |  |  |     const args = this.visitAll(ast.args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return new FunctionCall( | 
					
						
							|  |  |  |         ast.span, target, [new LiteralPrimitive(ast.span, slot), value, ...args]); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   visitLiteralArray(ast: LiteralArray, context: any): AST { | 
					
						
							|  |  |  |     return new BuiltinFunctionCall(ast.span, this.visitAll(ast.expressions), values => { | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  |       // If the literal has calculated (non-literal) elements transform it into
 | 
					
						
							| 
									
										
										
										
											2018-02-14 17:12:05 -08:00
										 |  |  |       // calls to literal factories that compose the literal and will cache intermediate
 | 
					
						
							|  |  |  |       // values. Otherwise, just return an literal array that contains the values.
 | 
					
						
							|  |  |  |       const literal = o.literalArr(values); | 
					
						
							|  |  |  |       return values.every(a => a.isConstant()) ? | 
					
						
							|  |  |  |           this.outputCtx.constantPool.getConstLiteral(literal, true) : | 
					
						
							|  |  |  |           getLiteralFactory(this.outputCtx, literal); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitLiteralMap(ast: LiteralMap, context: any): AST { | 
					
						
							|  |  |  |     return new BuiltinFunctionCall(ast.span, this.visitAll(ast.values), 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.
 | 
					
						
							|  |  |  |       const literal = o.literalMap(values.map( | 
					
						
							|  |  |  |           (value, index) => ({key: ast.keys[index].key, value, quoted: ast.keys[index].quoted}))); | 
					
						
							|  |  |  |       return values.every(a => a.isConstant()) ? | 
					
						
							|  |  |  |           this.outputCtx.constantPool.getConstLiteral(literal, true) : | 
					
						
							|  |  |  |           getLiteralFactory(this.outputCtx, literal); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-02-05 17:31:12 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 10:21:17 -08:00
										 |  |  | function invalid<T>(arg: o.Expression | o.Statement | TemplateAst): never { | 
					
						
							|  |  |  |   throw new Error( | 
					
						
							|  |  |  |       `Invalid state: Visitor ${this.constructor.name} doesn't handle ${o.constructor.name}`); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function findComponent(directives: DirectiveAst[]): DirectiveAst|undefined { | 
					
						
							|  |  |  |   return directives.filter(directive => directive.directive.isComponent)[0]; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-26 17:12:39 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | interface NgContentInfo { | 
					
						
							|  |  |  |   index: number; | 
					
						
							|  |  |  |   selector?: R3CssSelector; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ContentProjectionVisitor extends RecursiveTemplateAstVisitor { | 
					
						
							|  |  |  |   private index = 1; | 
					
						
							|  |  |  |   constructor( | 
					
						
							|  |  |  |       private projectionMap: Map<NgContentAst, NgContentInfo>, | 
					
						
							|  |  |  |       private ngContentSelectors: string[]) { | 
					
						
							|  |  |  |     super(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitNgContent(ast: NgContentAst) { | 
					
						
							|  |  |  |     const selectorText = this.ngContentSelectors[ast.index]; | 
					
						
							|  |  |  |     selectorText != null || error(`could not find selector for index ${ast.index} in ${ast}`); | 
					
						
							|  |  |  |     if (!selectorText || selectorText === '*') { | 
					
						
							|  |  |  |       this.projectionMap.set(ast, {index: 0}); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       const cssSelectors = CssSelector.parse(selectorText); | 
					
						
							|  |  |  |       this.projectionMap.set( | 
					
						
							|  |  |  |           ast, {index: this.index++, selector: parseSelectorsToR3Selector(cssSelectors)}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getContentProjection(asts: TemplateAst[], ngContentSelectors: string[]) { | 
					
						
							|  |  |  |   const projectIndexMap = new Map<NgContentAst, NgContentInfo>(); | 
					
						
							|  |  |  |   const visitor = new ContentProjectionVisitor(projectIndexMap, ngContentSelectors); | 
					
						
							|  |  |  |   templateVisitAll(visitor, asts); | 
					
						
							|  |  |  |   return projectIndexMap; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These are a copy the CSS types from core/src/render3/interfaces/projection.ts
 | 
					
						
							|  |  |  | // They are duplicated here as they cannot be directly referenced from core.
 | 
					
						
							|  |  |  | type R3SimpleCssSelector = (string | null)[]; | 
					
						
							|  |  |  | type R3CssSelectorWithNegations = | 
					
						
							|  |  |  |     [R3SimpleCssSelector, null] | [R3SimpleCssSelector, R3SimpleCssSelector]; | 
					
						
							|  |  |  | type R3CssSelector = R3CssSelectorWithNegations[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function parserSelectorToSimpleSelector(selector: CssSelector): R3SimpleCssSelector { | 
					
						
							|  |  |  |   const classes = | 
					
						
							|  |  |  |       selector.classNames && selector.classNames.length ? ['class', ...selector.classNames] : []; | 
					
						
							|  |  |  |   return [selector.element, ...selector.attrs, ...classes]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function parserSelectorToR3Selector(selector: CssSelector): R3CssSelectorWithNegations { | 
					
						
							|  |  |  |   const positive = parserSelectorToSimpleSelector(selector); | 
					
						
							|  |  |  |   const negative = selector.notSelectors && selector.notSelectors.length && | 
					
						
							|  |  |  |       parserSelectorToSimpleSelector(selector.notSelectors[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return negative ? [positive, negative] : [positive, null]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function parseSelectorsToR3Selector(selectors: CssSelector[]): R3CssSelector { | 
					
						
							|  |  |  |   return selectors.map(parserSelectorToR3Selector); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function asLiteral(value: any): o.Expression { | 
					
						
							|  |  |  |   if (Array.isArray(value)) { | 
					
						
							|  |  |  |     return o.literalArr(value.map(asLiteral)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return o.literal(value, o.INFERRED_TYPE); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-29 10:36:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 10:54:00 -08:00
										 |  |  | function mapToExpression(map: {[key: string]: any}, quoted = false): o.Expression { | 
					
						
							|  |  |  |   return o.literalMap( | 
					
						
							|  |  |  |       Object.getOwnPropertyNames(map).map(key => ({key, quoted, value: asLiteral(map[key])}))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parse i18n metas like:
 | 
					
						
							|  |  |  | // - "@@id",
 | 
					
						
							|  |  |  | // - "description[@@id]",
 | 
					
						
							|  |  |  | // - "meaning|description[@@id]"
 | 
					
						
							|  |  |  | function parseI18nMeta(i18n?: string): {description?: string, id?: string, meaning?: string} { | 
					
						
							|  |  |  |   let meaning: string|undefined; | 
					
						
							|  |  |  |   let description: string|undefined; | 
					
						
							|  |  |  |   let id: string|undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (i18n) { | 
					
						
							|  |  |  |     // TODO(vicb): figure out how to force a message ID with closure ?
 | 
					
						
							|  |  |  |     const idIndex = i18n.indexOf(ID_SEPARATOR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const descIndex = i18n.indexOf(MEANING_SEPARATOR); | 
					
						
							|  |  |  |     let meaningAndDesc: string; | 
					
						
							|  |  |  |     [meaningAndDesc, id] = | 
					
						
							|  |  |  |         (idIndex > -1) ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, '']; | 
					
						
							|  |  |  |     [meaning, description] = (descIndex > -1) ? | 
					
						
							|  |  |  |         [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : | 
					
						
							|  |  |  |         ['', meaningAndDesc]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return {description, id, meaning}; | 
					
						
							|  |  |  | } |