fix(ivy): enable packages/core/test/render3 test for AoT (#26863)

PR Close #26863
This commit is contained in:
Miško Hevery 2018-10-30 17:03:01 -07:00 committed by Kara Erickson
parent 516af6c531
commit c13f46c7c5
23 changed files with 54 additions and 6138 deletions

View File

@ -9,11 +9,10 @@ ng_module(
srcs = ["index.ts"], srcs = ["index.ts"],
tags = [ tags = [
"ivy-only", "ivy-only",
"no-ivy-jit",
], ],
deps = [ deps = [
"//packages/core", "//packages/core",
"//packages/platform-browser-dynamic", "//packages/platform-browser",
], ],
) )
@ -28,12 +27,11 @@ ng_rollup_bundle(
entry_point = "packages/core/test/bundling/hello_world_r2/index.js", entry_point = "packages/core/test/bundling/hello_world_r2/index.js",
tags = [ tags = [
"ivy-only", "ivy-only",
"no-ivy-jit",
], ],
deps = [ deps = [
":hello_world", ":hello_world",
"//packages/core", "//packages/core",
"//packages/platform-browser-dynamic", "//packages/platform-browser",
], ],
) )
@ -43,7 +41,6 @@ ts_library(
srcs = glob(["*_spec.ts"]), srcs = glob(["*_spec.ts"]),
tags = [ tags = [
"ivy-only", "ivy-only",
"no-ivy-jit",
], ],
deps = [ deps = [
"//packages:types", "//packages:types",
@ -63,7 +60,6 @@ jasmine_node_test(
], ],
tags = [ tags = [
"ivy-only", "ivy-only",
"no-ivy-jit",
], ],
deps = [":test_lib"], deps = [":test_lib"],
) )

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Component, NgModule} from '@angular/core'; import {Component, NgModule} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {platformBrowser} from '@angular/platform-browser';
@Component({selector: 'hello-world', template: 'Hello World!'}) @Component({selector: 'hello-world', template: 'Hello World!'})
export class HelloWorldComponent { export class HelloWorldComponent {
@ -16,4 +16,4 @@ export class HelloWorldComponent {
export class HelloWorldModule { export class HelloWorldModule {
} }
platformBrowserDynamic().bootstrapModule(HelloWorldModule); platformBrowser().bootstrapModule(HelloWorldModule);

View File

@ -61,7 +61,6 @@ jasmine_node_test(
"angular/packages/core/test/render3/load_domino", "angular/packages/core/test/render3/load_domino",
], ],
tags = [ tags = [
"fixme-ivy-aot",
"fixme-ivy-jit", "fixme-ivy-jit",
], ],
deps = [ deps = [
@ -73,7 +72,6 @@ jasmine_node_test(
ts_web_test_suite( ts_web_test_suite(
name = "render3_web", name = "render3_web",
tags = [ tags = [
"fixme-ivy-aot",
"fixme-ivy-jit", "fixme-ivy-jit",
], ],
deps = [ deps = [

View File

@ -1,961 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDef} from '../../../src/render3/interfaces/definition';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('components & directives', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
type $any$ = any;
type $number$ = number;
it('should instantiate directives', () => {
type $ChildComponent$ = ChildComponent;
type $MyComponent$ = MyComponent;
const log: string[] = [];
@Component({selector: 'child', template: 'child-view'})
class ChildComponent {
constructor() { log.push('ChildComponent'); }
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: ChildComponent,
selectors: [['child']],
factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); },
consts: 1,
vars: 0,
template: function ChildComponent_Template(rf: $RenderFlags$, ctx: $ChildComponent$) {
if (rf & 1) {
$r3$.ɵtext(0, 'child-view');
}
}
});
// /NORMATIVE
}
@Directive({
selector: '[some-directive]',
})
class SomeDirective {
constructor() { log.push('SomeDirective'); }
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [['', 'some-directive', '']],
factory: function SomeDirective_Factory(t) { return new (t || SomeDirective)(); },
});
// /NORMATIVE
}
// Important: keep arrays outside of function to not create new instances.
// NORMATIVE
const $e0_attrs$ = ['some-directive', ''];
// /NORMATIVE
@Component({selector: 'my-component', template: `<child some-directive></child>!`})
class MyComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'child', $e0_attrs$);
$r3$.ɵtext(1, '!');
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyComponent.ngComponentDef as ComponentDef<any>).directiveDefs =
[(ChildComponent.ngComponentDef as ComponentDef<any>), SomeDirective.ngDirectiveDef];
// /NON-NORMATIVE
expect(renderComp(MyComponent)).toEqual('<child some-directive="">child-view</child>!');
expect(log).toEqual(['ChildComponent', 'SomeDirective']);
});
it('should support host bindings', () => {
type $MyApp$ = MyApp;
@Directive({selector: '[hostBindingDir]'})
class HostBindingDir {
@HostBinding('id') dirId = 'some id';
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: HostBindingDir,
selectors: [['', 'hostBindingDir', '']],
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵelementProperty(
elIndex, 'id', $r3$.ɵbind($r3$.ɵload<HostBindingDir>(dirIndex).dirId));
}
});
// /NORMATIVE
}
const $e0_attrs$ = ['hostBindingDir', ''];
@Component({
selector: 'my-app',
template: `
<div hostBindingDir></div>
`
})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
}
}
});
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs = [HostBindingDir.ngDirectiveDef];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<div hostbindingdir="" id="some id"></div>`);
});
it('should support host listeners', () => {
type $MyApp$ = MyApp;
@Directive({selector: '[hostlistenerDir]'})
class HostListenerDir {
@HostListener('click')
onClick() {}
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
selectors: [['', 'hostListenerDir', '']],
type: HostListenerDir,
factory: function HostListenerDir_Factory() {
const $dir$ = new HostListenerDir();
$r3$.ɵlistener(
'click', function HostListenerDir_click_Handler(event: any) { $dir$.onClick(); });
return $dir$;
},
});
// /NORMATIVE
}
const $e0_attrs$ = ['hostListenerDir', ''];
@Component({
selector: 'my-app',
template: `
<button hostListenerDir>Click</button>
`
})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'button', $e0_attrs$);
$r3$.ɵtext(1, 'Click');
$r3$.ɵelementEnd();
}
}
});
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs = [HostListenerDir.ngDirectiveDef];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<button hostlistenerdir="">Click</button>`);
});
it('should support setting of host attributes', () => {
type $MyApp$ = MyApp;
@Directive({selector: '[hostAttributeDir]', host: {'role': 'listbox'}})
class HostAttributeDir {
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
selectors: [['', 'hostAttributeDir', '']],
type: HostAttributeDir,
factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); },
attributes: ['role', 'listbox']
});
// /NORMATIVE
}
const $e0_attrs$ = ['hostAttributeDir', ''];
@Component({
selector: 'my-app',
template: `
<div hostAttributeDir></div>
`
})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
}
}
});
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs = [HostAttributeDir.ngDirectiveDef];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<div hostattributedir="" role="listbox"></div>`);
});
it('should support bindings of host attributes', () => {
type $MyApp$ = MyApp;
@Directive({selector: '[hostBindingDir]'})
class HostBindingDir {
@HostBinding('attr.aria-label') label = 'some label';
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: HostBindingDir,
selectors: [['', 'hostBindingDir', '']],
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵelementAttribute(
elIndex, 'aria-label', $r3$.ɵbind($r3$.ɵload<HostBindingDir>(dirIndex).label));
}
});
// /NORMATIVE
}
const $e0_attrs$ = ['hostBindingDir', ''];
@Component({
selector: 'my-app',
template: `
<div hostBindingDir></div>
`
})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$);
}
}
});
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs = [HostBindingDir.ngDirectiveDef];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<div aria-label="some label" hostbindingdir=""></div>`);
});
it('should support onPush components', () => {
type $MyApp$ = MyApp;
type $MyComp$ = MyComp;
@Component({
selector: 'my-comp',
template: `
{{ name }}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
class MyComp {
// TODO(issue/24571): remove '!'.
@Input() name !: string;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵbind(ctx.name));
}
},
inputs: {name: 'name'},
changeDetection: ChangeDetectionStrategy.OnPush
});
// /NORMATIVE
}
@Component({
selector: 'my-app',
template: `
<my-comp [name]="name"></my-comp>
`
})
class MyApp {
name = 'some name';
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'name', $r3$.ɵbind(ctx.name));
}
}
});
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-comp>some name</my-comp>`);
});
xit('should support structural directives', () => {
type $MyComponent$ = MyComponent;
function C1(rf1: $RenderFlags$, ctx1: $any$) {
if (rf1 & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
if (rf1 & 2) {
const $comp$ = $r3$.ɵnextContext();
const $foo$ = $r3$.ɵreference(1);
$r3$.ɵtextBinding(1, $r3$.ɵinterpolation2('', $comp$.salutation, ' ', $foo$, ''));
}
}
const log: string[] = [];
@Directive({
selector: '[if]',
})
class IfDirective {
constructor(template: TemplateRef<any>) { log.push('ifDirective'); }
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [['', 'if', '']],
factory: function IfDirective_Factory(t) {
return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef as any));
},
});
// /NORMATIVE
}
// Important: keep arrays outside of function to not create new instances.
// NORMATIVE
const $e0_locals$ = ['foo', ''];
// /NORMATIVE
@Component(
{selector: 'my-component', template: `<ul #foo><li *if>{{salutation}} {{foo}}</li></ul>`})
class MyComponent {
salutation = 'Hello';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul', null, $e0_locals$);
$r3$.ɵtemplate(2, C1, 2, 1, '', ['if', '']);
$r3$.ɵelementEnd();
}
}
});
// /NORMATIVE
}
expect(renderComp(MyComponent)).toEqual('<child some-directive="">child-view</child>!');
expect(log).toEqual(['ChildComponent', 'SomeDirective']);
});
describe('value composition', () => {
type $MyArrayComp$ = MyArrayComp;
@Component({
selector: 'my-array-comp',
template: `
{{ names[0] }} {{ names[1] }}
`
})
class MyArrayComp {
// TODO(issue/24571): remove '!'.
@Input() names !: string[];
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyArrayComp,
selectors: [['my-array-comp']],
factory: function MyArrayComp_Factory(t) { return new (t || MyArrayComp)(); },
consts: 1,
vars: 2,
template: function MyArrayComp_Template(rf: $RenderFlags$, ctx: $MyArrayComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵinterpolation2('', ctx.names[0], ' ', ctx.names[1], ''));
}
},
inputs: {names: 'names'}
});
}
it('should support array literals of constants', () => {
type $MyApp$ = MyApp;
// NORMATIVE
const $e0_arr$ = ['Nancy', 'Bess'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-array-comp [names]="['Nancy', 'Bess']"></my-array-comp>
`
})
class MyApp {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'names', rf & 1 ? $e0_arr$ : $r3$.ɵNO_CHANGE);
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyArrayComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-array-comp>Nancy Bess</my-array-comp>`);
});
it('should support array literals of constants inside function calls', () => {
type $MyApp$ = MyApp;
// NORMATIVE
const $e0_ff$ = () => ['Nancy', 'Bess'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-array-comp [names]="someFn(['Nancy', 'Bess'])"></my-array-comp>
`
})
class MyApp {
someFn(arr: string[]): string[] {
arr[0] = arr[0].toUpperCase();
return arr;
}
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'names', $r3$.ɵbind(ctx.someFn($r3$.ɵpureFunction0(1, $e0_ff$))));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyArrayComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-array-comp>NANCY Bess</my-array-comp>`);
});
it('should support array literals of constants inside expressions', () => {
type $MyApp$ = MyApp;
type $MyComp$ = MyComp;
@Component({selector: 'my-comp', template: `{{ num }}`})
class MyComp {
// TODO(issue/24571): remove '!'.
num !: number;
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
}
if (rf & 2) {
// clang-format wants to break this line by changing the second 'ɵ' to an invalid
// unicode sequence.
// clang-format off
$r3$.ɵtextBinding(0, $r3$.ɵbind(ctx.num));
// clang-format on
}
},
inputs: {num: 'num'}
});
}
// NORMATIVE
const $e0_ff$ = () => ['Nancy', 'Bess'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-comp [num]="['Nancy', 'Bess'].length + 1"></my-comp>
`
})
class MyApp {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'num', $r3$.ɵbind($r3$.ɵpureFunction0(1, $e0_ff$).length + 1));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-comp>3</my-comp>`);
});
it('should support array literals', () => {
type $MyApp$ = MyApp;
// NORMATIVE
const $e0_ff$ = (v: any) => ['Nancy', v];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-array-comp [names]="['Nancy', customName]"></my-array-comp>
`
})
class MyApp {
customName = 'Bess';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 3,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'names', $r3$.ɵbind($r3$.ɵpureFunction1(1, $e0_ff$, ctx.customName)));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyArrayComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-array-comp>Nancy Bess</my-array-comp>`);
});
it('should support 9+ bindings in array literals', () => {
type $MyComp$ = MyComp;
@Component({
selector: 'my-comp',
template: `
{{ names[0] }}
{{ names[1] }}
{{ names[3] }}
{{ names[4] }}
{{ names[5] }}
{{ names[6] }}
{{ names[7] }}
{{ names[8] }}
{{ names[9] }}
{{ names[10] }}
{{ names[11] }}
`
})
class MyComp {
// TODO(issue/24571): remove '!'.
@Input() names !: string[];
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 12,
vars: 12,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
$r3$.ɵtext(1);
$r3$.ɵtext(2);
$r3$.ɵtext(3);
$r3$.ɵtext(4);
$r3$.ɵtext(5);
$r3$.ɵtext(6);
$r3$.ɵtext(7);
$r3$.ɵtext(8);
$r3$.ɵtext(9);
$r3$.ɵtext(10);
$r3$.ɵtext(11);
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵbind(ctx.names[0]));
$r3$.ɵtextBinding(1, $r3$.ɵbind(ctx.names[1]));
$r3$.ɵtextBinding(2, $r3$.ɵbind(ctx.names[2]));
$r3$.ɵtextBinding(3, $r3$.ɵbind(ctx.names[3]));
$r3$.ɵtextBinding(4, $r3$.ɵbind(ctx.names[4]));
$r3$.ɵtextBinding(5, $r3$.ɵbind(ctx.names[5]));
$r3$.ɵtextBinding(6, $r3$.ɵbind(ctx.names[6]));
$r3$.ɵtextBinding(7, $r3$.ɵbind(ctx.names[7]));
$r3$.ɵtextBinding(8, $r3$.ɵbind(ctx.names[8]));
$r3$.ɵtextBinding(9, $r3$.ɵbind(ctx.names[9]));
$r3$.ɵtextBinding(10, $r3$.ɵbind(ctx.names[10]));
$r3$.ɵtextBinding(11, $r3$.ɵbind(ctx.names[11]));
}
},
inputs: {names: 'names'}
});
}
// NORMATIVE
const $e0_ff$ =
(v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => ['start-', v0, v1, v2, v3, v4, '-middle-', v5, v6, v7, v8, '-end'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-comp [names]="['start-', n0, n1, n2, n3, n4, '-middle-', n5, n6, n7, n8, '-end']">
</my-comp>
`
})
class MyApp {
n0 = 'a';
n1 = 'b';
n2 = 'c';
n3 = 'd';
n4 = 'e';
n5 = 'f';
n6 = 'g';
n7 = 'h';
n8 = 'i';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 11,
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'names',
$r3$.ɵbind($r3$.ɵpureFunctionV(
1, $e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8])));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(MyComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<my-comp>start-abcde-middle-fghi-end</my-comp>`);
});
it('should support object literals', () => {
type $ObjectComp$ = ObjectComp;
type $MyApp$ = MyApp;
@Component({
selector: 'object-comp',
template: `
<p> {{ config['duration'] }} </p>
<p> {{ config.animation }} </p>
`
})
class ObjectComp {
// TODO(issue/24571): remove '!'.
config !: {[key: string]: any};
static ngComponentDef = $r3$.ɵdefineComponent({
type: ObjectComp,
selectors: [['object-comp']],
factory: function ObjectComp_Factory(t) { return new (t || ObjectComp)(); },
consts: 4,
vars: 2,
template: function ObjectComp_Template(rf: $RenderFlags$, ctx: $ObjectComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'p');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(2, 'p');
$r3$.ɵtext(3);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵtextBinding(1, $r3$.ɵbind(ctx.config['duration']));
$r3$.ɵtextBinding(3, $r3$.ɵbind(ctx.config.animation));
}
},
inputs: {config: 'config'}
});
}
// NORMATIVE
const $e0_ff$ = (v: any) => { return {'duration': 500, animation: v}; };
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<object-comp [config]="{'duration': 500, animation: name}"></object-comp>
`
})
class MyApp {
name = 'slide';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 3,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'object-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'config', $r3$.ɵbind($r3$.ɵpureFunction1(1, $e0_ff$, ctx.name)));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(ObjectComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp)).toEqual(`<object-comp><p>500</p><p>slide</p></object-comp>`);
});
it('should support expressions nested deeply in object/array literals', () => {
type $NestedComp$ = NestedComp;
type $MyApp$ = MyApp;
@Component({
selector: 'nested-comp',
template: `
<p> {{ config.animation }} </p>
<p> {{config.actions[0].opacity }} </p>
<p> {{config.actions[1].duration }} </p>
`
})
class NestedComp {
// TODO(issue/24571): remove '!'.
config !: {[key: string]: any};
static ngComponentDef = $r3$.ɵdefineComponent({
type: NestedComp,
selectors: [['nested-comp']],
factory: function NestedComp_Factory(t) { return new (t || NestedComp)(); },
consts: 6,
vars: 3,
template: function NestedComp_Template(rf: $RenderFlags$, ctx: $NestedComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'p');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(2, 'p');
$r3$.ɵtext(3);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(4, 'p');
$r3$.ɵtext(5);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵtextBinding(1, $r3$.ɵbind(ctx.config.animation));
$r3$.ɵtextBinding(3, $r3$.ɵbind(ctx.config.actions[0].opacity));
$r3$.ɵtextBinding(5, $r3$.ɵbind(ctx.config.actions[1].duration));
}
},
inputs: {config: 'config'}
});
}
// NORMATIVE
const $e0_ff$ = (v: any) => { return {opacity: 1, duration: v}; };
const $c0$ = {opacity: 0, duration: 0};
const $e0_ff_1$ = (v: any) => [$c0$, v];
const $e0_ff_2$ = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<nested-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1, duration: duration }]}">
</nested-comp>
`
})
class MyApp {
name = 'slide';
duration = 100;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 8,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'nested-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(
0, 'config',
$r3$.ɵbind($r3$.ɵpureFunction2(
5, $e0_ff_2$, ctx.name,
$r3$.ɵpureFunction1(
3, $e0_ff_1$, $r3$.ɵpureFunction1(1, $e0_ff$, ctx.duration)))));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE (done by defineNgModule)
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[(NestedComp.ngComponentDef as ComponentDef<any>)];
// /NON-NORMATIVE
expect(renderComp(MyApp))
.toEqual(`<nested-comp><p>slide</p><p>0</p><p>100</p></nested-comp>`);
});
});
});
function renderComp<T>(type: $r3$.ɵComponentType<T>): string {
return toHtml(renderComponent(type));
}

View File

@ -1,98 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
/// See: `normative.md`
describe('content projection', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should support content projection', () => {
type $SimpleComponent$ = SimpleComponent;
type $ComplexComponent$ = ComplexComponent;
type $MyApp$ = MyApp;
@Component({selector: 'simple', template: `<div><ng-content></ng-content></div>`})
class SimpleComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: SimpleComponent,
selectors: [['simple']],
factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); },
consts: 1,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) {
if (rf & 1) {
$r3$.ɵprojectionDef();
$r3$.ɵelement(0, 'div');
$r3$.ɵprojection(1);
}
}
});
// /NORMATIVE
}
// NORMATIVE
const $pD_0P$: $r3$.ɵCssSelectorList[] =
[[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]];
const $pD_0R$: string[] = ['span[title=toFirst]', 'span[title=toSecond]'];
// /NORMATIVE
@Component({
selector: 'complex',
template: `
<div id="first"><ng-content select="span[title=toFirst]"></ng-content></div>
<div id="second"><ng-content select="span[title=toSecond]"></ng-content></div>`
})
class ComplexComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: ComplexComponent,
selectors: [['complex']],
factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); },
consts: 4,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) {
if (rf & 1) {
$r3$.ɵprojectionDef($pD_0P$, $pD_0R$);
$r3$.ɵelement(0, 'div', ['id', 'first']);
$r3$.ɵprojection(1, 1);
$r3$.ɵelement(2, 'div', ['id', 'second']);
$r3$.ɵprojection(3, 2);
}
}
});
// /NORMATIVE
}
@Component({
selector: 'my-app',
template: `<simple>content</simple>
<complex></complex>`
})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'simple');
$r3$.ɵtext(1, 'content');
$r3$.ɵelementEnd();
}
},
directives: () => [SimpleComponent]
});
}
});
});

View File

@ -1,445 +0,0 @@
/**
* @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 {Component} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {AttributeMarker} from '../../../src/render3';
import {ComponentDef, InitialStylingFlags} from '../../../src/render3/interfaces/definition';
import {ComponentFixture, renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('elements', () => {
// Saving type as $any$, etc to simplify testing for compiler, as types aren't saved
type $any$ = any;
type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should translate DOM structure', () => {
type $MyComponent$ = MyComponent;
// Important: keep arrays outside of function to not create new instances.
const $e0_attrs$ = ['class', 'my-app', 'title', 'Hello'];
@Component({
selector: 'my-component',
template: `<div class="my-app" title="Hello">Hello <b>World</b>!</div>`
})
class MyComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 5,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div', $e0_attrs$);
$r3$.ɵtext(1, 'Hello ');
$r3$.ɵelementStart(2, 'b');
$r3$.ɵtext(3, 'World');
$r3$.ɵelementEnd();
$r3$.ɵtext(4, '!');
$r3$.ɵelementEnd();
}
}
});
// /NORMATIVE
}
expect(toHtml(renderComponent(MyComponent)))
.toEqual('<div class="my-app" title="Hello">Hello <b>World</b>!</div>');
});
it('should support local refs', () => {
type $LocalRefComp$ = LocalRefComp;
class Dir {
value = 'one';
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: Dir,
selectors: [['', 'dir', '']],
factory: function DirA_Factory(t) { return new (t || Dir)(); },
exportAs: 'dir'
});
}
// NORMATIVE
const $e0_attrs$ = ['dir', ''];
const $e0_locals$ = ['dir', 'dir', 'foo', ''];
// /NORMATIVE
@Component({
selector: 'local-ref-comp',
template: `
<div dir #dir="dir" #foo></div>
{{ dir.value }} - {{ foo.tagName }}
`
})
class LocalRefComp {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: LocalRefComp,
selectors: [['local-ref-comp']],
factory: function LocalRefComp_Factory(t) { return new (t || LocalRefComp)(); },
consts: 4,
vars: 2,
template: function LocalRefComp_Template(rf: $RenderFlags$, ctx: $LocalRefComp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div', $e0_attrs$, $e0_locals$);
$r3$.ɵtext(3);
}
if (rf & 2) {
const $tmp$ = $r3$.ɵreference(1) as any;
const $tmp_2$ = $r3$.ɵreference(2) as any;
$r3$.ɵtextBinding(
3, $r3$.ɵinterpolation2(' ', $tmp$.value, ' - ', $tmp_2$.tagName, ''));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(LocalRefComp.ngComponentDef as ComponentDef<any>).directiveDefs = () => [Dir.ngDirectiveDef];
// /NON-NORMATIVE
const fixture = new ComponentFixture(LocalRefComp);
expect(fixture.html).toEqual(`<div dir=""></div> one - DIV`);
});
it('should support listeners', () => {
type $ListenerComp$ = ListenerComp;
@Component({
selector: 'listener-comp',
template:
`<button (click)="onClick()" (keypress)="onPress($event); onPress2($event)">Click</button>`
})
class ListenerComp {
onClick() {}
onPress(e: Event) {}
onPress2(e: Event) {}
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: ListenerComp,
selectors: [['listener-comp']],
factory: function ListenerComp_Factory(t) { return new (t || ListenerComp)(); },
consts: 2,
vars: 0,
template: function ListenerComp_Template(rf: $RenderFlags$, ctx: $ListenerComp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'button');
$r3$.ɵlistener(
'click', function ListenerComp_click_Handler() { return ctx.onClick(); });
$r3$.ɵlistener('keypress', function ListenerComp_keypress_Handler($event: $any$) {
ctx.onPress($event);
return ctx.onPress2($event);
});
$r3$.ɵtext(1, 'Click');
$r3$.ɵelementEnd();
}
}
});
// /NORMATIVE
}
const listenerComp = renderComponent(ListenerComp);
expect(toHtml(listenerComp)).toEqual('<button>Click</button>');
});
it('should support namespaced attributes', () => {
type $MyComponent$ = MyComponent;
// Important: keep arrays outside of function to not create new instances.
const $e0_attrs$ = [
// class="my-app"
'class',
'my-app',
// foo:bar="baz"
AttributeMarker.NamespaceURI,
'http://someuri/foo',
'foo:bar',
'baz',
// title="Hello"
'title',
'Hello',
// foo:qux="quacks"
AttributeMarker.NamespaceURI,
'http://someuri/foo',
'foo:qux',
'quacks',
];
@Component({
selector: 'my-component',
template:
`<div xmlns:foo="http://someuri/foo" class="my-app" foo:bar="baz" title="Hello" foo:qux="quacks">Hello <b>World</b>!</div>`
})
class MyComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 5,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div', $e0_attrs$);
$r3$.ɵtext(1, 'Hello ');
$r3$.ɵelementStart(2, 'b');
$r3$.ɵtext(3, 'World');
$r3$.ɵelementEnd();
$r3$.ɵtext(4, '!');
$r3$.ɵelementEnd();
}
}
});
// /NORMATIVE
}
expect(toHtml(renderComponent(MyComponent)))
.toEqual(
'<div class="my-app" foo:bar="baz" foo:qux="quacks" title="Hello">Hello <b>World</b>!</div>');
});
describe('bindings', () => {
it('should bind to property', () => {
type $MyComponent$ = MyComponent;
@Component({selector: 'my-component', template: `<div [id]="someProperty"></div>`})
class MyComponent {
someProperty: string = 'initial';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div');
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'id', $r3$.ɵbind(ctx.someProperty));
}
}
});
// /NORMATIVE
}
const comp = renderComponent(MyComponent);
expect(toHtml(comp)).toEqual('<div id="initial"></div>');
comp.someProperty = 'changed';
$r3$.ɵdetectChanges(comp);
expect(toHtml(comp)).toEqual('<div id="changed"></div>');
});
it('should bind to attribute', () => {
type $MyComponent$ = MyComponent;
@Component({selector: 'my-component', template: `<div [attr.title]="someAttribute"></div>`})
class MyComponent {
someAttribute: string = 'initial';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelement(0, 'div');
}
if (rf & 2) {
$r3$.ɵelementAttribute(0, 'title', $r3$.ɵbind(ctx.someAttribute));
}
}
});
// /NORMATIVE
}
const comp = renderComponent(MyComponent);
expect(toHtml(comp)).toEqual('<div title="initial"></div>');
comp.someAttribute = 'changed';
$r3$.ɵdetectChanges(comp);
expect(toHtml(comp)).toEqual('<div title="changed"></div>');
});
it('should bind to a specific class', () => {
const c1: (string | InitialStylingFlags | boolean)[] = ['foo'];
type $MyComponent$ = MyComponent;
@Component({selector: 'my-component', template: `<div [class.foo]="someFlag"></div>`})
class MyComponent {
someFlag: boolean = false;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 0,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStyling(c1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementClassProp(0, 0, ctx.someFlag);
$r3$.ɵelementStylingApply(0);
}
}
});
// /NORMATIVE
}
const comp = renderComponent(MyComponent);
// This is a fix for a change in how Domino renders this on the server in v2.1.0
const source = toHtml(comp);
const matches = source === '<div></div>' || source === '<div class=""></div>';
expect(matches).toBeTruthy();
comp.someFlag = true;
$r3$.ɵdetectChanges(comp);
expect(toHtml(comp)).toEqual('<div class="foo"></div>');
});
it('should bind to a specific style', () => {
type $MyComponent$ = MyComponent;
const c0 = ['color', 'width'];
@Component({
selector: 'my-component',
template: `<div [style.color]="someColor" [style.width.px]="someWidth"></div>`
})
class MyComponent {
someColor: string = 'red';
someWidth: number = 50;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 0,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStyling(null, c0);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementStyleProp(0, 0, ctx.someColor);
$r3$.ɵelementStyleProp(0, 1, ctx.someWidth, 'px');
$r3$.ɵelementStylingApply(0);
}
}
});
// /NORMATIVE
}
const comp = renderComponent(MyComponent);
expect(toHtml(comp)).toEqual('<div style="color: red; width: 50px;"></div>');
comp.someColor = 'blue';
comp.someWidth = 100;
$r3$.ɵdetectChanges(comp);
expect(toHtml(comp)).toEqual('<div style="color: blue; width: 100px;"></div>');
});
it('should bind to many and keep order', () => {
type $MyComponent$ = MyComponent;
const c0 = ['foo'];
const c1 = ['color', InitialStylingFlags.VALUES_MODE, 'color', 'red'];
@Component({
selector: 'my-component',
template:
`<div [id]="someString+1" [class.foo]="someString=='initial'" [attr.style]="'color: red;'"></div>`
})
class MyComponent {
someString: string = 'initial';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStyling(c0, c1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'id', $r3$.ɵbind(ctx.someString + 1));
$r3$.ɵelementClassProp(0, 0, ctx.someString == 'initial');
$r3$.ɵelementStylingApply(0);
}
}
});
// /NORMATIVE
}
const comp = renderComponent(MyComponent);
expect(toHtml(comp)).toEqual('<div class="foo" id="initial1" style="color: red;"></div>');
comp.someString = 'changed';
$r3$.ɵdetectChanges(comp);
expect(toHtml(comp)).toEqual('<div class="" id="changed1" style="color: red;"></div>');
});
it('should bind [class] and [style] to the element', () => {
type $StyleComponent$ = StyleComponent;
@Component(
{selector: 'style-comp', template: `<div [class]="classExp" [style]="styleExp"></div>`})
class StyleComponent {
classExp: string[]|string = 'some-name';
styleExp: {[name: string]: string} = {'background-color': 'red'};
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: StyleComponent,
selectors: [['style-comp']],
factory: function StyleComponent_Factory(t) { return new (t || StyleComponent)(); },
consts: 1,
vars: 0,
template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStyling();
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementStylingMap(0, ctx.classExp, ctx.styleExp);
$r3$.ɵelementStylingApply(0);
}
}
});
// /NORMATIVE
}
const styleFixture = new ComponentFixture(StyleComponent);
expect(styleFixture.html)
.toEqual(`<div class="some-name" style="background-color: red;"></div>`);
});
});
});

View File

@ -1,147 +0,0 @@
/**
* @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 {NgForOfContext} from '@angular/common';
import {Component} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {NgForOf} from '../common_with_def';
/// See: `normative.md`
describe('i18n', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should support html', () => {
type $MyApp$ = MyApp;
const $msg_1$ = `{$START_P}contenu{$END_P}`;
const $i18n_1$ = $r3$.ɵi18nMapping($msg_1$, [{START_P: 1}]);
@Component({selector: 'my-app', template: `<div i18n><p>content</p></div>`})
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStart(1, 'p');
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(1, $i18n_1$[0]);
}
}
});
}
});
it('should support expressions', () => {
type $MyApp$ = MyApp;
const $msg_1$ = `contenu: {$EXP_1}`;
const $i18n_1$ = $r3$.ɵi18nMapping($msg_1$, null, [{EXP_1: 1}]);
@Component({selector: 'my-app', template: `<div i18n>content: {{exp1}}</div>`})
class MyApp {
exp1 = '1';
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(1, $i18n_1$[0]);
}
if (rf & 2) {
$r3$.ɵtextBinding(3, $r3$.ɵbind(ctx.exp1));
}
}
});
}
});
it('should support expressions in attributes', () => {
type $MyApp$ = MyApp;
const $msg_1$ = `titre: {$EXP_1}`;
const $i18n_1$ = $r3$.ɵi18nExpMapping($msg_1$, {EXP_1: 1});
@Component({selector: 'my-app', template: `<div i18n><p title="title: {{exp1}}"></p></div>`})
class MyApp {
exp1 = '1';
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStart(1, 'p');
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'title', $r3$.ɵi18nInterpolation1($i18n_1$, ctx.exp1));
}
}
});
}
});
it('should support embedded templates', () => {
type $MyApp$ = MyApp;
const $msg_1$ = `{$START_LI}valeur: {$EXP_1}!{$END_LI}`;
const $i18n_1$ = $r3$.ɵi18nMapping(
$msg_1$, [{START_LI: 1}, {START_LI: 0}], [null, {EXP_1: 1}], ['START_LI']);
function liTemplate(rf1: $RenderFlags$, row: NgForOfContext<string>) {
if (rf1 & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(0, $i18n_1$[1]);
}
if (rf1 & 2) {
$r3$.ɵtextBinding(1, $r3$.ɵbind(row.$implicit));
}
}
@Component({
selector: 'my-app',
template: `<ul i18n><li *ngFor="let item of items">value: {{item}}</li></ul>`
})
class MyApp {
items: string[] = ['1', '2'];
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
selectors: [['my-app']],
consts: 2,
vars: 1,
template: (rf: $RenderFlags$, myApp: $MyApp$) => {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, liTemplate, 2, 1, null, ['ngForOf', '']);
$r3$.ɵelementEnd();
$r3$.ɵi18nApply(1, $i18n_1$[0]);
}
if (rf & 2) {
$r3$.ɵelementProperty(1, 'ngForOf', $r3$.ɵbind(myApp.items));
}
},
directives: () => [NgForOf]
});
}
});
});

View File

@ -1,205 +0,0 @@
/**
* @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 {Attribute, ChangeDetectorRef, Component, INJECTOR, Inject, InjectFlags, Injectable, Injector, SkipSelf, defineInjectable, inject} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ProvidersFeature} from '../../../src/render3/features/providers_feature';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('injection', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
describe('directives', () => {
// Directives (and Components) should use `directiveInject`
it('should inject ChangeDetectorRef', () => {
type $MyComp$ = MyComp;
type $MyApp$ = MyApp;
@Component({selector: 'my-comp', template: `{{ value }}`})
class MyComp {
value: string;
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory(t) {
return new (t || MyComp)($r3$.ɵdirectiveInject(ChangeDetectorRef as any));
},
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵbind(ctx.value));
}
}
});
// /NORMATIVE
}
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
/** <my-comp></my-comp> */
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
}
},
directives: () => [MyComp]
});
}
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef is historically the constructor
expect(toHtml(app)).toEqual('<my-comp>ViewRef</my-comp>');
});
it('should inject attributes', () => {
type $MyComp$ = MyComp;
type $MyApp$ = MyApp;
@Component({selector: 'my-comp', template: `{{ title }}`})
class MyComp {
constructor(@Attribute('title') public title: string|undefined) {}
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory(t) {
return new (t || MyComp)($r3$.ɵinjectAttribute('title'));
},
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
if (rf & 1) {
$r3$.ɵtext(0);
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵbind(ctx.title));
}
}
});
// /NORMATIVE
}
class MyApp {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
/** <my-comp></my-comp> */
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp', e0_attrs);
}
},
directives: () => [MyComp]
});
}
const e0_attrs = ['title', 'WORKS'];
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef is historically the constructor
expect(toHtml(app)).toEqual('<my-comp title="WORKS">WORKS</my-comp>');
});
// TODO(misko): enable once `providers` and `viewProvdires` are implemented.
xit('should inject into an injectable', () => {
type $MyApp$ = MyApp;
@Injectable()
class ServiceA {
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: function ServiceA_Factory() { return new ServiceA(); },
});
// /NORMATIVE
}
@Injectable()
class ServiceB {
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: function ServiceA_Factory() { return new ServiceB(); },
});
// /NORMATIVE
}
@Component({
template: '',
providers: [ServiceA],
viewProviders: [ServiceB],
})
class MyApp {
constructor(serviceA: ServiceA, serviceB: ServiceB, injector: Injector) {}
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) {
return new (t || MyApp)(
$r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR));
},
consts: 0,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {},
features: [ProvidersFeature([ServiceA], [ServiceB])]
});
}
const e0_attrs = ['title', 'WORKS'];
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef is historically the constructor
expect(toHtml(app)).toEqual('<my-comp title="WORKS">WORKS</my-comp>');
});
});
describe('services', () => {
// Services should use `inject`
@Injectable()
class ServiceA {
constructor(@Inject(String) name: String, injector: Injector) {}
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: function ServiceA_Factory() {
return new ServiceA(inject(String), inject(INJECTOR));
},
});
// /NORMATIVE
}
@Injectable()
class ServiceB {
constructor(serviceA: ServiceA, @SkipSelf() injector: Injector) {}
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: function ServiceA_Factory() {
return new ServiceB(inject(ServiceA), inject(INJECTOR, InjectFlags.SkipSelf) !);
},
});
// /NORMATIVE
}
});
});

View File

@ -1,115 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDef} from '../../../src/render3/interfaces/definition';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('lifecycle hooks', () => {
let events: string[] = [];
let simpleLayout: SimpleLayout;
type $RenderFlags$ = $r3$.ɵRenderFlags;
type $LifecycleComp$ = LifecycleComp;
type $SimpleLayout$ = SimpleLayout;
beforeEach(() => { events = []; });
@Component({selector: 'lifecycle-comp', template: ``})
class LifecycleComp {
// TODO(issue/24571): remove '!'.
@Input('name') nameMin !: string;
ngOnChanges() { events.push('changes' + this.nameMin); }
ngOnInit() { events.push('init' + this.nameMin); }
ngDoCheck() { events.push('check' + this.nameMin); }
ngAfterContentInit() { events.push('content init' + this.nameMin); }
ngAfterContentChecked() { events.push('content check' + this.nameMin); }
ngAfterViewInit() { events.push('view init' + this.nameMin); }
ngAfterViewChecked() { events.push('view check' + this.nameMin); }
ngOnDestroy() { events.push(this.nameMin); }
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: LifecycleComp,
selectors: [['lifecycle-comp']],
factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); },
consts: 0,
vars: 0,
template: function LifecycleComp_Template(rf: $RenderFlags$, ctx: $LifecycleComp$) {},
inputs: {nameMin: ['name', 'nameMin']},
features: [$r3$.ɵNgOnChangesFeature]
});
// /NORMATIVE
}
@Component({
selector: 'simple-layout',
template: `
<lifecycle-comp [name]="name1"></lifecycle-comp>
<lifecycle-comp [name]="name2"></lifecycle-comp>
`
})
class SimpleLayout {
name1 = '1';
name2 = '2';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: SimpleLayout,
selectors: [['simple-layout']],
factory: function SimpleLayout_Factory(t) {
return simpleLayout = new (t || SimpleLayout)();
},
consts: 2,
vars: 2,
template: function SimpleLayout_Template(rf: $RenderFlags$, ctx: $SimpleLayout$) {
if (rf & 1) {
$r3$.ɵelement(0, 'lifecycle-comp');
$r3$.ɵelement(1, 'lifecycle-comp');
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'name', $r3$.ɵbind(ctx.name1));
$r3$.ɵelementProperty(1, 'name', $r3$.ɵbind(ctx.name2));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(SimpleLayout.ngComponentDef as ComponentDef<any>).directiveDefs = [LifecycleComp.ngComponentDef];
// /NON-NORMATIVE
it('should gen hooks with a few simple components', () => {
expect(toHtml(renderComponent(SimpleLayout)))
.toEqual(`<lifecycle-comp></lifecycle-comp><lifecycle-comp></lifecycle-comp>`);
expect(events).toEqual([
'changes1', 'init1', 'check1', 'changes2', 'init2', 'check2', 'content init1',
'content check1', 'content init2', 'content check2', 'view init1', 'view check1',
'view init2', 'view check2'
]);
events = [];
simpleLayout.name1 = '-one';
simpleLayout.name2 = '-two';
$r3$.ɵdetectChanges(simpleLayout);
expect(events).toEqual([
'changes-one', 'check-one', 'changes-two', 'check-two', 'content check-one',
'content check-two', 'view check-one', 'view check-two'
]);
});
});

View File

@ -1,92 +0,0 @@
/**
* @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 {ElementRef, TemplateRef} from '@angular/core';
import {Component} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentFixture} from '../render_util';
/// See: `normative.md`
describe('local references', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should translate DOM structure', () => {
type $MyComponent$ = MyComponent;
@Component(
{selector: 'my-component', template: `<input #user value="World">Hello, {{user.value}}!`})
class MyComponent {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
let l1_user: any;
if (rf & 1) {
$r3$.ɵelement(0, 'input', ['value', 'World'], ['user', '']);
$r3$.ɵtext(2);
}
if (rf & 2) {
l1_user = $r3$.ɵreference<any>(1);
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('Hello, ', l1_user.value, '!'));
}
}
});
// NORMATIVE
}
const fixture = new ComponentFixture(MyComponent);
expect(fixture.html).toEqual(`<input value="World">Hello, World!`);
});
it('should expose TemplateRef when a local ref is placed on ng-template', () => {
type $MyComponent$ = MyComponent;
type $any$ = any;
@Component({
selector: 'my-component',
template: `<ng-template #tpl></ng-template>{{isTemplateRef(tpl)}}`
})
class MyComponent {
isTemplateRef(tplRef: any): boolean { return tplRef.createEmbeddedView != null; }
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
let l1_tpl: any;
if (rf & 1) {
$r3$.ɵtemplate(
0, MyComponent_Template_0, 0, 0, null, null, ['tpl', ''],
$r3$.ɵtemplateRefExtractor);
$r3$.ɵtext(2);
}
if (rf & 2) {
l1_tpl = $r3$.ɵreference<any>(1);
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', ctx.isTemplateRef(l1_tpl), ''));
}
function MyComponent_Template_0(rf1: $RenderFlags$, ctx1: $any$) {}
}
});
// NORMATIVE
}
const fixture = new ComponentFixture(MyComponent);
expect(fixture.html).toEqual(`true`);
});
});

View File

@ -1,83 +0,0 @@
/**
* @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 * as $core$ from '../../../index';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
xdescribe('NgModule', () => {
interface Injectable {
providedIn?: /*InjectorDefType<any>*/ any;
factory: Function;
}
function defineInjectable(opts: Injectable): Injectable {
// This class should be imported from https://github.com/angular/angular/pull/20850
return opts;
}
function defineInjector(opts: any): any {
// This class should be imported from https://github.com/angular/angular/pull/20850
return opts;
}
it('should convert module', () => {
@Injectable()
class Toast {
constructor(name: String) {}
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: function Toast_Factory() { return new Toast($r3$.ɵdirectiveInject(String)); },
});
// /NORMATIVE
}
class CommonModule {
// NORMATIVE
static ngInjectorDef = defineInjector({});
// /NORMATIVE
}
@NgModule({
providers: [Toast, {provide: String, useValue: 'Hello'}],
imports: [CommonModule],
})
class MyModule {
constructor(toast: Toast) {}
// NORMATIVE
static ngInjectorDef = defineInjector({
factory: function MyModule_Factory() { return new MyModule($r3$.ɵdirectiveInject(Toast)); },
provider: [
{provide: Toast, deps: [String]}, // If Toast has metadata generate this line
Toast, // If Toast has no metadata generate this line.
{provide: String, useValue: 'Hello'}
],
imports: [CommonModule]
});
// /NORMATIVE
}
@Injectable(/*{MyModule}*/)
class BurntToast {
constructor(@Optional() toast: Toast|null, name: String) {}
// NORMATIVE
static ngInjectableDef = defineInjectable({
providedIn: MyModule,
factory: function BurntToast_Factory() {
return new BurntToast(
$r3$.ɵdirectiveInject(Toast, $core$.InjectFlags.Optional),
$r3$.ɵdirectiveInject(String));
},
});
// /NORMATIVE
}
});
});

View File

@ -1,11 +0,0 @@
This folder contains canonical examples of how the Ivy compiler translates annotations into code
- The specs are marked with `NORMATIVE` => `/NORMATIVE` comments which designates what the compiler is expected to generate.
- All local variable names are considered non-normative (informative). They should be wrapped in `$` on each end to simplify testing on the compiler side.
A common trick in spec files is to map types to `$x$` (such as `boolean` => `$boolean$`, etc) to simplify testing for compiler, as types aren't saved. (See bullet above).
```
type $boolean$ = boolean;
type $any$ = any;
type $number$ = number;
```

View File

@ -1,219 +0,0 @@
/**
* @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 {Component, Directive, Input, OnDestroy, Pipe, PipeTransform, TemplateRef, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDef} from '../../../src/render3/interfaces/definition';
import {containerEl, renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('pipes', () => {
type $any$ = any;
type $RenderFlags$ = $r3$.ɵRenderFlags;
let myPipeTransformCalls = 0;
let myPurePipeTransformCalls = 0;
@Pipe({
name: 'myPipe',
pure: false,
})
class MyPipe implements PipeTransform,
OnDestroy {
private numberOfBang = 1;
transform(value: string, size: number): string {
let result = value.substring(size);
for (let i = 0; i < this.numberOfBang; i++) result += '!';
this.numberOfBang++;
myPipeTransformCalls++;
return result;
}
ngOnDestroy() { this.numberOfBang = 1; }
// NORMATIVE
static ngPipeDef = $r3$.ɵdefinePipe({
name: 'myPipe',
type: MyPipe,
factory: function MyPipe_Factory(t) { return new (t || MyPipe)(); },
pure: false,
});
// /NORMATIVE
}
@Pipe({
name: 'myPurePipe',
pure: true,
})
class MyPurePipe implements PipeTransform {
transform(value: string, size: number): string {
myPurePipeTransformCalls++;
return value.substring(size);
}
// NORMATIVE
static ngPipeDef = $r3$.ɵdefinePipe({
name: 'myPurePipe',
type: MyPurePipe,
factory: function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); },
pure: true,
});
// /NORMATIVE
}
it('should render pipes', () => {
type $MyApp$ = MyApp;
myPipeTransformCalls = 0;
myPurePipeTransformCalls = 0;
@Component({template: `{{name | myPipe:size | myPurePipe:size }}`})
class MyApp {
name = '12World';
size = 1;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 3,
vars: 7,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵtext(0);
$r3$.ɵpipe(1, 'myPipe');
$r3$.ɵpipe(2, 'myPurePipe');
}
if (rf & 2) {
$r3$.ɵtextBinding(
0,
$r3$.ɵinterpolation1(
'', $r3$.ɵpipeBind2(1, 4, $r3$.ɵpipeBind2(2, 1, ctx.name, ctx.size), ctx.size),
''));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(MyApp.ngComponentDef as ComponentDef<any>).pipeDefs =
() => [MyPurePipe.ngPipeDef, MyPipe.ngPipeDef];
// /NON-NORMATIVE
let myApp: MyApp = renderComponent(MyApp);
expect(toHtml(containerEl)).toEqual('World!');
expect(myPurePipeTransformCalls).toEqual(1);
expect(myPipeTransformCalls).toEqual(1);
$r3$.ɵdetectChanges(myApp);
expect(toHtml(containerEl)).toEqual('World!!');
expect(myPurePipeTransformCalls).toEqual(1);
expect(myPipeTransformCalls).toEqual(2);
myApp.name = '34WORLD';
$r3$.ɵdetectChanges(myApp);
expect(toHtml(containerEl)).toEqual('WORLD!!!');
expect(myPurePipeTransformCalls).toEqual(2);
expect(myPipeTransformCalls).toEqual(3);
});
it('should render many pipes and forward the first instance (pure or impure pipe)', () => {
type $MyApp$ = MyApp;
myPipeTransformCalls = 0;
myPurePipeTransformCalls = 0;
@Directive({
selector: '[oneTimeIf]',
})
class OneTimeIf {
@Input() oneTimeIf: any;
constructor(private view: ViewContainerRef, private template: TemplateRef<any>) {}
ngDoCheck(): void {
if (this.oneTimeIf) {
this.view.createEmbeddedView(this.template);
}
}
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: OneTimeIf,
selectors: [['', 'oneTimeIf', '']],
factory: function OneTimeIf_Factory(t) {
return new (t || OneTimeIf)(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any));
},
inputs: {oneTimeIf: 'oneTimeIf'}
});
// /NORMATIVE
}
function MyApp_div_Template_4(rf: $RenderFlags$, ctx: any) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵtext(1);
$r3$.ɵpipe(2, 'myPurePipe');
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $comp$ = $r3$.ɵnextContext();
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 1, $comp$.name, $comp$.size), ''));
}
}
@Component({
template: `{{name | myPurePipe:size}}{{name | myPurePipe:size}}
<div *oneTimeIf="more">{{name | myPurePipe:size}}</div>`
})
class MyApp {
name = '1World';
size = 1;
more = true;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 5,
vars: 9,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵtext(0);
$r3$.ɵpipe(1, 'myPurePipe');
$r3$.ɵtext(2);
$r3$.ɵpipe(3, 'myPurePipe');
$r3$.ɵtemplate(4, MyApp_div_Template_4, 3, 4, '', ['oneTimeIf', '']);
}
if (rf & 2) {
$r3$.ɵtextBinding(
0, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(1, 3, ctx.name, ctx.size), ''));
$r3$.ɵtextBinding(
2, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(3, 6, ctx.name, ctx.size), ''));
$r3$.ɵelementProperty(4, 'oneTimeIf', $r3$.ɵbind(ctx.more));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs = [OneTimeIf.ngDirectiveDef];
(MyApp.ngComponentDef as ComponentDef<any>).pipeDefs = [MyPurePipe.ngPipeDef];
// /NON-NORMATIVE
let myApp: MyApp = renderComponent(MyApp);
expect(toHtml(containerEl)).toEqual('WorldWorld<div>World</div>');
expect(myPurePipeTransformCalls).toEqual(3);
expect(myPipeTransformCalls).toEqual(0);
});
});

View File

@ -1,188 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDef} from '../../../src/render3/interfaces/definition';
import {getDirectiveOnNode, renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('queries', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
type $number$ = number;
let someDir: SomeDirective;
@Directive({
selector: '[someDir]',
})
class SomeDirective {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [['', 'someDir', '']],
factory: function SomeDirective_Factory(t) { return someDir = new (t || SomeDirective)(); }
});
}
it('should support view queries', () => {
type $ViewQueryComponent$ = ViewQueryComponent;
// NORMATIVE
const $e1_attrs$ = ['someDir', ''];
// /NORMATIVE
@Component({
selector: 'view-query-component',
template: `
<div someDir></div>
`
})
class ViewQueryComponent {
// TODO(issue/24571): remove '!'.
@ViewChild(SomeDirective) someDir !: SomeDirective;
// TODO(issue/24571): remove '!'.
@ViewChildren(SomeDirective) someDirList !: QueryList<SomeDirective>;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: ViewQueryComponent,
selectors: [['view-query-component']],
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
consts: 3,
vars: 0,
template: function ViewQueryComponent_Template(
rf: $RenderFlags$, ctx: $ViewQueryComponent$) {
if (rf & 1) {
$r3$.ɵelement(2, 'div', $e1_attrs$);
}
},
viewQuery: function ViewQueryComponent_Query(rf: $RenderFlags$, ctx: $ViewQueryComponent$) {
if (rf & 1) {
$r3$.ɵquery(0, SomeDirective, false);
$r3$.ɵquery(1, SomeDirective, false);
}
if (rf & 2) {
let $tmp$: any;
$r3$.ɵqueryRefresh($tmp$ = $r3$.ɵload<QueryList<any>>(0)) &&
(ctx.someDir = $tmp$.first);
$r3$.ɵqueryRefresh($tmp$ = $r3$.ɵload<QueryList<any>>(1)) &&
(ctx.someDirList = $tmp$ as QueryList<any>);
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(ViewQueryComponent.ngComponentDef as ComponentDef<any>).directiveDefs =
[SomeDirective.ngDirectiveDef];
// /NON-NORMATIVE
const viewQueryComp = renderComponent(ViewQueryComponent);
expect(viewQueryComp.someDir).toEqual(someDir);
expect((viewQueryComp.someDirList as QueryList<SomeDirective>).toArray()).toEqual([someDir !]);
});
it('should support content queries', () => {
type $MyApp$ = MyApp;
type $ContentQueryComponent$ = ContentQueryComponent;
let contentQueryComp: ContentQueryComponent;
@Component({
selector: 'content-query-component',
template: `
<div><ng-content></ng-content></div>
`
})
class ContentQueryComponent {
// TODO(issue/24571): remove '!'.
@ContentChild(SomeDirective) someDir !: SomeDirective;
// TODO(issue/24571): remove '!'.
@ContentChildren(SomeDirective) someDirList !: QueryList<SomeDirective>;
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: ContentQueryComponent,
selectors: [['content-query-component']],
factory: function ContentQueryComponent_Factory(t) {
return new (t || ContentQueryComponent)();
},
consts: 2,
vars: 0,
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex: $number$) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(
dirIndex: $number$, queryStartIndex: $number$) {
let $tmp$: any;
const $instance$ = $r3$.ɵload<ContentQueryComponent>(dirIndex);
$r3$.ɵqueryRefresh($tmp$ = $r3$.ɵloadQueryList<any>(queryStartIndex)) &&
($instance$.someDir = $tmp$.first);
$r3$.ɵqueryRefresh($tmp$ = $r3$.ɵloadQueryList<any>(queryStartIndex + 1)) &&
($instance$.someDirList = $tmp$);
},
template: function ContentQueryComponent_Template(
rf: $number$, ctx: $ContentQueryComponent$) {
if (rf & 1) {
$r3$.ɵprojectionDef();
$r3$.ɵelementStart(0, 'div');
$r3$.ɵprojection(1);
$r3$.ɵelementEnd();
}
}
});
// /NORMATIVE
}
const $e2_attrs$ = ['someDir', ''];
@Component({
selector: 'my-app',
template: `
<content-query-component>
<div someDir></div>
</content-query-component>
`
})
class MyApp {
// NON-NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'content-query-component');
contentQueryComp = getDirectiveOnNode(0);
$r3$.ɵelement(1, 'div', $e2_attrs$);
$r3$.ɵelementEnd();
}
}
});
// /NON-NORMATIVE
}
// NON-NORMATIVE
(MyApp.ngComponentDef as ComponentDef<any>).directiveDefs =
[ContentQueryComponent.ngComponentDef, SomeDirective.ngDirectiveDef];
// /NON-NORMATIVE
expect(toHtml(renderComponent(MyApp)))
.toEqual(
`<content-query-component><div><div somedir=""></div></div></content-query-component>`);
expect(contentQueryComp !.someDir).toEqual(someDir !);
expect((contentQueryComp !.someDirList as QueryList<SomeDirective>).toArray()).toEqual([
someDir !
]);
});
});

View File

@ -1,81 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {getHostElement} from '../../../src/render3/index';
import {renderComponent, toHtml} from '../render_util';
/**
* NORMATIVE => /NORMATIVE: Designates what the compiler is expected to generate.
*
* All local variable names are considered non-normative (informative). They should be
* wrapped in $ on each end to simplify testing on the compiler side.
*/
describe('compiler sanitization', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
it('should translate DOM structure', () => {
type $MyComponent$ = MyComponent;
@Component({
selector: 'my-component',
template: `<div [innerHTML]="innerHTML" [hidden]="hidden"></div>` +
`<img [style.background-image]="style" [src]="src">` +
`<script [attr.src]=src></script>`
})
class MyComponent {
innerHTML: string = '<frame></frame>';
hidden: boolean = true;
style: string = `url("http://evil")`;
url: string = 'javascript:evil()';
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 4,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵelementStyling(['background-image']);
$r3$.ɵelementEnd();
$r3$.ɵelement(1, 'img');
}
if (rf & 2) {
$r3$.ɵelementProperty(0, 'innerHTML', $r3$.ɵbind(ctx.innerHTML), $r3$.ɵsanitizeHtml);
$r3$.ɵelementProperty(0, 'hidden', $r3$.ɵbind(ctx.hidden));
$r3$.ɵelementStyleProp(0, 0, ctx.style);
$r3$.ɵelementStylingApply(0);
$r3$.ɵelementProperty(1, 'src', $r3$.ɵbind(ctx.url), $r3$.ɵsanitizeUrl);
$r3$.ɵelementAttribute(1, 'srcset', $r3$.ɵbind(ctx.url), $r3$.ɵsanitizeUrl);
}
}
});
// /NORMATIVE
}
const myComponent = renderComponent(MyComponent);
const div = getHostElement(myComponent).querySelector('div') !;
// because sanitizer removed it is working.
expect(div.innerHTML).toEqual('');
expect(div.hidden).toEqual(true);
const img = getHostElement(myComponent).querySelector('img') !;
// because sanitizer removed it is working.
expect(img.getAttribute('src')).toEqual('unsafe:javascript:evil()');
// because sanitizer removed it is working.
expect(img.style.getPropertyValue('background-image')).toEqual('');
// because sanitizer removed it is working.
expect(img.getAttribute('srcset')).toEqual('unsafe:javascript:evil()');
});
});

View File

@ -1,225 +0,0 @@
/**
* @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 {Component, Directive, Input, SimpleChanges, TemplateRef, ViewContainerRef, inject} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDef} from '../../../src/render3/interfaces/definition';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('template variables', () => {
type $any$ = any;
type $number$ = number;
type $RenderFlags$ = $r3$.ɵRenderFlags;
interface ForOfContext {
$implicit: any;
index: number;
even: boolean;
odd: boolean;
}
@Directive({selector: '[forOf]'})
class ForOfDirective {
// TODO(issue/24571): remove '!'.
private previous !: any[];
constructor(private view: ViewContainerRef, private template: TemplateRef<any>) {}
// TODO(issue/24571): remove '!'.
@Input() forOf !: any[];
ngOnChanges(simpleChanges: SimpleChanges) {
if ('forOf' in simpleChanges) {
this.update();
}
}
ngDoCheck(): void {
const previous = this.previous;
const current = this.forOf;
if (!previous || previous.length != current.length ||
previous.some((value: any, index: number) => current[index] !== previous[index])) {
this.update();
}
}
private update() {
// TODO(chuckj): Not implemented yet
// this.view.clear();
if (this.forOf) {
const current = this.forOf;
for (let i = 0; i < current.length; i++) {
const context = {$implicit: current[i], index: i, even: i % 2 == 0, odd: i % 2 == 1};
// TODO(chuckj): Not implemented yet
// this.view.createEmbeddedView(this.template, context);
}
this.previous = [...this.forOf];
}
}
// NORMATIVE
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: ForOfDirective,
selectors: [['', 'forOf', '']],
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any));
},
// TODO(chuckj): Enable when ngForOf enabling lands.
// features: [NgOnChangesFeature],
inputs: {forOf: 'forOf'}
});
// /NORMATIVE
}
it('should support a let variable and reference', () => {
type $MyComponent$ = MyComponent;
interface Item {
name: string;
}
function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_item$ = ctx1.$implicit;
$r3$.ɵtextBinding(1, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
}
}
@Component({
selector: 'my-component',
template: `<ul><li *for="let item of items">{{item.name}}</li></ul>`
})
class MyComponent {
items = [{name: 'one'}, {name: 'two'}];
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 2, 1, '', ['forOf', '']);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementProperty(1, 'forOf', $r3$.ɵbind(ctx.items));
}
}
});
// /NORMATIVE
}
// NON-NORMATIVE
(MyComponent.ngComponentDef as ComponentDef<any>).directiveDefs =
[ForOfDirective.ngDirectiveDef];
// /NON-NORMATIVE
// TODO(chuckj): update when the changes to enable ngForOf lands.
expect(toHtml(renderComponent(MyComponent))).toEqual('<ul></ul>');
});
it('should support accessing parent template variables', () => {
type $MyComponent$ = MyComponent;
interface Info {
description: string;
}
interface Item {
name: string;
infos: Info[];
}
function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵelementStart(1, 'div');
$r3$.ɵtext(2);
$r3$.ɵelementEnd();
$r3$.ɵelementStart(3, 'ul');
$r3$.ɵtemplate(
4, MyComponent_ForOfDirective_ForOfDirective_Template_3, 2, 1, '', ['forOf', '']);
$r3$.ɵelementEnd();
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_item$ = ctx1.$implicit;
$r3$.ɵelementProperty(4, 'forOf', $r3$.ɵbind($l0_item$.infos));
$r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', $l0_item$.name, ''));
}
}
function MyComponent_ForOfDirective_ForOfDirective_Template_3(rf: $number$, ctx2: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'li');
$r3$.ɵtext(1);
$r3$.ɵelementEnd();
}
if (rf & 2) {
const $l0_info$ = ctx2.$implicit;
const $l0_item$ = $r3$.ɵnextContext();
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation2(' ', $l0_item$.name, ': ', $l0_info$.description, ' '));
}
}
@Component({
selector: 'my-component',
template: `
<ul>
<li *for="let item of items">
<div>{{item.name}}</div>
<ul>
<li *for="let info of item.infos">
{{item.name}}: {{info.description}}
</li>
</ul>
</li>
</ul>`
})
class MyComponent {
items: Item[] = [
{name: 'one', infos: [{description: '11'}, {description: '12'}]},
{name: 'two', infos: [{description: '21'}, {description: '22'}]}
];
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'ul');
$r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 5, 2, '', ['forOf', '']);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementProperty(1, 'forOf', $r3$.ɵbind(ctx.items));
}
}
});
// /NORMATIVE
}
});
});

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Component, ElementRef, InjectFlags, Injectable, InjectionToken, InjectorType, Provider, ViewEncapsulation, createInjector, defineInjectable, defineInjector, inject} from '../../src/core'; import {Component as _Component, ElementRef, InjectFlags, Injectable as _Injectable, InjectionToken, InjectorType, Provider, ViewEncapsulation, createInjector, defineInjectable, defineInjector, inject} from '../../src/core';
import {forwardRef} from '../../src/di/forward_ref'; import {forwardRef} from '../../src/di/forward_ref';
import {getRenderedText} from '../../src/render3/component'; import {getRenderedText} from '../../src/render3/component';
@ -18,6 +18,15 @@ import {NgIf} from './common_with_def';
import {getRendererFactory2} from './imported_renderer2'; import {getRendererFactory2} from './imported_renderer2';
import {ComponentFixture, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util'; import {ComponentFixture, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util';
const Component: typeof _Component = function(...args: any[]): any {
// In test we use @Component for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
const Injectable: typeof _Injectable = function(...args: any[]): any {
// In test we use @Injectable for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
describe('component', () => { describe('component', () => {
class CounterComponent { class CounterComponent {
count = 0; count = 0;

View File

@ -7,7 +7,7 @@
*/ */
import {NgForOfContext} from '@angular/common'; import {NgForOfContext} from '@angular/common';
import {Component} from '../../src/core'; import {Component as _Component} from '../../src/core';
import {defineComponent} from '../../src/render3/definition'; import {defineComponent} from '../../src/render3/definition';
import {I18nExpInstruction, I18nInstruction, i18nApply, i18nExpMapping, i18nInterpolation1, i18nInterpolation2, i18nInterpolation3, i18nInterpolation4, i18nInterpolation5, i18nInterpolation6, i18nInterpolation7, i18nInterpolation8, i18nInterpolationV, i18nMapping} from '../../src/render3/i18n'; import {I18nExpInstruction, I18nInstruction, i18nApply, i18nExpMapping, i18nInterpolation1, i18nInterpolation2, i18nInterpolation3, i18nInterpolation4, i18nInterpolation5, i18nInterpolation6, i18nInterpolation7, i18nInterpolation8, i18nInterpolationV, i18nMapping} from '../../src/render3/i18n';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, nextContext, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, nextContext, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions';
@ -15,6 +15,11 @@ import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgForOf} from './common_with_def'; import {NgForOf} from './common_with_def';
import {ComponentFixture, TemplateFixture} from './render_util'; import {ComponentFixture, TemplateFixture} from './render_util';
const Component: typeof _Component = function(...args: any[]): any {
// In test we use @Component for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
describe('Runtime i18n', () => { describe('Runtime i18n', () => {
it('should support html elements', () => { it('should support html elements', () => {
// Html tags are replaced by placeholders. // Html tags are replaced by placeholders.

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Directive, InjectionToken, OnChanges, OnDestroy, Pipe, PipeTransform, createInjector, defineInjectable, defineInjector, ɵNgModuleDef as NgModuleDef, ɵdefineComponent as defineComponent, ɵdirectiveInject as directiveInject} from '@angular/core'; import {Directive as _Directive, InjectionToken, OnChanges, OnDestroy, Pipe as _Pipe, PipeTransform, createInjector, defineInjectable, defineInjector, ɵNgModuleDef as NgModuleDef, ɵdefineComponent as defineComponent, ɵdirectiveInject as directiveInject} from '@angular/core';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {defineDirective, definePipe} from '../../src/render3/definition'; import {defineDirective, definePipe} from '../../src/render3/definition';
@ -17,6 +17,14 @@ import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render
import {RenderLog, getRendererFactory2, patchLoggingRenderer2} from './imported_renderer2'; import {RenderLog, getRendererFactory2, patchLoggingRenderer2} from './imported_renderer2';
import {ComponentFixture, createComponent, getDirectiveOnNode, renderToHtml} from './render_util'; import {ComponentFixture, createComponent, getDirectiveOnNode, renderToHtml} from './render_util';
const Directive: typeof _Directive = function(...args: any[]): any {
// In test we use @Directive for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
const Pipe: typeof _Pipe = function(...args: any[]): any {
// In test we use @Pipe for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
let log: string[] = []; let log: string[] = [];
let person: Person; let person: Person;

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, QueryList, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core'; import {Component as _Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, QueryList, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
import {ViewEncapsulation} from '../../src/metadata'; import {ViewEncapsulation} from '../../src/metadata';
import {AttributeMarker, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load, query, queryRefresh} from '../../src/render3/index'; import {AttributeMarker, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load, query, queryRefresh} from '../../src/render3/index';
@ -19,10 +19,17 @@ import {pipe, pipeBind1} from '../../src/render3/pipe';
import {getViewData} from '../../src/render3/state'; import {getViewData} from '../../src/render3/state';
import {getNativeByIndex} from '../../src/render3/util'; import {getNativeByIndex} from '../../src/render3/util';
import {NgForOf} from '../../test/render3/common_with_def'; import {NgForOf} from '../../test/render3/common_with_def';
import {fixmeIvy} from '@angular/private/testing';
import {getRendererFactory2} from './imported_renderer2'; import {getRendererFactory2} from './imported_renderer2';
import {ComponentFixture, TemplateFixture, createComponent, getDirectiveOnNode} from './render_util'; import {ComponentFixture, TemplateFixture, createComponent, getDirectiveOnNode} from './render_util';
const Component: typeof _Component = function(...args: any[]): any {
// In test we use @Component for documentation only so it's safe to mock out the implementation.
return () => undefined;
} as any;
describe('ViewContainerRef', () => { describe('ViewContainerRef', () => {
let directiveInstance: DirectiveWithVCRef|null; let directiveInstance: DirectiveWithVCRef|null;
@ -1465,7 +1472,7 @@ describe('ViewContainerRef', () => {
}); });
}); });
describe('life cycle hooks', () => { fixmeIvy(`Hooks don't run`) && describe('life cycle hooks', () => {
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
const log: string[] = []; const log: string[] = [];

View File

@ -15,3 +15,17 @@ ng_module(
"//packages/core", "//packages/core",
], ],
) )
## Controls if Ivy is enabled. (Temporary target until we permanently switch over to Ivy)
##
## This file generates `src/bazel_define_compile_value.ts` file which reexports
## `--define=compile` value as `bazelDefineCompileValue` symbols so that runtime can detect
## which mode it is running in.
##
## See: `//.bazelrc` where `--define=ivy=legacy` is defined as default.
## See: `./src/bazel_define_compile_value.ts` for more details.
genrule(
name = "bazel_define_compile_value",
outs = ["src/bazel_define_compile_value.ts"],
cmd = "echo export const bazelDefineCompileValue = \"'$(compile)'\"\; > $@",
)

View File

@ -7,3 +7,4 @@
*/ */
export * from './src/render3'; export * from './src/render3';
export * from './src/fixme';