From f5cbf0bb54d6f3a498430fad03ae0966d4be5809 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor Date: Wed, 13 May 2020 06:25:47 -0400 Subject: [PATCH] fix(core): support `Attribute` DI decorator in `deps` section of a token (#37085) This commit fixes a bug when `Attribute` DI decorator is used in the `deps` section of a token that uses a factory function. The problem appeared because the `Attribute` DI decorator was not handled correctly while injecting factory function attributes. Closes #36479 PR Close #37085 --- goldens/circular-deps/packages.json | 61 +++++++++++++++++++ .../core/src/core_render3_private_export.ts | 1 + packages/core/src/di/metadata.ts | 22 +++++-- packages/core/test/acceptance/di_spec.ts | 32 ++++++++++ 4 files changed, 112 insertions(+), 4 deletions(-) diff --git a/goldens/circular-deps/packages.json b/goldens/circular-deps/packages.json index 3e9bf12faa..18f105b46f 100644 --- a/goldens/circular-deps/packages.json +++ b/goldens/circular-deps/packages.json @@ -176,6 +176,57 @@ "packages/core/src/change_detection/differs/default_keyvalue_differ.ts", "packages/core/src/change_detection/differs/keyvalue_differs.ts" ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/util.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/reflective_injector.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/reflective_injector.ts", + "packages/core/src/di/reflective_provider.ts", + "packages/core/src/di/metadata.ts", + "packages/core/src/render3/instructions/di.ts" + ], [ "packages/core/src/di/injectable.ts", "packages/core/src/di/jit/injectable.ts" @@ -184,6 +235,16 @@ "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts" ], + [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/null_injector.ts" + ], + [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts" + ], [ "packages/core/src/di/injector_token.ts", "packages/core/src/di/injector.ts" diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 668ec0c720..358a4316c3 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -25,6 +25,7 @@ export { SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__, } from './di/injectable'; export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector'; +export {CREATE_ATTRIBUTE_DECORATOR__POST_R3__ as ɵCREATE_ATTRIBUTE_DECORATOR__POST_R3__} from './di/metadata'; export { NG_INJ_DEF as ɵNG_INJ_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, diff --git a/packages/core/src/di/metadata.ts b/packages/core/src/di/metadata.ts index 521d6faf7b..658a39ef62 100644 --- a/packages/core/src/di/metadata.ts +++ b/packages/core/src/di/metadata.ts @@ -7,7 +7,7 @@ */ import {makeParamDecorator} from '../util/decorators'; - +import {ɵɵinjectAttribute} from '../render3/instructions/di'; /** @@ -274,11 +274,25 @@ export interface Attribute { attributeName: string; } +function CREATE_ATTRIBUTE_DECORATOR__PRE_R3__(): AttributeDecorator { + return makeParamDecorator( + 'Attribute', + (attributeName?: string) => ({attributeName})); +} + +export function CREATE_ATTRIBUTE_DECORATOR__POST_R3__(): AttributeDecorator { + return makeParamDecorator( + 'Attribute', + (attributeName?: string) => + ({attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName!)})); +} + +const CREATE_ATTRIBUTE_DECORATOR_IMPL = CREATE_ATTRIBUTE_DECORATOR__PRE_R3__; + /** * Attribute decorator and metadata. * * @Annotation * @publicApi - */ -export const Attribute: AttributeDecorator = - makeParamDecorator('Attribute', (attributeName?: string) => ({attributeName})); +*/ +export const Attribute: AttributeDecorator = CREATE_ATTRIBUTE_DECORATOR_IMPL(); diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts index 820416d60e..70f59007a0 100644 --- a/packages/core/test/acceptance/di_spec.ts +++ b/packages/core/test/acceptance/di_spec.ts @@ -2771,6 +2771,38 @@ describe('di', () => { }); }); + describe('attribute tokens', () => { + it('should be able to provide an attribute token', () => { + const TOKEN = new InjectionToken('Some token'); + function factory(token: string): string { + return token + ' with factory'; + } + @Component({ + selector: 'my-comp', + template: '...', + providers: [{ + provide: TOKEN, + deps: [[new Attribute('token')]], + useFactory: factory, + }] + }) + class MyComp { + constructor(@Inject(TOKEN) readonly token: string) {} + } + + @Component({template: ``}) + class WrapperComp { + @ViewChild(MyComp) myComp!: MyComp; + } + + TestBed.configureTestingModule({declarations: [MyComp, WrapperComp]}); + + const fixture = TestBed.createComponent(WrapperComp); + fixture.detectChanges(); + expect(fixture.componentInstance.myComp.token).toBe('token with factory'); + }); + }); + it('should not cause cyclic dependency if same token is requested in deps with @SkipSelf', () => { @Component({ selector: 'my-comp',