From a4b4f35533fd1c64841bf2e744b6a2a7b9c47d00 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Fri, 7 Jun 2019 10:12:07 -0700 Subject: [PATCH] feat(ivy): require 'token' for ngInjectableDef (#30855) The compiler generates a 'token' field when it emits an ngInjectableDef, but this field was not required by defineInjectable or the InjectableDef interface, nor was it added by InjectionToken. This commit makes 'token' required and adds it where missing. PR Close #30855 --- packages/common/src/viewport_scroller.ts | 1 + .../differs/iterable_differs.ts | 1 + .../differs/keyvalue_differs.ts | 1 + packages/core/src/di/injectable.ts | 1 + packages/core/src/di/injection_token.ts | 1 + packages/core/src/di/injector.ts | 1 + packages/core/src/di/interface/defs.ts | 11 +++++- packages/core/src/render3/definition.ts | 2 +- .../core/test/bundling/injection/usage.ts | 2 ++ packages/core/test/di/r3_injector_spec.ts | 13 +++++++ .../test/linker/ng_module_integration_spec.ts | 2 ++ packages/core/test/render3/component_spec.ts | 7 ++-- packages/core/test/render3/ivy/jit_spec.ts | 1 + packages/core/test/render3/providers_spec.ts | 36 +++++++++++++------ packages/core/test/view/ng_module_spec.ts | 9 +++++ tools/public_api_guard/core/core.d.ts | 2 ++ 16 files changed, 77 insertions(+), 14 deletions(-) diff --git a/packages/common/src/viewport_scroller.ts b/packages/common/src/viewport_scroller.ts index fad2a4e3af..0e57c942d9 100644 --- a/packages/common/src/viewport_scroller.ts +++ b/packages/common/src/viewport_scroller.ts @@ -22,6 +22,7 @@ export abstract class ViewportScroller { // See #23917 /** @nocollapse */ static ngInjectableDef = ɵɵdefineInjectable({ + token: ViewportScroller, providedIn: 'root', factory: () => new BrowserViewportScroller(ɵɵinject(DOCUMENT), window, ɵɵinject(ErrorHandler)) }); diff --git a/packages/core/src/change_detection/differs/iterable_differs.ts b/packages/core/src/change_detection/differs/iterable_differs.ts index 2d08ea8b5a..c80508eb6d 100644 --- a/packages/core/src/change_detection/differs/iterable_differs.ts +++ b/packages/core/src/change_detection/differs/iterable_differs.ts @@ -144,6 +144,7 @@ export interface IterableDifferFactory { export class IterableDiffers { /** @nocollapse */ static ngInjectableDef = ɵɵdefineInjectable({ + token: IterableDiffers, providedIn: 'root', factory: () => new IterableDiffers([new DefaultIterableDifferFactory()]) }); diff --git a/packages/core/src/change_detection/differs/keyvalue_differs.ts b/packages/core/src/change_detection/differs/keyvalue_differs.ts index 5c9571ef05..83c11b2ed8 100644 --- a/packages/core/src/change_detection/differs/keyvalue_differs.ts +++ b/packages/core/src/change_detection/differs/keyvalue_differs.ts @@ -119,6 +119,7 @@ export interface KeyValueDifferFactory { export class KeyValueDiffers { /** @nocollapse */ static ngInjectableDef = ɵɵdefineInjectable({ + token: KeyValueDiffers, providedIn: 'root', factory: () => new KeyValueDiffers([new DefaultKeyValueDifferFactory()]) }); diff --git a/packages/core/src/di/injectable.ts b/packages/core/src/di/injectable.ts index d64dfb9281..eb6fd4782b 100644 --- a/packages/core/src/di/injectable.ts +++ b/packages/core/src/di/injectable.ts @@ -90,6 +90,7 @@ function render2CompileInjectable( options: {providedIn?: Type| 'root' | null} & InjectableProvider): void { if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) { injectableType.ngInjectableDef = ɵɵdefineInjectable({ + token: injectableType, providedIn: options.providedIn, factory: convertInjectableProviderToFactory(injectableType, options), }); diff --git a/packages/core/src/di/injection_token.ts b/packages/core/src/di/injection_token.ts index ac16ca838a..f93c31f36e 100644 --- a/packages/core/src/di/injection_token.ts +++ b/packages/core/src/di/injection_token.ts @@ -68,6 +68,7 @@ export class InjectionToken { (this as any).__NG_ELEMENT_ID__ = options; } else if (options !== undefined) { this.ngInjectableDef = ɵɵdefineInjectable({ + token: this, providedIn: options.providedIn || 'root', factory: options.factory, }); diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index cd6556c18e..cecd9cf15b 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -89,6 +89,7 @@ export abstract class Injector { /** @nocollapse */ static ngInjectableDef = ɵɵdefineInjectable({ + token: Injector, providedIn: 'any' as any, factory: () => ɵɵinject(INJECTOR), }); diff --git a/packages/core/src/di/interface/defs.ts b/packages/core/src/di/interface/defs.ts index e92f931825..724dcb2c5b 100644 --- a/packages/core/src/di/interface/defs.ts +++ b/packages/core/src/di/interface/defs.ts @@ -37,6 +37,13 @@ export interface ɵɵInjectableDef { */ providedIn: InjectorType|'root'|'any'|null; + /** + * The token to which this definition belongs. + * + * Note that this may not be the same as the type that the `factory` will create. + */ + token: unknown; + /** * Factory method to execute to create an instance of the injectable. */ @@ -132,11 +139,13 @@ export interface InjectorTypeWithProviders { * @codeGenApi */ export function ɵɵdefineInjectable(opts: { + token: unknown, providedIn?: Type| 'root' | 'any' | null, factory: () => T, }): never { return ({ - providedIn: opts.providedIn as any || null, factory: opts.factory, value: undefined, + token: opts.token, providedIn: opts.providedIn as any || null, factory: opts.factory, + value: undefined, } as ɵɵInjectableDef) as never; } diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index ed07f6a001..287654bbf9 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -307,7 +307,7 @@ export function ɵɵdefineComponent(componentDefinition: { // be retrieved through the node injector, so this isn't a problem. if (!type.hasOwnProperty(NG_INJECTABLE_DEF)) { (type as any)[NG_INJECTABLE_DEF] = - ɵɵdefineInjectable({factory: componentDefinition.factory as() => T}); + ɵɵdefineInjectable({token: type, factory: componentDefinition.factory as() => T}); } }) as never; diff --git a/packages/core/test/bundling/injection/usage.ts b/packages/core/test/bundling/injection/usage.ts index 8f4c9a1f5b..ec7f6ae7c6 100644 --- a/packages/core/test/bundling/injection/usage.ts +++ b/packages/core/test/bundling/injection/usage.ts @@ -10,6 +10,7 @@ import {Injector, ɵcreateInjector as createInjector, ɵɵdefineInjectable, ɵɵ export class RootService { static ngInjectableDef = ɵɵdefineInjectable({ + token: RootService, providedIn: 'root', factory: () => new RootService(), }); @@ -17,6 +18,7 @@ export class RootService { export class ScopedService { static ngInjectableDef = ɵɵdefineInjectable({ + token: ScopedService, providedIn: null, factory: () => new ScopedService(), }); diff --git a/packages/core/test/di/r3_injector_spec.ts b/packages/core/test/di/r3_injector_spec.ts index f60301a0f2..4307985b59 100644 --- a/packages/core/test/di/r3_injector_spec.ts +++ b/packages/core/test/di/r3_injector_spec.ts @@ -13,6 +13,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('InjectorDef-based createInjector()', () => { class CircularA { static ngInjectableDef = ɵɵdefineInjectable({ + token: CircularA, providedIn: null, factory: () => ɵɵinject(CircularB), }); @@ -20,6 +21,7 @@ describe('InjectorDef-based createInjector()', () => { class CircularB { static ngInjectableDef = ɵɵdefineInjectable({ + token: CircularB, providedIn: null, factory: () => ɵɵinject(CircularA), }); @@ -27,6 +29,7 @@ describe('InjectorDef-based createInjector()', () => { class Service { static ngInjectableDef = ɵɵdefineInjectable({ + token: Service, providedIn: null, factory: () => new Service(), }); @@ -34,6 +37,7 @@ describe('InjectorDef-based createInjector()', () => { class OptionalService { static ngInjectableDef = ɵɵdefineInjectable({ + token: OptionalService, providedIn: null, factory: () => new OptionalService(), }); @@ -56,6 +60,7 @@ describe('InjectorDef-based createInjector()', () => { constructor(readonly service: Service) {} static ngInjectableDef = ɵɵdefineInjectable({ + token: ServiceWithDep, providedIn: null, factory: () => new ServiceWithDep(ɵɵinject(Service)), }); @@ -65,6 +70,7 @@ describe('InjectorDef-based createInjector()', () => { constructor(@Optional() readonly service: OptionalService|null) {} static ngInjectableDef = ɵɵdefineInjectable({ + token: ServiceWithOptionalDep, providedIn: null, factory: () => new ServiceWithOptionalDep(ɵɵinject(OptionalService, InjectFlags.Optional)), }); @@ -74,6 +80,7 @@ describe('InjectorDef-based createInjector()', () => { constructor(readonly service: Service) {} static ngInjectableDef = ɵɵdefineInjectable({ + token: ServiceWithMissingDep, providedIn: null, factory: () => new ServiceWithMissingDep(ɵɵinject(Service)), }); @@ -83,6 +90,7 @@ describe('InjectorDef-based createInjector()', () => { constructor(readonly locale: string[]) {} static ngInjectableDef = ɵɵdefineInjectable({ + token: ServiceWithMultiDep, providedIn: null, factory: () => new ServiceWithMultiDep(ɵɵinject(LOCALE)), }); @@ -90,6 +98,7 @@ describe('InjectorDef-based createInjector()', () => { class ServiceTwo { static ngInjectableDef = ɵɵdefineInjectable({ + token: ServiceTwo, providedIn: null, factory: () => new ServiceTwo(), }); @@ -98,6 +107,7 @@ describe('InjectorDef-based createInjector()', () => { let deepServiceDestroyed = false; class DeepService { static ngInjectableDef = ɵɵdefineInjectable({ + token: DeepService, providedIn: null, factory: () => new DeepService(), }); @@ -108,6 +118,7 @@ describe('InjectorDef-based createInjector()', () => { let eagerServiceCreated: boolean = false; class EagerService { static ngInjectableDef = ɵɵdefineInjectable({ + token: EagerService, providedIn: undefined, factory: () => new EagerService(), }); @@ -203,6 +214,7 @@ describe('InjectorDef-based createInjector()', () => { let scopedServiceDestroyed = false; class ScopedService { static ngInjectableDef = ɵɵdefineInjectable({ + token: ScopedService, providedIn: Module, factory: () => new ScopedService(), }); @@ -212,6 +224,7 @@ describe('InjectorDef-based createInjector()', () => { class WrongScopeService { static ngInjectableDef = ɵɵdefineInjectable({ + token: WrongScopeService, providedIn: OtherModule, factory: () => new WrongScopeService(), }); diff --git a/packages/core/test/linker/ng_module_integration_spec.ts b/packages/core/test/linker/ng_module_integration_spec.ts index ee6eee8241..73ebe235f4 100644 --- a/packages/core/test/linker/ng_module_integration_spec.ts +++ b/packages/core/test/linker/ng_module_integration_spec.ts @@ -1397,6 +1397,7 @@ function declareTests(config?: {useJit: boolean}) { class Bar { static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: Bar, factory: () => new Bar(), providedIn: SomeModule, }); @@ -1429,6 +1430,7 @@ function declareTests(config?: {useJit: boolean}) { class Bar { static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: Bar, factory: () => new Bar(), providedIn: SomeModule, }); diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index 6526e39a43..97ee2c3690 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -63,8 +63,11 @@ describe('component', () => { class MyService { constructor(public value: string) {} - static ngInjectableDef = - ɵɵdefineInjectable({providedIn: 'root', factory: () => new MyService('no-injector')}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: MyService, + providedIn: 'root', + factory: () => new MyService('no-injector'), + }); } class MyComponent { constructor(public myService: MyService) {} diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index cb976aec2a..d0bf5b9e44 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -168,6 +168,7 @@ ivyEnabled && describe('render3 jit', () => { it('compiles a module to an ngInjectorDef with the providers', () => { class Token { static ngInjectableDef = ɵɵdefineInjectable({ + token: Token, providedIn: 'root', factory: () => 'default', }); diff --git a/packages/core/test/render3/providers_spec.ts b/packages/core/test/render3/providers_spec.ts index 0e64029c90..241443a20d 100644 --- a/packages/core/test/render3/providers_spec.ts +++ b/packages/core/test/render3/providers_spec.ts @@ -58,8 +58,10 @@ describe('providers', () => { public greet: string; constructor(private provider: GreeterProvider) { this.greet = this.provider.provide(); } - static ngInjectableDef = - ɵɵdefineInjectable({factory: () => new GreeterInj(ɵɵinject(GreeterProvider as any))}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: GreeterInj, + factory: () => new GreeterInj(ɵɵinject(GreeterProvider as any)), + }); } it('TypeProvider', () => { @@ -814,8 +816,11 @@ describe('providers', () => { it('should work with root', () => { @Injectable({providedIn: 'root'}) class FooForRoot { - static ngInjectableDef = - ɵɵdefineInjectable({factory: () => new FooForRoot(), providedIn: 'root'}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: FooForRoot, + factory: () => new FooForRoot(), + providedIn: 'root', + }); } expectProvidersScenario({ @@ -836,8 +841,11 @@ describe('providers', () => { @Injectable({providedIn: MyModule}) class FooForModule { - static ngInjectableDef = - ɵɵdefineInjectable({factory: () => new FooForModule(), providedIn: MyModule}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: FooForModule, + factory: () => new FooForModule(), + providedIn: MyModule, + }); } expectProvidersScenario({ @@ -1153,8 +1161,10 @@ describe('providers', () => { class MyService { constructor(public value: String) {} - static ngInjectableDef = - ɵɵdefineInjectable({factory: () => new MyService(ɵɵinject(String))}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: MyService, + factory: () => new MyService(ɵɵinject(String)), + }); } expectProvidersScenario({ @@ -1171,7 +1181,10 @@ describe('providers', () => { it('should make sure that parent service does not see overrides in child directives', () => { class Greeter { - static ngInjectableDef = ɵɵdefineInjectable({factory: () => new Greeter(ɵɵinject(String))}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: Greeter, + factory: () => new Greeter(ɵɵinject(String)), + }); constructor(public greeting: String) {} } @@ -1213,7 +1226,10 @@ describe('providers', () => { class SomeInj implements Some { constructor(public location: String) {} - static ngInjectableDef = ɵɵdefineInjectable({factory: () => new SomeInj(ɵɵinject(String))}); + static ngInjectableDef = ɵɵdefineInjectable({ + token: SomeInj, + factory: () => new SomeInj(ɵɵinject(String)), + }); } @Component({ diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index ec81d5c0ed..f6b75a8920 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -28,6 +28,7 @@ class NotMyModule {} class Bar { static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: Bar, factory: () => new Bar(), providedIn: MyModule, }); @@ -35,6 +36,7 @@ class Bar { class Baz { static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: Baz, factory: () => new Baz(), providedIn: NotMyModule, }); @@ -44,6 +46,7 @@ class HasNormalDep { constructor(public foo: Foo) {} static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: HasNormalDep, factory: () => new HasNormalDep(inject(Foo)), providedIn: MyModule, }); @@ -53,6 +56,7 @@ class HasDefinedDep { constructor(public bar: Bar) {} static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: HasDefinedDep, factory: () => new HasDefinedDep(inject(Bar)), providedIn: MyModule, }); @@ -62,6 +66,7 @@ class HasOptionalDep { constructor(public baz: Baz|null) {} static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: HasOptionalDep, factory: () => new HasOptionalDep(inject(Baz, InjectFlags.Optional)), providedIn: MyModule, }); @@ -69,6 +74,7 @@ class HasOptionalDep { class ChildDep { static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: ChildDep, factory: () => new ChildDep(), providedIn: MyChildModule, }); @@ -77,6 +83,7 @@ class ChildDep { class FromChildWithOptionalDep { constructor(public baz: Baz|null) {} static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: FromChildWithOptionalDep, factory: () => new FromChildWithOptionalDep(inject(Baz, InjectFlags.Default)), providedIn: MyChildModule, }); @@ -87,6 +94,7 @@ class FromChildWithSkipSelfDep { public skipSelfChildDep: ChildDep|null, public selfChildDep: ChildDep|null, public optionalSelfBar: Bar|null) {} static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: FromChildWithSkipSelfDep, factory: () => new FromChildWithSkipSelfDep( inject(ChildDep, InjectFlags.SkipSelf|InjectFlags.Optional), inject(ChildDep, InjectFlags.Self), @@ -210,6 +218,7 @@ describe('NgModuleRef_ injector', () => { ngOnDestroy(): void { Service.destroyed++; } static ngInjectableDef: ɵɵInjectableDef = ɵɵdefineInjectable({ + token: Service, factory: () => new Service(), providedIn: 'root', }); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index ef6757b785..92c4521d98 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -778,6 +778,7 @@ export declare const ɵɵdefineDirective: (directiveDefinition: { }) => never; export declare function ɵɵdefineInjectable(opts: { + token: unknown; providedIn?: Type | 'root' | 'any' | null; factory: () => T; }): never; @@ -869,6 +870,7 @@ export declare function ɵɵinject(token: Type | InjectionToken, flags? export interface ɵɵInjectableDef { factory: () => T; providedIn: InjectorType | 'root' | 'any' | null; + token: unknown; value: T | undefined; }