/** * @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 */ import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenReference} from '@angular/compiler/src/compile_metadata'; import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry'; import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry'; import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '@angular/compiler/src/template_parser/template_ast'; import {TEMPLATE_TRANSFORMS, TemplateParser, splitClasses} from '@angular/compiler/src/template_parser/template_parser'; import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings'; import {SchemaMetadata, SecurityContext} from '@angular/core'; import {Console} from '@angular/core/src/console'; import {TestBed, inject} from '@angular/core/testing'; import {Identifiers, createIdentifierToken, identifierToken} from '../../src/identifiers'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config'; import {MockSchemaRegistry} from '../../testing/index'; import {unparse} from '../expression_parser/unparser'; const someModuleUrl = 'package:someModule'; const MOCK_SCHEMA_REGISTRY = [{ provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry( {'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false}, ['onEvent'], ['onEvent']), }]; function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}): CompileTypeMetadata { return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []}; } export function main() { let ngIf: CompileDirectiveSummary; let parse: ( template: string, directives: CompileDirectiveSummary[], pipes?: CompilePipeSummary[], schemas?: SchemaMetadata[]) => TemplateAst[]; let console: ArrayConsole; function commonBeforeEach() { beforeEach(() => { console = new ArrayConsole(); TestBed.configureCompiler({providers: [{provide: Console, useValue: console}]}); }); beforeEach(inject([TemplateParser], (parser: TemplateParser) => { const someAnimation = new CompileAnimationEntryMetadata('someAnimation', []); const someTemplate = new CompileTemplateMetadata({animations: [someAnimation]}); const component = CompileDirectiveMetadata.create({ selector: 'root', template: someTemplate, type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Root'}}), isComponent: true }); ngIf = CompileDirectiveMetadata .create({ selector: '[ngIf]', template: someTemplate, type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'NgIf'}}), inputs: ['ngIf'] }) .toSummary(); parse = (template: string, directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[] = null, schemas: SchemaMetadata[] = []): TemplateAst[] => { if (pipes === null) { pipes = []; } return parser.parse(component, template, directives, pipes, schemas, 'TestComp') .template; }; })); } describe('TemplateAstVisitor', () => { function expectVisitedNode(visitor: TemplateAstVisitor, node: TemplateAst) { expect(node.visit(visitor, null)).toEqual(node); } it('should visit NgContentAst', () => { expectVisitedNode( new class extends NullVisitor{visitNgContent(ast: NgContentAst, context: any): any{return ast;}}, new NgContentAst(0, 0, null)); }); it('should visit EmbeddedTemplateAst', () => { expectVisitedNode( new class extends NullVisitor{ visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any) { return ast; } }, new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null)); }); it('should visit ElementAst', () => { expectVisitedNode( new class extends NullVisitor{visitElement(ast: ElementAst, context: any) { return ast; }}, new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null, null)); }); it('should visit RefererenceAst', () => { expectVisitedNode( new class extends NullVisitor{visitReference(ast: ReferenceAst, context: any): any{return ast;}}, new ReferenceAst('foo', null, null)); }); it('should visit VariableAst', () => { expectVisitedNode( new class extends NullVisitor{visitVariable(ast: VariableAst, context: any): any{return ast;}}, new VariableAst('foo', 'bar', null)); }); it('should visit BoundEventAst', () => { expectVisitedNode( new class extends NullVisitor{visitEvent(ast: BoundEventAst, context: any): any{return ast;}}, new BoundEventAst('foo', 'bar', 'goo', null, null)); }); it('should visit BoundElementPropertyAst', () => { expectVisitedNode( new class extends NullVisitor{ visitElementProperty(ast: BoundElementPropertyAst, context: any): any{return ast;} }, new BoundElementPropertyAst('foo', null, null, false, null, 'bar', null)); }); it('should visit AttrAst', () => { expectVisitedNode( new class extends NullVisitor{visitAttr(ast: AttrAst, context: any): any{return ast;}}, new AttrAst('foo', 'bar', null)); }); it('should visit BoundTextAst', () => { expectVisitedNode( new class extends NullVisitor{visitBoundText(ast: BoundTextAst, context: any): any{return ast;}}, new BoundTextAst(null, 0, null)); }); it('should visit TextAst', () => { expectVisitedNode( new class extends NullVisitor{visitText(ast: TextAst, context: any): any{return ast;}}, new TextAst('foo', 0, null)); }); it('should visit DirectiveAst', () => { expectVisitedNode( new class extends NullVisitor{visitDirective(ast: DirectiveAst, context: any): any{return ast;}}, new DirectiveAst(null, [], [], [], null)); }); it('should visit DirectiveAst', () => { expectVisitedNode( new class extends NullVisitor{ visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any{return ast;} }, new BoundDirectivePropertyAst('foo', 'bar', null, null)); }); it('should skip the typed call of a visitor if visit() returns a truthy value', () => { const visitor = new class extends ThrowingVisitor { visit(ast: TemplateAst, context: any): any { return true; } }; const nodes: TemplateAst[] = [ new NgContentAst(0, 0, null), new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null), new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null, null), new ReferenceAst('foo', null, null), new VariableAst('foo', 'bar', null), new BoundEventAst('foo', 'bar', 'goo', null, null), new BoundElementPropertyAst('foo', null, null, false, null, 'bar', null), new AttrAst('foo', 'bar', null), new BoundTextAst(null, 0, null), new TextAst('foo', 0, null), new DirectiveAst(null, [], [], [], null), new BoundDirectivePropertyAst('foo', 'bar', null, null) ]; const result = templateVisitAll(visitor, nodes, null); expect(result).toEqual(new Array(nodes.length).fill(true)); }); }); describe('TemplateParser template transform', () => { beforeEach(() => { TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); }); beforeEach(() => { TestBed.configureCompiler({ providers: [{provide: TEMPLATE_TRANSFORMS, useValue: new FooAstTransformer(), multi: true}] }); }); describe('single', () => { commonBeforeEach(); it('should transform TemplateAST', () => { expect(humanizeTplAst(parse('