feat(ivy): update specification to include template variables (#21677)
PR Close #21677
This commit is contained in:
parent
0ad02de47e
commit
c65634215b
|
@ -898,12 +898,12 @@ describe('ngc transformer command-line', () => {
|
||||||
|
|
||||||
export * from './util';
|
export * from './util';
|
||||||
|
|
||||||
// Note: the lamda will be lowered into an exported expression
|
// Note: the lambda will be lowered into an exported expression
|
||||||
@NgModule({providers: [{provide: 'aToken', useValue: () => 2}]})
|
@NgModule({providers: [{provide: 'aToken', useValue: () => 2}]})
|
||||||
export class MyModule {}
|
export class MyModule {}
|
||||||
`);
|
`);
|
||||||
write('util.ts', `
|
write('util.ts', `
|
||||||
// Note: The lamda will be lowered into an exported expression
|
// Note: The lambda will be lowered into an exported expression
|
||||||
const x = () => 2;
|
const x = () => 2;
|
||||||
|
|
||||||
export const y = x;
|
export const y = x;
|
||||||
|
@ -1144,7 +1144,7 @@ describe('ngc transformer command-line', () => {
|
||||||
shouldExist('app/main.js');
|
shouldExist('app/main.js');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shoud be able to compile libraries with summaries and flat modules', () => {
|
it('should be able to compile libraries with summaries and flat modules', () => {
|
||||||
writeFiles();
|
writeFiles();
|
||||||
compile();
|
compile();
|
||||||
|
|
||||||
|
@ -1466,7 +1466,7 @@ describe('ngc transformer command-line', () => {
|
||||||
`);
|
`);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should recomiple when the html file changes',
|
it('should recompile when the html file changes',
|
||||||
expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); }));
|
expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); }));
|
||||||
|
|
||||||
it('should recompile when the css file changes',
|
it('should recompile when the css file changes',
|
||||||
|
|
|
@ -62,7 +62,6 @@ export class Identifiers {
|
||||||
static bind6: o.ExternalReference = {name: 'ɵb6', moduleName: CORE};
|
static bind6: o.ExternalReference = {name: 'ɵb6', moduleName: CORE};
|
||||||
static bind7: o.ExternalReference = {name: 'ɵb7', moduleName: CORE};
|
static bind7: o.ExternalReference = {name: 'ɵb7', moduleName: CORE};
|
||||||
static bind8: o.ExternalReference = {name: 'ɵb8', moduleName: CORE};
|
static bind8: o.ExternalReference = {name: 'ɵb8', moduleName: CORE};
|
||||||
static bind9: o.ExternalReference = {name: 'ɵb9', moduleName: CORE};
|
|
||||||
static bindV: o.ExternalReference = {name: 'ɵbV', moduleName: CORE};
|
static bindV: o.ExternalReference = {name: 'ɵbV', moduleName: CORE};
|
||||||
|
|
||||||
static memory: o.ExternalReference = {name: 'ɵm', moduleName: CORE};
|
static memory: o.ExternalReference = {name: 'ɵm', moduleName: CORE};
|
||||||
|
|
|
@ -157,8 +157,6 @@ function interpolate(args: o.Expression[]): o.Expression {
|
||||||
return o.importExpr(R3.bind7).callFn(args);
|
return o.importExpr(R3.bind7).callFn(args);
|
||||||
case 17:
|
case 17:
|
||||||
return o.importExpr(R3.bind8).callFn(args);
|
return o.importExpr(R3.bind8).callFn(args);
|
||||||
case 19:
|
|
||||||
return o.importExpr(R3.bind9).callFn(args);
|
|
||||||
}
|
}
|
||||||
(args.length > 19 && args.length % 2 == 1) ||
|
(args.length > 19 && args.length % 2 == 1) ||
|
||||||
error(`Invalid interpolation argument length ${args.length}`);
|
error(`Invalid interpolation argument length ${args.length}`);
|
||||||
|
|
|
@ -11,6 +11,7 @@ export {
|
||||||
defineComponent as ɵdefineComponent,
|
defineComponent as ɵdefineComponent,
|
||||||
detectChanges as ɵdetectChanges,
|
detectChanges as ɵdetectChanges,
|
||||||
renderComponent as ɵrenderComponent,
|
renderComponent as ɵrenderComponent,
|
||||||
|
ComponentType as ɵComponentType,
|
||||||
C as ɵC,
|
C as ɵC,
|
||||||
E as ɵE,
|
E as ɵE,
|
||||||
L as ɵL,
|
L as ɵL,
|
||||||
|
@ -18,6 +19,14 @@ export {
|
||||||
V as ɵV,
|
V as ɵV,
|
||||||
b as ɵb,
|
b as ɵb,
|
||||||
b1 as ɵb1,
|
b1 as ɵb1,
|
||||||
|
b2 as ɵb2,
|
||||||
|
b3 as ɵb3,
|
||||||
|
b4 as ɵb4,
|
||||||
|
b5 as ɵb5,
|
||||||
|
b6 as ɵb6,
|
||||||
|
b7 as ɵb7,
|
||||||
|
b8 as ɵb8,
|
||||||
|
bV as ɵbV,
|
||||||
cR as ɵcR,
|
cR as ɵcR,
|
||||||
cr as ɵcr,
|
cr as ɵcr,
|
||||||
e as ɵe,
|
e as ɵe,
|
||||||
|
|
|
@ -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, Directive, Injectable, NgModule, Optional, TemplateRef, Type} from '../../src/core';
|
import {Component, Directive, Injectable, Input, NgModule, Optional, SimpleChanges, TemplateRef, Type, ViewContainerRef} from '../../src/core';
|
||||||
import * as r3 from '../../src/render3/index';
|
import * as r3 from '../../src/render3/index';
|
||||||
|
|
||||||
import {containerEl, renderComponent, requestAnimationFrame, toHtml} from './render_util';
|
import {containerEl, renderComponent, requestAnimationFrame, toHtml} from './render_util';
|
||||||
|
@ -193,6 +193,193 @@ describe('compiler specification', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('template variables', () => {
|
||||||
|
|
||||||
|
interface ForOfContext {
|
||||||
|
$implicit: any;
|
||||||
|
index: number;
|
||||||
|
even: boolean;
|
||||||
|
odd: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Directive({selector: '[forOf]'})
|
||||||
|
class ForOfDirective {
|
||||||
|
private previous: any[];
|
||||||
|
|
||||||
|
constructor(private view: ViewContainerRef, private template: TemplateRef<any>) {}
|
||||||
|
|
||||||
|
@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({
|
||||||
|
factory: function ForOfDirective_Factory() {
|
||||||
|
return new ForOfDirective(r3.injectViewContainerRef(), r3.injectTemplateRef());
|
||||||
|
},
|
||||||
|
// TODO(chuckj): Enable when ngForOf enabling lands.
|
||||||
|
// features: [NgOnChangesFeature(NgForOf)],
|
||||||
|
refresh: function ForOfDirective_Refresh(directiveIndex: number, elementIndex: number) {
|
||||||
|
r3.m<ForOfDirective>(directiveIndex).ngDoCheck();
|
||||||
|
},
|
||||||
|
inputs: {forOf: 'forOf'}
|
||||||
|
});
|
||||||
|
// /NORMATIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should support a let variable and reference', () => {
|
||||||
|
interface Item {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const c1_dirs = [ForOfDirective];
|
||||||
|
|
||||||
|
@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({
|
||||||
|
tag: 'my-component',
|
||||||
|
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||||
|
template: function MyComponentTemplate(ctx: MyComponent, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
r3.E(0, 'ul');
|
||||||
|
r3.C(1, c1_dirs, MyComponent_ForOfDirective_Template_1);
|
||||||
|
r3.e();
|
||||||
|
}
|
||||||
|
r3.p(1, 'forOf', r3.b(ctx.items));
|
||||||
|
r3.cR(1);
|
||||||
|
ForOfDirective.ngDirectiveDef.r(2, 1);
|
||||||
|
r3.cr();
|
||||||
|
|
||||||
|
function MyComponent_ForOfDirective_Template_1(ctx1: any, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
r3.E(0, 'li');
|
||||||
|
r3.T(1);
|
||||||
|
r3.e();
|
||||||
|
}
|
||||||
|
const l0_item = ctx1.$implicit;
|
||||||
|
r3.t(1, r3.b1('', l0_item.name, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// /NORMATIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(chuckj): update when the changes to enable ngForOf lands.
|
||||||
|
expect(renderComp(MyComponent)).toEqual('<ul></ul>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support accessing parent template variables', () => {
|
||||||
|
interface Info {
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
interface Item {
|
||||||
|
name: string;
|
||||||
|
infos: Info[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const c1_dirs = [ForOfDirective];
|
||||||
|
|
||||||
|
@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>
|
||||||
|
</ui>
|
||||||
|
</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({
|
||||||
|
tag: 'my-component',
|
||||||
|
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||||
|
template: function MyComponent_Template(ctx: MyComponent, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
r3.E(0, 'ul');
|
||||||
|
r3.C(1, c1_dirs, MyComponent_ForOfDirective_Template_1);
|
||||||
|
r3.e();
|
||||||
|
}
|
||||||
|
r3.p(1, 'forOf', r3.b(ctx.items));
|
||||||
|
r3.cR(1);
|
||||||
|
ForOfDirective.ngDirectiveDef.r(2, 1);
|
||||||
|
r3.cr();
|
||||||
|
|
||||||
|
function MyComponent_ForOfDirective_Template_1(ctx1: any, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
r3.E(0, 'div');
|
||||||
|
r3.T(1);
|
||||||
|
r3.e();
|
||||||
|
r3.E(2, 'ul');
|
||||||
|
r3.C(3, c1_dirs, MyComponent_ForOfDirective_ForOfDirective_Template_3);
|
||||||
|
r3.e();
|
||||||
|
}
|
||||||
|
const l0_item = ctx1.$implicit;
|
||||||
|
r3.t(1, r3.b1('', l0_item.name, ''));
|
||||||
|
r3.p(4, 'forOf', r3.b(ctx.items));
|
||||||
|
r3.cR(3);
|
||||||
|
ForOfDirective.ngDirectiveDef.r(4, 3);
|
||||||
|
r3.cr();
|
||||||
|
|
||||||
|
function MyComponent_ForOfDirective_ForOfDirective_Template_3(
|
||||||
|
ctx2: any, cm: boolean) {
|
||||||
|
if (cm) {
|
||||||
|
r3.E(0, 'li');
|
||||||
|
r3.T(1);
|
||||||
|
r3.e();
|
||||||
|
}
|
||||||
|
const l0_info = ctx2.info;
|
||||||
|
r3.t(1, r3.b2('', l0_item.name, ': ', l0_info.description, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// /NORMATIVE
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
xdescribe('NgModule', () => {
|
xdescribe('NgModule', () => {
|
||||||
|
@ -236,7 +423,7 @@ xdescribe('NgModule', () => {
|
||||||
static ngInjectorDef = defineInjector({
|
static ngInjectorDef = defineInjector({
|
||||||
factory: () => new MyModule(inject(Toast)),
|
factory: () => new MyModule(inject(Toast)),
|
||||||
provider: [
|
provider: [
|
||||||
{provide: Toast, deps: [String]}, // If Toast has matadata generate this line
|
{provide: Toast, deps: [String]}, // If Toast has metadata generate this line
|
||||||
Toast, // If toast has not metadata generate this line.
|
Toast, // If toast has not metadata generate this line.
|
||||||
{provide: String, useValue: 'Hello'}
|
{provide: String, useValue: 'Hello'}
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue