diff --git a/packages/core/src/context/container.ts b/packages/core/src/context/container.ts index a28046a8f26..7944c34ca3f 100644 --- a/packages/core/src/context/container.ts +++ b/packages/core/src/context/container.ts @@ -213,8 +213,6 @@ class ContainerConfiguration { } } -class ObjectCreateEventTarget extends EventEmitter {} - export class MidwayContainer implements IMidwayContainer, IModuleStore { private _resolverFactory: ManagedResolverFactory = null; private _registry: IObjectDefinitionRegistry = null; @@ -242,7 +240,7 @@ export class MidwayContainer implements IMidwayContainer, IModuleStore { get objectCreateEventTarget() { if (!this._objectCreateEventTarget) { - this._objectCreateEventTarget = new ObjectCreateEventTarget(); + this._objectCreateEventTarget = new EventEmitter(); } return this._objectCreateEventTarget; } @@ -363,6 +361,8 @@ export class MidwayContainer implements IMidwayContainer, IModuleStore { const refManaged = new ManagedReference(); refManaged.args = propertyMeta.args; refManaged.name = propertyMeta.value as any; + refManaged.injectMode = propertyMeta['injectMode']; + definition.properties.set(propertyMeta['targetKey'], refManaged); } diff --git a/packages/core/src/context/managedResolverFactory.ts b/packages/core/src/context/managedResolverFactory.ts index 92ca287b4c0..fe991ceeca5 100644 --- a/packages/core/src/context/managedResolverFactory.ts +++ b/packages/core/src/context/managedResolverFactory.ts @@ -1,7 +1,11 @@ /** * 管理对象解析构建 */ -import { IManagedInstance, ObjectIdentifier } from '@midwayjs/decorator'; +import { + IManagedInstance, + InjectModeEnum, + ObjectIdentifier, +} from '@midwayjs/decorator'; import { KEYS } from '../common/constants'; import { IManagedResolver, @@ -18,6 +22,7 @@ import * as EventEmitter from 'events'; import { MidwayCommonError, MidwayDefinitionNotFoundError, + MidwayMissingImportComponentError, MidwayResolverMissingError, MidwaySingletonInjectRequestError, } from '../error'; @@ -28,6 +33,7 @@ const debugLog = util.debuglog('midway:debug'); export class ManagedReference implements IManagedInstance { type = KEYS.REF_ELEMENT; name: string; + injectMode: InjectModeEnum; args?: any; } @@ -42,6 +48,14 @@ class RefResolver { resolve(managed: IManagedInstance, originName: string): any { const mr = managed as ManagedReference; + if ( + mr.injectMode === InjectModeEnum.Class && + !(this.factory.context.parent ?? this.factory.context).hasDefinition( + mr.name + ) + ) { + throw new MidwayMissingImportComponentError(originName); + } return this.factory.context.get(mr.name, mr.args, { originName, }); @@ -52,6 +66,14 @@ class RefResolver { originName: string ): Promise { const mr = managed as ManagedReference; + if ( + mr.injectMode === InjectModeEnum.Class && + !(this.factory.context.parent ?? this.factory.context).hasDefinition( + mr.name + ) + ) { + throw new MidwayMissingImportComponentError(originName); + } return this.factory.context.getAsync(mr.name, mr.args, { originName, }); diff --git a/packages/core/src/error/framework.ts b/packages/core/src/error/framework.ts index b45ea3ff5d9..3af7c895e4e 100644 --- a/packages/core/src/error/framework.ts +++ b/packages/core/src/error/framework.ts @@ -13,6 +13,7 @@ export const FrameworkErrorEnum = registerErrorCode('midway', { DUPLICATE_ROUTER: 10008, USE_WRONG_METHOD: 10009, SINGLETON_INJECT_REQUEST: 10010, + MISSING_IMPORTS: 10011, } as const); export class MidwayCommonError extends MidwayError { @@ -115,3 +116,10 @@ export class MidwaySingletonInjectRequestError extends MidwayError { super(text, FrameworkErrorEnum.SINGLETON_INJECT_REQUEST); } } + +export class MidwayMissingImportComponentError extends MidwayError { + constructor(originName: string) { + const text = `"${originName}" can't inject and maybe forgot add "{imports: [***]}" in @Configuration.`; + super(text, FrameworkErrorEnum.MISSING_IMPORTS); + } +} diff --git a/packages/core/src/setup.ts b/packages/core/src/setup.ts index 0319886ca99..7c1633ef790 100644 --- a/packages/core/src/setup.ts +++ b/packages/core/src/setup.ts @@ -62,14 +62,14 @@ export async function initializeGlobalApplicationContext( // bind inner service applicationContext.bindClass(MidwayEnvironmentService); applicationContext.bindClass(MidwayInformationService); + applicationContext.bindClass(MidwayAspectService); applicationContext.bindClass(MidwayDecoratorService); applicationContext.bindClass(MidwayConfigService); - applicationContext.bindClass(MidwayAspectService); applicationContext.bindClass(MidwayLoggerService); + applicationContext.bindClass(MidwayApplicationManager); applicationContext.bindClass(MidwayFrameworkService); applicationContext.bindClass(MidwayMiddlewareService); applicationContext.bindClass(MidwayLifeCycleService); - applicationContext.bindClass(MidwayApplicationManager); // bind preload module if (globalOptions.preloadModules && globalOptions.preloadModules.length) { diff --git a/packages/core/test/feature.test.ts b/packages/core/test/feature.test.ts new file mode 100644 index 00000000000..cb17e243e1e --- /dev/null +++ b/packages/core/test/feature.test.ts @@ -0,0 +1,21 @@ +import { createLightFramework } from './util'; +import { join } from 'path'; +import { MidwayMissingImportComponentError } from '../src'; + +describe('/test/feature.test.ts', () => { + it('should throw error when inject', async () => { + let err; + try { + await createLightFramework(join( + __dirname, + './fixtures/base-app-not-import-throw-error/src' + )); + } catch (error) { + err = error; + } + expect(err).toBeDefined(); + expect(() => { + throw err; + }).toThrowError(MidwayMissingImportComponentError); + }); +}); diff --git a/packages/core/test/fixtures/base-app-not-import-throw-error/package.json b/packages/core/test/fixtures/base-app-not-import-throw-error/package.json new file mode 100644 index 00000000000..621cdc6a417 --- /dev/null +++ b/packages/core/test/fixtures/base-app-not-import-throw-error/package.json @@ -0,0 +1,3 @@ +{ + "name": "ali-demo" +} diff --git a/packages/core/test/fixtures/base-app-not-import-throw-error/src/configuration.ts b/packages/core/test/fixtures/base-app-not-import-throw-error/src/configuration.ts new file mode 100644 index 00000000000..0569e8d91d8 --- /dev/null +++ b/packages/core/test/fixtures/base-app-not-import-throw-error/src/configuration.ts @@ -0,0 +1,16 @@ +import { Configuration, Inject } from '@midwayjs/decorator'; +// import * as book from 'midway-test-component'; +import { BookService } from 'midway-test-component'; + +@Configuration({ + imports: [], +}) +export class ContainerLifeCycle { + + @Inject() + bookService: BookService; + + async onReady() { + console.log('[ Midway ] onReady', this.bookService); + } +} diff --git a/packages/core/test/util.ts b/packages/core/test/util.ts index 01df126ec37..4caa16e5aed 100644 --- a/packages/core/test/util.ts +++ b/packages/core/test/util.ts @@ -85,7 +85,9 @@ export async function createLightFramework(baseDir: string = '', globalConfig: a } } - @Configuration() + @Configuration({ + namespace: 'empty' + }) class EmptyConfiguration { @Inject() @@ -97,8 +99,8 @@ export async function createLightFramework(baseDir: string = '', globalConfig: a } const imports = [{ + EmptyFramework, Configuration: EmptyConfiguration, - EmptyFramework }]; if (baseDir) { imports.push(safeRequire(join(baseDir, 'configuration'))); diff --git a/packages/decorator/src/decoratorManager.ts b/packages/decorator/src/decoratorManager.ts index fcb31c7b92a..cbc8315240d 100644 --- a/packages/decorator/src/decoratorManager.ts +++ b/packages/decorator/src/decoratorManager.ts @@ -1,11 +1,12 @@ import 'reflect-metadata'; import { + GroupModeType, + IModuleStore, + InjectModeEnum, ObjectDefinitionOptions, ObjectIdentifier, TagClsMetadata, TagPropsMetadata, - IModuleStore, - GroupModeType, } from './interface'; import { INJECT_CUSTOM_METHOD, @@ -16,7 +17,7 @@ import { TAGGED_CLS, } from './constant'; -import { isNullOrUndefined, isClass, generateRandomId, merge } from './util'; +import { generateRandomId, isClass, isNullOrUndefined, merge } from './util'; import { camelCase } from './util/camelCase'; const debug = require('util').debuglog('midway:decorator'); @@ -753,6 +754,7 @@ export function savePropertyInject(opts: { }) { // 1、use identifier by user let identifier = opts.identifier; + let injectMode = InjectModeEnum.Identifier; // 2、use identifier by class uuid if (!identifier) { const type = getPropertyType(opts.target, opts.targetKey); @@ -762,10 +764,12 @@ export function savePropertyInject(opts: { isProvide(type.originDesign) ) { identifier = getProviderUUId(type.originDesign); + injectMode = InjectModeEnum.Class; } if (!identifier) { // 3、use identifier by property name identifier = opts.targetKey; + injectMode = InjectModeEnum.PropertyName; } } attachClassMetadata( @@ -774,6 +778,7 @@ export function savePropertyInject(opts: { targetKey: opts.targetKey, // 注入的属性名 value: identifier, // 注入的 id args: opts.args, // 注入的其他参数 + injectMode, }, opts.target, opts.targetKey diff --git a/packages/decorator/src/interface.ts b/packages/decorator/src/interface.ts index a27f8fb54cc..b6776e79074 100644 --- a/packages/decorator/src/interface.ts +++ b/packages/decorator/src/interface.ts @@ -8,6 +8,12 @@ export enum ScopeEnum { Prototype = 'Prototype', } +export enum InjectModeEnum { + Identifier = 'Identifier', + Class = 'Class', + PropertyName = 'PropertyName', +} + /** * 内部管理的属性、json、ref等解析实例存储 */ diff --git a/packages/decorator/test/annotation/inject.test.ts b/packages/decorator/test/annotation/inject.test.ts index 373a6399926..ed2d95fb6fb 100644 --- a/packages/decorator/test/annotation/inject.test.ts +++ b/packages/decorator/test/annotation/inject.test.ts @@ -23,12 +23,14 @@ describe('/test/annotation/inject.test.ts', () => { it('inject decorator should be ok', () => { let meta = getPropertyInject(Test); expect(meta['aa']).toEqual({ + injectMode: 'PropertyName', value: 'aa', targetKey: 'aa' }); expect(meta['ee']['targetKey']).toEqual('ee'); expect(meta['ee']['value'].length).toEqual(32); expect(meta['ff']).toEqual({ + injectMode: 'PropertyName', value: 'ff', targetKey: 'ff' }); diff --git a/packages/decorator/test/common/utils.test.ts b/packages/decorator/test/common/utils.test.ts index 2d33aa78b1a..535a497fec5 100644 --- a/packages/decorator/test/common/utils.test.ts +++ b/packages/decorator/test/common/utils.test.ts @@ -34,6 +34,7 @@ describe('/test/common/util.test.ts', () => { let p = getPropertyInject(Test); expect(p['hello']).toEqual({ args: undefined, + injectMode: 'Identifier', targetKey: 'hello', value: '@testpackage', }); @@ -51,6 +52,7 @@ describe('/test/common/util.test.ts', () => { p = getPropertyInject(Test, false); expect(p['hello']).toEqual({ args: undefined, + injectMode: 'Identifier', targetKey: 'hello', value: '@testpackage2', });