feat(ivy): support providers and viewProviders (#25803)

PR Close #25803
This commit is contained in:
Marc Laval 2018-10-18 09:23:18 +02:00 committed by Matias Niemelä
parent 9dc52d9d04
commit b0476f308b
76 changed files with 4098 additions and 1645 deletions

View File

@ -128,7 +128,7 @@ describe('Renderer', () => {
}));
expect(addDefinitionsSpy.calls.first().args[2])
.toEqual(
`A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); }, features: [ɵngcc0.ɵPublicFeature] });`);
`A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`);
});
it('should call removeDecorators with the source code, a map of class decorators that have been analyzed',

View File

@ -118,6 +118,10 @@ export class ComponentDecoratorHandler implements
preserveWhitespaces = value;
}
const viewProviders: Expression|null = component.has('viewProviders') ?
new WrappedNodeExpr(component.get('viewProviders') !) :
null;
// Go through the root directories for this project, and select the one with the smallest
// relative path representation.
const filePath = node.getSourceFile().fileName;
@ -202,6 +206,7 @@ export class ComponentDecoratorHandler implements
directives: EMPTY_MAP,
wrapDirectivesInClosure: false, //
animations,
viewProviders
},
parsedTemplate: template.nodes,
},

View File

@ -146,6 +146,9 @@ export function extractDirectiveMetadata(
const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule);
const providers: Expression|null =
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
// Determine if `ngOnChanges` is a lifecycle hook defined on the component.
const usesOnChanges = members.some(
member => !member.isStatic && member.kind === ClassMemberKind.Method &&
@ -176,7 +179,7 @@ export function extractDirectiveMetadata(
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, selector,
type: new WrappedNodeExpr(clazz.name !),
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
typeSourceSpan: null !, usesInheritance, exportAs,
typeSourceSpan: null !, usesInheritance, exportAs, providers
};
return {decoratedElements, decorator: directive, metadata};
}

View File

@ -415,7 +415,6 @@ describe('compiler compliance', () => {
factory: function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf,ctx){
@ -470,7 +469,6 @@ describe('compiler compliance', () => {
type: ChildComponent,
selectors: [["child"]],
factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function ChildComponent_Template(rf, ctx) {
@ -485,8 +483,7 @@ describe('compiler compliance', () => {
SomeDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [["", "some-directive", ""]],
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }
});
`;
@ -498,7 +495,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -543,8 +539,7 @@ describe('compiler compliance', () => {
SomeDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [["div", "some-directive", "", 8, "foo", 3, "title", "", 9, "baz"]],
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }
});
`;
@ -553,8 +548,7 @@ describe('compiler compliance', () => {
OtherDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: OtherDirective,
selectors: [["", 5, "span", "title", "", 9, "baz"]],
factory: function OtherDirective_Factory(t) {return new (t || OtherDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function OtherDirective_Factory(t) {return new (t || OtherDirective)(); }
});
`;
@ -590,8 +584,7 @@ describe('compiler compliance', () => {
hostBindings: function HostBindingDir_HostBindings(dirIndex, elIndex) {
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵload(dirIndex).dirId));
},
hostVars: 1,
features: [$r3$.ɵPublicFeature]
hostVars: 1
});
`;
@ -635,7 +628,6 @@ describe('compiler compliance', () => {
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, $r3$.ɵload(dirIndex).id)));
},
hostVars: 3,
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function HostBindingComp_Template(rf, ctx) {}
@ -679,7 +671,6 @@ describe('compiler compliance', () => {
$r3$.ɵdirectiveInject(ElementRef), $r3$.ɵdirectiveInject(ViewContainerRef),
$r3$.ɵdirectiveInject(ChangeDetectorRef));
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, ctx) {}
@ -720,8 +711,7 @@ describe('compiler compliance', () => {
IfDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [["", "if", ""]],
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef)); },
features: [$r3$.ɵPublicFeature]
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef)); }
});`;
const MyComponentDefinition = `
const $c1$ = ["foo", ""];
@ -743,7 +733,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -806,7 +795,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 3,
template: function MyApp_Template(rf, ctx) {
@ -888,7 +876,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 11,
template: function MyApp_Template(rf, ctx) {
@ -952,7 +939,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 3,
template: function MyApp_Template(rf, ctx) {
@ -1020,7 +1006,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 8,
template: function MyApp_Template(rf, ctx) {
@ -1079,7 +1064,6 @@ describe('compiler compliance', () => {
type: SimpleComponent,
selectors: [["simple"]],
factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function SimpleComponent_Template(rf, ctx) {
@ -1102,7 +1086,6 @@ describe('compiler compliance', () => {
type: ComplexComponent,
selectors: [["complex"]],
factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
vars: 0,
template: function ComplexComponent_Template(rf, ctx) {
@ -1171,7 +1154,6 @@ describe('compiler compliance', () => {
type: ViewQueryComponent,
selectors: [["view-query-component"]],
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
features: [$r3$.ɵPublicFeature],
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵquery(0, SomeDirective, true);
@ -1348,9 +1330,9 @@ describe('compiler compliance', () => {
factory: function ContentQueryComponent_Factory(t) {
return new (t || ContentQueryComponent)();
},
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1358,7 +1340,6 @@ describe('compiler compliance', () => {
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && ($instance$.someDir = $tmp$.first));
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
},
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function ContentQueryComponent_Template(rf, ctx) {
@ -1406,9 +1387,9 @@ describe('compiler compliance', () => {
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1459,11 +1440,11 @@ describe('compiler compliance', () => {
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1552,7 +1533,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 17,
template: function MyApp_Template(rf, ctx) {
@ -1616,7 +1596,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 27,
template: function MyApp_Template(rf, ctx) {
@ -1671,7 +1650,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -1765,7 +1743,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -1911,7 +1888,7 @@ describe('compiler compliance', () => {
selectors: [["lifecycle-comp"]],
factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); },
inputs: {nameMin: "name"},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
features: [$r3$.ɵNgOnChangesFeature],
consts: 0,
vars: 0,
template: function LifecycleComp_Template(rf, ctx) {}
@ -1922,7 +1899,6 @@ describe('compiler compliance', () => {
type: SimpleLayout,
selectors: [["simple-layout"]],
factory: function SimpleLayout_Factory(t) { return new (t || SimpleLayout)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 2,
template: function SimpleLayout_Template(rf, ctx) {
@ -2032,7 +2008,7 @@ describe('compiler compliance', () => {
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
features: [$r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}
});
`;
@ -2052,7 +2028,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx){
@ -2108,7 +2083,7 @@ describe('compiler compliance', () => {
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
features: [$r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}
});
`;
@ -2131,7 +2106,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -2231,7 +2205,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx) {

View File

@ -42,7 +42,6 @@ describe('compiler compliance: directives', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -88,7 +87,6 @@ describe('compiler compliance: directives', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {

View File

@ -202,7 +202,6 @@ describe('compiler compliance: listen()', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
vars: 0,
template: function MyComponent_Template(rf, ctx) {

View File

@ -0,0 +1,152 @@
/**
* @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 {setup} from '@angular/compiler/test/aot/test_util';
import {compile, expectEmit} from './mock_compile';
describe('compiler compliance: providers', () => {
const angularFiles = setup({
compileAngular: false,
compileFakeCore: true,
compileAnimations: false,
});
it('should emit the ProvidersFeature feature when providers and viewProviders', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
providers: [GreeterEN, {provide: Greeter, useClass: GreeterEN}],
viewProviders: [GreeterEN]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source,
'features: [i0.ɵProvidersFeature([GreeterEN, {provide: Greeter, useClass: GreeterEN}], [GreeterEN])],',
'Incorrect features');
});
it('should emit the ProvidersFeature feature when providers only', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
providers: [GreeterEN, {provide: Greeter, useClass: GreeterEN}]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source,
'features: [i0.ɵProvidersFeature([GreeterEN, {provide: Greeter, useClass: GreeterEN}])],',
'Incorrect features');
});
it('should emit the ProvidersFeature feature when viewProviders only', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
viewProviders: [GreeterEN]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source, 'features: [i0.ɵProvidersFeature([], [GreeterEN])],', 'Incorrect features');
});
it('should not emit the ProvidersFeature feature when no providers', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>'
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source, `
export class MyComponent {
}
MyComponent.ngComponentDef = i0.ɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵelement(0, "div");
} } });`,
'Incorrect features');
});
});

View File

@ -128,7 +128,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, $ctx$) {
@ -170,7 +169,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, $ctx$) {
@ -308,7 +306,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 1,
template: function MyComponent_Template(rf, $ctx$) {
@ -367,7 +364,6 @@ describe('compiler compliance: styling', () => {
factory: function MyComponent_Factory(t) {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -506,7 +502,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 1,
template: function MyComponent_Template(rf, $ctx$) {
@ -563,7 +558,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 2,
template: function MyComponent_Template(rf, $ctx$) {

View File

@ -175,7 +175,7 @@ export class Identifiers {
static InheritDefinitionFeature:
o.ExternalReference = {name: 'ɵInheritDefinitionFeature', moduleName: CORE};
static PublicFeature: o.ExternalReference = {name: 'ɵPublicFeature', moduleName: CORE};
static ProvidersFeature: o.ExternalReference = {name: 'ɵProvidersFeature', moduleName: CORE};
static listener: o.ExternalReference = {name: 'ɵlistener', moduleName: CORE};

View File

@ -103,6 +103,11 @@ export interface R3DirectiveMetadata {
* if any.
*/
exportAs: string|null;
/**
* The list of providers defined in the directive.
*/
providers: o.Expression|null;
}
/**
@ -180,6 +185,11 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata {
* A collection of animation triggers that will be used in the component template.
*/
animations: o.Expression|null;
/**
* The list of view providers defined in the component.
*/
viewProviders: o.Expression|null;
}
/**

View File

@ -82,11 +82,30 @@ function baseDirectiveFields(
// e.g 'outputs: {a: 'a'}`
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
if (meta.exportAs !== null) {
definitionMap.set('exportAs', o.literal(meta.exportAs));
}
return {definitionMap, statements: result.statements};
}
/**
* Add features to the definition map.
*/
function addFeatures(
definitionMap: DefinitionMap, meta: R3DirectiveMetadata | R3ComponentMetadata) {
// e.g. `features: [NgOnChangesFeature]`
const features: o.Expression[] = [];
// TODO: add `PublicFeature` so that directives get registered to the DI - make this configurable
features.push(o.importExpr(R3.PublicFeature));
const providers = meta.providers;
const viewProviders = (meta as R3ComponentMetadata).viewProviders;
if (providers || viewProviders) {
const args = [providers || new o.LiteralArrayExpr([])];
if (viewProviders) {
args.push(viewProviders);
}
features.push(o.importExpr(R3.ProvidersFeature).callFn(args));
}
if (meta.usesInheritance) {
features.push(o.importExpr(R3.InheritDefinitionFeature));
@ -97,11 +116,6 @@ function baseDirectiveFields(
if (features.length) {
definitionMap.set('features', o.literalArr(features));
}
if (meta.exportAs !== null) {
definitionMap.set('exportAs', o.literal(meta.exportAs));
}
return {definitionMap, statements: result.statements};
}
/**
@ -111,6 +125,7 @@ export function compileDirectiveFromMetadata(
meta: R3DirectiveMetadata, constantPool: ConstantPool,
bindingParser: BindingParser): R3DirectiveDef {
const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser);
addFeatures(definitionMap, meta);
const expression = o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()]);
// On the type side, remove newlines from the selector as it will need to fit into a TypeScript
@ -164,6 +179,7 @@ export function compileComponentFromMetadata(
meta: R3ComponentMetadata, constantPool: ConstantPool,
bindingParser: BindingParser): R3ComponentDef {
const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser);
addFeatures(definitionMap, meta);
const selector = meta.selector && CssSelector.parse(meta.selector);
const firstSelector = selector && selector[0];
@ -320,6 +336,8 @@ export function compileComponentFromRender2(
encapsulation:
(summary.template && summary.template.encapsulation) || core.ViewEncapsulation.Emulated,
animations: null,
viewProviders:
component.viewProviders.length > 0 ? new o.WrappedNodeExpr(component.viewProviders) : null
};
const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser);
@ -362,6 +380,7 @@ function directiveMetadataFromGlobalMetadata(
outputs: directive.outputs,
usesInheritance: false,
exportAs: null,
providers: directive.providers.length > 0 ? new o.WrappedNodeExpr(directive.providers) : null
};
}
@ -451,11 +470,15 @@ function createContentQueriesFunction(
if (meta.queries.length) {
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
const queryDefinition = createQueryDefinition(query, constantPool, null);
return o.importExpr(R3.registerContentQuery).callFn([queryDefinition]).toStmt();
return o.importExpr(R3.registerContentQuery)
.callFn([queryDefinition, o.variable('dirIndex')])
.toStmt();
});
const typeName = meta.name;
const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)];
return o.fn(
[], statements, o.INFERRED_TYPE, null, typeName ? `${typeName}_ContentQueries` : null);
parameters, statements, o.INFERRED_TYPE, null,
typeName ? `${typeName}_ContentQueries` : null);
}
return null;

View File

@ -25,7 +25,7 @@ export {
getFactoryOf as ɵgetFactoryOf,
getInheritedFactory as ɵgetInheritedFactory,
templateRefExtractor as ɵtemplateRefExtractor,
PublicFeature as ɵPublicFeature,
ProvidersFeature as ɵProvidersResolver,
InheritDefinitionFeature as ɵInheritDefinitionFeature,
NgOnChangesFeature as ɵNgOnChangesFeature,
NgModuleType as ɵNgModuleType,

View File

@ -8,6 +8,7 @@
import {Type} from '../type';
import {stringify} from '../util';
import {getClosureSafeProperty} from '../util/property';
@ -22,6 +23,8 @@ import {stringify} from '../util';
*/
export interface ForwardRefFn { (): any; }
const __forward_ref__ = getClosureSafeProperty({__forward_ref__: getClosureSafeProperty});
/**
* Allows to refer to references which are not yet defined.
*
@ -53,10 +56,11 @@ export function forwardRef(forwardRefFn: ForwardRefFn): Type<any> {
* @see `forwardRef`
* @publicApi
*/
export function resolveForwardRef(type: any): any {
if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__') &&
type.__forward_ref__ === forwardRef) {
return (<ForwardRefFn>type)();
export function resolveForwardRef<T>(type: T): T {
const fn: any = type;
if (typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
fn.__forward_ref__ === forwardRef) {
return fn();
} else {
return type;
}

View File

@ -431,6 +431,17 @@ export function setCurrentInjector(injector: Injector | null | undefined): Injec
_currentInjector = injector;
return former;
}
/**
* Current implementation of inject.
*
* By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
* to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
* way for two reasons:
* 1. `Injector` should not depend on ivy logic.
* 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
*/
let _injectImplementation: (<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags) => T | null)|
undefined;
/**
* Injects a token from the currently active injector.
@ -452,21 +463,53 @@ export function setCurrentInjector(injector: Injector | null | undefined): Injec
export function inject<T>(token: Type<T>| InjectionToken<T>): T;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
return (_injectImplementation || injectInjectorOnly)(token, flags);
}
/**
* Sets the current inject implementation.
*/
export function setInjectImplementation(
impl: (<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null) | undefined):
(<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined {
const previous = _injectImplementation;
_injectImplementation = impl;
return previous;
}
export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>): T;
export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|
null;
export function injectInjectorOnly<T>(
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context`);
} else if (_currentInjector === null) {
const injectableDef: InjectableDef<T>|null = getInjectableDef(token);
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;
}
if (flags & InjectFlags.Optional) return null;
throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`);
return injectRootLimpMode(token, undefined, flags);
} else {
return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
}
}
/**
* Injects `root` tokens in limp mode.
*
* If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
* `"root"`. This is known as the limp mode injection. In such case the value is stored in the
* `InjectableDef`.
*/
export function injectRootLimpMode<T>(
token: Type<T>| InjectionToken<T>, notFoundValue: T | undefined, flags: InjectFlags): T|null {
const injectableDef: InjectableDef<T>|null = getInjectableDef(token);
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;
}
if (flags & InjectFlags.Optional) return null;
if (notFoundValue !== undefined) return notFoundValue;
throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`);
}
export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): any[] {
const args: any[] = [];
for (let i = 0; i < types.length; i++) {

View File

@ -165,7 +165,7 @@ export class R3Injector {
if (def && this.injectableDefInScope(def)) {
// Found an ngInjectableDef and it's scoped to this injector. Pretend as if it was here
// all along.
record = injectableDefRecord(token);
record = makeRecord(injectableDefFactory(token), NOT_YET);
this.records.set(token, record);
}
}
@ -328,7 +328,7 @@ export class R3Injector {
}
}
function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any> {
function injectableDefFactory(token: Type<any>| InjectionToken<any>): () => any {
const injectableDef = getInjectableDef(token as InjectableType<any>);
if (injectableDef === null) {
if (token instanceof InjectionToken) {
@ -336,21 +336,34 @@ function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any>
}
// TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
// no-args constructor.
return makeRecord(() => new (token as Type<any>)());
return () => new (token as Type<any>)();
}
return makeRecord(injectableDef.factory);
return injectableDef.factory;
}
function providerToRecord(provider: SingleProvider): Record<any> {
let factory: (() => any)|undefined = providerToFactory(provider);
if (isValueProvider(provider)) {
return makeRecord(undefined, provider.useValue);
} else {
return makeRecord(factory, NOT_YET);
}
}
/**
* Converts a `SingleProvider` into a factory function.
*
* @param provider provider to convert to factory
*/
export function providerToFactory(provider: SingleProvider): () => any {
let token = resolveForwardRef(provider);
let value: any = NOT_YET;
let factory: (() => any)|undefined = undefined;
if (isTypeProvider(provider)) {
return injectableDefRecord(provider);
return injectableDefFactory(provider);
} else {
token = resolveForwardRef(provider.provide);
if (isValueProvider(provider)) {
value = provider.useValue;
factory = () => provider.useValue;
} else if (isExistingProvider(provider)) {
factory = () => inject(provider.useExisting);
} else if (isFactoryProvider(provider)) {
@ -360,11 +373,11 @@ function providerToRecord(provider: SingleProvider): Record<any> {
if (hasDeps(provider)) {
factory = () => new (classRef)(...injectArgs(provider.deps));
} else {
return injectableDefRecord(classRef);
return injectableDefFactory(classRef);
}
}
}
return makeRecord(factory, value);
return factory;
}
function makeRecord<T>(
@ -392,7 +405,7 @@ function isFactoryProvider(value: SingleProvider): value is FactoryProvider {
return !!(value as FactoryProvider).useFactory;
}
function isTypeProvider(value: SingleProvider): value is TypeProvider {
export function isTypeProvider(value: SingleProvider): value is TypeProvider {
return typeof value === 'function';
}

View File

@ -15,14 +15,16 @@ import {Sanitizer} from '../sanitization/security';
import {assertComponentType, assertDefined} from './assert';
import {getComponentViewByInstance} from './context_discovery';
import {getComponentDef} from './definition';
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createNodeAtIndex, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, getOrCreateTView, leaveView, locateHostElement, prefillHostVars, resetComponentState, setHostBindings} from './instructions';
import {CLEAN_PROMISE, createLViewData, createNodeAtIndex, createTView, detectChangesInternal, executeInitAndContentHooks, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, prefillHostVars, setHostBindings} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition';
import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
import {PlayerHandler} from './interfaces/player';
import {RElement, RNode, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
import {publishDefaultGlobalUtils} from './publish_global_util';
import {enterView, leaveView, resetComponentState} from './state';
import {getRootView, readElementValue, readPatchedLViewData, stringify} from './util';
@ -130,13 +132,12 @@ export function renderComponent<T>(
let component: T;
try {
if (rendererFactory.begin) rendererFactory.begin();
const componentView =
createRootComponentView(hostRNode, componentDef, rootView, renderer, sanitizer);
component = createRootComponent(
hostRNode, componentView, componentDef, rootView, rootContext, opts.hostFeatures || null);
executeInitAndContentHooks();
executeInitAndContentHooks(rootView);
detectChangesInternal(componentView, component);
} finally {
leaveView(oldView);
@ -171,9 +172,9 @@ export function createRootComponentView(
if (tView.firstTemplatePass) {
tView.expandoInstructions = ROOT_EXPANDO_INSTRUCTIONS.slice();
if (def.diPublic) def.diPublic(def);
tNode.flags =
rootView.length << TNodeFlags.DirectiveStartingIndexShift | TNodeFlags.isComponent;
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), rootView, def.type);
tNode.flags = TNodeFlags.isComponent;
initNodeFlags(tNode, rootView.length, 1);
}
// Store component view at node index, with node as the HOST
@ -189,16 +190,17 @@ export function createRootComponentView(
export function createRootComponent<T>(
hostRNode: RNode | null, componentView: LViewData, componentDef: ComponentDef<T>,
rootView: LViewData, rootContext: RootContext, hostFeatures: HostFeature[] | null): any {
const tView = rootView[TVIEW];
// Create directive instance with factory() and store at next index in viewData
const component =
baseDirectiveCreate(rootView.length, componentDef.factory() as T, componentDef, hostRNode);
const component = instantiateRootComponent(tView, rootView, componentDef);
rootContext.components.push(component);
componentView[CONTEXT] = component;
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
if (rootView[TVIEW].firstTemplatePass) prefillHostVars(componentDef.hostVars);
setHostBindings();
if (tView.firstTemplatePass) prefillHostVars(tView, rootView, componentDef.hostVars);
setHostBindings(tView, rootView);
return component;
}

View File

@ -19,11 +19,12 @@ import {Type} from '../type';
import {assertComponentType, assertDefined} from './assert';
import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component';
import {getComponentDef} from './definition';
import {adjustBlueprintForNewNode, createLViewData, createNodeAtIndex, createTView, createViewNode, elementCreate, enterView, locateHostElement, renderEmbeddedTemplate} from './instructions';
import {createLViewData, createNodeAtIndex, createTView, createViewNode, elementCreate, locateHostElement, renderEmbeddedTemplate} from './instructions';
import {ComponentDef, RenderFlags} from './interfaces/definition';
import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {FLAGS, HEADER_OFFSET, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {enterView} from './state';
import {getTNode} from './util';
import {createElementRef} from './view_engine_compatibility';
import {RootViewRef, ViewRef} from './view_ref';
@ -114,9 +115,6 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef)) :
locateHostElement(rendererFactory, rootSelectorOrNode);
// The first index of the first selector is the tag name.
const componentTag = this.componentDef.selectors ![0] ![0] as string;
const rootFlags = this.componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot :
LViewFlags.CheckAlways | LViewFlags.IsRoot;
const rootContext: RootContext = ngModule && !isInternalRootView ?
@ -145,15 +143,25 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// projection instruction. This is needed to support the reprojection of these nodes.
if (projectableNodes) {
let index = 0;
const tView = rootView[TVIEW];
const projection: TNode[] = tElementNode.projection = [];
for (let i = 0; i < projectableNodes.length; i++) {
const nodeList = projectableNodes[i];
let firstTNode: TNode|null = null;
let previousTNode: TNode|null = null;
for (let j = 0; j < nodeList.length; j++) {
adjustBlueprintForNewNode(rootView);
if (tView.firstTemplatePass) {
// For dynamically created components such as ComponentRef, we create a new TView for
// each insert. This is not ideal since we should be sharing the TViews.
// Also the logic here should be shared with `component.ts`'s `renderComponent`
// method.
tView.expandoStartIndex++;
tView.blueprint.splice(++index + HEADER_OFFSET, 0, null);
tView.data.splice(index + HEADER_OFFSET, 0, null);
rootView.splice(index + HEADER_OFFSET, 0, null);
}
const tNode =
createNodeAtIndex(++index, TNodeType.Element, nodeList[j] as RElement, null, null);
createNodeAtIndex(index, TNodeType.Element, nodeList[j] as RElement, null, null);
previousTNode ? (previousTNode.next = tNode) : (firstTNode = tNode);
previousTNode = tNode;
}

View File

@ -54,7 +54,7 @@ export function defineComponent<T>(componentDefinition: {
/**
* Factory method used to create an instance of directive.
*/
factory: () => T;
factory: (t: Type<T>| null) => T;
/**
* The number of nodes, local refs, and pipes in this component template.
@ -154,7 +154,7 @@ export function defineComponent<T>(componentDefinition: {
/**
* Function to create instances of content queries associated with a given directive.
*/
contentQueries?: (() => void);
contentQueries?: ((dirIndex: number) => void);
/** Refreshes content queries associated with directives in a given view */
contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void);
@ -210,7 +210,7 @@ export function defineComponent<T>(componentDefinition: {
/**
* A list of optional features to apply.
*
* See: {@link NgOnChangesFeature}, {@link PublicFeature}
* See: {@link NgOnChangesFeature}, {@link ProvidersFeature}
*/
features?: ComponentDefFeature[];
@ -238,17 +238,6 @@ export function defineComponent<T>(componentDefinition: {
*/
changeDetection?: ChangeDetectionStrategy;
/**
* Defines the set of injectable objects that are visible to a Directive and its light DOM
* children.
*/
providers?: Provider[];
/**
* Defines the set of injectable objects that are visible to its view DOM children.
*/
viewProviders?: Provider[];
/**
* Registry of directives and components that may be found in this component's view.
*
@ -270,7 +259,7 @@ export function defineComponent<T>(componentDefinition: {
const declaredInputs: {[key: string]: string} = {} as any;
const def: Mutable<ComponentDef<any>, keyof ComponentDef<any>> = {
type: type,
diPublic: null,
providersResolver: null,
consts: componentDefinition.consts,
vars: componentDefinition.vars,
hostVars: componentDefinition.hostVars || 0,
@ -301,8 +290,6 @@ export function defineComponent<T>(componentDefinition: {
// TODO(misko): convert ViewEncapsulation into const enum so that it can be used directly in the
// next line. Also `None` should be 0 not 2.
encapsulation: componentDefinition.encapsulation || ViewEncapsulation.Emulated,
providers: EMPTY_ARRAY,
viewProviders: EMPTY_ARRAY,
id: 'c',
styles: componentDefinition.styles || EMPTY_ARRAY,
_: null as never,
@ -525,7 +512,7 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
/**
* Factory method used to create an instance of directive.
*/
factory: () => T;
factory: (t: Type<T>| null) => T;
/**
* Static attributes to set on host element.
@ -595,7 +582,7 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
/**
* A list of optional features to apply.
*
* See: {@link NgOnChangesFeature}, {@link PublicFeature}, {@link InheritDefinitionFeature}
* See: {@link NgOnChangesFeature}, {@link ProvidersFeature}, {@link InheritDefinitionFeature}
*/
features?: DirectiveDefFeature[];
@ -615,7 +602,7 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
/**
* Function to create instances of content queries associated with a given directive.
*/
contentQueries?: (() => void);
contentQueries?: ((directiveIndex: number) => void);
/** Refreshes content queries associated with directives in a given view */
contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void);
@ -650,7 +637,7 @@ export function definePipe<T>(pipeDef: {
type: Type<T>,
/** A factory for creating a pipe instance. */
factory: () => T,
factory: (t: Type<T>| null) => T,
/** Whether the pipe is pure. */
pure?: boolean

View File

@ -6,23 +6,67 @@
* found in the LICENSE file at https://angular.io/license
*/
// We are temporarily importing the existing viewEngine_from core so we can be sure we are
// correctly implementing its interfaces for backwards compatibility.
import {getInjectableDef, getInjectorDef} from '../di/defs';
import {InjectionToken} from '../di/injection_token';
import {InjectFlags, Injector, inject, setCurrentInjector} from '../di/injector';
import {InjectFlags, Injector, NullInjector, injectRootLimpMode, setInjectImplementation} from '../di/injector';
import {Type} from '../type';
import {assertDefined} from './assert';
import {assertDefined, assertEqual} from './assert';
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
import {NG_ELEMENT_ID} from './fields';
import {_getViewData, getPreviousOrParentTNode, resolveDirective, setEnvironment} from './instructions';
import {DirectiveDef} from './interfaces/definition';
import {InjectorLocationFlags, PARENT_INJECTOR, TNODE,} from './interfaces/injector';
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector';
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node';
import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert';
import {getPreviousOrParentTNode, getViewData, setTNodeAndViewData} from './state';
import {getParentInjectorIndex, getParentInjectorView, getParentInjectorViewOffset, hasParentInjector, isComponent, stringify} from './util';
/**
* Defines if the call to `inject` should include `viewProviders` in its resolution.
*
* This is set to true when we try to instantiate a component. This value is reset in
* `getNodeInjectable` to a value which matches the declaration location of the token about to be
* instantiated. This is done so that if we are injecting a token which was declared outside of
* `viewProviders` we don't accidentally pull `viewProviders` in.
*
* Example:
*
* ```
* @Injectable()
* class MyService {
* constructor(public value: String) {}
* }
*
* @Component({
* providers: [
* MyService,
* {provide: String, value: 'providers' }
* ]
* viewProviders: [
* {provide: String, value: 'viewProviders'}
* ]
* })
* class MyComponent {
* constructor(myService: MyService, value: String) {
* // We expect that Component can see into `viewProviders`.
* expect(value).toEqual('viewProviders');
* // `MyService` was not declared in `viewProviders` hence it can't see it.
* expect(myService.value).toEqual('providers');
* }
* }
*
* ```
*/
let includeViewProviders = false;
function setIncludeViewProviders(v: boolean): boolean {
const oldValue = includeViewProviders;
includeViewProviders = v;
return oldValue;
}
/**
* The number of slots in each bloom filter (used by DI). The larger this number, the fewer
@ -43,46 +87,40 @@ let nextNgElementId = 0;
* @param tView The TView for the injector's bloom filters
* @param type The directive token to register
*/
export function bloomAdd(injectorIndex: number, tView: TView, type: Type<any>): void {
if (tView.firstTemplatePass) {
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
export function bloomAdd(
injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>): void {
ngDevMode && assertEqual(tView.firstTemplatePass, true, 'expected firstTemplatePass to be true');
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
// Set a unique ID on the directive type, so if something tries to inject the directive,
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
if (id == null) {
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
}
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
const bloomBit = id & BLOOM_MASK;
// Create a mask that targets the specific bit associated with the directive.
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
// to bit positions 0 - 31 in a 32 bit integer.
const mask = 1 << bloomBit;
// Use the raw bloomBit number to determine which bloom filter bucket we should check
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
const b7 = bloomBit & 0x80;
const b6 = bloomBit & 0x40;
const b5 = bloomBit & 0x20;
const tData = tView.data as number[];
if (b7) {
b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) :
(b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask));
} else {
b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) :
(b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask));
}
// Set a unique ID on the directive type, so if something tries to inject the directive,
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
if (id == null) {
id = (type as any)[NG_ELEMENT_ID] = nextNgElementId++;
}
}
export function getOrCreateNodeInjector(): number {
return getOrCreateNodeInjectorForNode(
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode,
_getViewData());
// We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
// so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
const bloomBit = id & BLOOM_MASK;
// Create a mask that targets the specific bit associated with the directive.
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
// to bit positions 0 - 31 in a 32 bit integer.
const mask = 1 << bloomBit;
// Use the raw bloomBit number to determine which bloom filter bucket we should check
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
const b7 = bloomBit & 0x80;
const b6 = bloomBit & 0x40;
const b5 = bloomBit & 0x20;
const tData = tView.data as number[];
if (b7) {
b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) :
(b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask));
} else {
b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) :
(b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask));
}
}
/**
@ -102,26 +140,29 @@ export function getOrCreateNodeInjectorForNode(
const tView = hostView[TVIEW];
if (tView.firstTemplatePass) {
tNode.injectorIndex = hostView.length;
setUpBloom(tView.data, tNode); // foundation for node bloom
setUpBloom(hostView, null); // foundation for cumulative bloom
setUpBloom(tView.blueprint, null);
insertBloom(tView.data, tNode); // foundation for node bloom
insertBloom(hostView, null); // foundation for cumulative bloom
insertBloom(tView.blueprint, null);
ngDevMode && assertEqual(
tNode.flags === 0 || tNode.flags === TNodeFlags.isComponent, true,
'expected tNode.flags to not be initialized');
}
const parentLoc = getParentInjectorLocation(tNode, hostView);
const parentIndex = parentLoc & InjectorLocationFlags.InjectorIndexMask;
const parentIndex = getParentInjectorIndex(parentLoc);
const parentView: LViewData = getParentInjectorView(parentLoc, hostView);
const parentData = parentView[TVIEW].data as any;
const injectorIndex = tNode.injectorIndex;
// If a parent injector can't be found, its location is set to -1.
// In that case, we don't need to set up a cumulative bloom
if (parentLoc !== -1) {
for (let i = 0; i < PARENT_INJECTOR; i++) {
const bloomIndex = parentIndex + i;
// Creates a cumulative bloom filter that merges the parent's bloom filter
// and its own cumulative bloom (which contains tokens for all ancestors)
hostView[injectorIndex + i] = parentView[bloomIndex] | parentData[bloomIndex];
if (hasParentInjector(parentLoc)) {
const parentData = parentView[TVIEW].data as any;
// Creates a cumulative bloom filter that merges the parent's bloom filter
// and its own cumulative bloom (which contains tokens for all ancestors)
for (let i = 0; i < 8; i++) {
hostView[injectorIndex + i] = parentView[parentIndex + i] | parentData[parentIndex + i];
}
}
@ -129,10 +170,11 @@ export function getOrCreateNodeInjectorForNode(
return injectorIndex;
}
function setUpBloom(arr: any[], footer: TNode | null) {
function insertBloom(arr: any[], footer: TNode | null): void {
arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
}
export function getInjectorIndex(tNode: TNode, hostView: LViewData): number {
if (tNode.injectorIndex === -1 ||
// If the injector index is the same as its parent's injector index, then the index has been
@ -150,10 +192,12 @@ export function getInjectorIndex(tNode: TNode, hostView: LViewData): number {
/**
* Finds the index of the parent injector, with a view offset if applicable. Used to set the
* parent injector initially.
*
* Returns a combination of number of `ViewData` we have to go up and index in that `Viewdata`
*/
export function getParentInjectorLocation(tNode: TNode, view: LViewData): number {
export function getParentInjectorLocation(tNode: TNode, view: LViewData): RelativeInjectorLocation {
if (tNode.parent && tNode.parent.injectorIndex !== -1) {
return tNode.parent.injectorIndex; // view offset is 0
return tNode.parent.injectorIndex as any; // view offset is 0
}
// For most cases, the parent injector index can be found on the host node (e.g. for component
@ -167,81 +211,20 @@ export function getParentInjectorLocation(tNode: TNode, view: LViewData): number
viewOffset++;
}
return hostTNode ?
hostTNode.injectorIndex | (viewOffset << InjectorLocationFlags.ViewOffsetShift) :
-1;
hostTNode.injectorIndex | (viewOffset << RelativeInjectorLocationFlags.ViewOffsetShift) :
-1 as any;
}
/**
* Unwraps a parent injector location number to find the view offset from the current injector,
* then walks up the declaration view tree until the view is found that contains the parent
* injector.
*
* @param location The location of the parent injector, which contains the view offset
* @param startView The LViewData instance from which to start walking up the view tree
* @returns The LViewData instance that contains the parent injector
*/
export function getParentInjectorView(location: number, startView: LViewData): LViewData {
let viewOffset = location >> InjectorLocationFlags.ViewOffsetShift;
let parentView = startView;
// For most cases, the parent injector can be found on the host node (e.g. for component
// or container), but we must keep the loop here to support the rarer case of deeply nested
// <ng-template> tags or inline views, where the parent injector might live many views
// above the child injector.
while (viewOffset > 0) {
parentView = parentView[DECLARATION_VIEW] !;
viewOffset--;
}
return parentView;
}
/**
* Makes a directive public to the DI system by adding it to an injector's bloom filter.
* Makes a type or an injection token public to the DI system by adding it to an
* injector's bloom filter.
*
* @param di The node injector in which a directive will be added
* @param def The definition of the directive to be made public
* @param token The type or the injection token to be made public
*/
export function diPublicInInjector(
injectorIndex: number, view: LViewData, def: DirectiveDef<any>): void {
bloomAdd(injectorIndex, view[TVIEW], def.type);
}
/**
* Makes a directive public to the DI system by adding it to an injector's bloom filter.
*
* @param def The definition of the directive to be made public
*/
export function diPublic(def: DirectiveDef<any>): void {
diPublicInInjector(getOrCreateNodeInjector(), _getViewData(), def);
}
/**
* Returns the value associated to the given token from the injectors.
*
* `directiveInject` is intended to be used for directive, component and pipe factories.
* All other injection use `inject` which does not walk the node injector tree.
*
* Usage example (in factory function):
*
* class SomeDirective {
* constructor(directive: DirectiveA) {}
*
* static ngDirectiveDef = defineDirective({
* type: SomeDirective,
* factory: () => new SomeDirective(directiveInject(DirectiveA))
* });
* }
*
* @param token the type or token to inject
* @param flags Injection flags
* @returns the value from the injector or `null` when not found
*/
export function directiveInject<T>(token: Type<T>| InjectionToken<T>): T;
export function directiveInject<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags): T;
export function directiveInject<T>(
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
const hostTNode =
getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode;
return getOrCreateInjectable<T>(hostTNode, _getViewData(), token, flags);
injectorIndex: number, view: LViewData, token: InjectionToken<any>| Type<any>): void {
bloomAdd(injectorIndex, view[TVIEW], token);
}
/**
@ -275,8 +258,7 @@ export function directiveInject<T>(
*
* @publicApi
*/
export function injectAttribute(attrNameToInject: string): string|undefined {
const tNode = getPreviousOrParentTNode();
export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): string|undefined {
ngDevMode && assertNodeOfPossibleTypes(
tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
ngDevMode && assertDefined(tNode, 'expecting tNode');
@ -295,7 +277,7 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
/**
* Returns the value associated to the given token from the injectors.
* Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
*
* Look for the injector providing the token by walking up the node injector tree and then
* the module injector tree.
@ -306,133 +288,169 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
* @returns the value from the injector or `null` when not found
*/
export function getOrCreateInjectable<T>(
hostTNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData,
token: Type<T>| InjectionToken<T>, flags: InjectFlags = InjectFlags.Default): T|null {
tNode: TElementNode | TContainerNode | TElementContainerNode, lViewData: LViewData,
token: Type<T>| InjectionToken<T>, flags: InjectFlags = InjectFlags.Default,
notFoundValue?: any): T|null {
const bloomHash = bloomHashBitOrFactory(token);
// If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
// so just call the factory function to create it.
if (typeof bloomHash === 'function') return bloomHash();
if (typeof bloomHash === 'function') {
const savePreviousOrParentTNode = getPreviousOrParentTNode();
const saveViewData = getViewData();
setTNodeAndViewData(tNode, lViewData);
try {
return bloomHash();
} finally {
setTNodeAndViewData(savePreviousOrParentTNode, saveViewData);
}
} else if (typeof bloomHash == 'number') {
// If the token has a bloom hash, then it is a token which could be in NodeInjector.
// If the token has a bloom hash, then it is a directive that is public to the injection system
// (diPublic) otherwise fall back to the module injector.
if (bloomHash != null) {
const startInjectorIndex = getInjectorIndex(hostTNode, hostView);
// A reference to the previous injector TView that was found while climbing the element injector
// tree. This is used to know if viewProviders can be accessed on the current injector.
let previousTView: TView|null = null;
let injectorIndex = getInjectorIndex(tNode, lViewData);
let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR;
let injectorIndex = startInjectorIndex;
let injectorView = hostView;
let parentLocation: number = -1;
// If we should skip this injector, start by searching the parent injector.
if (flags & InjectFlags.SkipSelf) {
parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lViewData) :
lViewData[injectorIndex + PARENT_INJECTOR];
// If we should skip this injector or if an injector doesn't exist on this node (e.g. all
// directives on this node are private), start by searching the parent injector.
if (flags & InjectFlags.SkipSelf || injectorIndex === -1) {
parentLocation = injectorIndex === -1 ? getParentInjectorLocation(hostTNode, hostView) :
injectorView[injectorIndex + PARENT_INJECTOR];
if (shouldNotSearchParent(flags, parentLocation)) {
if (!shouldSearchParent(flags, parentLocation)) {
injectorIndex = -1;
} else {
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
injectorView = getParentInjectorView(parentLocation, injectorView);
previousTView = lViewData[TVIEW];
injectorIndex = getParentInjectorIndex(parentLocation);
lViewData = getParentInjectorView(parentLocation, lViewData);
}
}
// Traverse up the injector tree until we find a potential match or until we know there
// *isn't* a match.
while (injectorIndex !== -1) {
// Traverse up the injector tree until we find a potential match or until we know there
// *isn't* a match. Outer loop is necessary in case we get a false positive injector.
while (injectorIndex !== -1) {
// Check the current injector. If it matches, stop searching for an injector.
if (injectorHasToken(bloomHash, injectorIndex, injectorView[TVIEW].data)) {
break;
}
parentLocation = lViewData[injectorIndex + PARENT_INJECTOR];
parentLocation = injectorView[injectorIndex + PARENT_INJECTOR];
if (shouldNotSearchParent(flags, parentLocation)) {
injectorIndex = -1;
break;
}
// If the ancestor bloom filter value has the bit corresponding to the directive, traverse
// up to find the specific injector. If the ancestor bloom filter does not have the bit, we
// can abort.
if (injectorHasToken(bloomHash, injectorIndex, injectorView)) {
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
injectorView = getParentInjectorView(parentLocation, injectorView);
} else {
injectorIndex = -1;
break;
// Check the current injector. If it matches, see if it contains token.
const tView = lViewData[TVIEW];
if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
// At this point, we have an injector which *may* contain the token, so we step through
// the providers and directives associated with the injector's corresponding node to get
// the instance.
const instance: T|null =
searchTokensOnInjector<T>(injectorIndex, lViewData, token, previousTView);
if (instance !== NOT_FOUND) {
return instance;
}
}
// If no injector is found, we *know* that there is no ancestor injector that contains the
// token, so we abort.
if (injectorIndex === -1) {
break;
if (shouldSearchParent(flags, parentLocation) &&
bloomHasToken(bloomHash, injectorIndex, lViewData)) {
// The def wasn't found anywhere on this node, so it was a false positive.
// Traverse up the tree and continue searching.
previousTView = tView;
injectorIndex = getParentInjectorIndex(parentLocation);
lViewData = getParentInjectorView(parentLocation, lViewData);
} else {
// If we should not search parent OR If the ancestor bloom filter value does not have the
// bit corresponding to the directive we can give up on traversing up to find the specific
// injector.
injectorIndex = -1;
}
// At this point, we have an injector which *may* contain the token, so we step through the
// directives associated with the injector's corresponding node to get the directive instance.
let instance: T|null;
if (instance = searchDirectivesOnInjector<T>(injectorIndex, injectorView, token)) {
return instance;
}
// If we *didn't* find the directive for the token and we are searching the current node's
// injector, it's possible the directive is on this node and hasn't been created yet.
if (injectorIndex === startInjectorIndex && hostView === injectorView &&
(instance = searchMatchesQueuedForCreation<T>(token, injectorView[TVIEW]))) {
return instance;
}
// The def wasn't found anywhere on this node, so it was a false positive.
// Traverse up the tree and continue searching.
injectorIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
injectorView = getParentInjectorView(parentLocation, injectorView);
}
}
const moduleInjector = hostView[INJECTOR];
const formerInjector = setCurrentInjector(moduleInjector);
try {
return inject(token, flags);
} finally {
setCurrentInjector(formerInjector);
}
}
function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null {
const matches = hostTView.currentMatches;
if (matches) {
for (let i = 0; i < matches.length; i += 2) {
const def = matches[i] as DirectiveDef<any>;
if (def.type === token) {
return resolveDirective(def, i + 1, matches);
}
if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
const moduleInjector = lViewData[INJECTOR];
if (moduleInjector) {
return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
} else {
return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
}
}
return null;
if (flags & InjectFlags.Optional) {
return notFoundValue;
} else {
throw new Error(`NodeInjector: NOT_FOUND [${stringify(token)}]`);
}
}
function searchDirectivesOnInjector<T>(
injectorIndex: number, injectorView: LViewData, token: Type<T>| InjectionToken<T>) {
const tNode = injectorView[TVIEW].data[injectorIndex + TNODE] as TNode;
const NOT_FOUND = {};
function searchTokensOnInjector<T>(
injectorIndex: number, injectorView: LViewData, token: Type<T>| InjectionToken<T>,
previousTView: TView | null) {
const currentTView = injectorView[TVIEW];
const tNode = currentTView.data[injectorIndex + TNODE] as TNode;
const nodeFlags = tNode.flags;
const count = nodeFlags & TNodeFlags.DirectiveCountMask;
if (count !== 0) {
const start = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
const end = start + count;
const defs = injectorView[TVIEW].data;
for (let i = start; i < end; i++) {
// Get the definition for the directive at this index and, if it is injectable (diPublic),
// and matches the given token, return the directive instance.
const directiveDef = defs[i] as DirectiveDef<any>;
if (directiveDef.type === token && directiveDef.diPublic) {
return injectorView[i];
}
const nodeProviderIndexes = tNode.providerIndexes;
const tInjectables = currentTView.data;
// First, we step through providers
let canAccessViewProviders = false;
// We need to determine if view providers can be accessed by the starting element.
// It happens in 2 cases:
// 1) On the initial element injector , if we are instantiating a token which can see the
// viewProviders of the component of that element. Such token are:
// - the component itself (but not other directives)
// - viewProviders tokens of the component (but not providers tokens)
// 2) Upper in the element injector tree, if the starting element is actually in the view of
// the current element. To determine this, we track the transition of view during the climb,
// and check the host node of the current view to identify component views.
if (previousTView == null && isComponent(tNode) && includeViewProviders ||
previousTView != null && previousTView != currentTView &&
(currentTView.node == null || currentTView.node !.type === TNodeType.Element)) {
canAccessViewProviders = true;
}
const startInjectables = nodeProviderIndexes & TNodeProviderIndexes.ProvidersStartIndexMask;
const startDirectives = nodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
const cptViewProvidersCount =
nodeProviderIndexes >> TNodeProviderIndexes.CptViewProvidersCountShift;
const startingIndex =
canAccessViewProviders ? startInjectables : startInjectables + cptViewProvidersCount;
const directiveCount = nodeFlags & TNodeFlags.DirectiveCountMask;
for (let i = startingIndex; i < startDirectives + directiveCount; i++) {
const providerTokenOrDef = tInjectables[i] as InjectionToken<any>| Type<any>| DirectiveDef<any>;
if (i < startDirectives && token === providerTokenOrDef ||
i >= startDirectives && (providerTokenOrDef as DirectiveDef<any>).type === token) {
return getNodeInjectable(tInjectables, injectorView, i, tNode as TElementNode);
}
}
return null;
return NOT_FOUND;
}
/**
* Retrieve or instantiate the injectable from the `lData` at particular `index`.
*
* This function checks to see if the value has already been instantiated and if so returns the
* cached `injectable`. Otherwise if it detects that the value is still a factory it
* instantiates the `injectable` and caches the value.
*/
export function getNodeInjectable(
tData: TData, lData: LViewData, index: number, tNode: TElementNode): any {
let value = lData[index];
if (isFactory(value)) {
const factory: NodeInjectorFactory = value;
if (factory.resolving) {
throw new Error(`Circular dep for ${stringify(tData[index])}`);
}
const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
factory.resolving = true;
let previousInjectImplementation;
if (factory.injectImpl) {
previousInjectImplementation = setInjectImplementation(factory.injectImpl);
}
const savePreviousOrParentTNode = getPreviousOrParentTNode();
const saveViewData = getViewData();
setTNodeAndViewData(tNode, lData);
try {
value = lData[index] = factory.factory(null, tData, lData, tNode);
} finally {
if (factory.injectImpl) setInjectImplementation(previousInjectImplementation);
setIncludeViewProviders(previousIncludeViewProviders);
factory.resolving = false;
setTNodeAndViewData(savePreviousOrParentTNode, saveViewData);
}
}
return value;
}
/**
@ -452,7 +470,7 @@ export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): nu
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
}
export function injectorHasToken(
export function bloomHasToken(
bloomHash: number, injectorIndex: number, injectorView: LViewData | TData) {
// Create a mask that targets the specific bit associated with the directive we're looking for.
// JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
@ -481,26 +499,14 @@ export function injectorHasToken(
}
/** Returns true if flags prevent parent injector from being searched for tokens */
function shouldNotSearchParent(flags: InjectFlags, parentLocation: number): boolean|number {
return flags & InjectFlags.Self ||
(flags & InjectFlags.Host && (parentLocation >> InjectorLocationFlags.ViewOffsetShift) > 0);
function shouldSearchParent(flags: InjectFlags, parentLocation: RelativeInjectorLocation): boolean|
number {
return !(
flags & InjectFlags.Self ||
(flags & InjectFlags.Host && getParentInjectorViewOffset(parentLocation) > 0));
}
export class NodeInjector implements Injector {
private _injectorIndex: number;
constructor(
private _tNode: TElementNode|TContainerNode|TElementContainerNode,
private _hostView: LViewData) {
this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _hostView);
}
get(token: any): any {
setEnvironment(this._tNode, this._hostView);
return getOrCreateInjectable(this._tNode, this._hostView, token);
}
}
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
export function getFactoryOf<T>(type: Type<any>): ((type: Type<T>| null) => T)|null {
const typeAny = type as any;
const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) ||
getPipeDef<T>(typeAny) || getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);

View File

@ -0,0 +1,260 @@
/*
* @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 {resolveForwardRef} from '../di/forward_ref';
import {Provider} from '../di/provider';
import {isTypeProvider, providerToFactory} from '../di/r3_injector';
import {DirectiveDef} from '.';
import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from './di';
import {directiveInject} from './instructions';
import {NodeInjectorFactory} from './interfaces/injector';
import {TContainerNode, TElementContainerNode, TElementNode, TNodeFlags, TNodeProviderIndexes} from './interfaces/node';
import {LViewData, TData, TVIEW, TView} from './interfaces/view';
import {getPreviousOrParentTNode, getViewData} from './state';
import {isComponentDef} from './util';
/**
* Resolves the providers which are defined in the DirectiveDef.
*
* When inserting the tokens and the factories in their respective arrays, we can assume that
* this method is called first for the component (if any), and then for other directives on the same
* node.
* As a consequence,the providers are always processed in that order:
* 1) The view providers of the component
* 2) The providers of the component
* 3) The providers of the other directives
* This matches the structure of the injectables arrays of a view (for each node).
* So the tokens and the factories can be pushed at the end of the arrays, except
* in one case for multi providers.
*
* @param def the directive definition
* @param providers: Array of `providers`.
* @param viewProviders: Array of `viewProviders`.
*/
export function providersResolver<T>(
def: DirectiveDef<T>, providers: Provider[], viewProviders: Provider[]): void {
const viewData = getViewData();
const tView: TView = viewData[TVIEW];
if (tView.firstTemplatePass) {
const isComponent = isComponentDef(def);
// The list of view providers is processed first, and the flags are updated
resolveProvider(viewProviders, tView.data, tView.blueprint, isComponent, true);
// Then, the list of providers is processed, and the flags are updated
resolveProvider(providers, tView.data, tView.blueprint, isComponent, false);
}
}
/**
* Resolves a provider and publishes it to the DI system.
*/
function resolveProvider(
provider: Provider, tInjectables: TData, lInjectablesBlueprint: NodeInjectorFactory[],
isComponent: boolean, isViewProvider: boolean): void {
provider = resolveForwardRef(provider);
if (Array.isArray(provider)) {
// Recursively call `resolveProvider`
// Recursion is OK in this case because this code will not be in hot-path once we implement
// cloning of the initial state.
for (let i = 0; i < provider.length; i++) {
resolveProvider(
provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider);
}
} else {
const viewData = getViewData();
let token: any = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide);
let providerFactory: () => any = providerToFactory(provider);
const previousOrParentTNode = getPreviousOrParentTNode();
const beginIndex =
previousOrParentTNode.providerIndexes & TNodeProviderIndexes.ProvidersStartIndexMask;
const endIndex = previousOrParentTNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
const cptViewProvidersCount =
previousOrParentTNode.providerIndexes >> TNodeProviderIndexes.CptViewProvidersCountShift;
if (isTypeProvider(provider) || !provider.multi) {
// Single provider case: the factory is created and pushed immediately
const factory = new NodeInjectorFactory(providerFactory, isViewProvider, directiveInject);
const existingFactoryIndex = indexOf(
token, tInjectables, isViewProvider ? beginIndex : beginIndex + cptViewProvidersCount,
endIndex);
if (existingFactoryIndex == -1) {
diPublicInInjector(
getOrCreateNodeInjectorForNode(
previousOrParentTNode as TElementNode | TContainerNode | TElementContainerNode,
viewData),
viewData, token);
tInjectables.push(token);
previousOrParentTNode.flags += 1 << TNodeFlags.DirectiveStartingIndexShift;
if (isViewProvider) {
previousOrParentTNode.providerIndexes +=
TNodeProviderIndexes.CptViewProvidersCountShifter;
}
lInjectablesBlueprint.push(factory);
viewData.push(factory);
} else {
lInjectablesBlueprint[existingFactoryIndex] = factory;
viewData[existingFactoryIndex] = factory;
}
} else {
// Multi provider case:
// We create a multi factory which is going to aggregate all the values.
// Since the output of such a factory depends on content or view injection,
// we create two of them, which are linked together.
//
// The first one (for view providers) is always in the first block of the injectables array,
// and the second one (for providers) is always in the second block.
// This is important because view providers have higher priority. When a multi token
// is being looked up, the view providers should be found first.
// Note that it is not possible to have a multi factory in the third block (directive block).
//
// The algorithm to process multi providers is as follows:
// 1) If the multi provider comes from the `viewProviders` of the component:
// a) If the special view providers factory doesn't exist, it is created and pushed.
// b) Else, the multi provider is added to the existing multi factory.
// 2) If the multi provider comes from the `providers` of the component or of another
// directive:
// a) If the multi factory doesn't exist, it is created and provider pushed into it.
// It is also linked to the multi factory for view providers, if it exists.
// b) Else, the multi provider is added to the existing multi factory.
const existingProvidersFactoryIndex =
indexOf(token, tInjectables, beginIndex + cptViewProvidersCount, endIndex);
const existingViewProvidersFactoryIndex =
indexOf(token, tInjectables, beginIndex, beginIndex + cptViewProvidersCount);
const doesProvidersFactoryExist = existingProvidersFactoryIndex >= 0 &&
lInjectablesBlueprint[existingProvidersFactoryIndex];
const doesViewProvidersFactoryExist = existingViewProvidersFactoryIndex >= 0 &&
lInjectablesBlueprint[existingViewProvidersFactoryIndex];
if (isViewProvider && !doesViewProvidersFactoryExist ||
!isViewProvider && !doesProvidersFactoryExist) {
// Cases 1.a and 2.a
diPublicInInjector(
getOrCreateNodeInjectorForNode(
previousOrParentTNode as TElementNode | TContainerNode | TElementContainerNode,
viewData),
viewData, token);
const factory = multiFactory(
isViewProvider ? multiViewProvidersFactoryResolver : multiProvidersFactoryResolver,
lInjectablesBlueprint.length, isViewProvider, isComponent, providerFactory);
if (!isViewProvider && doesViewProvidersFactoryExist) {
lInjectablesBlueprint[existingViewProvidersFactoryIndex].providerFactory = factory;
}
tInjectables.push(token);
previousOrParentTNode.flags += 1 << TNodeFlags.DirectiveStartingIndexShift;
if (isViewProvider) {
previousOrParentTNode.providerIndexes +=
TNodeProviderIndexes.CptViewProvidersCountShifter;
}
lInjectablesBlueprint.push(factory);
viewData.push(factory);
} else {
// Cases 1.b and 2.b
multiFactoryAdd(
lInjectablesBlueprint ![isViewProvider ? existingViewProvidersFactoryIndex : existingProvidersFactoryIndex],
providerFactory, !isViewProvider && isComponent);
}
if (!isViewProvider && isComponent && doesViewProvidersFactoryExist) {
lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders !++;
}
}
}
}
/**
* Add a factory in a multi factory.
*/
function multiFactoryAdd(
multiFactory: NodeInjectorFactory, factory: () => any, isComponentProvider: boolean): void {
multiFactory.multi !.push(factory);
if (isComponentProvider) {
multiFactory.componentProviders !++;
}
}
/**
* Returns the index of item in the array, but only in the begin to end range.
*/
function indexOf(item: any, arr: any[], begin: number, end: number) {
for (let i = begin; i < end; i++) {
if (arr[i] === item) return i;
}
return -1;
}
/**
* Use this with `multi` `providers`.
*/
function multiProvidersFactoryResolver(
this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData,
tNode: TElementNode): any[] {
return multiResolve(this.multi !, []);
}
/**
* Use this with `multi` `viewProviders`.
*
* This factory knows how to concatenate itself with the existing `multi` `providers`.
*/
function multiViewProvidersFactoryResolver(
this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData,
tNode: TElementNode): any[] {
const factories = this.multi !;
let result: any[];
if (this.providerFactory) {
const componentCount = this.providerFactory.componentProviders !;
const multiProviders = getNodeInjectable(tData, lData, this.providerFactory !.index !, tNode);
// Copy the section of the array which contains `multi` `providers` from the component
result = multiProviders.slice(0, componentCount);
// Insert the `viewProvider` instances.
multiResolve(factories, result);
// Copy the section of the array which contains `multi` `providers` from other directives
for (let i = componentCount; i < multiProviders.length; i++) {
result.push(multiProviders[i]);
}
} else {
result = [];
// Insert the `viewProvider` instances.
multiResolve(factories, result);
}
return result;
}
/**
* Maps an array of factories into an array of values.
*/
function multiResolve(factories: Array<() => any>, result: any[]): any[] {
for (let i = 0; i < factories.length; i++) {
const factory = factories[i] !as() => null;
result.push(factory());
}
return result;
}
/**
* Creates a multi factory.
*/
function multiFactory(
factoryFn:
(this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData, tNode: TElementNode) =>
any,
index: number, isViewProvider: boolean, isComponent: boolean,
f: () => any): NodeInjectorFactory {
const factory = new NodeInjectorFactory(factoryFn, isViewProvider, directiveInject);
factory.multi = [];
factory.index = index;
factory.componentProviders = 0;
multiFactoryAdd(factory, f, isComponent && !isViewProvider);
return factory;
}

View File

@ -9,11 +9,12 @@ import {Injector} from '../di/injector';
import {assertDefined} from './assert';
import {discoverDirectives, discoverLocalRefs, getContext, isComponentInstance} from './context_discovery';
import {NodeInjector} from './di';
import {LContext} from './interfaces/context';
import {TElementNode, TNode, TNodeFlags} from './interfaces/node';
import {CONTEXT, FLAGS, LViewData, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view';
import {getComponentViewByIndex, readPatchedLViewData} from './util';
import {NodeInjector} from './view_engine_compatibility';
/**

View File

@ -102,9 +102,9 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
const superContentQueries = superDef.contentQueries;
if (superContentQueries) {
if (prevContentQueries) {
definition.contentQueries = () => {
superContentQueries();
prevContentQueries();
definition.contentQueries = (dirIndex: number) => {
superContentQueries(dirIndex);
prevContentQueries(dirIndex);
};
} else {
definition.contentQueries = superContentQueries;

View File

@ -0,0 +1,45 @@
/**
* @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 {Provider} from '../../di/provider';
import {providersResolver} from '../di_setup';
import {DirectiveDef} from '../interfaces/definition';
/**
* This feature resolves the providers of a directive (or component),
* and publish them into the DI system, making it visible to others for injection.
*
* For example:
* class ComponentWithProviders {
* constructor(private greeter: GreeterDE) {}
*
* static ngComponentDef = defineComponent({
* type: ComponentWithProviders,
* selectors: [['component-with-providers']],
* factory: () => new ComponentWithProviders(directiveInject(GreeterDE as any)),
* consts: 1,
* vars: 1,
* template: function(fs: RenderFlags, ctx: ComponentWithProviders) {
* if (fs & RenderFlags.Create) {
* text(0);
* }
* if (fs & RenderFlags.Update) {
* textBinding(0, bind(ctx.greeter.greet()));
* }
* },
* features: [ProvidersFeature([GreeterDE])]
* });
* }
*
* @param definition
*/
export function ProvidersFeature<T>(providers: Provider[], viewProviders: Provider[] = []) {
return (definition: DirectiveDef<T>) => {
definition.providersResolver = (def: DirectiveDef<T>) =>
providersResolver(def, providers, viewProviders);
};
}

View File

@ -1,19 +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 {diPublic} from '../di';
import {DirectiveDef} from '../interfaces/definition';
/**
* This feature publishes the directive (or component) into the DI system, making it visible to
* others for injection.
*
* @param definition
*/
export function PublicFeature<T>(definition: DirectiveDef<T>) {
definition.diPublic = diPublic;
}

View File

@ -9,13 +9,14 @@
import {NO_CHANGE} from '../../src/render3/tokens';
import {assertEqual, assertLessThan} from './assert';
import {_getViewData, adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createNodeAtIndex, getRenderer, load, resetComponentState} from './instructions';
import {adjustBlueprintForNewNode, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createNodeAtIndex, load} from './instructions';
import {LContainer, NATIVE, RENDER_PARENT} from './interfaces/container';
import {TElementNode, TNode, TNodeType} from './interfaces/node';
import {RComment, RElement} from './interfaces/renderer';
import {StylingContext} from './interfaces/styling';
import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, TVIEW} from './interfaces/view';
import {appendChild, createTextNode, removeChild} from './node_manipulation';
import {getRenderer, getViewData, resetComponentState} from './state';
import {getNativeByIndex, getNativeByTNode, getTNode, isLContainer, stringify} from './util';
@ -256,7 +257,7 @@ function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode):
ngDevMode.rendererMoveNode++;
}
const viewData = _getViewData();
const viewData = getViewData();
// On first pass, re-organize node tree to put this node in the correct position.
const firstTemplatePass = viewData[TVIEW].firstTemplatePass;
@ -311,7 +312,7 @@ export function i18nEnd(): void {
* @param instructions The list of instructions to apply on the current view.
*/
export function i18nApply(startIndex: number, instructions: I18nInstruction[]): void {
const viewData = _getViewData();
const viewData = getViewData();
if (ngDevMode) {
assertEqual(
viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex,
@ -411,7 +412,7 @@ export function i18nExpMapping(
* @returns The concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
*/
export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): string|NO_CHANGE {
const different = bindingUpdated(_getViewData()[BINDING_INDEX]++, v0);
const different = bindingUpdated(getViewData()[BINDING_INDEX]++, v0);
if (!different) {
return NO_CHANGE;
@ -442,7 +443,7 @@ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any):
*/
export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, v1: any): string|
NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
@ -482,7 +483,7 @@ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any,
*/
export function i18nInterpolation3(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any): string|NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
@ -524,7 +525,7 @@ export function i18nInterpolation3(
*/
export function i18nInterpolation4(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any): string|NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
@ -568,7 +569,7 @@ export function i18nInterpolation4(
export function i18nInterpolation5(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any): string|
NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
viewData[BINDING_INDEX] += 5;
@ -615,7 +616,7 @@ export function i18nInterpolation5(
i18nInterpolation6(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any):
string|NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
viewData[BINDING_INDEX] += 6;
@ -663,7 +664,7 @@ i18nInterpolation6(
export function i18nInterpolation7(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any): string|NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
viewData[BINDING_INDEX] += 7;
@ -712,7 +713,7 @@ export function i18nInterpolation7(
export function i18nInterpolation8(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any, v7: any): string|NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
viewData[BINDING_INDEX] += 8;
@ -753,7 +754,7 @@ export function i18nInterpolation8(
*/
export function i18nInterpolationV(instructions: I18nExpInstruction[], values: any[]): string|
NO_CHANGE {
const viewData = _getViewData();
const viewData = getViewData();
let different = false;
for (let i = 0; i < values.length; i++) {
// Check if bindings have changed

View File

@ -9,11 +9,11 @@ import {LifecycleHooksFeature, getHostElement, getRenderedText, renderComponent,
import {defineBase, defineComponent, defineDirective, defineNgModule, definePipe} from './definition';
import {InheritDefinitionFeature} from './features/inherit_definition_feature';
import {NgOnChangesFeature} from './features/ng_onchanges_feature';
import {PublicFeature} from './features/public_feature';
import {ProvidersFeature} from './features/providers_feature';
import {BaseDef, ComponentDef, ComponentDefWithMeta, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefWithMeta, DirectiveType, PipeDef, PipeDefWithMeta} from './interfaces/definition';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2, injectComponentFactoryResolver} from './component_ref';
export {directiveInject, getFactoryOf, getInheritedFactory, injectAttribute} from './di';
export {getFactoryOf, getInheritedFactory} from './di';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection';
@ -51,9 +51,6 @@ export {
elementStyleProp,
elementStylingApply,
getCurrentView,
restoreView,
listener,
store,
load,
@ -62,9 +59,6 @@ export {
namespaceMathML,
namespaceSVG,
enableBindings,
disableBindings,
projection,
projectionDef,
@ -79,8 +73,19 @@ export {
detectChanges,
markDirty,
tick,
directiveInject,
injectAttribute,
} from './instructions';
export {
getCurrentView,
restoreView,
enableBindings,
disableBindings,
} from './state';
export {
i18nAttribute,
i18nExp,
@ -157,7 +162,7 @@ export {
DirectiveType,
NgOnChangesFeature,
InheritDefinitionFeature,
PublicFeature,
ProvidersFeature,
PipeDef,
PipeDefWithMeta,
LifecycleHooksFeature,

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Provider, ViewEncapsulation} from '../../core';
import {ViewEncapsulation} from '../../core';
import {Type} from '../../type';
import {CssSelectorList} from './projection';
@ -112,11 +112,11 @@ export interface DirectiveDef<T> extends BaseDef<T> {
/** Token representing the directive. Used by DI. */
type: Type<T>;
/** Function that makes a directive public to the DI system. */
diPublic: ((def: DirectiveDef<T>) => void)|null;
/** Function that resolves providers and publishes them into the DI system. */
providersResolver: ((def: DirectiveDef<T>) => void)|null;
/** The selectors that will be used to match nodes to this directive. */
selectors: CssSelectorList;
readonly selectors: CssSelectorList;
/**
* Name under which the directive is exported (for use with local references in template)
@ -126,12 +126,12 @@ export interface DirectiveDef<T> extends BaseDef<T> {
/**
* Factory function used to create a new directive instance.
*/
factory(): T;
factory: (t: Type<T>|null) => T;
/**
* Function to create instances of content queries associated with a given directive.
*/
contentQueries: (() => void)|null;
contentQueries: ((directiveIndex: number) => void)|null;
/** Refreshes content queries associated with directives in a given view */
contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null;
@ -142,7 +142,7 @@ export interface DirectiveDef<T> extends BaseDef<T> {
* Used to calculate the length of the LViewData array for the *parent* component
* of this directive/component.
*/
hostVars: number;
readonly hostVars: number;
/** Refreshes host bindings on the associated directive. */
hostBindings: HostBindingsFunction|null;
@ -153,7 +153,7 @@ export interface DirectiveDef<T> extends BaseDef<T> {
* Even indices: attribute name
* Odd indices: attribute value
*/
attributes: string[]|null;
readonly attributes: string[]|null;
/* The following are lifecycle hooks for this component */
onInit: (() => void)|null;
@ -167,7 +167,7 @@ export interface DirectiveDef<T> extends BaseDef<T> {
/**
* The features applied to this directive
*/
features: DirectiveDefFeature[]|null;
readonly features: DirectiveDefFeature[]|null;
}
export type ComponentDefWithMeta<
@ -245,18 +245,7 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
readonly onPush: boolean;
/**
* Defines the set of injectable providers that are visible to a Directive and its content DOM
* children.
*/
readonly providers: Provider[]|null;
/**
* Defines the set of injectable providers that are visible to a Directive and its view DOM
* children only.
*/
readonly viewProviders: Provider[]|null;
/**
* Registry of directives and components that may be found in this view.
*
* The property is either an array of `DirectiveDef`s or a function which returns the array of
@ -297,12 +286,12 @@ export interface PipeDef<T> {
*
* Used to resolve pipe in templates.
*/
name: string;
readonly name: string;
/**
* Factory function used to create a new pipe instance.
*/
factory: () => T;
factory: (t: Type<T>|null) => T;
/**
* Whether or not the pipe is pure.
@ -310,7 +299,7 @@ export interface PipeDef<T> {
* Pure pipes result only depends on the pipe input and not on internal
* state of the pipe.
*/
pure: boolean;
readonly pure: boolean;
/* The following are lifecycle hooks for this pipe */
onDestroy: (() => void)|null;

View File

@ -6,18 +6,32 @@
* found in the LICENSE file at https://angular.io/license
*/
import {TContainerNode, TElementContainerNode, TElementNode,} from './node';
import {InjectionToken} from '../../di/injection_token';
import {InjectFlags} from '../../di/injector';
import {Type} from '../../type';
import {TElementNode} from './node';
import {LViewData, TData} from './view';
export const TNODE = 8;
export const PARENT_INJECTOR = 8;
export const INJECTOR_SIZE = 9;
export const enum InjectorLocationFlags {
/**
* Represents a relative location of parent injector.
*
* The interfaces encodes number of parents `LViewData`s to traverse and index in the `LViewData`
* pointing to the parent injector.
*/
export interface RelativeInjectorLocation { __brand__: 'RelativeInjectorLocationFlags'; }
export const enum RelativeInjectorLocationFlags {
InjectorIndexMask = 0b111111111111111,
ViewOffsetShift = 15
ViewOffsetShift = 15,
NO_PARENT = -1,
}
export const NO_PARENT_INJECTOR: RelativeInjectorLocation = -1 as any;
/**
* Each injector is saved in 9 contiguous slots in `LViewData` and 9 contiguous slots in
* `TView.data`. This allows us to store information about the current node's tokens (which
@ -98,6 +112,140 @@ export const enum InjectorLocationFlags {
* }
*/
/**
* Factory for creating instances of injectors in the NodeInjector.
*
* This factory is complicated by the fact that it can resolve `multi` factories as well.
*
* NOTE: Some of the fields are optional which means that this class has two hidden classes.
* - One without `multi` support (most common)
* - One with `multi` values, (rare).
*
* Since VMs can cache up to 4 inline hidden classes this is OK.
*
* - Single factory: Only `resolving` and `factory` is defined.
* - `providers` factory: `componentProviders` is a number and `index = -1`.
* - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`.
*/
export class NodeInjectorFactory {
/**
* The inject implementation to be activated when using the factory.
*/
injectImpl: null|(<T>(token: Type<T>|InjectionToken<T>, flags: InjectFlags) => T);
/**
* Marker set to true during factory invocation to see if we get into recursive loop.
* Recursive loop causes an error to be displayed.
*/
resolving = false;
/**
* Marks that the token can see other Tokens declared in `viewProviders` on the same node.
*/
canSeeViewProviders: boolean;
/**
* An array of factories to use in case of `multi` provider.
*/
multi?: Array<() => any>;
/**
* Number of `multi`-providers which belong to the component.
*
* This is needed because when multiple components and directives declare the `multi` provider
* they have to be concatenated in the correct order.
*
* Example:
*
* If we have a component and directive active an a single element as declared here
* ```
* component:
* provides: [ {provide: String, useValue: 'component', multi: true} ],
* viewProvides: [ {provide: String, useValue: 'componentView', multi: true} ],
*
* directive:
* provides: [ {provide: String, useValue: 'directive', multi: true} ],
* ```
*
* Then the expected results are:
*
* ```
* providers: ['component', 'directive']
* viewProviders: ['component', 'componentView', 'directive']
* ```
*
* The way to think about it is that the `viewProviders` have been inserted after the component
* but before the directives, which is why we need to know how many `multi`s have been declared by
* the component.
*/
componentProviders?: number;
/**
* Current index of the Factory in the `data`. Needed for `viewProviders` and `providers` merging.
* See `providerFactory`.
*/
index?: number;
/**
* Because the same `multi` provider can be declared in `provides` and `viewProvides` it is
* possible for `viewProvides` to shadow the `provides`. For this reason we store the
* `provideFactory` of the `providers` so that `providers` can be extended with `viewProviders`.
*
* Example:
*
* Given:
* ```
* provides: [ {provide: String, useValue: 'all', multi: true} ],
* viewProvides: [ {provide: String, useValue: 'viewOnly', multi: true} ],
* ```
*
* We have to return `['all']` in case of content injection, but `['all', 'viewOnly']` in case
* of view injection. We further have to make sure that the shared instances (in our case
* `all`) are the exact same instance in both the content as well as the view injection. (We
* have to make sure that we don't double instantiate.) For this reason the `viewProvides`
* `Factory` has a pointer to the shadowed `provides` factory so that it can instantiate the
* `providers` (`['all']`) and then extend it with `viewProviders` (`['all'] + ['viewOnly'] =
* ['all', 'viewOnly']`).
*/
providerFactory?: NodeInjectorFactory|null;
constructor(
/**
* Factory to invoke in order to create a new instance.
*/
public factory:
(this: NodeInjectorFactory, _: null,
/**
* array where injectables tokens are stored. This is used in
* case of an error reporting to produce friendlier errors.
*/
tData: TData,
/**
* array where existing instances of injectables are stored. This is used in case
* of multi shadow is needed. See `multi` field documentation.
*/
lData: LViewData,
/**
* The TNode of the same element injector.
*/
tNode: TElementNode) => any,
/**
* Set to `true` if the token is declared in `viewProviders` (or if it is component).
*/
isViewProvider: boolean,
injectImplementation: null|(<T>(token: Type<T>|InjectionToken<T>, flags: InjectFlags) => T)) {
this.canSeeViewProviders = isViewProvider;
this.injectImpl = injectImplementation;
}
}
const FactoryPrototype = NodeInjectorFactory.prototype;
export function isFactory(obj: any): obj is NodeInjectorFactory {
// See: https://jsperf.com/instanceof-vs-getprototypeof
return obj != null && typeof obj == 'object' && Object.getPrototypeOf(obj) == FactoryPrototype;
}
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.
export const unusedValueExportToPlacateAjd = 1;

View File

@ -46,6 +46,18 @@ export const enum TNodeFlags {
DirectiveStartingIndexShift = 16,
}
/**
* Corresponds to the TNode.providerIndexes property.
*/
export const enum TNodeProviderIndexes {
/** The index of the first provider on this node is encoded on the least significant bits */
ProvidersStartIndexMask = 0b00000000000000001111111111111111,
/** The count of view providers from the component on this node is encoded on the 16 most
significant bits */
CptViewProvidersCountShift = 16,
CptViewProvidersCountShifter = 0b00000000000000010000000000000000,
}
/**
* A set of marker values to be used in the attributes arrays. Those markers indicate that some
* items are not regular attributes and the processing should be adapted accordingly.
@ -125,6 +137,14 @@ export interface TNode {
*/
flags: TNodeFlags;
/**
* This number stores two values using its bits:
*
* - the index of the first provider on that node (first 16 bits)
* - the count of view providers from the component on this node (last 16 bits)
*/
providerIndexes: TNodeProviderIndexes;
/** The tag name associated with this node. */
tagName: string|null;

View File

@ -6,9 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {InjectionToken} from '../../di/injection_token';
import {Injector} from '../../di/injector';
import {QueryList} from '../../linker';
import {Sanitizer} from '../../sanitization/security';
import {Type} from '../../type';
import {LContainer} from './container';
import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList} from './definition';
@ -335,24 +337,6 @@ export interface TView {
*/
firstChild: TNode|null;
/**
* Selector matches for a node are temporarily cached on the TView so the
* DI system can eagerly instantiate directives on the same node if they are
* created out of order. They are overwritten after each node.
*
* <div dirA dirB></div>
*
* e.g. DirA injects DirB, but DirA is created first. DI should instantiate
* DirB when it finds that it's on the same node, but not yet created.
*
* Even indices: Directive defs
* Odd indices:
* - Null if the associated directive hasn't been instantiated yet
* - Directive index, if associated directive has been created
* - String, temporary 'CIRCULAR' token set while dependencies are being resolved
*/
currentMatches: CurrentMatchesList|null;
/**
* Set of instructions used to process host bindings efficiently.
*
@ -549,10 +533,9 @@ export type HookData = (number | (() => void))[];
*
* Injector bloom filters are also stored here.
*/
export type TData = (TNode | PipeDef<any>| DirectiveDef<any>| ComponentDef<any>| number | null)[];
/** Type for TView.currentMatches */
export type CurrentMatchesList = [DirectiveDef<any>, (string | number | null)];
export type TData =
(TNode | PipeDef<any>| DirectiveDef<any>| ComponentDef<any>| number | Type<any>|
InjectionToken<any>| null)[];
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.

View File

@ -80,6 +80,8 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
wrapDirectivesInClosure: false,
styles: metadata.styles || [],
encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, animations,
viewProviders: metadata.viewProviders ? new WrappedNodeExpr(metadata.viewProviders) :
null
},
constantPool, makeBindingParser());
const preStatements = [...constantPool.statements, ...res.statements];
@ -180,6 +182,7 @@ function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMet
typeSourceSpan: null !,
usesInheritance: !extendsDirectlyFromObject(type),
exportAs: metadata.exportAs || null,
providers: metadata.providers ? new WrappedNodeExpr(metadata.providers) : null
};
}

View File

@ -32,7 +32,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
'ɵinjectAttribute': r3.injectAttribute,
'ɵtemplateRefExtractor': r3.templateRefExtractor,
'ɵNgOnChangesFeature': r3.NgOnChangesFeature,
'ɵPublicFeature': r3.PublicFeature,
'ɵProvidersFeature': r3.ProvidersFeature,
'ɵInheritDefinitionFeature': r3.InheritDefinitionFeature,
'ɵelementAttribute': r3.elementAttribute,
'ɵbind': r3.bind,

View File

@ -8,10 +8,11 @@
import {PipeTransform} from '../change_detection/pipe_transform';
import {getTView, load, store} from './instructions';
import {load, store} from './instructions';
import {PipeDef, PipeDefList} from './interfaces/definition';
import {HEADER_OFFSET} from './interfaces/view';
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunctionV} from './pure_function';
import {getTView} from './state';
/**
* Create a pipe.
@ -36,7 +37,7 @@ export function pipe(index: number, pipeName: string): any {
pipeDef = tView.data[adjustedIndex] as PipeDef<any>;
}
const pipeInstance = pipeDef.factory();
const pipeInstance = pipeDef.factory(null);
store(index, pipeInstance);
return pipeInstance;
}

View File

@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, bindingUpdated3, getBindingRoot, getTView,} from './instructions';
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, getBinding, updateBinding} from './instructions';
import {getBindingRoot, getCreationMode} from './state';
/**
* Bindings for pure functions are stored after regular bindings.

View File

@ -19,12 +19,13 @@ import {getSymbolIterator} from '../util';
import {assertDefined, assertEqual} from './assert';
import {NG_ELEMENT_ID} from './fields';
import {_getViewData, assertPreviousIsParent, getOrCreateCurrentQueries, store, storeCleanupWithContext} from './instructions';
import {store, storeCleanupWithContext} from './instructions';
import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
import {LViewData, TVIEW} from './interfaces/view';
import {assertPreviousIsParent, getOrCreateCurrentQueries, getViewData} from './state';
import {flatten, isContentQueryHost} from './util';
import {createElementRef, createTemplateRef} from './view_engine_compatibility';
@ -259,7 +260,7 @@ function getIdxOfMatchingDirective(tNode: TNode, currentView: LViewData, type: T
const end = start + count;
for (let i = start; i < end; i++) {
const def = defs[i] as DirectiveDef<any>;
if (def.type === type && def.diPublic) {
if (def.type === type) {
return i;
}
}
@ -293,7 +294,7 @@ function queryReadByTNodeType(tNode: TNode, currentView: LViewData): any {
function add(
query: LQuery<any>| null, tNode: TElementNode | TContainerNode | TElementContainerNode) {
const currentView = _getViewData();
const currentView = getViewData();
while (query) {
const predicate = query.predicate;

View File

@ -0,0 +1,432 @@
/**
* @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 {Sanitizer} from '../sanitization/security';
import {assertDefined, assertEqual} from './assert';
import {executeHooks} from './hooks';
import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node';
import {LQueries} from './interfaces/query';
import {Renderer3, RendererFactory3} from './interfaces/renderer';
import {BINDING_INDEX, CLEANUP, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LViewData, LViewFlags, OpaqueViewState, QUERIES, RENDERER, SANITIZER, TVIEW, TView} from './interfaces/view';
import {assertDataInRangeInternal, isContentQueryHost} from './util';
/**
* This property gets set before entering a template.
*
* This renderer can be one of two varieties of Renderer3:
*
* - ObjectedOrientedRenderer3
*
* This is the native browser API style, e.g. operations are methods on individual objects
* like HTMLElement. With this style, no additional code is needed as a facade (reducing payload
* size).
*
* - ProceduralRenderer3
*
* In non-native browser environments (e.g. platforms such as web-workers), this is the facade
* that enables element manipulation. This also facilitates backwards compatibility with
* Renderer2.
*/
let renderer: Renderer3;
export function getRenderer(): Renderer3 {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return renderer;
}
export function setRenderer(r: Renderer3): void {
renderer = r;
}
let rendererFactory: RendererFactory3;
export function getRendererFactory(): RendererFactory3 {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return rendererFactory;
}
export function setRendererFactory(factory: RendererFactory3): void {
rendererFactory = factory;
}
export function getCurrentSanitizer(): Sanitizer|null {
return viewData && viewData[SANITIZER];
}
/**
* Store the element depth count. This is used to identify the root elements of the template
* so that we can than attach `LViewData` to only those elements.
*/
let elementDepthCount !: number;
export function getElementDepthCount() {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return elementDepthCount;
}
export function increaseElementDepthCount() {
elementDepthCount++;
}
export function decreaseElementDepthCount() {
elementDepthCount--;
}
/**
* Stores whether directives should be matched to elements.
*
* When template contains `ngNonBindable` than we need to prevent the runtime form matching
* directives on children of that element.
*
* Example:
* ```
* <my-comp my-directive>
* Should match component / directive.
* </my-comp>
* <div ngNonBindable>
* <my-comp my-directive>
* Should not match component / directive because we are in ngNonBindable.
* </my-comp>
* </div>
* ```
*/
let bindingsEnabled !: boolean;
export function getBindingsEnabled(): boolean {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return bindingsEnabled;
}
/**
* Enables directive matching on elements.
*
* * Example:
* ```
* <my-comp my-directive>
* Should match component / directive.
* </my-comp>
* <div ngNonBindable>
* <!-- disabledBindings() -->
* <my-comp my-directive>
* Should not match component / directive because we are in ngNonBindable.
* </my-comp>
* <!-- enableBindings() -->
* </div>
* ```
*/
export function enableBindings(): void {
bindingsEnabled = true;
}
/**
* Disables directive matching on element.
*
* * Example:
* ```
* <my-comp my-directive>
* Should match component / directive.
* </my-comp>
* <div ngNonBindable>
* <!-- disabledBindings() -->
* <my-comp my-directive>
* Should not match component / directive because we are in ngNonBindable.
* </my-comp>
* <!-- enableBindings() -->
* </div>
* ```
*/
export function disableBindings(): void {
bindingsEnabled = false;
}
/**
* Returns the current OpaqueViewState instance.
*
* Used in conjunction with the restoreView() instruction to save a snapshot
* of the current view and restore it when listeners are invoked. This allows
* walking the declaration view tree in listeners to get vars from parent views.
*/
export function getCurrentView(): OpaqueViewState {
return viewData as any as OpaqueViewState;
}
/**
* Restores `contextViewData` to the given OpaqueViewState instance.
*
* Used in conjunction with the getCurrentView() instruction to save a snapshot
* of the current view and restore it when listeners are invoked. This allows
* walking the declaration view tree in listeners to get vars from parent views.
*
* @param viewToRestore The OpaqueViewState instance to restore.
*/
export function restoreView(viewToRestore: OpaqueViewState) {
contextViewData = viewToRestore as any as LViewData;
}
/** Used to set the parent property when nodes are created and track query results. */
let previousOrParentTNode: TNode;
export function getPreviousOrParentTNode(): TNode {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return previousOrParentTNode;
}
export function setPreviousOrParentTNode(tNode: TNode) {
previousOrParentTNode = tNode;
}
export function setTNodeAndViewData(tNode: TNode, view: LViewData) {
previousOrParentTNode = tNode;
viewData = view;
}
/**
* If `isParent` is:
* - `true`: then `previousOrParentTNode` points to a parent node.
* - `false`: then `previousOrParentTNode` points to previous node (sibling).
*/
let isParent: boolean;
export function getIsParent(): boolean {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return isParent;
}
export function setIsParent(value: boolean): void {
isParent = value;
}
let tView: TView;
export function getTView(): TView {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return tView;
}
let currentQueries: LQueries|null;
export function getCurrentQueries(): LQueries|null {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return currentQueries;
}
export function setCurrentQueries(queries: LQueries | null): void {
currentQueries = queries;
}
/**
* Query instructions can ask for "current queries" in 2 different cases:
* - when creating view queries (at the root of a component view, before any node is created - in
* this case currentQueries points to view queries)
* - when creating content queries (i.e. this previousOrParentTNode points to a node on which we
* create content queries).
*/
export function getOrCreateCurrentQueries(
QueryType: {new (parent: null, shallow: null, deep: null): LQueries}): LQueries {
// if this is the first content query on a node, any existing LQueries needs to be cloned
// in subsequent template passes, the cloning occurs before directive instantiation.
if (previousOrParentTNode && previousOrParentTNode !== viewData[HOST_NODE] &&
!isContentQueryHost(previousOrParentTNode)) {
currentQueries && (currentQueries = currentQueries.clone());
previousOrParentTNode.flags |= TNodeFlags.hasContentQuery;
}
return currentQueries || (currentQueries = new QueryType(null, null, null));
}
/**
* This property gets set before entering a template.
*/
let creationMode: boolean;
export function getCreationMode(): boolean {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return creationMode;
}
/**
* State of the current view being processed.
*
* An array of nodes (text, element, container, etc), pipes, their bindings, and
* any local variables that need to be stored between invocations.
*/
let viewData: LViewData;
/**
* Internal function that returns the current LViewData instance.
*
* The getCurrentView() instruction should be used for anything public.
*/
export function getViewData(): LViewData {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return viewData;
}
/**
* The last viewData retrieved by nextContext().
* Allows building nextContext() and reference() calls.
*
* e.g. const inner = x().$implicit; const outer = x().$implicit;
*/
let contextViewData: LViewData = null !;
export function getContextViewData(): LViewData {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return contextViewData;
}
export function getCleanup(view: LViewData): any[] {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return view[CLEANUP] || (view[CLEANUP] = []);
}
export function getTViewCleanup(view: LViewData): any[] {
return view[TVIEW].cleanup || (view[TVIEW].cleanup = []);
}
/**
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
*
* Necessary to support ChangeDetectorRef.checkNoChanges().
*/
let checkNoChangesMode = false;
export function getCheckNoChangesMode(): boolean {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return checkNoChangesMode;
}
export function setCheckNoChangesMode(mode: boolean): void {
checkNoChangesMode = mode;
}
/** Whether or not this is the first time the current view has been processed. */
let firstTemplatePass = true;
export function getFirstTemplatePass(): boolean {
return firstTemplatePass;
}
export function setFirstTemplatePass(value: boolean): void {
firstTemplatePass = value;
}
/**
* The root index from which pure function instructions should calculate their binding
* indices. In component views, this is TView.bindingStartIndex. In a host binding
* context, this is the TView.expandoStartIndex + any dirs/hostVars before the given dir.
*/
let bindingRootIndex: number = -1;
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
export function getBindingRoot() {
return bindingRootIndex;
}
export function setBindingRoot(value: number) {
bindingRootIndex = value;
}
/**
* Swap the current state with a new state.
*
* For performance reasons we store the state in the top level of the module.
* This way we minimize the number of properties to read. Whenever a new view
* is entered we have to store the state for later, and when the view is
* exited the state has to be restored
*
* @param newView New state to become active
* @param host Element to which the View is a child of
* @returns the previous state;
*/
export function enterView(
newView: LViewData, hostTNode: TElementNode | TViewNode | null): LViewData {
const oldView: LViewData = viewData;
tView = newView && newView[TVIEW];
creationMode = newView && (newView[FLAGS] & LViewFlags.CreationMode) === LViewFlags.CreationMode;
firstTemplatePass = newView && tView.firstTemplatePass;
bindingRootIndex = newView && tView.bindingStartIndex;
renderer = newView && newView[RENDERER];
previousOrParentTNode = hostTNode !;
isParent = true;
viewData = contextViewData = newView;
oldView && (oldView[QUERIES] = currentQueries);
currentQueries = newView && newView[QUERIES];
return oldView;
}
export function nextContextImpl<T = any>(level: number = 1): T {
contextViewData = walkUpViews(level, contextViewData !);
return contextViewData[CONTEXT] as T;
}
function walkUpViews(nestingLevel: number, currentView: LViewData): LViewData {
while (nestingLevel > 0) {
ngDevMode && assertDefined(
currentView[DECLARATION_VIEW],
'Declaration view should be defined if nesting level is greater than 0.');
currentView = currentView[DECLARATION_VIEW] !;
nestingLevel--;
}
return currentView;
}
/**
* Resets the application state.
*/
export function resetComponentState() {
isParent = false;
previousOrParentTNode = null !;
elementDepthCount = 0;
bindingsEnabled = true;
}
/**
* Used in lieu of enterView to make it clear when we are exiting a child view. This makes
* the direction of traversal (up or down the view tree) a bit clearer.
*
* @param newView New state to become active
* @param creationOnly An optional boolean to indicate that the view was processed in creation mode
* only, i.e. the first update will be done later. Only possible for dynamically created views.
*/
export function leaveView(newView: LViewData, creationOnly?: boolean): void {
if (!creationOnly) {
if (!checkNoChangesMode) {
executeHooks(viewData, tView.viewHooks, tView.viewCheckHooks, creationMode);
}
// Views are clean and in update mode after being checked, so these bits are cleared
viewData[FLAGS] &= ~(LViewFlags.CreationMode | LViewFlags.Dirty);
}
viewData[FLAGS] |= LViewFlags.RunInit;
viewData[BINDING_INDEX] = tView.bindingStartIndex;
enterView(newView, null);
}
export function assertPreviousIsParent() {
assertEqual(isParent, true, 'previousOrParentTNode should be a parent');
}
export function assertHasParent() {
assertDefined(previousOrParentTNode.parent, 'previousOrParentTNode should have a parent');
}
export function assertDataInRange(index: number, arr?: any[]) {
if (arr == null) arr = viewData;
assertDataInRangeInternal(index, arr || viewData);
}
export function assertDataNext(index: number, arr?: any[]) {
if (arr == null) arr = viewData;
assertEqual(
arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
}

View File

@ -11,10 +11,13 @@ import {devModeEqual} from '../change_detection/change_detection_util';
import {assertDefined, assertLessThan} from './assert';
import {ACTIVE_INDEX, LContainer} from './interfaces/container';
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
import {TNode, TNodeFlags} from './interfaces/node';
import {ComponentDef, DirectiveDef} from './interfaces/definition';
import {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags} from './interfaces/injector';
import {TContainerNode, TElementNode, TNode, TNodeFlags} from './interfaces/node';
import {RComment, RElement, RText} from './interfaces/renderer';
import {StylingContext} from './interfaces/styling';
import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LViewData, LViewFlags, PARENT, RootContext, TData, TVIEW} from './interfaces/view';
import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LViewData, LViewFlags, PARENT, RootContext, TData, TVIEW} from './interfaces/view';
/**
@ -122,6 +125,10 @@ export function isComponent(tNode: TNode): boolean {
return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent;
}
export function isComponentDef<T>(def: DirectiveDef<T>): def is ComponentDef<T> {
return (def as ComponentDef<T>).template !== null;
}
export function isLContainer(value: RElement | RComment | LContainer | StylingContext): boolean {
// Styling contexts are also arrays, but their first index contains an element node
return Array.isArray(value) && typeof value[ACTIVE_INDEX] === 'number';
@ -161,3 +168,72 @@ export function readPatchedLViewData(target: any): LViewData|null {
}
return null;
}
export function hasParentInjector(parentLocation: RelativeInjectorLocation): boolean {
return parentLocation !== NO_PARENT_INJECTOR;
}
export function getParentInjectorIndex(parentLocation: RelativeInjectorLocation): number {
return (parentLocation as any as number) & RelativeInjectorLocationFlags.InjectorIndexMask;
}
export function getParentInjectorViewOffset(parentLocation: RelativeInjectorLocation): number {
return (parentLocation as any as number) >> RelativeInjectorLocationFlags.ViewOffsetShift;
}
/**
* Unwraps a parent injector location number to find the view offset from the current injector,
* then walks up the declaration view tree until the view is found that contains the parent
* injector.
*
* @param location The location of the parent injector, which contains the view offset
* @param startView The LViewData instance from which to start walking up the view tree
* @returns The LViewData instance that contains the parent injector
*/
export function getParentInjectorView(
location: RelativeInjectorLocation, startView: LViewData): LViewData {
let viewOffset = getParentInjectorViewOffset(location);
let parentView = startView;
// For most cases, the parent injector can be found on the host node (e.g. for component
// or container), but we must keep the loop here to support the rarer case of deeply nested
// <ng-template> tags or inline views, where the parent injector might live many views
// above the child injector.
while (viewOffset > 0) {
parentView = parentView[DECLARATION_VIEW] !;
viewOffset--;
}
return parentView;
}
/**
* Unwraps a parent injector location number to find the view offset from the current injector,
* then walks up the declaration view tree until the TNode of the parent injector is found.
*
* @param location The location of the parent injector, which contains the view offset
* @param startView The LViewData instance from which to start walking up the view tree
* @param startTNode The TNode instance of the starting element
* @returns The TNode of the parent injector
*/
export function getParentInjectorTNode(
location: RelativeInjectorLocation, startView: LViewData, startTNode: TNode): TElementNode|
TContainerNode|null {
if (startTNode.parent && startTNode.parent.injectorIndex !== -1) {
// view offset is 0
const injectorIndex = startTNode.parent.injectorIndex;
let parentTNode = startTNode.parent;
while (parentTNode.parent != null && injectorIndex == parentTNode.injectorIndex) {
parentTNode = parentTNode.parent;
}
return parentTNode;
}
let viewOffset = getParentInjectorViewOffset(location);
let parentView = startView;
let parentTNode = startView[HOST_NODE] as TElementNode;
while (viewOffset > 0) {
parentView = parentView[DECLARATION_VIEW] !;
parentTNode = parentView[HOST_NODE] as TElementNode;
viewOffset--;
}
return parentTNode;
}

View File

@ -17,18 +17,18 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_Vie
import {Renderer2} from '../render/api';
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
import {NodeInjector, getParentInjectorLocation, getParentInjectorView} from './di';
import {_getViewData, addToViewTree, createEmbeddedViewAndNode, createLContainer, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate} from './instructions';
import {ACTIVE_INDEX, LContainer, NATIVE, RENDER_PARENT, VIEWS} from './interfaces/container';
import {getOrCreateInjectable, getParentInjectorLocation} from './di';
import {addToViewTree, createEmbeddedViewAndNode, createLContainer, renderEmbeddedTemplate} from './instructions';
import {ACTIVE_INDEX, LContainer, NATIVE, VIEWS} from './interfaces/container';
import {RenderFlags} from './interfaces/definition';
import {InjectorLocationFlags} from './interfaces/injector';
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
import {LQueries} from './interfaces/query';
import {RComment, RElement, Renderer3, isProceduralRenderer} from './interfaces/renderer';
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getRenderParent, insertView, removeView} from './node_manipulation';
import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer} from './util';
import {getPreviousOrParentTNode, getRenderer, getViewData} from './state';
import {getComponentViewByIndex, getNativeByTNode, getParentInjectorTNode, getParentInjectorView, hasParentInjector, isComponent, isLContainer} from './util';
import {ViewRef} from './view_ref';
@ -40,7 +40,7 @@ import {ViewRef} from './view_ref';
*/
export function injectElementRef(ElementRefToken: typeof ViewEngine_ElementRef):
ViewEngine_ElementRef {
return createElementRef(ElementRefToken, getPreviousOrParentTNode(), _getViewData());
return createElementRef(ElementRefToken, getPreviousOrParentTNode(), getViewData());
}
let R3ElementRef: {new (native: RElement | RComment): ViewEngine_ElementRef};
@ -79,7 +79,7 @@ export function injectTemplateRef<T>(
TemplateRefToken: typeof ViewEngine_TemplateRef,
ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_TemplateRef<T> {
return createTemplateRef<T>(
TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), _getViewData());
TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), getViewData());
}
/**
@ -147,9 +147,18 @@ export function injectViewContainerRef(
ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_ViewContainerRef {
const previousTNode =
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode;
return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, _getViewData());
return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, getViewData());
}
export class NodeInjector implements Injector {
constructor(
private _tNode: TElementNode|TContainerNode|TElementContainerNode,
private _hostView: LViewData) {}
get(token: any, notFoundValue?: any): any {
return getOrCreateInjectable(this._tNode, this._hostView, token, notFoundValue);
}
}
/**
* Creates a ViewContainerRef and stores it on the injector.
@ -187,11 +196,11 @@ export function createContainerRef(
get parentInjector(): Injector {
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostView);
const parentView = getParentInjectorView(parentLocation, this._hostView);
const parentIndex = parentLocation & InjectorLocationFlags.InjectorIndexMask;
const parentTNode = parentView[TVIEW].data[parentIndex] as TElementNode | TContainerNode;
const parentTNode = getParentInjectorTNode(parentLocation, this._hostView, this._hostTNode);
return parentLocation === -1 ? new NullInjector() :
new NodeInjector(parentTNode, parentView);
return !hasParentInjector(parentLocation) || parentTNode == null ?
new NullInjector() :
new NodeInjector(parentTNode, parentView);
}
clear(): void {
@ -310,7 +319,7 @@ export function createContainerRef(
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef {
return createViewRef(getPreviousOrParentTNode(), _getViewData(), null);
return createViewRef(getPreviousOrParentTNode(), getViewData(), null);
}
/**
@ -345,5 +354,5 @@ function getOrCreateRenderer2(view: LViewData): Renderer2 {
/** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */
export function injectRenderer2(): Renderer2 {
return getOrCreateRenderer2(_getViewData());
return getOrCreateRenderer2(getViewData());
}

View File

@ -11,10 +11,11 @@ import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detec
import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, getRendererFactory, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, markViewDirty, storeCleanupFn, viewAttached} from './instructions';
import {TViewNode} from './interfaces/node';
import {FLAGS, LViewData, LViewFlags, PARENT} from './interfaces/view';
import {destroyLView} from './node_manipulation';
import {getRendererFactory} from './state';
// Needed due to tsickle downleveling where multiple `implements` with classes creates

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {getCurrentSanitizer} from '../render3/instructions';
import {getCurrentSanitizer} from '../render3/state';
import {stringify} from '../render3/util';
import {BypassType, allowSanitizationBypass} from './bypass';

View File

@ -17,9 +17,6 @@
{
"name": "BoundPlayerFactory"
},
{
"name": "CIRCULAR$1"
},
{
"name": "CLEANUP"
},
@ -71,6 +68,9 @@
{
"name": "FLAGS"
},
{
"name": "FactoryPrototype"
},
{
"name": "HEADER_OFFSET"
},
@ -119,9 +119,15 @@
{
"name": "NG_PROJECT_AS_ATTR_NAME"
},
{
"name": "NOT_FOUND"
},
{
"name": "NO_CHANGE"
},
{
"name": "NO_PARENT_INJECTOR"
},
{
"name": "NgForOf"
},
@ -134,6 +140,9 @@
{
"name": "NodeInjector"
},
{
"name": "NodeInjectorFactory"
},
{
"name": "NullInjector"
},
@ -152,9 +161,6 @@
{
"name": "PARENT_INJECTOR"
},
{
"name": "PublicFeature"
},
{
"name": "QUERIES"
},
@ -263,18 +269,12 @@
{
"name": "_c4"
},
{
"name": "_currentInjector"
},
{
"name": "_currentNamespace"
},
{
"name": "_devMode"
},
{
"name": "_getViewData"
},
{
"name": "_global"
},
@ -315,7 +315,7 @@
"name": "attachPatchData"
},
{
"name": "baseDirectiveCreate"
"name": "baseResolveDirective"
},
{
"name": "bind"
@ -323,24 +323,21 @@
{
"name": "bindPlayerFactory"
},
{
"name": "bindingRootIndex"
},
{
"name": "bindingUpdated"
},
{
"name": "bloomAdd"
},
{
"name": "bloomHasToken"
},
{
"name": "bloomHashBitOrFactory"
},
{
"name": "buildAnimationPlayer"
},
{
"name": "cacheMatchingDirectivesForNode"
},
{
"name": "cacheMatchingLocalNames"
},
@ -437,6 +434,9 @@
{
"name": "createViewQuery"
},
{
"name": "decreaseElementDepthCount"
},
{
"name": "defineComponent"
},
@ -464,15 +464,9 @@
{
"name": "detectChangesInternal"
},
{
"name": "diPublic"
},
{
"name": "diPublicInInjector"
},
{
"name": "directiveCreate"
},
{
"name": "directiveInject"
},
@ -558,7 +552,7 @@
"name": "firstTemplatePass"
},
{
"name": "generateExpandoBlock"
"name": "generateExpandoInstructionBlock"
},
{
"name": "generateInitialInputs"
@ -569,6 +563,12 @@
{
"name": "getBeforeNodeForView"
},
{
"name": "getBindingsEnabled"
},
{
"name": "getCheckNoChangesMode"
},
{
"name": "getCleanup"
},
@ -590,6 +590,12 @@
{
"name": "getContext"
},
{
"name": "getCreationMode"
},
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
@ -602,6 +608,12 @@
{
"name": "getDirectiveStartIndex"
},
{
"name": "getElementDepthCount"
},
{
"name": "getFirstTemplatePass"
},
{
"name": "getHighestElementContainer"
},
@ -620,6 +632,9 @@
{
"name": "getInjectorIndex"
},
{
"name": "getIsParent"
},
{
"name": "getLContainer"
},
@ -639,10 +654,10 @@
"name": "getNativeByTNode"
},
{
"name": "getOrCreateInjectable"
"name": "getNodeInjectable"
},
{
"name": "getOrCreateNodeInjector"
"name": "getOrCreateInjectable"
},
{
"name": "getOrCreateNodeInjectorForNode"
@ -653,12 +668,21 @@
{
"name": "getOrCreateTView"
},
{
"name": "getParentInjectorIndex"
},
{
"name": "getParentInjectorLocation"
},
{
"name": "getParentInjectorTNode"
},
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentNative"
},
@ -705,7 +729,7 @@
"name": "getRootContext"
},
{
"name": "getRootContext$2"
"name": "getRootContext$1"
},
{
"name": "getRootView"
@ -725,6 +749,9 @@
{
"name": "getTNode"
},
{
"name": "getTView"
},
{
"name": "getTViewCleanup"
},
@ -737,20 +764,35 @@
{
"name": "getValue"
},
{
"name": "getViewData"
},
{
"name": "hasParentInjector"
},
{
"name": "hasPlayerBuilderChanged"
},
{
"name": "hasValueChanged"
},
{
"name": "includeViewProviders"
},
{
"name": "increaseElementDepthCount"
},
{
"name": "initNodeFlags"
},
{
"name": "initializeTNodeInputs"
},
{
"name": "inject"
"name": "injectElementRef"
},
{
"name": "injectElementRef"
"name": "injectRootLimpMode"
},
{
"name": "injectTemplateRef"
@ -759,7 +801,7 @@
"name": "injectViewContainerRef"
},
{
"name": "injectorHasToken"
"name": "insertBloom"
},
{
"name": "insertNewMultiProperty"
@ -768,7 +810,10 @@
"name": "insertView"
},
{
"name": "instantiateDirectivesDirectly"
"name": "instantiateAllDirectives"
},
{
"name": "instantiateRootComponent"
},
{
"name": "interpolation1"
@ -783,10 +828,10 @@
"name": "isComponent"
},
{
"name": "isComponentInstance"
"name": "isComponentDef"
},
{
"name": "isContentQueryHost"
"name": "isComponentInstance"
},
{
"name": "isContextDirty"
@ -806,6 +851,9 @@
{
"name": "isDirty"
},
{
"name": "isFactory"
},
{
"name": "isJsObject"
},
@ -878,6 +926,9 @@
{
"name": "nextContext"
},
{
"name": "nextContextImpl"
},
{
"name": "nextNgElementId"
},
@ -887,6 +938,12 @@
{
"name": "pointers"
},
{
"name": "postProcessBaseDirective"
},
{
"name": "postProcessDirective"
},
{
"name": "prefillHostVars"
},
@ -960,7 +1017,7 @@
"name": "resetComponentState"
},
{
"name": "resolveDirective"
"name": "resolveDirectives"
},
{
"name": "saveNameToExportMap"
@ -972,14 +1029,17 @@
"name": "scheduleTick"
},
{
"name": "searchDirectivesOnInjector"
},
{
"name": "searchMatchesQueuedForCreation"
"name": "searchTokensOnInjector"
},
{
"name": "setAnimationPlayState"
},
{
"name": "setBindingRoot"
},
{
"name": "setCheckNoChangesMode"
},
{
"name": "setClass"
},
@ -990,13 +1050,13 @@
"name": "setContextPlayersDirty"
},
{
"name": "setCurrentInjector"
"name": "setCurrentQueries"
},
{
"name": "setDirty"
},
{
"name": "setEnvironment"
"name": "setFirstTemplatePass"
},
{
"name": "setFlag"
@ -1004,35 +1064,50 @@
{
"name": "setHostBindings"
},
{
"name": "setIncludeViewProviders"
},
{
"name": "setInjectImplementation"
},
{
"name": "setInputsForProperty"
},
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsParent"
},
{
"name": "setPlayerBuilder"
},
{
"name": "setPlayerBuilderIndex"
},
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setStyle"
},
{
"name": "setUpAttributes"
"name": "setTNodeAndViewData"
},
{
"name": "setUpBloom"
"name": "setUpAttributes"
},
{
"name": "setValue"
},
{
"name": "shouldNotSearchParent"
"name": "shouldSearchParent"
},
{
"name": "storeCleanupFn"
@ -1061,9 +1136,6 @@
{
"name": "textBinding"
},
{
"name": "throwCyclicDependencyError"
},
{
"name": "throwErrorIfNoChangesMode"
},

View File

@ -35,6 +35,9 @@
{
"name": "FLAGS"
},
{
"name": "FactoryPrototype"
},
{
"name": "HEADER_OFFSET"
},
@ -77,6 +80,12 @@
{
"name": "NO_CHANGE"
},
{
"name": "NO_PARENT_INJECTOR"
},
{
"name": "NodeInjectorFactory"
},
{
"name": "ObjectUnsubscribedErrorImpl"
},
@ -86,9 +95,6 @@
{
"name": "PARENT_INJECTOR"
},
{
"name": "PublicFeature"
},
{
"name": "QUERIES"
},
@ -116,9 +122,6 @@
{
"name": "ViewEncapsulation$1"
},
{
"name": "_getViewData"
},
{
"name": "_renderCompCount"
},
@ -129,10 +132,7 @@
"name": "attachPatchData"
},
{
"name": "baseDirectiveCreate"
},
{
"name": "bindingRootIndex"
"name": "baseResolveDirective"
},
{
"name": "bloomAdd"
@ -191,9 +191,6 @@
{
"name": "detectChangesInternal"
},
{
"name": "diPublic"
},
{
"name": "diPublicInInjector"
},
@ -224,6 +221,9 @@
{
"name": "getBeforeNodeForView"
},
{
"name": "getCheckNoChangesMode"
},
{
"name": "getClosureSafeProperty"
},
@ -236,9 +236,15 @@
{
"name": "getContainerRenderParent"
},
{
"name": "getCreationMode"
},
{
"name": "getDirectiveDef"
},
{
"name": "getFirstTemplatePass"
},
{
"name": "getHighestElementContainer"
},
@ -248,6 +254,9 @@
{
"name": "getInjectorIndex"
},
{
"name": "getIsParent"
},
{
"name": "getLContainer"
},
@ -258,7 +267,7 @@
"name": "getNativeByTNode"
},
{
"name": "getOrCreateNodeInjector"
"name": "getNodeInjectable"
},
{
"name": "getOrCreateNodeInjectorForNode"
@ -266,12 +275,18 @@
{
"name": "getOrCreateTView"
},
{
"name": "getParentInjectorIndex"
},
{
"name": "getParentInjectorLocation"
},
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentNative"
},
@ -287,9 +302,42 @@
{
"name": "getRenderParent"
},
{
"name": "getRenderer"
},
{
"name": "getRendererFactory"
},
{
"name": "getTView"
},
{
"name": "getViewData"
},
{
"name": "hasParentInjector"
},
{
"name": "includeViewProviders"
},
{
"name": "initNodeFlags"
},
{
"name": "insertBloom"
},
{
"name": "instantiateRootComponent"
},
{
"name": "invertObject"
},
{
"name": "isComponentDef"
},
{
"name": "isFactory"
},
{
"name": "isProceduralRenderer"
},
@ -311,6 +359,9 @@
{
"name": "noSideEffects"
},
{
"name": "postProcessBaseDirective"
},
{
"name": "prefillHostVars"
},
@ -350,14 +401,35 @@
{
"name": "resetComponentState"
},
{
"name": "setBindingRoot"
},
{
"name": "setFirstTemplatePass"
},
{
"name": "setHostBindings"
},
{
"name": "setUpAttributes"
"name": "setIncludeViewProviders"
},
{
"name": "setUpBloom"
"name": "setInjectImplementation"
},
{
"name": "setIsParent"
},
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setRendererFactory"
},
{
"name": "setTNodeAndViewData"
},
{
"name": "setUpAttributes"
},
{
"name": "stringify$2"

View File

@ -1967,6 +1967,9 @@
{
"name": "__extends$p"
},
{
"name": "__forward_ref__"
},
{
"name": "__metadata"
},
@ -3098,6 +3101,12 @@
{
"name": "injectArgs"
},
{
"name": "injectInjectorOnly"
},
{
"name": "injectRootLimpMode"
},
{
"name": "inlineInterpolate"
},

View File

@ -3,7 +3,7 @@
"name": "APP_ROOT"
},
{
"name": "CIRCULAR$2"
"name": "CIRCULAR$1"
},
{
"name": "EMPTY_ARRAY$2"
@ -68,6 +68,9 @@
{
"name": "_THROW_IF_NOT_FOUND"
},
{
"name": "__forward_ref__"
},
{
"name": "__read"
},
@ -120,7 +123,13 @@
"name": "injectArgs"
},
{
"name": "injectableDefRecord"
"name": "injectInjectorOnly"
},
{
"name": "injectRootLimpMode"
},
{
"name": "injectableDefFactory"
},
{
"name": "isExistingProvider"
@ -143,6 +152,9 @@
{
"name": "makeRecord"
},
{
"name": "providerToFactory"
},
{
"name": "providerToRecord"
},

View File

@ -11,9 +11,6 @@
{
"name": "BoundPlayerFactory"
},
{
"name": "CIRCULAR$1"
},
{
"name": "CLEANUP"
},
@ -59,6 +56,9 @@
{
"name": "FLAGS"
},
{
"name": "FactoryPrototype"
},
{
"name": "HEADER_OFFSET"
},
@ -107,9 +107,15 @@
{
"name": "NG_PROJECT_AS_ATTR_NAME"
},
{
"name": "NOT_FOUND"
},
{
"name": "NO_CHANGE"
},
{
"name": "NO_PARENT_INJECTOR"
},
{
"name": "NgForOf"
},
@ -128,6 +134,9 @@
{
"name": "NodeInjector"
},
{
"name": "NodeInjectorFactory"
},
{
"name": "NullInjector"
},
@ -146,9 +155,6 @@
{
"name": "PARENT_INJECTOR"
},
{
"name": "PublicFeature"
},
{
"name": "QUERIES"
},
@ -329,18 +335,12 @@
{
"name": "_c9"
},
{
"name": "_currentInjector"
},
{
"name": "_currentNamespace"
},
{
"name": "_devMode"
},
{
"name": "_getViewData"
},
{
"name": "_global"
},
@ -378,14 +378,11 @@
"name": "attachPatchData"
},
{
"name": "baseDirectiveCreate"
"name": "baseResolveDirective"
},
{
"name": "bind"
},
{
"name": "bindingRootIndex"
},
{
"name": "bindingUpdated"
},
@ -393,10 +390,10 @@
"name": "bloomAdd"
},
{
"name": "bloomHashBitOrFactory"
"name": "bloomHasToken"
},
{
"name": "cacheMatchingDirectivesForNode"
"name": "bloomHashBitOrFactory"
},
{
"name": "cacheMatchingLocalNames"
@ -494,6 +491,9 @@
{
"name": "createViewQuery"
},
{
"name": "decreaseElementDepthCount"
},
{
"name": "defineComponent"
},
@ -521,15 +521,9 @@
{
"name": "detectChangesInternal"
},
{
"name": "diPublic"
},
{
"name": "diPublicInInjector"
},
{
"name": "directiveCreate"
},
{
"name": "directiveInject"
},
@ -603,7 +597,7 @@
"name": "firstTemplatePass"
},
{
"name": "generateExpandoBlock"
"name": "generateExpandoInstructionBlock"
},
{
"name": "generateInitialInputs"
@ -614,6 +608,12 @@
{
"name": "getBeforeNodeForView"
},
{
"name": "getBindingsEnabled"
},
{
"name": "getCheckNoChangesMode"
},
{
"name": "getCleanup"
},
@ -632,6 +632,15 @@
{
"name": "getContainerRenderParent"
},
{
"name": "getContextViewData"
},
{
"name": "getCreationMode"
},
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
@ -641,6 +650,12 @@
{
"name": "getDirectiveDef"
},
{
"name": "getElementDepthCount"
},
{
"name": "getFirstTemplatePass"
},
{
"name": "getHighestElementContainer"
},
@ -659,6 +674,9 @@
{
"name": "getInjectorIndex"
},
{
"name": "getIsParent"
},
{
"name": "getLContainer"
},
@ -678,10 +696,10 @@
"name": "getNativeByTNode"
},
{
"name": "getOrCreateInjectable"
"name": "getNodeInjectable"
},
{
"name": "getOrCreateNodeInjector"
"name": "getOrCreateInjectable"
},
{
"name": "getOrCreateNodeInjectorForNode"
@ -689,12 +707,21 @@
{
"name": "getOrCreateTView"
},
{
"name": "getParentInjectorIndex"
},
{
"name": "getParentInjectorLocation"
},
{
"name": "getParentInjectorTNode"
},
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentNative"
},
@ -755,6 +782,9 @@
{
"name": "getTNode"
},
{
"name": "getTView"
},
{
"name": "getTViewCleanup"
},
@ -767,20 +797,35 @@
{
"name": "getValue"
},
{
"name": "getViewData"
},
{
"name": "hasParentInjector"
},
{
"name": "hasPlayerBuilderChanged"
},
{
"name": "hasValueChanged"
},
{
"name": "includeViewProviders"
},
{
"name": "increaseElementDepthCount"
},
{
"name": "initNodeFlags"
},
{
"name": "initializeTNodeInputs"
},
{
"name": "inject"
"name": "injectElementRef"
},
{
"name": "injectElementRef"
"name": "injectRootLimpMode"
},
{
"name": "injectTemplateRef"
@ -789,13 +834,16 @@
"name": "injectViewContainerRef"
},
{
"name": "injectorHasToken"
"name": "insertBloom"
},
{
"name": "insertView"
},
{
"name": "instantiateDirectivesDirectly"
"name": "instantiateAllDirectives"
},
{
"name": "instantiateRootComponent"
},
{
"name": "interpolation1"
@ -807,7 +855,7 @@
"name": "isComponent"
},
{
"name": "isContentQueryHost"
"name": "isComponentDef"
},
{
"name": "isContextDirty"
@ -824,6 +872,9 @@
{
"name": "isDirty"
},
{
"name": "isFactory"
},
{
"name": "isJsObject"
},
@ -893,6 +944,9 @@
{
"name": "nextContext"
},
{
"name": "nextContextImpl"
},
{
"name": "nextNgElementId"
},
@ -902,6 +956,12 @@
{
"name": "pointers"
},
{
"name": "postProcessBaseDirective"
},
{
"name": "postProcessDirective"
},
{
"name": "prefillHostVars"
},
@ -978,7 +1038,7 @@
"name": "resetComponentState"
},
{
"name": "resolveDirective"
"name": "resolveDirectives"
},
{
"name": "restoreView"
@ -993,10 +1053,13 @@
"name": "scheduleTick"
},
{
"name": "searchDirectivesOnInjector"
"name": "searchTokensOnInjector"
},
{
"name": "searchMatchesQueuedForCreation"
"name": "setBindingRoot"
},
{
"name": "setCheckNoChangesMode"
},
{
"name": "setClass"
@ -1008,13 +1071,13 @@
"name": "setContextPlayersDirty"
},
{
"name": "setCurrentInjector"
"name": "setCurrentQueries"
},
{
"name": "setDirty"
},
{
"name": "setEnvironment"
"name": "setFirstTemplatePass"
},
{
"name": "setFlag"
@ -1022,35 +1085,50 @@
{
"name": "setHostBindings"
},
{
"name": "setIncludeViewProviders"
},
{
"name": "setInjectImplementation"
},
{
"name": "setInputsForProperty"
},
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsParent"
},
{
"name": "setPlayerBuilder"
},
{
"name": "setPlayerBuilderIndex"
},
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setStyle"
},
{
"name": "setUpAttributes"
"name": "setTNodeAndViewData"
},
{
"name": "setUpBloom"
"name": "setUpAttributes"
},
{
"name": "setValue"
},
{
"name": "shouldNotSearchParent"
"name": "shouldSearchParent"
},
{
"name": "storeCleanupFn"
@ -1076,9 +1154,6 @@
{
"name": "textBinding"
},
{
"name": "throwCyclicDependencyError"
},
{
"name": "throwErrorIfNoChangesMode"
},

View File

@ -80,9 +80,6 @@
{
"name": "CIRCULAR$1"
},
{
"name": "CIRCULAR$2"
},
{
"name": "CLEANUP"
},
@ -308,6 +305,9 @@
{
"name": "FLAGS"
},
{
"name": "FactoryPrototype"
},
{
"name": "FormStyle"
},
@ -500,6 +500,9 @@
{
"name": "NON_ALPHANUMERIC_REGEXP"
},
{
"name": "NOT_FOUND"
},
{
"name": "NOT_YET"
},
@ -509,6 +512,9 @@
{
"name": "NO_NEW_LINE"
},
{
"name": "NO_PARENT_INJECTOR"
},
{
"name": "NULL_INJECTOR"
},
@ -587,6 +593,9 @@
{
"name": "NodeInjector"
},
{
"name": "NodeInjectorFactory"
},
{
"name": "NoopNgZone"
},
@ -668,9 +677,6 @@
{
"name": "Plural"
},
{
"name": "PublicFeature"
},
{
"name": "QUERIES"
},
@ -998,6 +1004,9 @@
{
"name": "__extends$p"
},
{
"name": "__forward_ref__"
},
{
"name": "__read"
},
@ -1115,9 +1124,6 @@
{
"name": "_enable_super_gross_mode_that_will_cause_bad_things"
},
{
"name": "_getViewData"
},
{
"name": "_global"
},
@ -1184,9 +1190,6 @@
{
"name": "addToViewTree"
},
{
"name": "adjustBlueprintForNewNode"
},
{
"name": "allocPlayerContext"
},
@ -1208,17 +1211,14 @@
{
"name": "attachPatchData"
},
{
"name": "baseDirectiveCreate"
},
{
"name": "baseElement"
},
{
"name": "bind"
"name": "baseResolveDirective"
},
{
"name": "bindingRootIndex"
"name": "bind"
},
{
"name": "bindingUpdated"
@ -1230,10 +1230,10 @@
"name": "bloomAdd"
},
{
"name": "bloomHashBitOrFactory"
"name": "bloomHasToken"
},
{
"name": "cacheMatchingDirectivesForNode"
"name": "bloomHashBitOrFactory"
},
{
"name": "cacheMatchingLocalNames"
@ -1394,6 +1394,9 @@
{
"name": "decoratePreventDefault"
},
{
"name": "decreaseElementDepthCount"
},
{
"name": "deepForEach"
},
@ -1451,15 +1454,9 @@
{
"name": "detectWTF"
},
{
"name": "diPublic"
},
{
"name": "diPublicInInjector"
},
{
"name": "directiveCreate"
},
{
"name": "directiveInject"
},
@ -1605,7 +1602,7 @@
"name": "fromPromise"
},
{
"name": "generateExpandoBlock"
"name": "generateExpandoInstructionBlock"
},
{
"name": "generateInitialInputs"
@ -1619,6 +1616,12 @@
{
"name": "getBeforeNodeForView"
},
{
"name": "getBindingsEnabled"
},
{
"name": "getCheckNoChangesMode"
},
{
"name": "getCleanup"
},
@ -1637,9 +1640,18 @@
{
"name": "getContainerRenderParent"
},
{
"name": "getContextViewData"
},
{
"name": "getCreationMode"
},
{
"name": "getCurrencySymbol"
},
{
"name": "getCurrentQueries"
},
{
"name": "getCurrentSanitizer"
},
@ -1667,9 +1679,15 @@
{
"name": "getDirectiveDef"
},
{
"name": "getElementDepthCount"
},
{
"name": "getErrorLogger"
},
{
"name": "getFirstTemplatePass"
},
{
"name": "getFirstThursdayOfYear"
},
@ -1694,6 +1712,9 @@
{
"name": "getInjectorIndex"
},
{
"name": "getIsParent"
},
{
"name": "getLContainer"
},
@ -1766,6 +1787,9 @@
{
"name": "getNgZone"
},
{
"name": "getNodeInjectable"
},
{
"name": "getNullInjector"
},
@ -1775,9 +1799,6 @@
{
"name": "getOrCreateInjectable"
},
{
"name": "getOrCreateNodeInjector"
},
{
"name": "getOrCreateNodeInjectorForNode"
},
@ -1790,12 +1811,21 @@
{
"name": "getOriginalError"
},
{
"name": "getParentInjectorIndex"
},
{
"name": "getParentInjectorLocation"
},
{
"name": "getParentInjectorTNode"
},
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentNative"
},
@ -1868,6 +1898,9 @@
{
"name": "getTNode"
},
{
"name": "getTView"
},
{
"name": "getTViewCleanup"
},
@ -1886,6 +1919,9 @@
{
"name": "getValue"
},
{
"name": "getViewData"
},
{
"name": "globalListener"
},
@ -1898,6 +1934,9 @@
{
"name": "hasOnDestroy"
},
{
"name": "hasParentInjector"
},
{
"name": "hasPlayerBuilderChanged"
},
@ -1910,9 +1949,18 @@
{
"name": "identity"
},
{
"name": "includeViewProviders"
},
{
"name": "increaseElementDepthCount"
},
{
"name": "initDomAdapter"
},
{
"name": "initNodeFlags"
},
{
"name": "initializeTNodeInputs"
},
@ -1925,15 +1973,24 @@
{
"name": "injectAttribute"
},
{
"name": "injectAttributeImpl"
},
{
"name": "injectChangeDetectorRef"
},
{
"name": "injectElementRef"
},
{
"name": "injectInjectorOnly"
},
{
"name": "injectRenderer2"
},
{
"name": "injectRootLimpMode"
},
{
"name": "injectTemplateRef"
},
@ -1941,10 +1998,10 @@
"name": "injectViewContainerRef"
},
{
"name": "injectableDefRecord"
"name": "injectableDefFactory"
},
{
"name": "injectorHasToken"
"name": "insertBloom"
},
{
"name": "insertView"
@ -1953,7 +2010,10 @@
"name": "inspectNativeElement"
},
{
"name": "instantiateDirectivesDirectly"
"name": "instantiateAllDirectives"
},
{
"name": "instantiateRootComponent"
},
{
"name": "interpolation1"
@ -1977,7 +2037,7 @@
"name": "isComponent"
},
{
"name": "isContentQueryHost"
"name": "isComponentDef"
},
{
"name": "isContextDirty"
@ -2006,6 +2066,9 @@
{
"name": "isExistingProvider"
},
{
"name": "isFactory"
},
{
"name": "isFactoryProvider"
},
@ -2153,6 +2216,9 @@
{
"name": "nextContext"
},
{
"name": "nextContextImpl"
},
{
"name": "nextNgElementId"
},
@ -2216,6 +2282,12 @@
{
"name": "pointers"
},
{
"name": "postProcessBaseDirective"
},
{
"name": "postProcessDirective"
},
{
"name": "prefillHostVars"
},
@ -2228,6 +2300,9 @@
{
"name": "promise"
},
{
"name": "providerToFactory"
},
{
"name": "providerToRecord"
},
@ -2307,7 +2382,7 @@
"name": "resetComponentState"
},
{
"name": "resolveDirective"
"name": "resolveDirectives"
},
{
"name": "resolveForwardRef$1"
@ -2343,10 +2418,13 @@
"name": "scheduleTick"
},
{
"name": "searchDirectivesOnInjector"
"name": "searchTokensOnInjector"
},
{
"name": "searchMatchesQueuedForCreation"
"name": "setBindingRoot"
},
{
"name": "setCheckNoChangesMode"
},
{
"name": "setClass"
@ -2360,11 +2438,14 @@
{
"name": "setCurrentInjector"
},
{
"name": "setCurrentQueries"
},
{
"name": "setDirty"
},
{
"name": "setEnvironment"
"name": "setFirstTemplatePass"
},
{
"name": "setFlag"
@ -2372,36 +2453,51 @@
{
"name": "setHostBindings"
},
{
"name": "setIncludeViewProviders"
},
{
"name": "setInjectImplementation"
},
{
"name": "setInputsForProperty"
},
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsParent"
},
{
"name": "setPlayerBuilder"
},
{
"name": "setPlayerBuilderIndex"
},
{
"name": "setPreviousOrParentTNode"
},
{
"name": "setProp"
},
{
"name": "setRendererFactory"
},
{
"name": "setRootDomAdapter"
},
{
"name": "setStyle"
},
{
"name": "setTNodeAndViewData"
},
{
"name": "setTestabilityGetter"
},
{
"name": "setUpAttributes"
},
{
"name": "setUpBloom"
},
{
"name": "setValue"
},
@ -2418,7 +2514,7 @@
"name": "shimHostAttribute"
},
{
"name": "shouldNotSearchParent"
"name": "shouldSearchParent"
},
{
"name": "staticError"
@ -2483,9 +2579,6 @@
{
"name": "textBinding"
},
{
"name": "throwCyclicDependencyError"
},
{
"name": "throwErrorIfNoChangesMode"
},

View File

@ -397,7 +397,7 @@ describe('InheritDefinitionFeature', () => {
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
subDef.contentQueries !();
subDef.contentQueries !(0);
expect(log).toEqual(['super', 'sub']);
});

View File

@ -11,9 +11,8 @@ import {withBody} from '@angular/private/testing';
import {ChangeDetectionStrategy, ChangeDetectorRef, DoCheck, RendererType2} from '../../src/core';
import {getRenderedText, whenRendered} from '../../src/render3/component';
import {directiveInject} from '../../src/render3/di';
import {LifecycleHooksFeature, defineComponent, defineDirective, templateRefExtractor} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, reference, text, template, textBinding, tick} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, reference, text, template, textBinding, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {RElement, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer';

View File

@ -10,8 +10,9 @@ import {NgForOfContext} from '@angular/common';
import {ElementRef, TemplateRef} from '@angular/core';
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding, elementContainerStart, elementContainerEnd, reference} from '../../src/render3/instructions';
import {bind, template, elementEnd, elementProperty, elementStart, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, text, textBinding, elementContainerStart, elementContainerEnd, reference} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {getCurrentView, restoreView} from '../../src/render3/state';
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
import {ComponentFixture} from './render_util';

View File

@ -31,7 +31,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ChildComponent,
selectors: [['child']],
factory: function ChildComponent_Factory() { return new ChildComponent(); },
factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); },
consts: 1,
vars: 0,
template: function ChildComponent_Template(rf: $RenderFlags$, ctx: $ChildComponent$) {
@ -52,7 +52,7 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [['', 'some-directive', '']],
factory: () => new SomeDirective(),
factory: function SomeDirective_Factory(t) { return new (t || SomeDirective)(); },
});
// /NORMATIVE
}
@ -68,7 +68,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -101,7 +101,7 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: HostBindingDir,
selectors: [['', 'hostBindingDir', '']],
factory: function HostBindingDir_Factory() { return new HostBindingDir(); },
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵelementProperty(
@ -123,7 +123,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -175,7 +175,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -205,7 +205,7 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
selectors: [['', 'hostAttributeDir', '']],
type: HostAttributeDir,
factory: function HostAttributeDir_Factory() { return new HostAttributeDir(); },
factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); },
attributes: ['role', 'listbox']
});
// /NORMATIVE
@ -223,7 +223,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -252,7 +252,7 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: HostBindingDir,
selectors: [['', 'hostBindingDir', '']],
factory: function HostBindingDir_Factory() { return new HostBindingDir(); },
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵelementAttribute(
@ -274,7 +274,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -311,7 +311,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
@ -340,7 +340,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 1,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -388,7 +388,9 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [['', 'if', '']],
factory: () => new IfDirective($r3$.ɵdirectiveInject(TemplateRef as any)),
factory: function IfDirective_Factory(t) {
return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef as any));
},
});
// /NORMATIVE
}
@ -406,7 +408,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -440,7 +442,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyArrayComp,
selectors: [['my-array-comp']],
factory: function MyArrayComp_Factory() { return new MyArrayComp(); },
factory: function MyArrayComp_Factory(t) { return new (t || MyArrayComp)(); },
consts: 1,
vars: 2,
template: function MyArrayComp_Template(rf: $RenderFlags$, ctx: $MyArrayComp$) {
@ -473,7 +475,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -519,7 +521,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -555,7 +557,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
@ -589,7 +591,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 2,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -634,7 +636,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 3,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -684,7 +686,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp(); },
factory: function MyComp_Factory(t) { return new (t || MyComp)(); },
consts: 12,
vars: 12,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
@ -749,7 +751,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 11,
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
@ -793,7 +795,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ObjectComp,
selectors: [['object-comp']],
factory: function ObjectComp_Factory() { return new ObjectComp(); },
factory: function ObjectComp_Factory(t) { return new (t || ObjectComp)(); },
consts: 4,
vars: 2,
template: function ObjectComp_Template(rf: $RenderFlags$, ctx: $ObjectComp$) {
@ -831,7 +833,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 3,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -874,7 +876,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: NestedComp,
selectors: [['nested-comp']],
factory: function NestedComp_Factory() { return new NestedComp(); },
factory: function NestedComp_Factory(t) { return new (t || NestedComp)(); },
consts: 6,
vars: 3,
template: function NestedComp_Template(rf: $RenderFlags$, ctx: $NestedComp$) {
@ -921,7 +923,7 @@ describe('components & directives', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 8,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {

View File

@ -24,7 +24,7 @@ describe('content projection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: SimpleComponent,
selectors: [['simple']],
factory: () => new SimpleComponent(),
factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); },
consts: 1,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) {
@ -55,7 +55,7 @@ describe('content projection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ComplexComponent,
selectors: [['complex']],
factory: () => new ComplexComponent(),
factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); },
consts: 4,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) {
@ -80,7 +80,7 @@ describe('content projection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {

View File

@ -34,7 +34,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 5,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -65,7 +65,7 @@ describe('elements', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: Dir,
selectors: [['', 'dir', '']],
factory: function DirA_Factory() { return new Dir(); },
factory: function DirA_Factory(t) { return new (t || Dir)(); },
exportAs: 'dir'
});
}
@ -87,7 +87,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: LocalRefComp,
selectors: [['local-ref-comp']],
factory: function LocalRefComp_Factory() { return new LocalRefComp(); },
factory: function LocalRefComp_Factory(t) { return new (t || LocalRefComp)(); },
consts: 4,
vars: 2,
template: function LocalRefComp_Template(rf: $RenderFlags$, ctx: $LocalRefComp$) {
@ -131,7 +131,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ListenerComp,
selectors: [['listener-comp']],
factory: function ListenerComp_Factory() { return new ListenerComp(); },
factory: function ListenerComp_Factory(t) { return new (t || ListenerComp)(); },
consts: 2,
vars: 0,
template: function ListenerComp_Template(rf: $RenderFlags$, ctx: $ListenerComp$) {
@ -188,7 +188,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent(),
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 5,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -222,7 +222,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -255,7 +255,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -289,7 +289,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 0,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -334,7 +334,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 0,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -379,7 +379,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 1,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -419,7 +419,7 @@ describe('elements', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: StyleComponent,
selectors: [['style-comp']],
factory: function StyleComponent_Factory() { return new StyleComponent(); },
factory: function StyleComponent_Factory(t) { return new (t || StyleComponent)(); },
consts: 1,
vars: 0,
template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) {

View File

@ -25,7 +25,7 @@ describe('i18n', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
@ -52,7 +52,7 @@ describe('i18n', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
@ -81,7 +81,7 @@ describe('i18n', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyApp$) {
@ -125,7 +125,7 @@ describe('i18n', () => {
items: string[] = ['1', '2'];
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
factory: () => new MyApp(),
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
selectors: [['my-app']],
consts: 2,
vars: 1,

View File

@ -8,6 +8,7 @@
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';
@ -31,8 +32,8 @@ describe('injection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() {
return new MyComp($r3$.ɵdirectiveInject(ChangeDetectorRef as any));
factory: function MyComp_Factory(t) {
return new (t || MyComp)($r3$.ɵdirectiveInject(ChangeDetectorRef as any));
},
consts: 1,
vars: 1,
@ -52,7 +53,7 @@ describe('injection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
/** <my-comp></my-comp> */
@ -83,7 +84,9 @@ describe('injection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); },
factory: function MyComp_Factory(t) {
return new (t || MyComp)($r3$.ɵinjectAttribute('title'));
},
consts: 1,
vars: 1,
template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) {
@ -102,7 +105,7 @@ describe('injection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 1,
vars: 0,
/** <my-comp></my-comp> */
@ -153,15 +156,14 @@ describe('injection', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() {
return new MyApp(
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$) {},
providers: [ServiceA],
viewProviders: [ServiceB],
features: [ProvidersFeature([ServiceA], [ServiceB])]
});
}
const e0_attrs = ['title', 'WORKS'];

View File

@ -45,7 +45,7 @@ describe('lifecycle hooks', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: LifecycleComp,
selectors: [['lifecycle-comp']],
factory: function LifecycleComp_Factory() { return new LifecycleComp(); },
factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); },
consts: 0,
vars: 0,
template: function LifecycleComp_Template(rf: $RenderFlags$, ctx: $LifecycleComp$) {},
@ -70,7 +70,9 @@ describe('lifecycle hooks', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: SimpleLayout,
selectors: [['simple-layout']],
factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); },
factory: function SimpleLayout_Factory(t) {
return simpleLayout = new (t || SimpleLayout)();
},
consts: 2,
vars: 2,
template: function SimpleLayout_Template(rf: $RenderFlags$, ctx: $SimpleLayout$) {

View File

@ -27,7 +27,7 @@ describe('local references', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent,
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -64,7 +64,7 @@ describe('local references', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: () => new MyComponent,
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 3,
vars: 1,
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {

View File

@ -34,7 +34,7 @@ xdescribe('NgModule', () => {
constructor(name: String) {}
// NORMATIVE
static ngInjectableDef = defineInjectable({
factory: () => new Toast($r3$.ɵdirectiveInject(String)),
factory: function Toast_Factory() { return new Toast($r3$.ɵdirectiveInject(String)); },
});
// /NORMATIVE
}
@ -53,7 +53,7 @@ xdescribe('NgModule', () => {
constructor(toast: Toast) {}
// NORMATIVE
static ngInjectorDef = defineInjector({
factory: () => new MyModule($r3$.ɵdirectiveInject(Toast)),
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.
@ -70,9 +70,11 @@ xdescribe('NgModule', () => {
// NORMATIVE
static ngInjectableDef = defineInjectable({
providedIn: MyModule,
factory: () => new BurntToast(
$r3$.ɵdirectiveInject(Toast, $core$.InjectFlags.Optional),
$r3$.ɵdirectiveInject(String)),
factory: function BurntToast_Factory() {
return new BurntToast(
$r3$.ɵdirectiveInject(Toast, $core$.InjectFlags.Optional),
$r3$.ɵdirectiveInject(String));
},
});
// /NORMATIVE
}

View File

@ -43,7 +43,7 @@ describe('pipes', () => {
static ngPipeDef = $r3$.ɵdefinePipe({
name: 'myPipe',
type: MyPipe,
factory: function MyPipe_Factory() { return new MyPipe(); },
factory: function MyPipe_Factory(t) { return new (t || MyPipe)(); },
pure: false,
});
// /NORMATIVE
@ -63,7 +63,7 @@ describe('pipes', () => {
static ngPipeDef = $r3$.ɵdefinePipe({
name: 'myPurePipe',
type: MyPurePipe,
factory: function MyPurePipe_Factory() { return new MyPurePipe(); },
factory: function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); },
pure: true,
});
// /NORMATIVE
@ -83,7 +83,7 @@ describe('pipes', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 3,
vars: 7,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
@ -146,9 +146,11 @@ describe('pipes', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: OneTimeIf,
selectors: [['', 'oneTimeIf', '']],
factory: () => new OneTimeIf(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any)),
factory: function OneTimeIf_Factory(t) {
return new (t || OneTimeIf)(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any));
},
inputs: {oneTimeIf: 'oneTimeIf'}
});
// /NORMATIVE
@ -181,7 +183,7 @@ describe('pipes', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 5,
vars: 9,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {

View File

@ -25,8 +25,7 @@ describe('queries', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [['', 'someDir', '']],
factory: function SomeDirective_Factory() { return someDir = new SomeDirective(); },
features: [$r3$.ɵPublicFeature]
factory: function SomeDirective_Factory(t) { return someDir = new (t || SomeDirective)(); }
});
}
@ -53,7 +52,7 @@ describe('queries', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ViewQueryComponent,
selectors: [['view-query-component']],
factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); },
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
consts: 3,
vars: 0,
template: function ViewQueryComponent_Template(
@ -111,12 +110,14 @@ describe('queries', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: ContentQueryComponent,
selectors: [['content-query-component']],
factory: function ContentQueryComponent_Factory() { return new ContentQueryComponent(); },
factory: function ContentQueryComponent_Factory(t) {
return new (t || ContentQueryComponent)();
},
consts: 2,
vars: 0,
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
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$) {
@ -155,7 +156,7 @@ describe('queries', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: function MyApp_Factory() { return new MyApp(); },
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
consts: 2,
vars: 0,
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {

View File

@ -40,7 +40,7 @@ describe('compiler sanitization', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 4,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {

View File

@ -74,8 +74,8 @@ class ToDoAppComponent {
static ngComponentDef = r3.defineComponent({
type: ToDoAppComponent,
selectors: [['todo-app']],
factory: function ToDoAppComponent_Factory() {
return new ToDoAppComponent(r3.directiveInject(AppState));
factory: function ToDoAppComponent_Factory(t) {
return new (t || ToDoAppComponent)(r3.directiveInject(AppState));
},
consts: 6,
vars: 1,
@ -135,7 +135,7 @@ class ToDoItemComponent {
static ngComponentDef = r3.defineComponent({
type: ToDoItemComponent,
selectors: [['todo']],
factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); },
factory: function ToDoItemComponent_Factory(t) { return new (t || ToDoItemComponent)(); },
consts: 6,
vars: 2,
template: function ToDoItemComponent_Template(rf: $RenderFlags$, ctx: ToDoItemComponent) {
@ -174,7 +174,7 @@ const e1_attrs = ['type', 'checkbox'];
class ToDoAppModule {
// NORMATIVE
static ngInjectorDef = defineInjector({
factory: () => new ToDoAppModule(),
factory: function ToDoAppModule_Factory() { return new ToDoAppModule(); },
providers: [AppState],
});
// /NORMATIVE

View File

@ -69,8 +69,8 @@ describe('template variables', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: ForOfDirective,
selectors: [['', 'forOf', '']],
factory: function ForOfDirective_Factory() {
return new ForOfDirective(
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any));
},
@ -111,7 +111,7 @@ describe('template variables', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
@ -205,7 +205,7 @@ describe('template variables', () => {
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [['my-component']],
factory: function MyComponent_Factory() { return new MyComponent(); },
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
consts: 2,
vars: 1,
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,15 @@ import {Attribute, ChangeDetectorRef, ElementRef, Host, InjectFlags, Injector, O
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
import {defineComponent} from '../../src/render3/definition';
import {bloomAdd, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjector, injectAttribute, injectorHasToken} from '../../src/render3/di';
import {PublicFeature, defineDirective, directiveInject, elementProperty, load, templateRefExtractor} from '../../src/render3/index';
import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
import {defineDirective, elementProperty, load, templateRefExtractor} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd, _getViewData} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, directiveInject, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, injectAttribute, interpolation2, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
import {isProceduralRenderer, RElement} from '../../src/render3/interfaces/renderer';
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
import {getNativeByIndex} from '../../src/render3/util';
import {LViewFlags} from '../../src/render3/interfaces/view';
import {getViewData, enterView, leaveView} from '../../src/render3/state';
import {ViewRef} from '../../src/render3/view_ref';
import {getRendererFactory2} from './imported_renderer2';
@ -68,7 +69,6 @@ describe('di', () => {
selectors: [['', 'dirB', '']],
type: DirB,
factory: () => new DirB(),
features: [PublicFeature],
inputs: {value: 'value'}
});
}
@ -78,12 +78,8 @@ describe('di', () => {
it('should create directive with intra view dependencies', () => {
class DirA {
value: string = 'DirA';
static ngDirectiveDef = defineDirective({
type: DirA,
selectors: [['', 'dirA', '']],
factory: () => new DirA(),
features: [PublicFeature]
});
static ngDirectiveDef =
defineDirective({type: DirA, selectors: [['', 'dirA', '']], factory: () => new DirA()});
}
class DirC {
@ -246,12 +242,8 @@ describe('di', () => {
value = 'DirA';
constructor() { log.push(this.value); }
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirA', '']],
type: DirA,
factory: () => new DirA(),
features: [PublicFeature]
});
static ngDirectiveDef =
defineDirective({selectors: [['', 'dirA', '']], type: DirA, factory: () => new DirA()});
}
class DirB {
@ -270,12 +262,8 @@ describe('di', () => {
value = 'DirC';
constructor() { log.push(this.value); }
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirC', '']],
type: DirC,
factory: () => new DirC(),
features: [PublicFeature]
});
static ngDirectiveDef =
defineDirective({selectors: [['', 'dirC', '']], type: DirC, factory: () => new DirC()});
}
/** <div dirA dirB dirC></div> */
@ -310,8 +298,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirA', '']],
type: DirA,
factory: () => new DirA(directiveInject(DirC)),
features: [PublicFeature]
factory: () => new DirA(directiveInject(DirC))
});
}
@ -322,8 +309,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirC', '']],
type: DirC,
factory: () => new DirC(directiveInject(DirB)),
features: [PublicFeature]
factory: () => new DirC(directiveInject(DirB))
});
}
@ -334,8 +320,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirD', '']],
type: DirD,
factory: () => new DirD(directiveInject(DirA)),
features: [PublicFeature]
factory: () => new DirD(directiveInject(DirA))
});
}
@ -379,8 +364,7 @@ describe('di', () => {
element(0, 'div', ['dirA', '', 'dirB', '', 'dirC', 'dirC']);
}
},
directives: [DirA, DirB],
features: [PublicFeature],
directives: [DirA, DirB]
});
}
@ -409,12 +393,8 @@ describe('di', () => {
this.count = count++;
}
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirB', '']],
type: DirB,
factory: () => new DirB(),
features: [PublicFeature],
});
static ngDirectiveDef =
defineDirective({selectors: [['', 'dirB', '']], type: DirB, factory: () => new DirB()});
}
/** <div dirA dirB></div> */
@ -447,7 +427,6 @@ describe('di', () => {
type: DirA,
selectors: [['', 'dirA', '']],
factory: () => new DirA(directiveInject(DirB), directiveInject(ViewContainerRef as any)),
features: [PublicFeature],
exportAs: 'dirA'
});
}
@ -599,8 +578,7 @@ describe('di', () => {
selectors: [['', 'structuralDir', '']],
factory: () => structuralDir =
new StructuralDir(directiveInject(ViewContainerRef as any)),
inputs: {tmp: 'tmp'},
features: [PublicFeature]
inputs: {tmp: 'tmp'}
});
}
@ -763,18 +741,13 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dir', '']],
type: Dir,
factory: () => new Dir(directiveInject(OtherDir)),
features: [PublicFeature]
factory: () => new Dir(directiveInject(OtherDir))
});
}
class OtherDir {
static ngDirectiveDef = defineDirective({
selectors: [['', 'other', '']],
type: OtherDir,
factory: () => new OtherDir(),
features: [PublicFeature]
});
static ngDirectiveDef = defineDirective(
{selectors: [['', 'other', '']], type: OtherDir, factory: () => new OtherDir()});
}
/** <div dir></div> */
@ -794,18 +767,13 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dir', '']],
type: Dir,
factory: () => new Dir(directiveInject(OtherDir)),
features: [PublicFeature]
factory: () => new Dir(directiveInject(OtherDir))
});
}
class OtherDir {
static ngDirectiveDef = defineDirective({
selectors: [['', 'other', '']],
type: OtherDir,
factory: () => new OtherDir(),
features: [PublicFeature]
});
static ngDirectiveDef = defineDirective(
{selectors: [['', 'other', '']], type: OtherDir, factory: () => new OtherDir()});
}
/**
@ -830,8 +798,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirA', '']],
type: DirA,
factory: () => new DirA(directiveInject(DirB)),
features: [PublicFeature]
factory: () => new DirA(directiveInject(DirB))
});
}
@ -841,8 +808,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dirB', '']],
type: DirB,
factory: () => new DirB(directiveInject(DirA)),
features: [PublicFeature]
factory: () => new DirB(directiveInject(DirA))
});
}
@ -853,7 +819,7 @@ describe('di', () => {
}
}, 1, 0, [DirA, DirB]);
expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/);
expect(() => new ComponentFixture(App)).toThrowError(/Circular dep for/);
});
it('should throw if directive tries to inject itself', () => {
@ -863,8 +829,7 @@ describe('di', () => {
static ngDirectiveDef = defineDirective({
selectors: [['', 'dir', '']],
type: Dir,
factory: () => new Dir(directiveInject(Dir)),
features: [PublicFeature]
factory: () => new Dir(directiveInject(Dir))
});
}
@ -875,7 +840,7 @@ describe('di', () => {
}
}, 1, 0, [Dir]);
expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/);
expect(() => new ComponentFixture(App)).toThrowError(/Circular dep for/);
});
describe('flags', () => {
@ -888,8 +853,7 @@ describe('di', () => {
type: DirB,
selectors: [['', 'dirB', '']],
factory: () => new DirB(),
inputs: {value: 'dirB'},
features: [PublicFeature]
inputs: {value: 'dirB'}
});
}
@ -1006,7 +970,9 @@ describe('di', () => {
}
}, 2, 0, [DirA, DirB]);
expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/);
expect(() => {
new ComponentFixture(App);
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB\]/);
});
it('should check only the current node with @Self even with false positive', () => {
@ -1041,7 +1007,7 @@ describe('di', () => {
(DirA as any)['__NG_ELEMENT_ID__'] = 1;
(DirC as any)['__NG_ELEMENT_ID__'] = 257;
new ComponentFixture(App);
}).toThrowError(/Injector: NOT_FOUND \[DirB\]/);
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB\]/);
});
it('should not pass component boundary with @Host', () => {
@ -1071,7 +1037,9 @@ describe('di', () => {
}
}, 1, 0, [Comp, DirB]);
expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/);
expect(() => {
new ComponentFixture(App);
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB\]/);
});
@ -1097,7 +1065,6 @@ describe('di', () => {
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(directiveInject(ElementRef)),
features: [PublicFeature],
exportAs: 'dir'
});
}
@ -1121,7 +1088,7 @@ describe('di', () => {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
elementEnd();
div = getNativeByIndex(0, _getViewData());
div = getNativeByIndex(0, getViewData());
}
}, 1, 0, [Directive, DirectiveSameInstance]);
@ -1148,7 +1115,6 @@ describe('di', () => {
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(directiveInject(ElementRef)),
features: [PublicFeature],
exportAs: 'dir'
});
}
@ -1179,7 +1145,6 @@ describe('di', () => {
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(directiveInject(TemplateRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
@ -1234,7 +1199,6 @@ describe('di', () => {
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(directiveInject(ViewContainerRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
@ -1298,8 +1262,7 @@ describe('di', () => {
projectionDef();
projection(0);
}
},
features: [PublicFeature]
}
});
}
@ -1312,7 +1275,6 @@ describe('di', () => {
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(directiveInject(ChangeDetectorRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
@ -1324,8 +1286,7 @@ describe('di', () => {
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => dirSameInstance =
new DirectiveSameInstance(directiveInject(ChangeDetectorRef as any)),
features: [PublicFeature]
new DirectiveSameInstance(directiveInject(ChangeDetectorRef as any))
});
}
@ -1421,8 +1382,7 @@ describe('di', () => {
textBinding(3, bind(tmp.value));
}
},
directives: directives,
features: [PublicFeature]
directives: directives
});
}
@ -1749,15 +1709,15 @@ describe('di', () => {
bloomAdd(0, mockTView, Dir198);
bloomAdd(0, mockTView, Dir231);
expect(injectorHasToken(bloomHash(Dir0) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir1) as number, 0, mockTView.data)).toEqual(false);
expect(injectorHasToken(bloomHash(Dir33) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir66) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir99) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir132) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir165) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir198) as number, 0, mockTView.data)).toEqual(true);
expect(injectorHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir0) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir1) as number, 0, mockTView.data)).toEqual(false);
expect(bloomHasToken(bloomHash(Dir33) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir66) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir99) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir132) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir165) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir198) as number, 0, mockTView.data)).toEqual(true);
expect(bloomHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
});
});
@ -1771,7 +1731,6 @@ describe('di', () => {
type: ChildDirective,
selectors: [['', 'childDir', '']],
factory: () => new ChildDirective(directiveInject(ParentDirective)),
features: [PublicFeature],
exportAs: 'childDir'
});
}
@ -1847,7 +1806,7 @@ describe('di', () => {
// so that we have smaller HelloWorld.
(parentTNode as{parent: any}).parent = undefined;
const injector: any = getOrCreateNodeInjector(); // TODO: Review use of `any` here (#19904)
const injector = getOrCreateNodeInjectorForNode(parentTNode, contentView);
expect(injector).not.toEqual(-1);
} finally {
leaveView(oldView);

View File

@ -7,7 +7,7 @@
*/
import {StaticInjector} from '../../src/di/injector';
import {getComponent, getDirectives, getHostComponent, getInjector, getLocalRefs, getRootComponents} from '../../src/render3/discovery_utils';
import {PublicFeature, RenderFlags, defineComponent, defineDirective} from '../../src/render3/index';
import {RenderFlags, defineComponent, defineDirective} from '../../src/render3/index';
import {element, elementEnd, elementStart, elementStyling, elementStylingApply} from '../../src/render3/instructions';
import {ComponentFixture} from './render_util';
@ -231,8 +231,7 @@ describe('discovery utils', () => {
factory: () => new Comp(),
consts: 0,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {},
features: [PublicFeature]
template: (rf: RenderFlags, ctx: Comp) => {}
});
}
@ -252,8 +251,7 @@ describe('discovery utils', () => {
factory: () => new Comp(),
consts: 0,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {},
features: [PublicFeature]
template: (rf: RenderFlags, ctx: Comp) => {}
});
}

View File

@ -10,11 +10,12 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {RendererStyleFlags2, RendererType2} from '../../src/render/api';
import {AttributeMarker, defineComponent, defineDirective, templateRefExtractor} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, enableBindings, disableBindings, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, reference, text, textBinding, template, elementStylingMap} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, reference, text, textBinding, template, elementStylingMap, directiveInject} from '../../src/render3/instructions';
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3, RText, RComment, RNode, RendererStyleFlags3, ProceduralRenderer3} from '../../src/render3/interfaces/renderer';
import {NO_CHANGE} from '../../src/render3/tokens';
import {HEADER_OFFSET, CONTEXT} from '../../src/render3/interfaces/view';
import {enableBindings, disableBindings} from '../../src/render3/state';
import {sanitizeUrl} from '../../src/sanitization/sanitization';
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
@ -23,7 +24,6 @@ import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from '
import {getContext} from '../../src/render3/context_discovery';
import {StylingIndex} from '../../src/render3/interfaces/styling';
import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context';
import {directiveInject} from '../../src/render3/di';
describe('render3 integration test', () => {

View File

@ -239,7 +239,7 @@ ivyEnabled && describe('render3 jit', () => {
const pipeDef = (P as any).ngPipeDef as PipeDef<P>;
expect(pipeDef.name).toBe('test-pipe');
expect(pipeDef.pure).toBe(false, 'pipe should not be pure');
expect(pipeDef.factory() instanceof P)
expect(pipeDef.factory(null) instanceof P)
.toBe(true, 'factory() should create an instance of the pipe');
});

View File

@ -36,7 +36,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory() as MyDirective;
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory(null) as MyDirective;
myDir.valA = 'first';
expect(myDir.valA).toEqual('first');
myDir.valB = 'second';
@ -89,7 +89,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory() as SubDirective;
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory(null) as SubDirective;
myDir.valA = 'first';
expect(myDir.valA).toEqual('first');
@ -142,7 +142,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory() as SubDirective;
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory(null) as SubDirective;
myDir.valA = 'first';
myDir.valB = 'second';
@ -183,7 +183,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory() as SubDirective;
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory(null) as SubDirective;
myDir.valA = 'first';
myDir.valB = 'second';
@ -237,7 +237,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory() as SubDirective;
(SubDirective.ngDirectiveDef as DirectiveDef<SubDirective>).factory(null) as SubDirective;
myDir.valA = 'first';
expect(myDir.valA).toEqual('first');
@ -279,7 +279,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory() as MyDirective;
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory(null) as MyDirective;
myDir.valA = 'first';
myDir.valB = 'second';
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).doCheck !.call(myDir);
@ -315,7 +315,7 @@ describe('NgOnChangesFeature', () => {
}
const myDir =
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory() as MyDirective;
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).factory(null) as MyDirective;
myDir.onlySetter = 'someValue';
expect(myDir.onlySetter).toBeUndefined();
(MyDirective.ngDirectiveDef as DirectiveDef<MyDirective>).doCheck !.call(myDir);

View File

@ -11,15 +11,16 @@ import {AttributeMarker, TAttributes, TNode, TNodeType} from '../../src/render3/
import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} from '../../src/render3/interfaces/projection';
import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher';
import {createTNode} from '@angular/core/src/render3/instructions';
import {getViewData} from '@angular/core/src/render3/state';
function testLStaticData(tagName: string, attrs: TAttributes | null): TNode {
return createTNode(TNodeType.Element, 0, tagName, attrs, null);
return createTNode(getViewData(), TNodeType.Element, 0, tagName, attrs, null);
}
describe('css selector matching', () => {
function isMatching(tagName: string, attrs: TAttributes | null, selector: CssSelector): boolean {
return isNodeMatchingSelector(
createTNode(TNodeType.Element, 0, tagName, attrs, null), selector);
createTNode(getViewData(), TNodeType.Element, 0, tagName, attrs, null), selector);
}
describe('isNodeMatchingSimpleSelector', () => {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, InjectionToken, OnChanges, OnDestroy, Pipe, PipeTransform, createInjector, defineInjectable, defineInjector, ɵNgModuleDef as NgModuleDef, ɵPublicFeature as PublicFeature, ɵdefineComponent as defineComponent, ɵdirectiveInject as directiveInject} from '@angular/core';
import {Directive, InjectionToken, OnChanges, OnDestroy, 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 {defineDirective, definePipe} from '../../src/render3/definition';
@ -367,7 +367,6 @@ describe('pipe', () => {
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['my-app']],
features: [PublicFeature],
factory: function MyComponent_Factory() { return new MyComponent(); },
consts: 2,
vars: 3,

View File

@ -8,7 +8,7 @@
import {EventEmitter} from '@angular/core';
import {AttributeMarker, PublicFeature, defineComponent, template, defineDirective} from '../../src/render3/index';
import {AttributeMarker, defineComponent, template, defineDirective} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, load, reference, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NO_CHANGE} from '../../src/render3/tokens';
@ -168,8 +168,7 @@ describe('elementProperty', () => {
hostVars: 1,
hostBindings: (directiveIndex: number, elementIndex: number) => {
elementProperty(elementIndex, 'id', bind(load<HostBindingDir>(directiveIndex).id));
},
features: [PublicFeature]
}
});
}
@ -190,8 +189,7 @@ describe('elementProperty', () => {
const ctx = load(dirIndex) as HostBindingComp;
elementProperty(elIndex, 'title', bind(ctx.title));
},
template: (rf: RenderFlags, ctx: HostBindingComp) => {},
features: [PublicFeature]
template: (rf: RenderFlags, ctx: HostBindingComp) => {}
});
}
@ -231,8 +229,7 @@ describe('elementProperty', () => {
hostVars: 1,
hostBindings: (directiveIndex: number, elementIndex: number) => {
elementProperty(elementIndex, 'id', bind(load<HostBindingDir>(directiveIndex).id));
},
features: [PublicFeature]
}
});
}
@ -272,8 +269,7 @@ describe('elementProperty', () => {
hostVars: 1,
hostBindings: (directiveIndex: number, elementIndex: number) => {
elementProperty(elementIndex, 'id', bind(load<HostBindingDir>(directiveIndex).id));
},
features: [PublicFeature]
}
});
}

View File

@ -10,13 +10,13 @@ import {NgForOfContext} from '@angular/common';
import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {EventEmitter} from '../..';
import {directiveInject} from '../../src/render3/di';
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges} from '../../src/render3/index';
import {getNativeByIndex} from '../../src/render3/util';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadQueryList, reference, registerContentQuery, template, _getViewData} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadQueryList, reference, registerContentQuery, template} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {query, queryRefresh} from '../../src/render3/query';
import {getViewData} from '../../src/render3/state';
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
@ -115,7 +115,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', ['child', '']);
elToQuery = getNativeByIndex(1, _getViewData());
elToQuery = getNativeByIndex(1, getViewData());
}
},
2, 0, [Child], [],
@ -222,7 +222,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']);
elToQuery = getNativeByIndex(1, _getViewData());
elToQuery = getNativeByIndex(1, getViewData());
element(3, 'div');
}
},
@ -259,7 +259,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(2, 'div', null, ['foo', '', 'bar', '']);
elToQuery = getNativeByIndex(2, _getViewData());
elToQuery = getNativeByIndex(2, getViewData());
element(5, 'div');
}
},
@ -306,10 +306,10 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']);
el1ToQuery = getNativeByIndex(1, _getViewData());
el1ToQuery = getNativeByIndex(1, getViewData());
element(3, 'div');
element(4, 'div', null, ['bar', '']);
el2ToQuery = getNativeByIndex(4, _getViewData());
el2ToQuery = getNativeByIndex(4, getViewData());
}
},
6, 0, [], [],
@ -345,7 +345,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', null, ['foo', '']);
elToQuery = getNativeByIndex(1, _getViewData());
elToQuery = getNativeByIndex(1, getViewData());
element(3, 'div');
}
},
@ -381,7 +381,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementContainerStart(1, null, ['foo', '']);
elToQuery = getNativeByIndex(1, _getViewData());
elToQuery = getNativeByIndex(1, getViewData());
elementContainerEnd();
}
},
@ -417,7 +417,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementContainerStart(1, null, ['foo', '']);
elToQuery = getNativeByIndex(1, _getViewData());
elToQuery = getNativeByIndex(1, getViewData());
elementContainerEnd();
}
},
@ -480,7 +480,7 @@ describe('query', () => {
elementContainerStart(2);
{
element(3, 'div', null, ['foo', '']);
elToQuery = getNativeByIndex(3, _getViewData());
elToQuery = getNativeByIndex(3, getViewData());
}
elementContainerEnd();
}
@ -890,7 +890,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', ['child', ''], ['foo', 'child']);
div = getNativeByIndex(1, _getViewData());
div = getNativeByIndex(1, getViewData());
}
},
3, 0, [Child], [],
@ -925,7 +925,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']);
div = getNativeByIndex(1, _getViewData());
div = getNativeByIndex(1, getViewData());
}
if (rf & RenderFlags.Update) {
childInstance = getDirectiveOnNode(1);
@ -1409,7 +1409,7 @@ describe('query', () => {
{
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
firstEl = getNativeByIndex(0, _getViewData());
firstEl = getNativeByIndex(0, getViewData());
}
}
embeddedViewEnd();
@ -1461,10 +1461,10 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(1, 'span', null, ['foo', '']);
firstEl = getNativeByIndex(1, _getViewData());
firstEl = getNativeByIndex(1, getViewData());
container(3);
element(4, 'span', null, ['foo', '']);
lastEl = getNativeByIndex(4, _getViewData());
lastEl = getNativeByIndex(4, getViewData());
}
if (rf & RenderFlags.Update) {
containerRefreshStart(3);
@ -1474,7 +1474,7 @@ describe('query', () => {
{
if (rf1 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
viewEl = getNativeByIndex(0, _getViewData());
viewEl = getNativeByIndex(0, getViewData());
}
}
embeddedViewEnd();
@ -1541,7 +1541,7 @@ describe('query', () => {
{
if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
firstEl = getNativeByIndex(0, _getViewData());
firstEl = getNativeByIndex(0, getViewData());
}
}
embeddedViewEnd();
@ -1551,7 +1551,7 @@ describe('query', () => {
{
if (rf1 & RenderFlags.Create) {
element(0, 'span', null, ['foo', '']);
lastEl = getNativeByIndex(0, _getViewData());
lastEl = getNativeByIndex(0, getViewData());
}
}
embeddedViewEnd();
@ -1614,7 +1614,7 @@ describe('query', () => {
{
if (rf0 & RenderFlags.Create) {
element(0, 'div', null, ['foo', '']);
firstEl = getNativeByIndex(0, _getViewData());
firstEl = getNativeByIndex(0, getViewData());
container(2);
}
if (rf0 & RenderFlags.Update) {
@ -1625,7 +1625,7 @@ describe('query', () => {
{
if (rf2) {
element(0, 'span', null, ['foo', '']);
lastEl = getNativeByIndex(0, _getViewData());
lastEl = getNativeByIndex(0, getViewData());
}
}
embeddedViewEnd();
@ -1911,7 +1911,8 @@ describe('query', () => {
type: WithContentDirective,
selectors: [['', 'with-content', '']],
factory: () => new WithContentDirective(),
contentQueries: () => { registerContentQuery(query(null, ['foo'], true)); },
contentQueries:
(dirIndex) => { registerContentQuery(query(null, ['foo'], true), dirIndex); },
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
withContentInstance = load<WithContentDirective>(dirIndex);
@ -1932,7 +1933,8 @@ describe('query', () => {
template: function(rf: RenderFlags, ctx: any) {},
consts: 0,
vars: 0,
contentQueries: () => { registerContentQuery(query(null, ['foo'], false)); },
contentQueries:
(dirIndex) => { registerContentQuery(query(null, ['foo'], false), dirIndex); },
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
shallowCompInstance = load<ShallowComp>(dirIndex);
@ -1971,6 +1973,51 @@ describe('query', () => {
`Expected content query results to be available when ngAfterContentChecked was called.`);
});
it('should support content queries for directives within repeated embedded views', () => {
/**
* % for (let i = 0; i < 3; i++) {
* <div with-content>
* <span #foo></span>
* </div>
* % }
*/
const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
container(0);
}
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
{
for (let i = 0; i < 3; i++) {
let rf = embeddedViewStart(1, 3, 0);
if (rf & RenderFlags.Create) {
elementStart(0, 'div', [AttributeMarker.SelectOnly, 'with-content']);
{ element(1, 'span', null, ['foo', '']); }
elementEnd();
}
embeddedViewEnd();
}
}
containerRefreshEnd();
}
}, 1, 0, [WithContentDirective]);
const fixture = new ComponentFixture(AppComponent);
expect(withContentInstance !.foos.length)
.toBe(1, `Expected content query to match <span #foo>.`);
expect(withContentInstance !.contentInitQuerySnapshot)
.toBe(
1,
`Expected content query results to be available when ngAfterContentInit was called.`);
expect(withContentInstance !.contentCheckedQuerySnapshot)
.toBe(
1,
`Expected content query results to be available when ngAfterContentChecked was called.`);
});
it('should support content query matches on directive hosts', () => {
/**
* <div with-content #foo>
@ -2109,10 +2156,10 @@ describe('query', () => {
selectors: [['', 'query', '']],
exportAs: 'query',
factory: () => new QueryDirective(),
contentQueries: () => {
contentQueries: (dirIndex) => {
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
// QueryList<ElementRef>;
registerContentQuery(query(null, ['foo', 'bar', 'baz'], true));
registerContentQuery(query(null, ['foo', 'bar', 'baz'], true), dirIndex);
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2173,10 +2220,10 @@ describe('query', () => {
selectors: [['', 'query', '']],
exportAs: 'query',
factory: () => new QueryDirective(),
contentQueries: () => {
contentQueries: (dirIndex) => {
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
// QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], false));
registerContentQuery(query(null, ['foo'], false), dirIndex);
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2227,9 +2274,9 @@ describe('query', () => {
selectors: [['', 'shallow-query', '']],
exportAs: 'shallow-query',
factory: () => new ShallowQueryDirective(),
contentQueries: () => {
contentQueries: (dirIndex) => {
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], false));
registerContentQuery(query(null, ['foo'], false), dirIndex);
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2247,9 +2294,9 @@ describe('query', () => {
selectors: [['', 'deep-query', '']],
exportAs: 'deep-query',
factory: () => new DeepQueryDirective(),
contentQueries: () => {
contentQueries: (dirIndex) => {
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], true));
registerContentQuery(query(null, ['foo'], true), dirIndex);
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;

View File

@ -23,12 +23,13 @@ import {CreateComponentOptions} from '../../src/render3/component';
import {discoverDirectives, getContext, isComponentInstance} from '../../src/render3/context_discovery';
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';
import {NG_ELEMENT_ID} from '../../src/render3/fields';
import {ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, PublicFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {_getViewData, renderTemplate} from '../../src/render3/instructions';
import {ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {renderTemplate} from '../../src/render3/instructions';
import {DirectiveDefList, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
import {PlayerHandler} from '../../src/render3/interfaces/player';
import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer';
import {HEADER_OFFSET, LViewData} from '../../src/render3/interfaces/view';
import {getViewData} from '../../src/render3/state';
import {Sanitizer} from '../../src/sanitization/security';
import {Type} from '../../src/type';
@ -275,7 +276,6 @@ export function createComponent(
factory: () => new Component,
template: template,
viewQuery: viewQuery,
features: [PublicFeature],
directives: directives,
pipes: pipes
});
@ -289,7 +289,6 @@ export function createDirective(
type: Directive,
selectors: [['', name, '']],
factory: () => new Directive(),
features: [PublicFeature],
exportAs: exportAs,
});
};
@ -297,7 +296,7 @@ export function createDirective(
/** Gets the directive on the given node at the given index */
export function getDirectiveOnNode(nodeIndex: number, dirIndex: number = 0) {
const directives = discoverDirectives(nodeIndex + HEADER_OFFSET, _getViewData(), true);
const directives = discoverDirectives(nodeIndex + HEADER_OFFSET, getViewData(), true);
if (directives == null) {
throw new Error(`No directives exist on node in slot ${nodeIndex}`);
}

View File

@ -8,10 +8,9 @@
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
import {ViewEncapsulation} from '../../src/metadata';
import {directiveInject} from '../../src/render3/di';
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
import {NgModuleFactory} from '../../src/render3/ng_module_ref';

View File

@ -717,7 +717,7 @@ export interface ResolvedReflectiveProvider {
resolvedFactories: ResolvedReflectiveFactory[];
}
export declare function resolveForwardRef(type: any): any;
export declare function resolveForwardRef<T>(type: T): T;
/** @deprecated */
export declare abstract class RootRenderer {