fix(ivy): don't accidently read the inherited definition (#25736)

Create getter methods `getXXXDef` for each definition which
uses `hasOwnProperty` to verify that we don't accidently read form the
parent class.

Fixes: #24011
Fixes: #25026

PR Close #25736
This commit is contained in:
Miško Hevery 2018-08-29 16:34:44 -07:00 committed by Igor Minar
parent a9099e8f70
commit d5bd86ae5d
29 changed files with 245 additions and 103 deletions

View File

@ -143,6 +143,23 @@ describe('ngInjectableDef Bazel Integration', () => {
expect(TestBed.get(Service).value).toEqual(true);
});
it('does not override existing ngInjectableDef in case of inheritance', () => {
@Injectable({
providedIn: 'root',
useValue: new ParentService(false),
})
class ParentService {
constructor(public value: boolean) {}
}
// ChildServices exteds ParentService but does not have @Injectable
class ChildService extends ParentService {}
TestBed.configureTestingModule({});
// We are asserting that system throws an error, rather than taking the inherited annotation.
expect(() => TestBed.get(ChildService).value).toThrowError(/ChildService/);
});
it('NgModule injector understands requests for INJECTABLE', () => {
TestBed.configureTestingModule({
providers: [{provide: 'foo', useValue: 'bar'}],

View File

@ -13,7 +13,7 @@ export {devModeEqual as ɵdevModeEqual} from './change_detection/change_detectio
export {isListLikeIterable as ɵisListLikeIterable} from './change_detection/change_detection_util';
export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants';
export {Console as ɵConsole} from './console';
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef} from './di/defs';
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NG_INJECTABLE_DEF, NG_INJECTOR_DEF} from '../render3/fields';
import {Type} from '../type';
import {ClassProvider, ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, StaticClassProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
@ -160,3 +161,21 @@ export function defineInjector(options: {factory: () => any, providers?: any[],
factory: options.factory, providers: options.providers || [], imports: options.imports || [],
} as InjectorDef<any>) as never;
}
/**
* Read the `ngInjectableDef` type in a way which is immune to accidentally reading inherited value.
*
* @param type type which may have `ngInjectableDef`
*/
export function getInjectableDef<T>(type: any): InjectableDef<T>|null {
return type.hasOwnProperty(NG_INJECTABLE_DEF) ? (type as any)[NG_INJECTABLE_DEF] : null;
}
/**
* Read the `ngInjectorDef` type in a way which is immune to accidentally reading inherited value.
*
* @param type type which may have `ngInjectorDef`
*/
export function getInjectorDef<T>(type: any): InjectorDef<T>|null {
return type.hasOwnProperty(NG_INJECTOR_DEF) ? (type as any)[NG_INJECTOR_DEF] : null;
}

View File

@ -8,8 +8,9 @@
import {Type} from '../type';
import {stringify} from '../util';
import {getClosureSafeProperty} from '../util/property';
import {InjectableDef, defineInjectable} from './defs';
import {InjectableDef, defineInjectable, getInjectableDef} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {Inject, Optional, Self, SkipSelf} from './metadata';
@ -115,9 +116,8 @@ const CIRCULAR = IDENT;
const MULTI_PROVIDER_FN = function(): any[] {
return Array.prototype.slice.call(arguments);
};
const GET_PROPERTY_NAME = {} as any;
export const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: GET_PROPERTY_NAME});
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
const NG_TOKEN_PATH = 'ngTokenPath';
const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath';
const enum OptionFlags {
@ -397,15 +397,6 @@ function staticError(text: string, obj: any): Error {
return new Error(formatError(text, obj));
}
function getClosureSafeProperty<T>(objWithPropertyToExtract: T): string {
for (let key in objWithPropertyToExtract) {
if (objWithPropertyToExtract[key] === GET_PROPERTY_NAME) {
return key;
}
}
throw Error('!prop');
}
/**
* Injection flags for DI.
*/
@ -462,7 +453,7 @@ export function inject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context`);
} else if (_currentInjector === null) {
const injectableDef: InjectableDef<T> = (token as any).ngInjectableDef;
const injectableDef: InjectableDef<T>|null = getInjectableDef(token);
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;

View File

@ -10,9 +10,9 @@ import {OnDestroy} from '../metadata/lifecycle_hooks';
import {Type} from '../type';
import {stringify} from '../util';
import {InjectableDef, InjectableType, InjectorDef, InjectorType, InjectorTypeWithProviders} from './defs';
import {InjectableDef, InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectableDefToken, InjectionToken} from './injection_token';
import {InjectionToken} from './injection_token';
import {INJECTOR, InjectFlags, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, inject, injectArgs, setCurrentInjector} from './injector';
import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, Provider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './provider';
import {APP_ROOT} from './scope';
@ -161,10 +161,8 @@ export class R3Injector {
if (record === undefined) {
// No record, but maybe the token is scoped to this injector. Look for an ngInjectableDef
// with a scope matching this injector.
const def = couldBeInjectableType(token) &&
(token as InjectableType<any>| InjectableDefToken<any>).ngInjectableDef ||
undefined;
if (def !== undefined && this.injectableDefInScope(def)) {
const def = couldBeInjectableType(token) && getInjectableDef(token);
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);
@ -207,7 +205,7 @@ export class R3Injector {
// read, so care is taken to only do the read once.
// First attempt to read the ngInjectorDef.
let def = (defOrWrappedDef as InjectorType<any>).ngInjectorDef as(InjectorDef<any>| undefined);
let def = getInjectorDef(defOrWrappedDef);
// If that's not present, then attempt to read ngModule from the InjectorDefTypeWithProviders.
const ngModule =
@ -228,7 +226,7 @@ export class R3Injector {
// Finally, if defOrWrappedType was an `InjectorDefTypeWithProviders`, then the actual
// `InjectorDef` is on its `ngModule`.
if (ngModule !== undefined) {
def = ngModule.ngInjectorDef;
def = getInjectorDef(ngModule);
}
// If no definition was found, it might be from exports. Remove it.
@ -331,8 +329,8 @@ export class R3Injector {
}
function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any> {
const def = (token as InjectableType<any>).ngInjectableDef as InjectableDef<any>;
if (def === undefined) {
const injectableDef = getInjectableDef(token as InjectableType<any>);
if (injectableDef === null) {
if (token instanceof InjectionToken) {
throw new Error(`Token ${stringify(token)} is missing an ngInjectableDef definition.`);
}
@ -340,7 +338,7 @@ function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any>
// no-args constructor.
return makeRecord(() => new (token as Type<any>)());
}
return makeRecord(def.factory);
return makeRecord(injectableDef.factory);
}
function providerToRecord(provider: SingleProvider): Record<any> {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {InjectableType, InjectorType, defineInjectable, defineInjector} from './di/defs';
import {InjectableType, InjectorType, defineInjectable, defineInjector, getInjectableDef} from './di/defs';
import {InjectableProvider} from './di/injectable';
import {inject, injectArgs} from './di/injector';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './di/provider';
@ -59,9 +59,8 @@ function preR3NgModuleCompile(moduleType: InjectorType<any>, metadata: NgModule)
});
}
const GET_PROPERTY_NAME = {} as any;
const USE_VALUE = getClosureSafeProperty<ValueProvider>(
{provide: String, useValue: GET_PROPERTY_NAME}, GET_PROPERTY_NAME);
const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
const EMPTY_ARRAY: any[] = [];
function convertInjectableProviderToFactory(type: Type<any>, provider?: InjectableProvider): () =>
@ -106,7 +105,7 @@ function convertInjectableProviderToFactory(type: Type<any>, provider?: Injectab
function preR3InjectableCompile(
injectableType: InjectableType<any>,
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
if (options && options.providedIn !== undefined && injectableType.ngInjectableDef === undefined) {
if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
injectableType.ngInjectableDef = defineInjectable({
providedIn: options.providedIn,
factory: convertInjectableProviderToFactory(injectableType, options),

View File

@ -9,12 +9,15 @@
import {ChangeDetectionStrategy} from '../change_detection/constants';
import {Provider} from '../di';
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE, R3_COMPILE_PIPE} from '../ivy_switch';
import {NG_BASE_DEF} from '../render3/fields';
import {Type} from '../type';
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
import {fillProperties} from '../util/property';
import {ViewEncapsulation} from './view';
/**
* Type of the Directive decorator / constructor function.
*/
@ -778,11 +781,6 @@ const initializeBaseDef = (target: any): void => {
}
};
/**
* Used to get the minified alias of ngBaseDef
*/
const NG_BASE_DEF = Object.keys({ngBaseDef: true})[0];
/**
* Does the work of creating the `ngBaseDef` property for the @Input and @Output decorators.
* @param key "inputs" or "outputs"

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {getComponentDef, getNgModuleDef} from './definition';
// The functions in this file verify that the assumptions we are making
// about state in an instruction are correct before implementing any logic.
// They are meant only to be called in dev mode as sanity checks.
@ -62,7 +64,7 @@ export function assertComponentType(
actual: any,
msg: string =
'Type passed in is not ComponentType, it does not have \'ngComponentDef\' property.') {
if (!actual.ngComponentDef) {
if (!getComponentDef(actual)) {
throwError(msg);
}
}
@ -71,7 +73,7 @@ export function assertNgModuleType(
actual: any,
msg: string =
'Type passed in is not NgModuleType, it does not have \'ngModuleDef\' property.') {
if (!actual.ngModuleDef) {
if (!getNgModuleDef(actual)) {
throwError(msg);
}
}

View File

@ -20,6 +20,7 @@ import {LElementNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {LViewData, LViewFlags, RootContext, BINDING_INDEX, INJECTOR, CONTEXT, TVIEW} from './interfaces/view';
import {stringify} from './util';
import {getComponentDef} from './definition';
/** Options that control how the component should be bootstrapped. */
@ -96,8 +97,7 @@ export function renderComponent<T>(
ngDevMode && assertComponentType(componentType);
const rendererFactory = opts.rendererFactory || domRendererFactory3;
const sanitizer = opts.sanitizer || null;
const componentDef =
(componentType as ComponentType<T>).ngComponentDef as ComponentDefInternal<T>;
const componentDef = getComponentDef<T>(componentType) !;
if (componentDef.type != componentType) componentDef.type = componentType;
// The first index of the first selector is the tag name.

View File

@ -18,6 +18,7 @@ import {Type} from '../type';
import {assertComponentType, assertDefined} from './assert';
import {LifecycleHooksFeature, createRootContext} from './component';
import {getComponentDef} from './definition';
import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, queueHostBindingForCheck, renderEmbeddedTemplate, setHostBindings} from './instructions';
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
import {LElementNode, TNode, TNodeType} from './interfaces/node';
@ -28,7 +29,7 @@ import {RootViewRef, ViewRef} from './view_ref';
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
resolveComponentFactory<T>(component: Type<T>): viewEngine_ComponentFactory<T> {
ngDevMode && assertComponentType(component);
const componentDef = (component as ComponentType<T>).ngComponentDef;
const componentDef = getComponentDef(component) !;
return new ComponentFactory(componentDef);
}
}

View File

@ -14,6 +14,7 @@ import {NgModuleDef, NgModuleDefInternal} from '../metadata/ng_module';
import {ViewEncapsulation} from '../metadata/view';
import {Type} from '../type';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
import {BaseDef, ComponentDefFeature, ComponentDefInternal, ComponentQuery, ComponentTemplate, ComponentType, DirectiveDefFeature, DirectiveDefInternal, DirectiveType, DirectiveTypesOrFactory, PipeDefInternal, PipeType, PipeTypesOrFactory} from './interfaces/definition';
import {CssSelectorList, SelectorFlags} from './interfaces/projection';
@ -328,19 +329,19 @@ export function defineComponent<T>(componentDefinition: {
export function extractDirectiveDef(type: DirectiveType<any>& ComponentType<any>):
DirectiveDefInternal<any>|ComponentDefInternal<any> {
const def = type.ngComponentDef || type.ngDirectiveDef;
const def = getComponentDef(type) || getDirectiveDef(type);
if (ngDevMode && !def) {
throw new Error(`'${type.name}' is neither 'ComponentType' or 'DirectiveType'.`);
}
return def;
return def !;
}
export function extractPipeDef(type: PipeType<any>): PipeDefInternal<any> {
const def = type.ngPipeDef;
const def = getPipeDef(type);
if (ngDevMode && !def) {
throw new Error(`'${type.name}' is not a 'PipeType'.`);
}
return def;
return def !;
}
export function defineNgModule<T>(def: {type: T} & Partial<NgModuleDef<T, any, any, any>>): never {
@ -662,3 +663,25 @@ export function definePipe<T>(pipeDef: {
onDestroy: pipeDef.type.prototype.ngOnDestroy || null
}) as never;
}
/**
* The following getter methods retrieve the definition form the type. Currently the retrieval
* honors inheritance, but in the future we may change the rule to require that definitions are
* explicit. This would require some sort of migration strategy.
*/
export function getComponentDef<T>(type: any): ComponentDefInternal<T>|null {
return (type as any)[NG_COMPONENT_DEF] || null;
}
export function getDirectiveDef<T>(type: any): DirectiveDefInternal<T>|null {
return (type as any)[NG_DIRECTIVE_DEF] || null;
}
export function getPipeDef<T>(type: any): PipeDefInternal<T>|null {
return (type as any)[NG_PIPE_DEF] || null;
}
export function getNgModuleDef<T>(type: any): NgModuleDefInternal<T>|null {
return (type as any)[NG_MODULE_DEF] || null;
}

View File

@ -10,6 +10,7 @@
// correctly implementing its interfaces for backwards compatibility.
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {getInjectableDef, getInjectorDef} from '../di/defs';
import {InjectionToken} from '../di/injection_token';
import {InjectFlags, Injector, NullInjector, inject, setCurrentInjector} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
@ -24,6 +25,7 @@ import {Type} from '../type';
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
import {ComponentFactoryResolver} from './component_ref';
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
import {addToViewTree, assertPreviousIsParent, createEmbeddedViewNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getPreviousOrParentTNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
import {VIEWS} from './interfaces/container';
import {DirectiveDefInternal, RenderFlags} from './interfaces/definition';
@ -797,9 +799,9 @@ export function getOrCreateTemplateRef<T>(di: LInjector): viewEngine_TemplateRef
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
const typeAny = type as any;
const def = typeAny.ngComponentDef || typeAny.ngDirectiveDef || typeAny.ngPipeDef ||
typeAny.ngInjectableDef || typeAny.ngInjectorDef;
if (def === undefined || def.factory === undefined) {
const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) ||
getPipeDef<T>(typeAny) || getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);
if (!def || def.factory === undefined) {
return null;
}
return def.factory;

View File

@ -39,11 +39,13 @@ export function InheritDefinitionFeature(
while (superType) {
let superDef: DirectiveDefInternal<any>|ComponentDefInternal<any>|undefined = undefined;
if (isComponentDef(definition)) {
// Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
superDef = superType.ngComponentDef || superType.ngDirectiveDef;
} else {
if (superType.ngComponentDef) {
throw new Error('Directives cannot inherit Components');
}
// Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance.
superDef = superType.ngDirectiveDef;
}

View File

@ -6,13 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {getClosureSafeProperty} from '../../util/property';
import {getClosureSafeProperty} from '../util/property';
const TARGET = {} as any;
export const NG_COMPONENT_DEF = getClosureSafeProperty({ngComponentDef: TARGET}, TARGET);
export const NG_DIRECTIVE_DEF = getClosureSafeProperty({ngDirectiveDef: TARGET}, TARGET);
export const NG_INJECTABLE_DEF = getClosureSafeProperty({ngInjectableDef: TARGET}, TARGET);
export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: TARGET}, TARGET);
export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: TARGET}, TARGET);
export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: TARGET}, TARGET);
export const NG_COMPONENT_DEF = getClosureSafeProperty({ngComponentDef: getClosureSafeProperty});
export const NG_DIRECTIVE_DEF = getClosureSafeProperty({ngDirectiveDef: getClosureSafeProperty});
export const NG_INJECTABLE_DEF = getClosureSafeProperty({ngInjectableDef: getClosureSafeProperty});
export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: getClosureSafeProperty});
export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: getClosureSafeProperty});
export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: getClosureSafeProperty});
export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProperty});

View File

@ -13,9 +13,9 @@ import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from
import {ViewEncapsulation} from '../../metadata/view';
import {Type} from '../../type';
import {stringify} from '../../util';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields';
import {angularCoreEnv} from './environment';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from './fields';
import {patchComponentDefWithScope, transitiveScopesFor} from './module';
import {getReflect, reflectDependencies} from './util';

View File

@ -12,9 +12,9 @@ import {Injectable} from '../../di/injectable';
import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
import {Type} from '../../type';
import {getClosureSafeProperty} from '../../util/property';
import {NG_INJECTABLE_DEF} from '../fields';
import {angularCoreEnv} from './environment';
import {NG_INJECTABLE_DEF} from './fields';
import {convertDependencies, reflectDependencies} from './util';
@ -106,9 +106,8 @@ function isUseClassProvider(meta: Injectable): meta is UseClassProvider {
return (meta as UseClassProvider).useClass !== undefined;
}
const GET_PROPERTY_NAME = {} as any;
const USE_VALUE = getClosureSafeProperty<ValueProvider>(
{provide: String, useValue: GET_PROPERTY_NAME}, GET_PROPERTY_NAME);
const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
function isUseValueProvider(meta: Injectable): meta is Injectable&ValueSansProvider {
return USE_VALUE in meta;

View File

@ -10,10 +10,11 @@ import {Expression, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, Wrapped
import {ModuleWithProviders, NgModule, NgModuleDefInternal, NgModuleTransitiveScopes} from '../../metadata/ng_module';
import {Type} from '../../type';
import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields';
import {ComponentDefInternal} from '../interfaces/definition';
import {angularCoreEnv} from './environment';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
import {reflectDependencies} from './util';
const EMPTY_ARRAY: Type<any>[] = [];
@ -100,7 +101,7 @@ function setScopeOnDeclaredComponents(moduleType: Type<any>, ngModule: NgModule)
if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) {
// An `ngComponentDef` field exists - go ahead and patch the component directly.
const component = declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>};
const componentDef = component.ngComponentDef;
const componentDef = getComponentDef(component) !;
patchComponentDefWithScope(componentDef, transitiveScopes);
} else if (
!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
@ -117,10 +118,10 @@ function setScopeOnDeclaredComponents(moduleType: Type<any>, ngModule: NgModule)
export function patchComponentDefWithScope<C>(
componentDef: ComponentDefInternal<C>, transitiveScopes: NgModuleTransitiveScopes) {
componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives)
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
.map(dir => getDirectiveDef(dir) || getComponentDef(dir) !)
.filter(def => !!def);
componentDef.pipeDefs = () =>
Array.from(transitiveScopes.compilation.pipes).map(pipe => pipe.ngPipeDef);
Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef(pipe) !);
}
/**
@ -134,7 +135,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
if (!isNgModule(moduleType)) {
throw new Error(`${moduleType.name} does not have an ngModuleDef`);
}
const def = moduleType.ngModuleDef;
const def = getNgModuleDef(moduleType) !;
if (def.transitiveCompileScopes !== null) {
return def.transitiveCompileScopes;
@ -154,7 +155,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
def.declarations.forEach(declared => {
const declaredWithDefs = declared as Type<any>& { ngPipeDef?: any; };
if (declaredWithDefs.ngPipeDef !== undefined) {
if (getPipeDef(declaredWithDefs)) {
scopes.compilation.pipes.add(declared);
} else {
// Either declared has an ngComponentDef or ngDirectiveDef, or it's a component which hasn't
@ -204,7 +205,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
scopes.compilation.pipes.add(entry);
scopes.exported.pipes.add(entry);
});
} else if (exportedTyped.ngPipeDef !== undefined) {
} else if (getNgModuleDef(exportedTyped)) {
scopes.exported.pipes.add(exportedTyped);
} else {
scopes.exported.directives.add(exportedTyped);
@ -248,5 +249,5 @@ function isModuleWithProviders(value: any): value is ModuleWithProviders {
}
function isNgModule<T>(value: Type<T>): value is Type<T>&{ngModuleDef: NgModuleDefInternal<T>} {
return (value as{ngModuleDef?: NgModuleDefInternal<T>}).ngModuleDef !== undefined;
return !!getNgModuleDef(value);
}

View File

@ -10,10 +10,10 @@ import {WrappedNodeExpr, compilePipeFromMetadata, jitExpression} from '@angular/
import {Pipe} from '../../metadata/directives';
import {Type} from '../../type';
import {NG_PIPE_DEF} from '../fields';
import {stringify} from '../util';
import {angularCoreEnv} from './environment';
import {NG_PIPE_DEF} from './fields';
import {reflectDependencies} from './util';
export function compilePipe(type: Type<any>, meta: Pipe): void {

View File

@ -16,6 +16,7 @@ import {Type} from '../type';
import {stringify} from '../util';
import {assertDefined} from './assert';
import {ComponentFactoryResolver} from './component_ref';
import {getNgModuleDef} from './definition';
export interface NgModuleType { ngModuleDef: NgModuleDefInternal<any>; }
@ -35,12 +36,12 @@ export class NgModuleRef<T> extends viewEngine_NgModuleRef<T> implements Interna
constructor(ngModuleType: Type<T>, parentInjector: Injector|null) {
super();
const ngModuleDef = (ngModuleType as any as NgModuleType).ngModuleDef;
const ngModuleDef = getNgModuleDef(ngModuleType);
ngDevMode && assertDefined(
ngModuleDef,
`NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`);
this._bootstrapComponents = ngModuleDef.bootstrap;
this._bootstrapComponents = ngModuleDef !.bootstrap;
const additionalProviders: StaticProvider[] = [
COMPONENT_FACTORY_RESOLVER, {
provide: viewEngine_NgModuleRef,

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
export function getClosureSafeProperty<T>(objWithPropertyToExtract: T, target: any): string {
export function getClosureSafeProperty<T>(objWithPropertyToExtract: T): string {
for (let key in objWithPropertyToExtract) {
if (objWithPropertyToExtract[key] === target) {
if (objWithPropertyToExtract[key] === getClosureSafeProperty as any) {
return key;
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {InjectableDef} from '../di/defs';
import {InjectableDef, getInjectableDef} from '../di/defs';
import {resolveForwardRef} from '../di/forward_ref';
import {INJECTOR, InjectFlags, Injector, setCurrentInjector} from '../di/injector';
import {APP_ROOT} from '../di/scope';
@ -97,6 +97,7 @@ export function resolveNgModuleDep(
return data;
}
const providerDef = data._def.providersByKey[tokenKey];
let injectableDef: InjectableDef<any>|null;
if (providerDef) {
let providerInstance = data._providers[providerDef.index];
if (providerInstance === undefined) {
@ -104,9 +105,8 @@ export function resolveNgModuleDep(
_createProviderInstance(data, providerDef);
}
return providerInstance === UNDEFINED_VALUE ? undefined : providerInstance;
} else if (depDef.token.ngInjectableDef && targetsModule(data, depDef.token.ngInjectableDef)) {
const injectableDef = depDef.token.ngInjectableDef as InjectableDef<any>;
const key = tokenKey;
} else if (
(injectableDef = getInjectableDef(depDef.token)) && targetsModule(data, injectableDef)) {
const index = data._providers.length;
data._def.providersByKey[depDef.tokenKey] = {
flags: NodeFlags.TypeFactoryProvider | NodeFlags.LazyProvider,

View File

@ -8,6 +8,7 @@
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {Injector} from '../di';
import {InjectableDef, getInjectableDef} from '../di/defs';
import {InjectableType} from '../di/injectable';
import {ErrorHandler} from '../error_handler';
import {isDevMode} from '../is_dev_mode';
@ -169,8 +170,9 @@ const viewDefOverrides = new Map<any, ViewDefinition>();
function debugOverrideProvider(override: ProviderOverride) {
providerOverrides.set(override.token, override);
if (typeof override.token === 'function' && override.token.ngInjectableDef &&
typeof override.token.ngInjectableDef.providedIn === 'function') {
let injectableDef: InjectableDef<any>|null;
if (typeof override.token === 'function' && (injectableDef = getInjectableDef(override.token)) &&
typeof injectableDef.providedIn === 'function') {
providerOverridesWithScope.set(override.token as InjectableType<any>, override);
}
}
@ -276,7 +278,7 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi
});
def.modules.forEach(module => {
providerOverridesWithScope.forEach((override, token) => {
if (token.ngInjectableDef.providedIn === module) {
if (getInjectableDef(token) !.providedIn === module) {
hasOverrides = true;
hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior;
}
@ -304,7 +306,7 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi
if (providerOverridesWithScope.size > 0) {
let moduleSet = new Set<any>(def.modules);
providerOverridesWithScope.forEach((override, token) => {
if (moduleSet.has(token.ngInjectableDef.providedIn)) {
if (moduleSet.has(getInjectableDef(token) !.providedIn)) {
let provider = {
token: token,
flags:

View File

@ -50,9 +50,18 @@
{
"name": "NEXT"
},
{
"name": "NG_COMPONENT_DEF"
},
{
"name": "NG_DIRECTIVE_DEF"
},
{
"name": "NG_ELEMENT_ID"
},
{
"name": "NG_PIPE_DEF"
},
{
"name": "NG_PROJECT_AS_ATTR_NAME"
},
@ -200,6 +209,15 @@
{
"name": "getChildLNode"
},
{
"name": "getClosureSafeProperty"
},
{
"name": "getComponentDef"
},
{
"name": "getDirectiveDef"
},
{
"name": "getLElementFromComponent"
},
@ -221,6 +239,9 @@
{
"name": "getParentLNode"
},
{
"name": "getPipeDef"
},
{
"name": "getPreviousOrParentNode"
},

View File

@ -710,12 +710,6 @@
{
"name": "FunctionExpr"
},
{
"name": "GET_PROPERTY_NAME"
},
{
"name": "GET_PROPERTY_NAME$2"
},
{
"name": "GOOG_GET_MSG"
},
@ -1001,6 +995,9 @@
{
"name": "NG_CONTENT_SELECT_ATTR"
},
{
"name": "NG_INJECTABLE_DEF"
},
{
"name": "NG_NON_BINDABLE_ATTR"
},
@ -2939,9 +2936,6 @@
{
"name": "getClosureSafeProperty"
},
{
"name": "getClosureSafeProperty$1"
},
{
"name": "getComponentViewDefinitionFactory"
},
@ -2969,6 +2963,9 @@
{
"name": "getHtmlTagDefinition"
},
{
"name": "getInjectableDef"
},
{
"name": "getNgZone"
},

View File

@ -8,9 +8,6 @@
{
"name": "EMPTY_ARRAY$2"
},
{
"name": "GET_PROPERTY_NAME"
},
{
"name": "INJECTOR"
},
@ -20,6 +17,12 @@
{
"name": "InjectionToken"
},
{
"name": "NG_INJECTABLE_DEF"
},
{
"name": "NG_INJECTOR_DEF"
},
{
"name": "NOT_YET"
},
@ -86,6 +89,12 @@
{
"name": "getClosureSafeProperty"
},
{
"name": "getInjectableDef"
},
{
"name": "getInjectorDef"
},
{
"name": "getNullInjector"
},

View File

@ -80,9 +80,21 @@
{
"name": "NEXT"
},
{
"name": "NG_COMPONENT_DEF"
},
{
"name": "NG_DIRECTIVE_DEF"
},
{
"name": "NG_ELEMENT_ID"
},
{
"name": "NG_INJECTABLE_DEF"
},
{
"name": "NG_PIPE_DEF"
},
{
"name": "NG_PROJECT_AS_ATTR_NAME"
},
@ -557,18 +569,30 @@
{
"name": "getClosestComponentAncestor"
},
{
"name": "getClosureSafeProperty"
},
{
"name": "getComponentDef"
},
{
"name": "getCurrentSanitizer"
},
{
"name": "getCurrentView"
},
{
"name": "getDirectiveDef"
},
{
"name": "getInitialIndex"
},
{
"name": "getInitialValue"
},
{
"name": "getInjectableDef"
},
{
"name": "getLElementFromComponent"
},
@ -620,6 +644,9 @@
{
"name": "getParentState"
},
{
"name": "getPipeDef"
},
{
"name": "getPointers"
},

View File

@ -311,9 +311,6 @@
{
"name": "FormatWidth"
},
{
"name": "GET_PROPERTY_NAME"
},
{
"name": "GROUP_SEP"
},
@ -461,9 +458,27 @@
{
"name": "NEXT"
},
{
"name": "NG_COMPONENT_DEF"
},
{
"name": "NG_DIRECTIVE_DEF"
},
{
"name": "NG_ELEMENT_ID"
},
{
"name": "NG_INJECTABLE_DEF"
},
{
"name": "NG_INJECTOR_DEF"
},
{
"name": "NG_MODULE_DEF"
},
{
"name": "NG_PIPE_DEF"
},
{
"name": "NG_PROJECT_AS_ATTR_NAME"
},
@ -1553,6 +1568,9 @@
{
"name": "getClosureSafeProperty"
},
{
"name": "getComponentDef"
},
{
"name": "getCurrencySymbol"
},
@ -1580,6 +1598,9 @@
{
"name": "getDebugNode"
},
{
"name": "getDirectiveDef"
},
{
"name": "getErrorLogger"
},
@ -1592,6 +1613,12 @@
{
"name": "getInitialValue"
},
{
"name": "getInjectableDef"
},
{
"name": "getInjectorDef"
},
{
"name": "getLElementFromComponent"
},
@ -1655,6 +1682,9 @@
{
"name": "getNamedFormat"
},
{
"name": "getNgModuleDef"
},
{
"name": "getNgZone"
},
@ -1703,6 +1733,9 @@
{
"name": "getParentState"
},
{
"name": "getPipeDef"
},
{
"name": "getPlatform"
},

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, Injector, NgModule, Pipe, PlatformRef, Provider, RendererFactory2, SchemaMetadata, Type, ɵNgModuleDefInternal as NgModuleDefInternal, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵRender3ComponentFactory as ComponentFactory, ɵRender3DebugRendererFactory2 as Render3DebugRendererFactory2, ɵRender3NgModuleRef as NgModuleRef, ɵWRAP_RENDERER_FACTORY2 as WRAP_RENDERER_FACTORY2, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵstringify as stringify} from '@angular/core';
import {Component, Directive, Injector, NgModule, Pipe, PlatformRef, Provider, RendererFactory2, SchemaMetadata, Type, ɵInjectableDef as InjectableDef, ɵNgModuleDefInternal as NgModuleDefInternal, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵRender3ComponentFactory as ComponentFactory, ɵRender3DebugRendererFactory2 as Render3DebugRendererFactory2, ɵRender3NgModuleRef as NgModuleRef, ɵWRAP_RENDERER_FACTORY2 as WRAP_RENDERER_FACTORY2, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵstringify as stringify} from '@angular/core';
import {ComponentFixture} from './component_fixture';
import {MetadataOverride} from './metadata_override';
@ -314,9 +314,10 @@ export class TestBedRender3 implements Injector, TestBed {
*/
overrideProvider(token: any, provider: {useFactory?: Function, useValue?: any, deps?: any[]}):
void {
let injectableDef: InjectableDef<any>|null;
const isRoot =
(typeof token !== 'string' && token.ngInjectableDef &&
token.ngInjectableDef.providedIn === 'root');
(typeof token !== 'string' && (injectableDef = getInjectableDef(token)) &&
injectableDef.providedIn === 'root');
const overrides = isRoot ? this._rootProviderOverrides : this._providerOverrides;
if (provider.useFactory) {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ApplicationInitStatus, CompilerOptions, Component, Directive, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵAPP_ROOT as APP_ROOT, ɵDepFlags as DepFlags, ɵNodeFlags as NodeFlags, ɵclearOverrides as clearOverrides, ɵgetComponentViewDefinitionFactory as getComponentViewDefinitionFactory, ɵivyEnabled as ivyEnabled, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify} from '@angular/core';
import {ApplicationInitStatus, CompilerOptions, Component, Directive, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵAPP_ROOT as APP_ROOT, ɵDepFlags as DepFlags, ɵInjectableDef as InjectableDef, ɵNodeFlags as NodeFlags, ɵclearOverrides as clearOverrides, ɵgetComponentViewDefinitionFactory as getComponentViewDefinitionFactory, ɵgetInjectableDef as getInjectableDef, ɵivyEnabled as ivyEnabled, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify} from '@angular/core';
import {AsyncTestCompleter} from './async_test_completer';
import {ComponentFixture} from './component_fixture';
@ -549,8 +549,8 @@ export class TestBedViewEngine implements Injector, TestBed {
deps?: any[],
},
deprecated = false): void {
if (typeof token !== 'string' && token.ngInjectableDef &&
token.ngInjectableDef.providedIn === 'root') {
let def: InjectableDef<any>|null = null;
if (typeof token !== 'string' && (def = getInjectableDef(token)) && def.providedIn === 'root') {
if (provider.useFactory) {
this._rootProviderOverrides.push(
{provide: token, useFactory: provider.useFactory, deps: provider.deps || []});