From c3e15b328c184318e364bf40d32fa4df6be2a30a Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Fri, 18 Sep 2020 23:33:56 +0800 Subject: [PATCH] feat: add aop (#640) --- package.json | 2 +- packages/bootstrap/src/bootstrap.ts | 18 +- packages/bootstrap/src/index.ts | 6 +- packages/core/package.json | 2 + packages/core/src/baseFramework.ts | 15 +- packages/core/src/common/constants.ts | 4 +- packages/core/src/common/lodashWrap.ts | 11 +- packages/core/src/common/notFoundError.ts | 4 +- packages/core/src/common/reflectTool.ts | 6 +- packages/core/src/common/util.ts | 1 + .../core/src/context/applicationContext.ts | 74 ++++++--- packages/core/src/context/configuration.ts | 45 +++-- packages/core/src/context/container.ts | 46 ++++-- packages/core/src/context/managed.ts | 4 +- .../src/context/managedResolverFactory.ts | 154 ++++++++++++------ packages/core/src/context/midwayContainer.ts | 133 +++++++++++++-- packages/core/src/context/providerWrapper.ts | 14 +- packages/core/src/context/requestContainer.ts | 8 +- packages/core/src/context/resolverHandler.ts | 4 +- .../src/definitions/functionDefinition.ts | 22 ++- .../core/src/definitions/messageSource.ts | 12 +- .../core/src/definitions/objectCreator.ts | 16 +- packages/core/src/definitions/properties.ts | 4 +- packages/core/src/definitions/resource.ts | 4 +- packages/core/src/features/index.ts | 2 +- packages/core/src/features/pipeline.ts | 31 ++-- packages/core/src/index.ts | 10 +- packages/core/src/interface.ts | 6 + packages/core/src/loader.ts | 43 ++++- packages/core/src/service/configService.ts | 1 + packages/core/src/util/index.ts | 41 ++++- packages/core/src/util/webRouterParam.ts | 8 +- .../fixtures/base-app-aspect/package.json | 3 + .../fixtures/base-app-aspect/src/aspect/a.ts | 10 ++ .../fixtures/base-app-aspect/src/aspect/b.ts | 18 ++ .../test/fixtures/base-app-aspect/src/home.ts | 29 ++++ packages/core/test/loader.test.ts | 35 ++-- packages/decorator/package.json | 1 + packages/decorator/src/annotation/aspect.ts | 47 ++++++ packages/decorator/src/annotation/check.ts | 14 +- packages/decorator/src/annotation/index.ts | 1 + packages/decorator/src/annotation/rule.ts | 7 +- packages/decorator/src/common/constant.ts | 1 + .../decorator/src/common/decoratorManager.ts | 40 ++--- .../decorator/test/annotation/aspect.test.ts | 22 +++ .../decorator/test/annotation/check.test.ts | 46 +++++- packages/faas/src/framework.ts | 34 ++-- packages/midway-schedule/agent.ts | 14 +- packages/midway-schedule/app.ts | 14 +- packages/midway/cluster/master.js | 10 +- packages/midway/cluster/utils.js | 9 +- packages/midway/server.js | 4 +- packages/mock/app/extend/application.js | 2 +- packages/mock/bootstrap.d.ts | 3 +- packages/mock/bootstrap.js | 7 +- packages/mock/config/plugin.default.js | 6 +- packages/mock/package.json | 5 +- packages/mock/src/app/extend/application.ts | 17 +- packages/mock/src/bootstrap.ts | 9 +- packages/mock/src/interface.ts | 6 +- packages/mock/src/mock.ts | 76 +++++---- packages/mock/src/resolve.ts | 1 + packages/mock/src/utils.ts | 39 ++++- packages/socketio/src/framework.ts | 134 +++++++++++---- .../test/fixtures/base-app/src/socket/api.ts | 11 +- packages/web-express/src/framework.ts | 70 +++++--- packages/web-koa/src/framework.ts | 67 +++++--- packages/web-koa/src/index.ts | 5 +- .../fixtures/base-app/src/controller/api.ts | 4 +- packages/web/package.json | 2 + packages/web/src/agent.ts | 6 +- packages/web/src/app.ts | 15 +- packages/web/src/application.ts | 44 +++-- packages/web/src/config/config.default.ts | 9 +- packages/web/src/config/plugin.ts | 4 +- packages/web/src/framework.ts | 35 ++-- packages/web/src/index.ts | 7 +- packages/web/src/utils.ts | 6 +- 78 files changed, 1211 insertions(+), 489 deletions(-) create mode 100644 packages/core/test/fixtures/base-app-aspect/package.json create mode 100644 packages/core/test/fixtures/base-app-aspect/src/aspect/a.ts create mode 100644 packages/core/test/fixtures/base-app-aspect/src/aspect/b.ts create mode 100644 packages/core/test/fixtures/base-app-aspect/src/home.ts create mode 100644 packages/decorator/src/annotation/aspect.ts create mode 100644 packages/decorator/test/annotation/aspect.test.ts diff --git a/package.json b/package.json index c33622ccac4..8bd4bf36af1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "next": "sh scripts/publish.sh --npm-tag next", "release": "rm -f ./packages/.DS* && sh scripts/publish.sh", "bootstrap": "rm -f ./packages/.DS* && lerna bootstrap", - "clean": "lerna clean --yes && rm -rf ./packages/**/package-lock.json", + "clean": "lerna clean --yes && rm -rf ./packages/**/package-lock.json && rm -f package-lock.json", "build": "sh scripts/build.sh", "authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS", "postinstall": "opencollective-postinstall", diff --git a/packages/bootstrap/src/bootstrap.ts b/packages/bootstrap/src/bootstrap.ts index 7770a5a0dcd..4c86177df9f 100644 --- a/packages/bootstrap/src/bootstrap.ts +++ b/packages/bootstrap/src/bootstrap.ts @@ -26,7 +26,7 @@ export class BootstrapStarter { } public async init() { - this.appDir = this.globalOptions.baseDir; + this.appDir = this.globalOptions.baseDir; await Promise.all( this.getActions('initialize', { ...this.globalOptions, @@ -37,15 +37,11 @@ export class BootstrapStarter { } public async run() { - await Promise.all( - this.getActions('run', {}) - ); + await Promise.all(this.getActions('run', {})); } public async stop() { - await Promise.all( - this.getActions('stop', {}) - ); + await Promise.all(this.getActions('stop', {})); } public getActions(action: string, args?): any[] { @@ -93,14 +89,10 @@ export class Bootstrap { static async run() { await this.getStarter().init(); - return this.getStarter().run().catch( - console.error - ); + return this.getStarter().run().catch(console.error); } static async stop() { - return this.getStarter().stop().catch( - console.error - ); + return this.getStarter().stop().catch(console.error); } } diff --git a/packages/bootstrap/src/index.ts b/packages/bootstrap/src/index.ts index 156ecf8c0b5..8d40cedf05c 100644 --- a/packages/bootstrap/src/index.ts +++ b/packages/bootstrap/src/index.ts @@ -1 +1,5 @@ -export { isTypeScriptEnvironment, Bootstrap, BootstrapStarter } from './bootstrap'; +export { + isTypeScriptEnvironment, + Bootstrap, + BootstrapStarter, +} from './bootstrap'; diff --git a/packages/core/package.json b/packages/core/package.json index 522b1dbe065..03669dea5b9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -30,6 +30,7 @@ "dependencies": { "@midwayjs/decorator": "^2.2.5", "@midwayjs/glob": "^1.0.2", + "class-transformer": "^0.3.1", "debug": "^4.1.1", "extend2": "^1.0.0", "is-type-of": "^1.2.1", @@ -39,6 +40,7 @@ "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "lodash.template": "^4.4.0", + "picomatch": "^2.2.2", "reflect-metadata": "^0.1.13" }, "author": "Harry Chen ", diff --git a/packages/core/src/baseFramework.ts b/packages/core/src/baseFramework.ts index 0846f86b4c2..b16bb80ce73 100644 --- a/packages/core/src/baseFramework.ts +++ b/packages/core/src/baseFramework.ts @@ -3,7 +3,8 @@ import { IMidwayApplication, IMidwayBootstrapOptions, IMidwayContainer, - IMidwayFramework, MidwayFrameworkType, + IMidwayFramework, + MidwayFrameworkType, } from './interface'; import { ContainerLoader } from './'; import { APPLICATION_KEY, CONFIG_KEY } from '@midwayjs/decorator'; @@ -95,23 +96,19 @@ export abstract class BaseFramework await this.containerLoader.stop(); } - protected async beforeStop(): Promise { - } + protected async beforeStop(): Promise {} protected async beforeInitialize( options: Partial - ): Promise { - }; + ): Promise {} protected async beforeDirectoryLoad( options: Partial - ): Promise { - }; + ): Promise {} protected async afterDirectoryLoad( options: Partial - ): Promise { - }; + ): Promise {} protected abstract async afterInitialize( options: Partial diff --git a/packages/core/src/common/constants.ts b/packages/core/src/common/constants.ts index 18c0e3e69b2..3de7cbf8134 100644 --- a/packages/core/src/common/constants.ts +++ b/packages/core/src/common/constants.ts @@ -41,7 +41,7 @@ export const KEYS = { ASPECT_ELEMENT: 'aspect', AROUND_ELEMENT: 'around', EXPRESSION_ATTRIBUTE: 'expression', - EXECUTE_ATTRIBUTE: 'execute' + EXECUTE_ATTRIBUTE: 'execute', }; export const VALUE_TYPE = { @@ -52,5 +52,5 @@ export const VALUE_TYPE = { TEMPLATE: 'template', MANAGED: 'managed', OBJECT: 'object', // 仅仅在解析时使用 - BOOLEAN: 'boolean' + BOOLEAN: 'boolean', }; diff --git a/packages/core/src/common/lodashWrap.ts b/packages/core/src/common/lodashWrap.ts index e31f875be52..38efbf42fb8 100644 --- a/packages/core/src/common/lodashWrap.ts +++ b/packages/core/src/common/lodashWrap.ts @@ -1,4 +1,3 @@ - import * as assign from 'lodash.assign'; import * as get from 'lodash.get'; import * as set from 'lodash.set'; @@ -8,12 +7,4 @@ import * as defaultsDeep from 'lodash.defaultsdeep'; const isArray = Array.isArray; -export { - assign, - set, - get, - isArray, - template, - cloneDeep, - defaultsDeep, -}; +export { assign, set, get, isArray, template, cloneDeep, defaultsDeep }; diff --git a/packages/core/src/common/notFoundError.ts b/packages/core/src/common/notFoundError.ts index 0b8d1a3bc3c..5df83c11639 100644 --- a/packages/core/src/common/notFoundError.ts +++ b/packages/core/src/common/notFoundError.ts @@ -10,7 +10,9 @@ export class NotFoundError extends Error { this[NotFoundError.type] = NotFoundError.type; } updateErrorMsg(className: string): void { - const identifier = this.message.split(' is not valid in current context')[0]; + const identifier = this.message.split( + ' is not valid in current context' + )[0]; const msg = `${identifier} in class ${className} is not valid in current context`; this.message = msg; } diff --git a/packages/core/src/common/reflectTool.ts b/packages/core/src/common/reflectTool.ts index 2650659631d..500702118f8 100644 --- a/packages/core/src/common/reflectTool.ts +++ b/packages/core/src/common/reflectTool.ts @@ -64,7 +64,11 @@ export function recursiveGetPrototypeOf(target: any): any[] { * @param metadataKey metadata's key * @param target the target of metadataKey */ -export function recursiveGetMetadata(metadataKey: any, target: any, propertyKey?: string | symbol): ReflectResult[] { +export function recursiveGetMetadata( + metadataKey: any, + target: any, + propertyKey?: string | symbol +): ReflectResult[] { const metadatas: ReflectResult[] = []; // get metadata value of a metadata key on the prototype diff --git a/packages/core/src/common/util.ts b/packages/core/src/common/util.ts index d431c36a6ce..41480b39818 100644 --- a/packages/core/src/common/util.ts +++ b/packages/core/src/common/util.ts @@ -13,6 +13,7 @@ export const safeRequire = p => { }; export const isPath = (p): boolean => { + // eslint-disable-next-line no-useless-escape if (/(^[\.\/])|:|\\/.test(p)) { return true; } diff --git a/packages/core/src/context/applicationContext.ts b/packages/core/src/context/applicationContext.ts index f503c456ad5..f01fc517c75 100644 --- a/packages/core/src/context/applicationContext.ts +++ b/packages/core/src/context/applicationContext.ts @@ -8,7 +8,7 @@ import { IObjectDefinition, IObjectDefinitionRegistry, IObjectFactory, - ObjectDependencyTree + ObjectDependencyTree, } from '../interface'; import { ObjectProperties } from '../definitions/properties'; import { ManagedResolverFactory } from './managedResolverFactory'; @@ -17,7 +17,9 @@ import { parsePrefix, isPathEqual } from '../common/util'; const PREFIX = '_id_default_'; -export class ObjectDefinitionRegistry extends Map implements IObjectDefinitionRegistry { +export class ObjectDefinitionRegistry + extends Map + implements IObjectDefinitionRegistry { private singletonIds = []; get identifiers() { @@ -49,7 +51,10 @@ export class ObjectDefinitionRegistry extends Map implements IObjectDefinitionRe return definitions; } - registerDefinition(identifier: ObjectIdentifier, definition: IObjectDefinition) { + registerDefinition( + identifier: ObjectIdentifier, + definition: IObjectDefinition + ) { if (definition.isSingletonScope()) { this.singletonIds.push(identifier); } @@ -96,7 +101,8 @@ export class ObjectDefinitionRegistry extends Map implements IObjectDefinitionRe } } -export class BaseApplicationContext implements IApplicationContext, IObjectFactory { +export class BaseApplicationContext + implements IApplicationContext, IObjectFactory { protected readied = false; private _resolverFactory: ManagedResolverFactory = null; private _registry: IObjectDefinitionRegistry = null; @@ -145,8 +151,7 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto /** * 继承实现时需要调用super */ - protected init(): void { - } + protected init(): void {} async stop(): Promise { await this.getManagedResolverFactory().destroyCache(); @@ -159,8 +164,7 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto this.readied = true; } - protected loadDefinitions(): void { - } + protected loadDefinitions(): void {} isAsync(identifier: ObjectIdentifier): boolean { if (this.registry.hasDefinition(identifier)) { @@ -224,11 +228,16 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto * @param {ObjectIdentifier} identifier * @param {IObjectDefinition} definition */ - registerDefinition(identifier: ObjectIdentifier, definition: IObjectDefinition) { + registerDefinition( + identifier: ObjectIdentifier, + definition: IObjectDefinition + ) { if (!this.disableConflictCheck && this.registry.hasDefinition(identifier)) { const def = this.registry.getDefinition(identifier); if (!isPathEqual(definition.srcPath, def.srcPath)) { - throw new Error(`${identifier} path = ${definition.srcPath} is exist (${def.srcPath})!`); + throw new Error( + `${identifier} path = ${definition.srcPath} is exist (${def.srcPath})!` + ); } } this.registry.registerDefinition(identifier, definition); @@ -248,7 +257,13 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto * register handler after instance create * @param fn */ - afterEachCreated(fn: (ins: any, context: IApplicationContext, definition?: IObjectDefinition) => void) { + afterEachCreated( + fn: ( + ins: any, + context: IApplicationContext, + definition?: IObjectDefinition + ) => void + ) { this.getManagedResolverFactory().afterEachCreated(fn); } @@ -256,26 +271,39 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto * register handler before instance create * @param fn */ - beforeEachCreated(fn: (Clzz: any, constructorArgs: any[], context: IApplicationContext) => void) { + beforeEachCreated( + fn: ( + Clzz: any, + constructorArgs: any[], + context: IApplicationContext + ) => void + ) { this.getManagedResolverFactory().beforeEachCreated(fn); } protected createObjectDependencyTree(identifier, definition) { if (!this.dependencyMap.has(identifier)) { - let constructorArgs = definition.constructorArgs || []; - constructorArgs = constructorArgs.map((ref) => { - return ref.name; - }).filter(name => { - return !!name; - }); - - const properties = (definition.properties && definition.properties.keys().map((key) => { - return definition.properties.get(key).name; - })) || []; + constructorArgs = constructorArgs + .map(ref => { + return ref.name; + }) + .filter(name => { + return !!name; + }); + + const properties = + (definition.properties && + definition.properties.keys().map(key => { + return definition.properties.get(key).name; + })) || + []; this.dependencyMap.set(identifier, { - name: typeof definition.path !== 'string' ? definition.path.name : identifier, + name: + typeof definition.path !== 'string' + ? definition.path.name + : identifier, scope: definition.scope, constructorArgs, properties, diff --git a/packages/core/src/context/configuration.ts b/packages/core/src/context/configuration.ts index a6acd1f02f6..0f1f4ce8f99 100644 --- a/packages/core/src/context/configuration.ts +++ b/packages/core/src/context/configuration.ts @@ -39,9 +39,13 @@ export class ContainerConfiguration implements IContainerConfiguration { // for package const subContainerConfiguration = this.container.createConfiguration(); const subPackageDir = this.resolvePackageBaseDir(importPackage, baseDir); - debug(`\n---------- start load configuration from sub package "${importPackage}" ----------`); + debug( + `\n---------- start load configuration from sub package "${importPackage}" ----------` + ); subContainerConfiguration.load(subPackageDir); - debug(`---------- end load configuration from sub package "${importPackage}" ----------`); + debug( + `---------- end load configuration from sub package "${importPackage}" ----------` + ); } } @@ -57,7 +61,11 @@ export class ContainerConfiguration implements IContainerConfiguration { addImportConfigs(importConfigs: string[], baseDir: string) { if (importConfigs && importConfigs.length) { - debug(' import configs %j from baseDir => "%s".', importConfigs, baseDir); + debug( + ' import configs %j from baseDir => "%s".', + importConfigs, + baseDir + ); this.container.getConfigService().add( importConfigs.map(importConfigPath => { if (isAbsolute(importConfigPath)) { @@ -98,7 +106,11 @@ export class ContainerConfiguration implements IContainerConfiguration { debug('load configuration.ts from "%s"', packageName); } else { // package name is a normal npm package - debug('load configuration.ts in "%s" from "%s"', packageName, packageBaseDir); + debug( + 'load configuration.ts in "%s" from "%s"', + packageName, + packageBaseDir + ); } let pkg = safeRequire(join(packageBaseDir, 'package.json')); if (!pkg) { @@ -114,7 +126,9 @@ export class ContainerConfiguration implements IContainerConfiguration { } else { // no package.json debug('not found package.json from "%s".', packageBaseDir); - debug(`will be load configuration.ts from "${packageBaseDir}/configuration" directly`); + debug( + `will be load configuration.ts from "${packageBaseDir}/configuration" directly` + ); } let configuration; @@ -145,10 +159,7 @@ export class ContainerConfiguration implements IContainerConfiguration { debug(' add loadDir => "%s".', loadDir); debug(' add namespace => "%s".', this.namespace); } - debug( - ' has configuration file => %s.', - configuration ? true : false - ); + debug(' has configuration file => %s.', configuration ? true : false); this.loadConfiguration(configuration, packageBaseDir, cfgFile); } @@ -178,10 +189,14 @@ export class ContainerConfiguration implements IContainerConfiguration { this.container.containsConfiguration(this.packageName) && this.namespace !== '' ) { - debug(` configuration "namespace(${this.namespace})/packageName(${this.packageName})" exist than ignore.`); + debug( + ` configuration "namespace(${this.namespace})/packageName(${this.packageName})" exist than ignore.` + ); return; } else { - debug(` configuration "namespace(${this.namespace})/packageName(${this.packageName})" not exist than add.`); + debug( + ` configuration "namespace(${this.namespace})/packageName(${this.packageName})" not exist than add.` + ); this.container.addConfiguration(this); } this.addImports(configurationOptions.imports, baseDir); @@ -195,10 +210,14 @@ export class ContainerConfiguration implements IContainerConfiguration { this.container.containsConfiguration(this.packageName) && this.namespace !== '' ) { - debug(` configuration "namespace(${this.namespace})/packageName(${this.packageName})" exist than ignore.`); + debug( + ` configuration "namespace(${this.namespace})/packageName(${this.packageName})" exist than ignore.` + ); return; } else { - debug(` configuration "namespace(${this.namespace})/packageName(${this.packageName})" not exist than add.`); + debug( + ` configuration "namespace(${this.namespace})/packageName(${this.packageName})" not exist than add.` + ); this.container.addConfiguration(this); } } diff --git a/packages/core/src/context/container.ts b/packages/core/src/context/container.ts index 42e51cf5fdd..44505590512 100644 --- a/packages/core/src/context/container.ts +++ b/packages/core/src/context/container.ts @@ -1,10 +1,12 @@ import 'reflect-metadata'; -import { ObjectDefinitionOptions, +import { + ObjectDefinitionOptions, ObjectIdentifier, getConstructorInject, getObjectDefProps, TAGGED_PROP, - getProviderId} from '@midwayjs/decorator'; + getProviderId, +} from '@midwayjs/decorator'; import { IContainer } from '../interface'; import { ObjectDefinition } from '../definitions/objectDefinition'; import { ManagedReference, ManagedValue } from './managed'; @@ -16,13 +18,21 @@ import { generateProvideId } from '../common/util'; const is = require('is-type-of'); export class Container extends BaseApplicationContext implements IContainer { - id = (Math.random()).toString(10).slice(-5); + id = Math.random().toString(10).slice(-5); debugLogger = require('debug')(`midway:container:${this.id}`); // 自己内部实现的,可注入的 feature(见 features) protected midwayIdentifiers: string[] = []; bind(target: T, options?: ObjectDefinitionOptions): void; - bind(identifier: ObjectIdentifier, target: T, options?: ObjectDefinitionOptions): void; - bind(identifier: ObjectIdentifier, target: T, options?: ObjectDefinitionOptions): void { + bind( + identifier: ObjectIdentifier, + target: T, + options?: ObjectDefinitionOptions + ): void; + bind( + identifier: ObjectIdentifier, + target: T, + options?: ObjectDefinitionOptions + ): void { let definition; if (is.class(identifier) || is.function(identifier)) { @@ -51,14 +61,14 @@ export class Container extends BaseApplicationContext implements IContainer { // inject constructArgs const constructorMetaData = getConstructorInject(target); if (constructorMetaData) { - this.debugLogger(`inject constructor => length = ${target[ 'length' ]}`); + this.debugLogger(`inject constructor => length = ${target['length']}`); const maxLength = Math.max.apply(null, Object.keys(constructorMetaData)); for (let i = 0; i < maxLength + 1; i++) { - const propertyMeta = constructorMetaData[ i ]; + const propertyMeta = constructorMetaData[i]; if (propertyMeta) { const refManagedIns = new ManagedReference(); - const name = propertyMeta[ 0 ].value; - refManagedIns.args = propertyMeta[ 0 ].args; + const name = propertyMeta[0].value; + refManagedIns.args = propertyMeta[0].args; if (this.midwayIdentifiers.includes(name)) { refManagedIns.name = name; } else { @@ -79,13 +89,16 @@ export class Container extends BaseApplicationContext implements IContainer { for (const metaData of metaDatas) { this.debugLogger(` inject properties => [${Object.keys(metaData)}]`); for (const metaKey in metaData) { - for (const propertyMeta of metaData[ metaKey ]) { + for (const propertyMeta of metaData[metaKey]) { const refManaged = new ManagedReference(); refManaged.args = propertyMeta.args; if (this.midwayIdentifiers.includes(propertyMeta.value)) { refManaged.name = propertyMeta.value; } else { - refManaged.name = generateProvideId(propertyMeta.value, definition.namespace); + refManaged.name = generateProvideId( + propertyMeta.value, + definition.namespace + ); } definition.properties.set(metaKey, refManaged); } @@ -106,10 +119,13 @@ export class Container extends BaseApplicationContext implements IContainer { this.convertOptionsToDefinition(objDefOptions, objectDefinition); } - private convertOptionsToDefinition(options: ObjectDefinitionOptions, definition: ObjectDefinition): ObjectDefinition { + private convertOptionsToDefinition( + options: ObjectDefinitionOptions, + definition: ObjectDefinition + ): ObjectDefinition { if (options) { if (options.isAsync) { - this.debugLogger(` register isAsync = true`); + this.debugLogger(' register isAsync = true'); definition.asynchronous = true; } @@ -129,7 +145,9 @@ export class Container extends BaseApplicationContext implements IContainer { } if (options.constructorArgs) { - this.debugLogger(` register constructorArgs = ${options.constructorArgs}`); + this.debugLogger( + ` register constructorArgs = ${options.constructorArgs}` + ); definition.constructorArgs = options.constructorArgs; } diff --git a/packages/core/src/context/managed.ts b/packages/core/src/context/managed.ts index e9cb93b81d0..5c6628d04e4 100644 --- a/packages/core/src/context/managed.ts +++ b/packages/core/src/context/managed.ts @@ -41,7 +41,9 @@ export class ManagedMap extends Map implements IManagedInstance { type = KEYS.MAP_ELEMENT; } -export class ManagedProperties extends ObjectProperties implements IManagedInstance { +export class ManagedProperties + extends ObjectProperties + implements IManagedInstance { type = KEYS.PROPS_ELEMENT; } diff --git a/packages/core/src/context/managedResolverFactory.ts b/packages/core/src/context/managedResolverFactory.ts index a3fc27eb28d..292b083a64f 100644 --- a/packages/core/src/context/managedResolverFactory.ts +++ b/packages/core/src/context/managedResolverFactory.ts @@ -1,10 +1,7 @@ /** * 管理对象解析构建 */ -import { - IManagedInstance, - ObjectIdentifier -} from '@midwayjs/decorator'; +import { IManagedInstance, ObjectIdentifier } from '@midwayjs/decorator'; import * as _ from '../common/lodashWrap'; import { KEYS, VALUE_TYPE } from '../common/constants'; import { @@ -16,7 +13,7 @@ import { ManagedProperty, ManagedReference, ManagedSet, - ManagedValue + ManagedValue, } from './managed'; import { IApplicationContext, @@ -24,7 +21,7 @@ import { IObjectDefinition, REQUEST_CTX_KEY, REQUEST_OBJ_CTX_KEY, - IManagedResolverFactoryCreateOptions + IManagedResolverFactoryCreateOptions, } from '../interface'; import { ObjectProperties } from '../definitions/properties'; import { NotFoundError } from '../common/notFoundError'; @@ -246,7 +243,10 @@ class PropertiesResolver extends BaseManagedResolver { const cfg = new ObjectProperties(); const keys = m.keys(); for (const key of keys) { - cfg.setProperty(key, await this._factory.resolveManagedAsync(m.getProperty(key))); + cfg.setProperty( + key, + await this._factory.resolveManagedAsync(m.getProperty(key)) + ); } return cfg; } @@ -303,7 +303,6 @@ export class ManagedResolverFactory { beforeCreateHandler = []; constructor(context: IApplicationContext) { - this.context = context; // 初始化解析器 @@ -316,7 +315,7 @@ export class ManagedResolverFactory { props: new PropertiesResolver(this), property: new PropertyResolver(this), object: new ObjectResolver(this), - ref: new RefResolver(this) + ref: new RefResolver(this), }; } @@ -336,7 +335,7 @@ export class ManagedResolverFactory { if (typeof value === 'string' && value.indexOf('{{') > -1) { return _.template(value, { // use `{{` and `}}` as delimiters - interpolate: /{{([\s\S]+?)}}/g + interpolate: /{{([\s\S]+?)}}/g, })(this.props); } return value; @@ -369,8 +368,10 @@ export class ManagedResolverFactory { */ create(opt: IManagedResolverFactoryCreateOptions): any { const { definition, args } = opt; - if (definition.isSingletonScope() && - this.singletonCache.has(definition.id)) { + if ( + definition.isSingletonScope() && + this.singletonCache.has(definition.id) + ) { return this.singletonCache.get(definition.id); } // 如果非 null 表示已经创建 proxy @@ -407,7 +408,10 @@ export class ManagedResolverFactory { inst = definition.creator.doConstruct(Clzz, constructorArgs, this.context); // binding ctx object - if (definition.isRequestScope() && definition.constructor.name === 'ObjectDefinition') { + if ( + definition.isRequestScope() && + definition.constructor.name === 'ObjectDefinition' + ) { Object.defineProperty(inst, REQUEST_OBJ_CTX_KEY, { value: this.context.get(REQUEST_CTX_KEY), writable: false, @@ -420,7 +424,7 @@ export class ManagedResolverFactory { for (const key of keys) { const identifier = definition.properties.getProperty(key); try { - inst[ key ] = this.resolveManaged(identifier); + inst[key] = this.resolveManaged(identifier); } catch (error) { if (NotFoundError.isClosePrototypeOf(error)) { const className = definition.path.name; @@ -459,8 +463,10 @@ export class ManagedResolverFactory { */ async createAsync(opt: IManagedResolverFactoryCreateOptions): Promise { const { definition, args } = opt; - if (definition.isSingletonScope() && - this.singletonCache.has(definition.id)) { + if ( + definition.isSingletonScope() && + this.singletonCache.has(definition.id) + ) { debug('id = %s from singleton cache.', definition.id); return this.singletonCache.get(definition.id); } @@ -499,14 +505,21 @@ export class ManagedResolverFactory { handler.call(this, Clzz, constructorArgs, this.context); } - inst = await definition.creator.doConstructAsync(Clzz, constructorArgs, this.context); + inst = await definition.creator.doConstructAsync( + Clzz, + constructorArgs, + this.context + ); if (!inst) { this.removeCreateStatus(definition, false); throw new Error(`${definition.id} construct return undefined`); } // binding ctx object - if (definition.isRequestScope() && definition.constructor.name === 'ObjectDefinition') { + if ( + definition.isRequestScope() && + definition.constructor.name === 'ObjectDefinition' + ) { debug('id = %s inject ctx', definition.id); Object.defineProperty(inst, REQUEST_OBJ_CTX_KEY, { value: this.context.get(REQUEST_CTX_KEY), @@ -520,8 +533,13 @@ export class ManagedResolverFactory { for (const key of keys) { const identifier = definition.properties.getProperty(key); try { - debug('id = %s resolve property key = %s => %s.', definition.id, key, identifier); - inst[ key ] = await this.resolveManagedAsync(identifier); + debug( + 'id = %s resolve property key = %s => %s.', + definition.id, + key, + identifier + ); + inst[key] = await this.resolveManagedAsync(identifier); } catch (error) { if (NotFoundError.isClosePrototypeOf(error)) { const className = definition.path.name; @@ -566,11 +584,19 @@ export class ManagedResolverFactory { this.creating.clear(); } - beforeEachCreated(fn: (Clzz: any, constructorArgs: [], context: IApplicationContext) => void) { + beforeEachCreated( + fn: (Clzz: any, constructorArgs: [], context: IApplicationContext) => void + ) { this.beforeCreateHandler.push(fn); } - afterEachCreated(fn: (ins: any, context: IApplicationContext, definition?: IObjectDefinition) => void) { + afterEachCreated( + fn: ( + ins: any, + context: IApplicationContext, + definition?: IObjectDefinition + ) => void + ) { this.afterCreateHandler.push(fn); } /** @@ -578,7 +604,10 @@ export class ManagedResolverFactory { * @param definition 单例定义 * @param success 成功 or 失败 */ - private removeCreateStatus(definition: IObjectDefinition, success: boolean): boolean { + private removeCreateStatus( + definition: IObjectDefinition, + success: boolean + ): boolean { // 如果map中存在表示需要设置状态 if (this.creating.has(definition.id)) { this.creating.set(definition.id, false); @@ -591,7 +620,10 @@ export class ManagedResolverFactory { } private compareAndSetCreateStatus(definition: IObjectDefinition) { - if (!this.creating.has(definition.id) || !this.creating.get(definition.id)) { + if ( + !this.creating.has(definition.id) || + !this.creating.get(definition.id) + ) { this.creating.set(definition.id, true); } } @@ -608,27 +640,30 @@ export class ManagedResolverFactory { return null; } // 创建代理对象 - return new Proxy({ __is_proxy__: true, __target_id__: definition.id }, { - get: (obj, prop) => { - let target; - if (definition.isRequestScope()) { - target = this.context.registry.getObject(definition.id); - } else if (definition.isSingletonScope()) { - target = this.singletonCache.get(definition.id); - } else { - target = this.context.get(definition.id); - } + return new Proxy( + { __is_proxy__: true, __target_id__: definition.id }, + { + get: (obj, prop) => { + let target; + if (definition.isRequestScope()) { + target = this.context.registry.getObject(definition.id); + } else if (definition.isSingletonScope()) { + target = this.singletonCache.get(definition.id); + } else { + target = this.context.get(definition.id); + } - if (target) { - if (typeof target[prop] === 'function') { - return target[prop].bind(target); + if (target) { + if (typeof target[prop] === 'function') { + return target[prop].bind(target); + } + return target[prop]; } - return target[prop]; - } - return undefined; + return undefined; + }, } - }); + ); } return null; } @@ -637,13 +672,23 @@ export class ManagedResolverFactory { * @param identifier 目标id * @param definition 定义描述 */ - public depthFirstSearch(identifier: string, definition: IObjectDefinition, depth?: string[]): boolean { + public depthFirstSearch( + identifier: string, + definition: IObjectDefinition, + depth?: string[] + ): boolean { if (definition) { debug('dfs for %s == %s start.', identifier, definition.id); if (definition.constructorArgs) { - const args = definition.constructorArgs.map(val => (val as ManagedReference).name); + const args = definition.constructorArgs.map( + val => (val as ManagedReference).name + ); if (args.indexOf(identifier) > -1) { - debug('dfs exist in constructor %s == %s.', identifier, definition.id); + debug( + 'dfs exist in constructor %s == %s.', + identifier, + definition.id + ); return true; } } @@ -663,11 +708,21 @@ export class ManagedResolverFactory { iden = ref.name; } if (iden === identifier) { - debug('dfs exist in properties key %s == %s.', identifier, definition.id); + debug( + 'dfs exist in properties key %s == %s.', + identifier, + definition.id + ); return true; } if (depth.indexOf(iden) > -1) { - debug('dfs depth circular %s == %s, %s, %j.', identifier, definition.id, iden, depth); + debug( + 'dfs depth circular %s == %s, %s, %j.', + identifier, + definition.id, + iden, + depth + ); continue; } else { depth.push(iden); @@ -678,7 +733,12 @@ export class ManagedResolverFactory { subDefinition = this.context.parent.registry.getDefinition(iden); } if (this.depthFirstSearch(identifier, subDefinition, depth)) { - debug('dfs exist in sub tree %s == %s subId = %s.', identifier, definition.id, subDefinition.id); + debug( + 'dfs exist in sub tree %s == %s subId = %s.', + identifier, + definition.id, + subDefinition.id + ); return true; } } diff --git a/packages/core/src/context/midwayContainer.ts b/packages/core/src/context/midwayContainer.ts index 130251175f9..7dbff4d096d 100644 --- a/packages/core/src/context/midwayContainer.ts +++ b/packages/core/src/context/midwayContainer.ts @@ -1,35 +1,38 @@ import { + AspectMetadata, + CONFIGURATION_KEY, getObjectDefinition, getProviderId, + IMethodAspect, + isProvide, + listModule, ObjectDefinitionOptions, ObjectIdentifier, - ScopeEnum, PIPELINE_IDENTIFIER, - listModule, - CONFIGURATION_KEY, - isProvide, saveClassMetadata, + ScopeEnum, } from '@midwayjs/decorator'; import * as is from 'is-type-of'; import { ContainerConfiguration } from './configuration'; -import { FUNCTION_INJECT_KEY, PRIVATE_META_DATA_KEY } from '..'; +import { FUNCTION_INJECT_KEY, generateProvideId, PRIVATE_META_DATA_KEY } from '..'; import { + IApplicationContext, IConfigService, + IContainerConfiguration, IEnvironmentService, + ILifeCycle, IMidwayContainer, - IApplicationContext, MAIN_MODULE_KEY, - IContainerConfiguration, - ILifeCycle, REQUEST_CTX_KEY, } from '../interface'; import { MidwayConfigService } from '../service/configService'; import { MidwayEnvironmentService } from '../service/environmentService'; import { Container } from './container'; -import { generateProvideId } from '../common/util'; import { pipelineFactory } from '../features/pipeline'; import { ResolverHandler } from './resolverHandler'; import { run } from '@midwayjs/glob'; +import { isAsyncFunction } from '../util'; +import * as pm from 'picomatch'; const DEFAULT_PATTERN = ['**/**.ts', '**/**.tsx', '**/**.js']; const DEFAULT_IGNORE_PATTERN = [ @@ -62,7 +65,10 @@ export class MidwayContainer extends Container implements IMidwayContainer { init(): void { this.initService(); - this.resolverHandler = new ResolverHandler(this, this.getManagedResolverFactory()); + this.resolverHandler = new ResolverHandler( + this, + this.getManagedResolverFactory() + ); // 防止直接从applicationContext.getAsync or get对象实例时依赖当前上下文信息出错 // ctx is in requestContainer this.registerObject(REQUEST_CTX_KEY, this.ctx); @@ -86,17 +92,17 @@ export class MidwayContainer extends Container implements IMidwayContainer { this.midwayIdentifiers.push(PIPELINE_IDENTIFIER); this.midwayIdentifiers.push(REQUEST_CTX_KEY); - this.debugLogger(`main:create "Main Module" and "Main Configuration"`); + this.debugLogger('main:create "Main Module" and "Main Configuration"'); // create main module configuration const configuration = this.createConfiguration(); configuration.namespace = MAIN_MODULE_KEY; this.debugLogger(`main:"Main Configuration" load from "${this.baseDir}"`); configuration.load(this.baseDir); // loadDir - this.debugLogger(`main:load directory`); + this.debugLogger('main:load directory'); this.loadDirectory(opts); - this.debugLogger(`main:main configuration register import objects`); + this.debugLogger('main:main configuration register import objects'); this.registerImportObjects(configuration.getImportObjects()); // load configuration @@ -188,8 +194,7 @@ export class MidwayContainer extends Container implements IMidwayContainer { } createChild() { - const child = new MidwayContainer(this.baseDir, this); - return child; + return new MidwayContainer(this.baseDir, this); } registerDataHandler(handlerType: string, handler: (handlerKey) => any) { @@ -202,7 +207,7 @@ export class MidwayContainer extends Container implements IMidwayContainer { // Override the default scope to request const objDefOptions: ObjectDefinitionOptions = getObjectDefinition(target); if (objDefOptions && !objDefOptions.scope) { - this.debugLogger(` @scope => request`); + this.debugLogger(' @scope => request'); objectDefinition.scope = ScopeEnum.Request; } } @@ -236,6 +241,97 @@ export class MidwayContainer extends Container implements IMidwayContainer { return this.environmentService.getCurrentEnvironment(); } + public async addAspect( + aspectIns: IMethodAspect, + aspectData: AspectMetadata + ) { + const module = aspectData.aspectTarget; + const names = Object.getOwnPropertyNames(module.prototype); + const isMatch = aspectData.match ? pm(aspectData.match) : () => true; + + for (const name of names) { + if (name === 'constructor' || !isMatch(name)) { + continue; + } + const descriptor = Object.getOwnPropertyDescriptor( + module.prototype, + name + ); + if (!descriptor || descriptor.writable === false) { + continue; + } + const originMethod = descriptor.value; + if (isAsyncFunction(originMethod)) { + this.debugLogger(`aspect [#${module.name}:${name}], isAsync=true, aspect class=[${aspectIns.constructor.name}]`); + descriptor.value = async function (...args) { + let error, result; + const joinPoint = { + methodName: name, + target: this, + args: args, + proceed: originMethod, + }; + try { + await aspectIns.before?.(joinPoint); + if (aspectIns.around) { + result = await aspectIns.around(joinPoint); + } else { + result = await originMethod.apply(this, joinPoint.args); + } + const resultTemp = await aspectIns.afterReturn?.( + joinPoint, + result + ); + result = typeof resultTemp === 'undefined' ? result : resultTemp; + return result; + } catch (err) { + error = err; + if (aspectIns.afterThrow) { + await aspectIns.afterThrow(joinPoint, error); + } else { + throw err; + } + } finally { + await aspectIns.after?.(joinPoint, result, error); + } + }; + } else { + this.debugLogger(`aspect [#${module.name}:${name}], isAsync=false, aspect class=[${aspectIns.constructor.name}]`); + descriptor.value = function (...args) { + let error, result; + const joinPoint = { + methodName: name, + target: this, + args: args, + proceed: originMethod, + }; + try { + aspectIns.before?.(joinPoint); + if (aspectIns.around) { + result = aspectIns.around(joinPoint); + } else { + result = originMethod.apply(this, joinPoint.args); + } + const resultTemp = aspectIns.afterReturn?.(joinPoint, result); + result = typeof resultTemp === 'undefined' ? result : resultTemp; + return result; + } catch (err) { + error = err; + if (aspectIns.afterThrow) { + aspectIns.afterThrow(joinPoint, error); + } else { + throw err; + } + } finally { + aspectIns.after?.(joinPoint, result, error); + } + }; + } + + Object.defineProperty(module.prototype, name, descriptor); + } + } + async ready() { super.ready(); if (this.configService) { @@ -249,7 +345,10 @@ export class MidwayContainer extends Container implements IMidwayContainer { async stop(): Promise { const cycles = listModule(CONFIGURATION_KEY); - this.debugLogger('load lifecycle length => %s when stop.', cycles && cycles.length); + this.debugLogger( + 'load lifecycle length => %s when stop.', + cycles && cycles.length + ); for (const cycle of cycles) { const providerId = getProviderId(cycle); this.debugLogger('onStop lifecycle id => %s.', providerId); diff --git a/packages/core/src/context/providerWrapper.ts b/packages/core/src/context/providerWrapper.ts index 939b372f128..23794fba012 100644 --- a/packages/core/src/context/providerWrapper.ts +++ b/packages/core/src/context/providerWrapper.ts @@ -2,12 +2,14 @@ import { ObjectIdentifier, ScopeEnum } from '@midwayjs/decorator'; import { IApplicationContext } from '../interface'; import { FUNCTION_INJECT_KEY } from '../common/constants'; -export function providerWrapper(wrapperInfo: Array<{ - id: ObjectIdentifier; - provider: (context: IApplicationContext, args?: any) => any; - scope?: ScopeEnum; - isAutowire?: boolean; -}>): void { +export function providerWrapper( + wrapperInfo: Array<{ + id: ObjectIdentifier; + provider: (context: IApplicationContext, args?: any) => any; + scope?: ScopeEnum; + isAutowire?: boolean; + }> +): void { for (const info of wrapperInfo) { Object.defineProperty(info.provider, FUNCTION_INJECT_KEY, { value: info, diff --git a/packages/core/src/context/requestContainer.ts b/packages/core/src/context/requestContainer.ts index 3d3d0b4e87c..5193a10711a 100644 --- a/packages/core/src/context/requestContainer.ts +++ b/packages/core/src/context/requestContainer.ts @@ -19,8 +19,12 @@ export class MidwayRequestContainer extends MidwayContainer { } const resolverHandler = this.applicationContext.resolverHandler; - this.beforeEachCreated(resolverHandler.beforeEachCreated.bind(resolverHandler)); - this.afterEachCreated(resolverHandler.afterEachCreated.bind(resolverHandler)); + this.beforeEachCreated( + resolverHandler.beforeEachCreated.bind(resolverHandler) + ); + this.afterEachCreated( + resolverHandler.afterEachCreated.bind(resolverHandler) + ); } init() { diff --git a/packages/core/src/context/resolverHandler.ts b/packages/core/src/context/resolverHandler.ts index d78049ccffd..46d4d06a397 100644 --- a/packages/core/src/context/resolverHandler.ts +++ b/packages/core/src/context/resolverHandler.ts @@ -67,9 +67,7 @@ export class ResolverHandler { const propertyMeta = constructorMetaData[index]; const hook = this.getHandler(propertyMeta.type); if (hook) { - constructorArgs[index] = hook( - propertyMeta.key - ); + constructorArgs[index] = hook(propertyMeta.key); } } } diff --git a/packages/core/src/definitions/functionDefinition.ts b/packages/core/src/definitions/functionDefinition.ts index 3a8030d7c0d..d49794ad792 100644 --- a/packages/core/src/definitions/functionDefinition.ts +++ b/packages/core/src/definitions/functionDefinition.ts @@ -1,14 +1,17 @@ -import { IManagedInstance, ObjectIdentifier, ScopeEnum } from '@midwayjs/decorator'; +import { + IManagedInstance, + ObjectIdentifier, + ScopeEnum, +} from '@midwayjs/decorator'; import { IProperties, IObjectCreator, IObjectDefinition, - IApplicationContext + IApplicationContext, } from '../interface'; import { ObjectCreator } from './objectCreator'; class FunctionWrapperCreator extends ObjectCreator { - doConstruct(Clzz: any, args?: any, context?: IApplicationContext): any { if (!Clzz) { return null; @@ -16,7 +19,11 @@ class FunctionWrapperCreator extends ObjectCreator { return Clzz(context, args); } - async doConstructAsync(Clzz: any, args?: any, context?: IApplicationContext): Promise { + async doConstructAsync( + Clzz: any, + args?: any, + context?: IApplicationContext + ): Promise { if (!Clzz) { return null; } @@ -26,7 +33,6 @@ class FunctionWrapperCreator extends ObjectCreator { } export class FunctionDefinition implements IObjectDefinition { - constructor() { this.creator = new FunctionWrapperCreator(this); } @@ -53,8 +59,7 @@ export class FunctionDefinition implements IObjectDefinition { this.innerAutowire = autowire; } - getAttr(key: ObjectIdentifier): any { - } + getAttr(key: ObjectIdentifier): any {} hasAttr(key: ObjectIdentifier): boolean { return false; @@ -96,6 +101,5 @@ export class FunctionDefinition implements IObjectDefinition { return this.innerScope === ScopeEnum.Request; } - setAttr(key: ObjectIdentifier, value: any): void { - } + setAttr(key: ObjectIdentifier, value: any): void {} } diff --git a/packages/core/src/definitions/messageSource.ts b/packages/core/src/definitions/messageSource.ts index df79ec41b87..2d1b7c47ef4 100644 --- a/packages/core/src/definitions/messageSource.ts +++ b/packages/core/src/definitions/messageSource.ts @@ -53,11 +53,12 @@ export class MessageSource extends Map implements IMessageSource { } } - getMessage(code: string, - args?: any[], - defaultMessage?: string, - locale?: Locale): string { - + getMessage( + code: string, + args?: any[], + defaultMessage?: string, + locale?: Locale + ): string { let messages; if (locale) { messages = this.get(locale); @@ -75,6 +76,7 @@ export class MessageSource extends Map implements IMessageSource { if (args && args.length > 0) { args.unshift(messages[code]); + // eslint-disable-next-line prefer-spread return format.apply(null, args); } return messages[code]; diff --git a/packages/core/src/definitions/objectCreator.ts b/packages/core/src/definitions/objectCreator.ts index c7b96298d66..b5cb8a89609 100644 --- a/packages/core/src/definitions/objectCreator.ts +++ b/packages/core/src/definitions/objectCreator.ts @@ -45,6 +45,7 @@ export class ObjectCreator implements IObjectCreator { let inst; if (this.definition.constructMethod) { + // eslint-disable-next-line prefer-spread inst = Clzz[this.definition.constructMethod].apply(Clzz, args); } else { inst = Reflect.construct(Clzz, args); @@ -86,14 +87,19 @@ export class ObjectCreator implements IObjectCreator { const inst = obj; // after properties set then do init if (this.definition.initMethod && inst[this.definition.initMethod]) { - if (is.generatorFunction(inst[this.definition.initMethod]) - || is.asyncFunction(inst[this.definition.initMethod])) { - - throw new Error(`${this.definition.id} not valid by context.get, Use context.getAsync instead!`); + if ( + is.generatorFunction(inst[this.definition.initMethod]) || + is.asyncFunction(inst[this.definition.initMethod]) + ) { + throw new Error( + `${this.definition.id} not valid by context.get, Use context.getAsync instead!` + ); } else { const rt = inst[this.definition.initMethod].call(inst); if (is.promise(rt)) { - throw new Error(`${this.definition.id} not valid by context.get, Use context.getAsync instead!`); + throw new Error( + `${this.definition.id} not valid by context.get, Use context.getAsync instead!` + ); } } } diff --git a/packages/core/src/definitions/properties.ts b/packages/core/src/definitions/properties.ts index 524142b1413..b29614c7375 100644 --- a/packages/core/src/definitions/properties.ts +++ b/packages/core/src/definitions/properties.ts @@ -17,6 +17,7 @@ export class ObjectProperties implements IProperties { get(key: ObjectIdentifier, ...args: any[]): any { if (args && args.length > 0) { args.unshift(_.get(this.innerConfig, key)); + // eslint-disable-next-line prefer-spread return format.apply(null, args); } return _.get(this.innerConfig, key); @@ -43,8 +44,7 @@ export class ObjectProperties implements IProperties { const keys = props.keys(); for (const key of keys) { if (typeof this.innerConfig[key] === 'object') { - this.set(key, - _.defaultsDeep(props.get(key), this.innerConfig[key])); + this.set(key, _.defaultsDeep(props.get(key), this.innerConfig[key])); } else { this.set(key, props.get(key)); } diff --git a/packages/core/src/definitions/resource.ts b/packages/core/src/definitions/resource.ts index 8cde24c5ec3..6bcf76b58e9 100644 --- a/packages/core/src/definitions/resource.ts +++ b/packages/core/src/definitions/resource.ts @@ -93,8 +93,8 @@ export class Resource implements IResource { const buf = readFileSync(this.getPath()); try { return JSON.parse(buf.toString()); - } catch (e) { - } + // eslint-disable-next-line no-empty + } catch (e) {} return {}; } return require(this.getPath()); diff --git a/packages/core/src/features/index.ts b/packages/core/src/features/index.ts index e407f3913ec..949610ebc6e 100644 --- a/packages/core/src/features/index.ts +++ b/packages/core/src/features/index.ts @@ -3,5 +3,5 @@ export { IPipelineHandler, IPipelineOptions, IPipelineResult, - IValveHandler + IValveHandler, } from './pipeline'; diff --git a/packages/core/src/features/pipeline.ts b/packages/core/src/features/pipeline.ts index ed3a841c343..bf9fbfb424a 100644 --- a/packages/core/src/features/pipeline.ts +++ b/packages/core/src/features/pipeline.ts @@ -235,7 +235,7 @@ export class PipelineHandler implements IPipelineHandler { result.error = { valveName: v, message: e.message, - error: e + error: e, }; return result; @@ -281,7 +281,7 @@ export class PipelineHandler implements IPipelineHandler { result.error = { valveName: v, message: e.message, - error: e + error: e, }; return result; @@ -296,7 +296,7 @@ export class PipelineHandler implements IPipelineHandler { const result = await this.concatSeries(opts); if (result.success) { const data = result.result; - result.result = data[(data as any).length - 1 ]; + result.result = data[(data as any).length - 1]; } return result; } @@ -321,11 +321,13 @@ export class PipelineHandler implements IPipelineHandler { return newItems; } - private prepareParallelValves(opts: IPipelineOptions): Array> { + private prepareParallelValves( + opts: IPipelineOptions + ): Array> { const valves = this.mergeValves(opts.valves); const ctx = new PipelineContext(opts.args); - return valves.map(async (v) => { + return valves.map(async v => { const rt: IValveResult = { valveName: v, dataKey: v, data: null }; try { const inst: IValveHandler = await this.applicationContext.getAsync(v); @@ -355,7 +357,7 @@ export class PipelineHandler implements IPipelineHandler { result.error = { valveName: r.valveName, message: r.error.message, - error: r.error + error: r.error, }; return result; @@ -372,12 +374,17 @@ export class PipelineHandler implements IPipelineHandler { } } -export function pipelineFactory(applicationContext: IApplicationContext, valves?: string[]) { +export function pipelineFactory( + applicationContext: IApplicationContext, + valves?: string[] +) { return new PipelineHandler(applicationContext, valves); } -providerWrapper([{ - id: PIPELINE_IDENTIFIER, - provider: pipelineFactory, - scope: ScopeEnum.Prototype -}]); +providerWrapper([ + { + id: PIPELINE_IDENTIFIER, + provider: pipelineFactory, + scope: ScopeEnum.Prototype, + }, +]); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index dde0db268cf..1ef78aeda34 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -29,7 +29,7 @@ export { getParamNames, getProviderId, getObjectDefinition, - classNamed + classNamed, } from '@midwayjs/decorator'; export * from './interface'; export { ContainerLoader } from './loader'; @@ -38,6 +38,12 @@ export { MidwayRequestContainer } from './context/requestContainer'; export { BaseFramework } from './baseFramework'; export * from './context/providerWrapper'; export * from './common/constants'; -export { safelyGet, safeRequire, generateProvideId, parsePrefix} from './common/util'; +export { + safelyGet, + safeRequire, + generateProvideId, + parsePrefix, +} from './common/util'; export * from './features'; export * from './util/webRouterParam'; +export { plainToClass, classToPlain } from 'class-transformer'; diff --git a/packages/core/src/interface.ts b/packages/core/src/interface.ts index 7e1052ed1ce..1ef103d5ecd 100644 --- a/packages/core/src/interface.ts +++ b/packages/core/src/interface.ts @@ -3,6 +3,8 @@ import { IManagedInstance, ScopeEnum, ObjectDefinitionOptions, + IMethodAspect, + AspectMetadata, } from '@midwayjs/decorator'; /** * 生命周期定义 @@ -217,6 +219,10 @@ export interface IMidwayContainer extends IContainer { getConfigService(): IConfigService; getEnvironmentService(): IEnvironmentService; getCurrentEnv(): string; + addAspect( + aspectIns: IMethodAspect, + aspectData: AspectMetadata + ) } export interface IConfigService { diff --git a/packages/core/src/loader.ts b/packages/core/src/loader.ts index f1bd67b5db7..b4136aa04ac 100644 --- a/packages/core/src/loader.ts +++ b/packages/core/src/loader.ts @@ -1,6 +1,14 @@ import * as path from 'path'; import { MidwayContainer } from './context/midwayContainer'; import { Container } from './context/container'; +import { + ASPECT_KEY, + getClassMetadata, + IMethodAspect, + listModule, + listPreloadModule, +} from '@midwayjs/decorator'; +import { IMidwayContainer } from './interface'; function buildLoadDir(baseDir, dir) { if (!path.isAbsolute(dir)) { @@ -37,7 +45,7 @@ export class ContainerLoader { this.applicationContext.registerObject('isTsMode', this.isTsMode); } - getApplicationContext() { + getApplicationContext(): IMidwayContainer { return this.applicationContext; } @@ -90,6 +98,39 @@ export class ContainerLoader { async refresh() { await this.pluginContext.ready(); await this.applicationContext.ready(); + + // some common decorator implementation + const modules = listPreloadModule(); + for (const module of modules) { + // preload init context + await this.getApplicationContext().getAsync(module); + } + + // for aop implementation + const aspectModules = listModule(ASPECT_KEY); + // sort for aspect target + let aspectDataList = []; + for (const module of aspectModules) { + const data = getClassMetadata(ASPECT_KEY, module); + aspectDataList = aspectDataList.concat( + data.map(el => { + el.aspectModule = module; + return el; + }) + ); + } + + // sort priority + aspectDataList.sort((pre, next) => { + return (next.priority || 0) - (pre.priority || 0); + }); + + for (const aspectData of aspectDataList) { + const aspectIns = await this.getApplicationContext().getAsync< + IMethodAspect + >(aspectData.aspectModule); + await this.getApplicationContext().addAspect(aspectIns, aspectData); + } } async stop() { diff --git a/packages/core/src/service/configService.ts b/packages/core/src/service/configService.ts index 09d6b131887..fb4f70686d1 100644 --- a/packages/core/src/service/configService.ts +++ b/packages/core/src/service/configService.ts @@ -112,6 +112,7 @@ export class MidwayConfigService implements IConfigService { } let result = exports; if (is.function(exports)) { + // eslint-disable-next-line prefer-spread result = await exports.apply(null, [].concat(this.container)); } return result; diff --git a/packages/core/src/util/index.ts b/packages/core/src/util/index.ts index f29d629d426..908325c007b 100644 --- a/packages/core/src/util/index.ts +++ b/packages/core/src/util/index.ts @@ -1,7 +1,44 @@ -export function sleep(sleepTime: number = 1000) { - return new Promise((resolve) => { +export function sleep(sleepTime = 1000) { + return new Promise(resolve => { setTimeout(() => { resolve(); }, sleepTime); }); } + +/** + * get all method names from obj or it's prototype + * @param obj + */ +export function getPrototypeNames(obj) { + const enumerableOwnKeys = Object.keys(obj); + const ownKeysOnObjectPrototype = Object.getOwnPropertyNames( + Object.getPrototypeOf({}) + ); + const result = []; + // methods on obj itself should be always included + for (const k of enumerableOwnKeys) { + if (typeof obj[k] === 'function') { + result.push(k); + } + } + // searching prototype chain for methods + let proto = obj; + do { + proto = Object.getPrototypeOf(proto); + const allOwnKeysOnPrototype = Object.getOwnPropertyNames(proto); + // get methods from es6 class + for (const k of allOwnKeysOnPrototype) { + if (typeof obj[k] === 'function' && k !== 'constructor') { + result.push(k); + } + } + } while (proto && proto !== Object.prototype); + + // leave out those methods on Object's prototype + return result.filter(k => ownKeysOnObjectPrototype.indexOf(k) === -1); +} + +export function isAsyncFunction(fn) { + return fn[Symbol.toStringTag] === 'AsyncFunction'; +} diff --git a/packages/core/src/util/webRouterParam.ts b/packages/core/src/util/webRouterParam.ts index 9f8ca63bb8f..00f8ce73cb4 100644 --- a/packages/core/src/util/webRouterParam.ts +++ b/packages/core/src/util/webRouterParam.ts @@ -1,7 +1,7 @@ import { ALL_VALUE, RouteParamTypes } from '@midwayjs/decorator'; export const extractKoaLikeValue = (key, data) => { - if(ALL_VALUE === data) { + if (ALL_VALUE === data) { data = undefined; } return async function (ctx, next) { @@ -9,7 +9,9 @@ export const extractKoaLikeValue = (key, data) => { case RouteParamTypes.NEXT: return next; case RouteParamTypes.BODY: - return data && ctx.request.body ? ctx.request.body[data] : ctx.request.body; + return data && ctx.request.body + ? ctx.request.body[data] + : ctx.request.body; case RouteParamTypes.PARAM: return data ? ctx.params[data] : ctx.params; case RouteParamTypes.QUERY: @@ -29,7 +31,7 @@ export const extractKoaLikeValue = (key, data) => { }; export const extractExpressLikeValue = (key, data) => { - if(ALL_VALUE === data) { + if (ALL_VALUE === data) { data = undefined; } return async function (req, res, next) { diff --git a/packages/core/test/fixtures/base-app-aspect/package.json b/packages/core/test/fixtures/base-app-aspect/package.json new file mode 100644 index 00000000000..b7dd10831ca --- /dev/null +++ b/packages/core/test/fixtures/base-app-aspect/package.json @@ -0,0 +1,3 @@ +{ + "name": "ali-demo-aspect" +} diff --git a/packages/core/test/fixtures/base-app-aspect/src/aspect/a.ts b/packages/core/test/fixtures/base-app-aspect/src/aspect/a.ts new file mode 100644 index 00000000000..b38cc8f93ff --- /dev/null +++ b/packages/core/test/fixtures/base-app-aspect/src/aspect/a.ts @@ -0,0 +1,10 @@ +import { Aspect, IMethodAspect, JoinPoint, Provide } from '@midwayjs/decorator'; +import { Home } from '../home'; + +@Provide() +@Aspect([Home]) +export class MyAspect1 implements IMethodAspect { + before(point: JoinPoint): any { + point.args = ['ddd'] + } +} diff --git a/packages/core/test/fixtures/base-app-aspect/src/aspect/b.ts b/packages/core/test/fixtures/base-app-aspect/src/aspect/b.ts new file mode 100644 index 00000000000..5cb9161943d --- /dev/null +++ b/packages/core/test/fixtures/base-app-aspect/src/aspect/b.ts @@ -0,0 +1,18 @@ +import { Aspect, IMethodAspect, JoinPoint, Provide } from '@midwayjs/decorator'; +import { Home } from "../home"; + +@Provide() +@Aspect([Home], '*2', 1) +export class MyAspect2 implements IMethodAspect { + + async before(point: JoinPoint) { + point.args = ['ccc', 'ppp'] + } + + async around(point: JoinPoint) { + console.log('before around in aspect2'); + const data = await point.proceed(...point.args); + console.log('after around in aspect2'); + return data; + } +} diff --git a/packages/core/test/fixtures/base-app-aspect/src/home.ts b/packages/core/test/fixtures/base-app-aspect/src/home.ts new file mode 100644 index 00000000000..de58368e772 --- /dev/null +++ b/packages/core/test/fixtures/base-app-aspect/src/home.ts @@ -0,0 +1,29 @@ +import { Provide } from '@midwayjs/decorator'; + +class Parent { + ddd = 'ddd'; + + hello() { + return 'hello world parent'; + } + + async hello1() { + return 'hello world 1' + } +} + +@Provide() +export class Home extends Parent { + + bbb = 'aaa'; + + ccc: string; + + hello(data1: string = 'ggg', data2 = 'fff') { + return 'hello world' + data1 + data2; + } + + async hello2(data1: string = 'ggg', data2 = 'fff') { + return 'hello world' + data1 + data2; + } +} diff --git a/packages/core/test/loader.test.ts b/packages/core/test/loader.test.ts index 13a37fe37c0..f4f5684f213 100644 --- a/packages/core/test/loader.test.ts +++ b/packages/core/test/loader.test.ts @@ -601,23 +601,22 @@ describe('/test/loader.test.ts', () => { assert(value === 'pre'); }); - it('load local env', async () => { - mm(process.env, 'NODE_ENV', 'local'); - const loader = new ContainerLoader({ - baseDir: path.join( - __dirname, - './fixtures/app-with-configuration-config-dir/src' - ), - disableConflictCheck: true, - }); - loader.initialize(); - loader.loadDirectory(); - await loader.refresh(); - const applicationContext = loader.getApplicationContext(); - const value = applicationContext - .getConfigService() - .getConfiguration('env'); - assert(value === 'local'); - }); }); + + it('should test aspect decorator', async () => { + const loader = new ContainerLoader({ + baseDir: path.join( + __dirname, + './fixtures/base-app-aspect/src' + ) + }); + loader.initialize(); + loader.loadDirectory(); + await loader.refresh(); + + const home: any = await loader.getApplicationContext().getAsync('home'); + expect(home.hello()).toEqual('hello worlddddfff'); + expect(await home.hello1()).toEqual('hello world 1'); + expect(await home.hello2()).toEqual('hello worldcccppp'); + }) }); diff --git a/packages/decorator/package.json b/packages/decorator/package.json index d6e7af2e402..4eca6fb43e4 100644 --- a/packages/decorator/package.json +++ b/packages/decorator/package.json @@ -16,6 +16,7 @@ "@types/joi": "^14.3.4", "@types/koa": "^2.11.4", "camelcase": "^5.0.0", + "class-transformer": "^0.3.1", "debug": "^4.1.1", "joi": "^14.3.1", "reflect-metadata": "^0.1.13" diff --git a/packages/decorator/src/annotation/aspect.ts b/packages/decorator/src/annotation/aspect.ts new file mode 100644 index 00000000000..41ec4b01fac --- /dev/null +++ b/packages/decorator/src/annotation/aspect.ts @@ -0,0 +1,47 @@ +import { ASPECT_KEY, attachClassMetadata, saveModule, ScopeEnum } from '..'; +import { Scope } from './objectDef'; + +export interface JoinPoint { + methodName: string; + target: any; + args: any[]; + proceed(...args: any[]): any; +} + +export interface AspectMetadata { + aspectTarget: any; + match?: string | (() => boolean); + priority?: number; +} + +export interface IMethodAspect { + after?(joinPoint: JoinPoint, result: any, error: Error); + afterReturn?(joinPoint: JoinPoint, result: any): any; + afterThrow?(joinPoint: JoinPoint, error: Error): void; + before?(joinPoint: JoinPoint): void; + around?(joinPoint: JoinPoint): any; +} + +export function Aspect( + aspectTarget: any | any[], + match?: string | (() => boolean), + priority?: number +) { + return function (target) { + saveModule(ASPECT_KEY, target); + const aspectTargets = [].concat(aspectTarget); + for (const aspectTarget of aspectTargets) { + attachClassMetadata( + ASPECT_KEY, + { + aspectTarget, + match, + priority, + }, + target + ); + } + + Scope(ScopeEnum.Singleton); + }; +} diff --git a/packages/decorator/src/annotation/check.ts b/packages/decorator/src/annotation/check.ts index 4a5038fdbc2..b7f92a881fe 100644 --- a/packages/decorator/src/annotation/check.ts +++ b/packages/decorator/src/annotation/check.ts @@ -1,22 +1,28 @@ import * as joi from 'joi'; -import { getMethodParamTypes, getClassMetadata, RULES_KEY } from '..'; +import { getClassMetadata, getMethodParamTypes, RULES_KEY } from '..'; +import { plainToClass } from 'class-transformer'; -export function Check(failValue?: any) { +export function Check(isTransform = true) { return function ( target, propertyKey: string | symbol, descriptor: PropertyDescriptor ) { const origin = descriptor.value; + const paramTypes = getMethodParamTypes(target, propertyKey); + descriptor.value = function (...args: any[]) { - const paramTypes = getMethodParamTypes(target, propertyKey); for (let i = 0; i < paramTypes.length; i++) { const item = paramTypes[i]; const rules = getClassMetadata(RULES_KEY, item); if (rules) { const result = joi.validate(args[i], rules); if (result.error) { - return failValue ? failValue : result; + throw new Error(result.error as any); + } + // passed + if (isTransform) { + args[i] = plainToClass(item, args[i]); } } } diff --git a/packages/decorator/src/annotation/index.ts b/packages/decorator/src/annotation/index.ts index bff7a709548..593dfaf1d7c 100644 --- a/packages/decorator/src/annotation/index.ts +++ b/packages/decorator/src/annotation/index.ts @@ -7,3 +7,4 @@ export * from './schedule'; export * from './pipeline'; export * from './check'; export * from './rule'; +export * from './aspect'; diff --git a/packages/decorator/src/annotation/rule.ts b/packages/decorator/src/annotation/rule.ts index 89fc771193c..70b252ad864 100644 --- a/packages/decorator/src/annotation/rule.ts +++ b/packages/decorator/src/annotation/rule.ts @@ -1,5 +1,10 @@ import * as joi from 'joi'; -import { attachClassMetadata, getClassMetadata, getPropertyType, RULES_KEY } from '..'; +import { + attachClassMetadata, + getClassMetadata, + getPropertyType, + RULES_KEY, +} from '..'; export function Rule(rule) { return function (target: any, propertyKey: string) { diff --git a/packages/decorator/src/common/constant.ts b/packages/decorator/src/common/constant.ts index 150304303ee..4acfa028ad2 100644 --- a/packages/decorator/src/common/constant.ts +++ b/packages/decorator/src/common/constant.ts @@ -6,6 +6,7 @@ export const PRIORITY_KEY = 'common:priority'; export const SCHEDULE_KEY = 'common:schedule'; export const CONFIGURATION_KEY = 'common:configuration'; export const RULES_KEY = 'common:rules'; +export const ASPECT_KEY = 'common:aspect'; // faas export const FUNC_KEY = 'faas:func'; diff --git a/packages/decorator/src/common/decoratorManager.ts b/packages/decorator/src/common/decoratorManager.ts index 6a2a82cf794..497ae560a27 100644 --- a/packages/decorator/src/common/decoratorManager.ts +++ b/packages/decorator/src/common/decoratorManager.ts @@ -109,7 +109,7 @@ export class DecoratorManager extends Map { target: any, dataKey: string, data: any, - groupBy?: string, + groupBy?: string ) { debug( 'attachMetadata %s on target %o with dataKey = %s.', @@ -206,7 +206,13 @@ export class DecoratorManager extends Map { * @param target * @param propertyName */ - attachMetadata(decoratorNameKey: decoratorKey, data, target, propertyName?: string, groupBy?: string) { + attachMetadata( + decoratorNameKey: decoratorKey, + data, + target, + propertyName?: string, + groupBy?: string + ) { if (propertyName) { const dataKey = DecoratorManager.getDecoratorMethod( decoratorNameKey, @@ -298,7 +304,7 @@ export class DecoratorManager extends Map { data, target, propertyName, - groupBy?: string, + groupBy?: string ) { const dataKey = DecoratorManager.getDecoratorClsMethodKey( decoratorNameKey, @@ -386,9 +392,15 @@ export function attachClassMetadata( decoratorNameKey: decoratorKey, data: any, target, - groupBy?: string, + groupBy?: string ) { - return manager.attachMetadata(decoratorNameKey, data, target, undefined, groupBy); + return manager.attachMetadata( + decoratorNameKey, + data, + target, + undefined, + groupBy + ); } const testKeyMap = new Map(); @@ -739,25 +751,13 @@ export function getObjectDefinition(module): ObjectDefinitionOptions { * get parameters type by reflect-metadata */ export function getMethodParamTypes(target, propertyKey: string | symbol) { - return Reflect.getMetadata( - 'design:paramtypes', - target, - propertyKey - ); + return Reflect.getMetadata('design:paramtypes', target, propertyKey); } export function getPropertyType(target, propertyKey: string | symbol) { - return Reflect.getMetadata( - 'design:type', - target, - propertyKey - ); + return Reflect.getMetadata('design:type', target, propertyKey); } export function getMethodReturnTypes(target, propertyKey: string | symbol) { - return Reflect.getMetadata( - 'design:returntype', - target, - propertyKey - ); + return Reflect.getMetadata('design:returntype', target, propertyKey); } diff --git a/packages/decorator/test/annotation/aspect.test.ts b/packages/decorator/test/annotation/aspect.test.ts new file mode 100644 index 00000000000..6c0321c9b8c --- /dev/null +++ b/packages/decorator/test/annotation/aspect.test.ts @@ -0,0 +1,22 @@ +import { Aspect, ASPECT_KEY, IMethodAspect, JoinPoint, listModule } from '../../src'; + +describe('/test/annotation/aspect.test.ts', () => { + it('test inspect key in module', () => { + class MyAspect implements IMethodAspect { + around(point: JoinPoint): any { + point.proceed(); + } + } + + @Aspect(MyAspect) + class MyAspectClass { + async hello() {} + } + + const myAspect = new MyAspectClass(); + myAspect.hello(); + + const modules = listModule(ASPECT_KEY); + expect(modules[0].name).toEqual('MyAspectClass'); + }); +}); diff --git a/packages/decorator/test/annotation/check.test.ts b/packages/decorator/test/annotation/check.test.ts index 9a06e159408..a40cd5d6dd2 100644 --- a/packages/decorator/test/annotation/check.test.ts +++ b/packages/decorator/test/annotation/check.test.ts @@ -20,6 +20,42 @@ describe('/test/annotation/check.test.ts', () => { assert.deepEqual(result, user); }); + it('check with check and transform object', () => { + class UserDTO { + @Rule(RuleType.number().max(10)) + age: number; + + @Rule(RuleType.string().required()) + firstName: string; + + @Rule(RuleType.string().max(10)) + lastName: string; + + getName?() { + return this.firstName + ' ' + this.lastName; + } + + isAdult?() { + return this.age > 36 && this.age < 60; + } + } + + class Hello { + @Check(true) + school(a, data: UserDTO) { + return data; + } + } + const user = { + age: 8, + firstName: 'Johny', + lastName: 'Cage', + }; + const result = new Hello().school(1, user); + expect(result.getName()).toEqual('Johny Cage'); + assert.deepEqual(result, user); + }); + it('check with no check', () => { class UserDTO { @Rule(RuleType.number().max(10)) @@ -94,8 +130,9 @@ describe('/test/annotation/check.test.ts', () => { age: 22, }, }; - const result = new Hello().school(1, user); - assert.notDeepEqual(result, user); + expect(() => { + new Hello().school(1, user); + }).toThrow(Error); }); it('check with check when two level and array and not equal', () => { @@ -126,7 +163,8 @@ describe('/test/annotation/check.test.ts', () => { }, ], }; - const result = new Hello().school(1, user); - assert.notDeepEqual(result, user); + expect(() => { + new Hello().school(1, user); + }).toThrow(Error); }); }); diff --git a/packages/faas/src/framework.ts b/packages/faas/src/framework.ts index 7c5616711ae..09b7b63bdc5 100644 --- a/packages/faas/src/framework.ts +++ b/packages/faas/src/framework.ts @@ -3,7 +3,7 @@ import { FaaSMiddleware, IFaaSConfigurationOptions, IMidwayFaaSApplication, - WebMiddleware + WebMiddleware, } from './interface'; import { BaseFramework, @@ -20,7 +20,7 @@ import { } from '@midwayjs/core'; import { dirname, resolve } from 'path'; -import { FUNC_KEY, LOGGER_KEY, PLUGIN_KEY, } from '@midwayjs/decorator'; +import { FUNC_KEY, LOGGER_KEY, PLUGIN_KEY } from '@midwayjs/decorator'; import SimpleLock from '@midwayjs/simple-lock'; import * as compose from 'koa-compose'; import { MidwayHooks } from './hooks'; @@ -29,7 +29,9 @@ const LOCK_KEY = '_faas_starter_start_key'; // const MIDWAY_FAAS_KEY = '__midway_faas__'; -export class MidwayFaaSFramework extends BaseFramework { +export class MidwayFaaSFramework extends BaseFramework< + IFaaSConfigurationOptions +> { protected defaultHandlerMethod = 'handler'; private globalMiddleware: string[]; protected funMappingStore: Map = new Map(); @@ -37,7 +39,9 @@ export class MidwayFaaSFramework extends BaseFramework) { + protected async beforeDirectoryLoad( + options: Partial + ) { this.logger = options.logger || console; this.globalMiddleware = this.configurationOptions.middleware || []; this.webApplication = this.defineApplicationProperties( @@ -80,9 +84,9 @@ export class MidwayFaaSFramework extends BaseFramework { - } + public async stop(): Promise {} public getApplication(): IMidwayApplication { return this.webApplication; @@ -156,8 +159,12 @@ export class MidwayFaaSFramework extends BaseFramework { - const mwIns = await this.getApplicationContext().getAsync(middlewareId); + public async generateMiddleware( + middlewareId: string + ): Promise { + const mwIns = await this.getApplicationContext().getAsync( + middlewareId + ); return mwIns.resolve(); } @@ -210,8 +217,9 @@ export class MidwayFaaSFramework extends BaseFramework { return this.generateMiddleware(middlewareId); - } + }, }); } diff --git a/packages/midway-schedule/agent.ts b/packages/midway-schedule/agent.ts index cd13108ec2f..fd5b522b2a1 100644 --- a/packages/midway-schedule/agent.ts +++ b/packages/midway-schedule/agent.ts @@ -1,7 +1,12 @@ -import { SCHEDULE_KEY, ScheduleOpts, getClassMetadata, getProviderId, listModule } from '@midwayjs/decorator'; - -export = (agent) => { - +import { + SCHEDULE_KEY, + ScheduleOpts, + getClassMetadata, + getProviderId, + listModule, +} from '@midwayjs/decorator'; + +export = agent => { if (!agent.schedule) { return; } @@ -44,5 +49,4 @@ export = (agent) => { instance.start(); } }); - }; diff --git a/packages/midway-schedule/app.ts b/packages/midway-schedule/app.ts index 43cf8f0c6c2..0e3d113b60e 100644 --- a/packages/midway-schedule/app.ts +++ b/packages/midway-schedule/app.ts @@ -1,8 +1,13 @@ -import { ScheduleOpts, SCHEDULE_KEY, getClassMetadata, listModule, getProviderId } from '@midwayjs/decorator'; +import { + ScheduleOpts, + SCHEDULE_KEY, + getClassMetadata, + listModule, + getProviderId, +} from '@midwayjs/decorator'; import * as is from 'is-type-of'; -export = (app) => { - +export = app => { // egg-schedule 的 app 里没有 schedule if (!app.runSchedule) { return; @@ -24,7 +29,7 @@ export = (app) => { const envList = opts.env; if (is.array(envList) && !envList.includes(env)) { app.coreLogger.info( - `[midway-schedule]: ignore schedule ${key} due to \`schedule.env\` not match`, + `[midway-schedule]: ignore schedule ${key} due to \`schedule.env\` not match` ); return; } @@ -34,6 +39,5 @@ export = (app) => { key, }; } - } }; diff --git a/packages/midway/cluster/master.js b/packages/midway/cluster/master.js index 63ae9de66ba..31e45fe71d6 100644 --- a/packages/midway/cluster/master.js +++ b/packages/midway/cluster/master.js @@ -2,15 +2,17 @@ const EggMaster = require('egg-cluster/lib/master'); const formatOptions = require('./utils').formatOptions; class Master extends EggMaster { - constructor(options) { options = formatOptions(options); super(options); - this.log('[master] egg version %s, egg-core version %s', + this.log( + '[master] egg version %s, egg-core version %s', + // eslint-disable-next-line node/no-extraneous-require require('egg/package').version, - require('egg-core/package').version); + // eslint-disable-next-line node/no-extraneous-require + require('egg-core/package').version + ); } - } module.exports = Master; diff --git a/packages/midway/cluster/utils.js b/packages/midway/cluster/utils.js index aff44648e3e..030972c5de5 100644 --- a/packages/midway/cluster/utils.js +++ b/packages/midway/cluster/utils.js @@ -1,8 +1,7 @@ 'use strict'; -const path = require('path'); - exports.isTypeScriptEnvironment = () => { + // eslint-disable-next-line node/no-deprecated-api return !!require.extensions['.ts']; }; @@ -11,13 +10,13 @@ exports.isTypeScriptEnvironment = () => { * @param options * @returns {*} */ -exports.formatOptions = (options) => { +exports.formatOptions = options => { options.framework = options.framework || 'midway'; - if(!options.baseDir) { + if (!options.baseDir) { options.baseDir = process.cwd(); } - if(typeof options.typescript === 'undefined') { + if (typeof options.typescript === 'undefined') { options.typescript = true; } diff --git a/packages/midway/server.js b/packages/midway/server.js index dd2790d1230..14d1713588b 100644 --- a/packages/midway/server.js +++ b/packages/midway/server.js @@ -17,8 +17,8 @@ let options = {}; try { const pkg = require(path.join(process.cwd(), 'package.json')); const serverOpts = pkg['midway-server-options']; - if(serverOpts) { - if(typeof serverOpts === 'string') { + if (serverOpts) { + if (typeof serverOpts === 'string') { options = require(path.join(process.cwd(), serverOpts)); } else { options = serverOpts; diff --git a/packages/mock/app/extend/application.js b/packages/mock/app/extend/application.js index b1d13adf0d7..8554371c680 100644 --- a/packages/mock/app/extend/application.js +++ b/packages/mock/app/extend/application.js @@ -1,3 +1,3 @@ -"use strict"; +'use strict'; module.exports = require('../../dist/app/extend/application'); diff --git a/packages/mock/bootstrap.d.ts b/packages/mock/bootstrap.d.ts index feca1731b5f..6fc578aa1ba 100644 --- a/packages/mock/bootstrap.d.ts +++ b/packages/mock/bootstrap.d.ts @@ -1,2 +1 @@ - -export * from './dist/bootstrap' +export * from './dist/bootstrap'; diff --git a/packages/mock/bootstrap.js b/packages/mock/bootstrap.js index 1d0237ed3ba..6973adc1269 100644 --- a/packages/mock/bootstrap.js +++ b/packages/mock/bootstrap.js @@ -3,7 +3,8 @@ // exports = require('./dist/bootstrap') function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; + // eslint-disable-next-line no-prototype-builtins + for (const p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } -Object.defineProperty(exports, "__esModule", { value: true }); -__export(require("./dist/bootstrap")); +Object.defineProperty(exports, '__esModule', { value: true }); +__export(require('./dist/bootstrap')); diff --git a/packages/mock/config/plugin.default.js b/packages/mock/config/plugin.default.js index ee6798253bb..c1a67068844 100644 --- a/packages/mock/config/plugin.default.js +++ b/packages/mock/config/plugin.default.js @@ -2,9 +2,9 @@ module.exports = { watcher: { - enable: false + enable: false, }, development: { - enable: false - } + enable: false, + }, }; diff --git a/packages/mock/package.json b/packages/mock/package.json index 253381d0bc0..a5c14dec8d6 100644 --- a/packages/mock/package.json +++ b/packages/mock/package.json @@ -31,13 +31,14 @@ }, "license": "MIT", "devDependencies": { - "@midwayjs/cli": "^1.0.x", - "@midwayjs/decorator": "^2.2.5" + "@midwayjs/cli": "^1.0.x" }, "dependencies": { "@midwayjs/bootstrap": "^2.2.5", "@midwayjs/core": "^2.2.5", + "@midwayjs/decorator": "^2.2.5", "egg-mock": "^3.21.0", + "fs-extra": "^8.0.1", "power-assert": "^1.6.1", "supertest": "^4.0.2" }, diff --git a/packages/mock/src/app/extend/application.ts b/packages/mock/src/app/extend/application.ts index 87a7cafb231..74e51f65439 100644 --- a/packages/mock/src/app/extend/application.ts +++ b/packages/mock/src/app/extend/application.ts @@ -1,24 +1,29 @@ -import { MidwayMockApplication, MockClassFunctionHandler } from '../../interface'; +import { + MidwayMockApplication, + MockClassFunctionHandler, +} from '../../interface'; interface MidwayMockApplicationInner extends MidwayMockApplication { _mockFn( service: string, methodName: string, /** {Object|Function|Error} - mock you data */ - fnOrData: any, + fnOrData: any ): void; } -export const mockClassFunction: MockClassFunctionHandler = function( +export const mockClassFunction: MockClassFunctionHandler = function ( this: MidwayMockApplicationInner, className: string, methodName: string, - fnOrData: any, + fnOrData: any ): void { const { applicationContext } = this; const def = applicationContext.registry.getDefinition(className); - if (! def) { - throw new TypeError(`def undefined with className: "${className}", methodName: "${methodName}"`); + if (!def) { + throw new TypeError( + `def undefined with className: "${className}", methodName: "${methodName}"` + ); } else { const clazz = def.path; this._mockFn(clazz.prototype, methodName, fnOrData); diff --git a/packages/mock/src/bootstrap.ts b/packages/mock/src/bootstrap.ts index d9544dd5c2c..c8d29ca1a6f 100644 --- a/packages/mock/src/bootstrap.ts +++ b/packages/mock/src/bootstrap.ts @@ -7,7 +7,9 @@ const isJest = process.env.MIDWAY_JEST_MODE === 'true'; // 由于使用Object.assign,丢了默认的mm执行函数,所以使用default输出mm export const mm: MidwayMock['default'] = mock.default; -export const app: MidwayMockApplication = mock.app(isJest ? {typescript: true} : {}); +export const app: MidwayMockApplication = mock.app( + isJest ? { typescript: true } : {} +); if (isJest) { (global as any).beforeAll(app.ready); @@ -17,7 +19,4 @@ if (isJest) { afterEach(mock.restore); -export { - assert, - mock, -}; +export { assert, mock }; diff --git a/packages/mock/src/interface.ts b/packages/mock/src/interface.ts index 7f6baa7812f..c7ff7bb32ea 100644 --- a/packages/mock/src/interface.ts +++ b/packages/mock/src/interface.ts @@ -25,12 +25,12 @@ export type MockClassFunctionHandler = ( ) => any; export interface MidwayMockApplication extends MockApplication { - applicationContext: IApplicationContext; - pluginContext: IApplicationContext; + applicationContext: IMidwayContainer; + pluginContext: IMidwayContainer; appDir: string; baseDir: string; enablePlugins: any; - getApplicationContext(): IApplicationContext; + getApplicationContext(): IMidwayContainer; getPluginContext(): IApplicationContext; getPlugin(pluginName: string): any; getLogger(name?: string): any; diff --git a/packages/mock/src/mock.ts b/packages/mock/src/mock.ts index 44d8852f3aa..73111a1c9f4 100644 --- a/packages/mock/src/mock.ts +++ b/packages/mock/src/mock.ts @@ -20,50 +20,66 @@ function mockContainer(options: MidwayApplicationOptions): MockContainer { return new MockContainer(options); } -const getDefaultFramework: () => string = () => resolveModule('midway') || resolveModule('midway-mirror'); +const getDefaultFramework: () => string = () => + resolveModule('midway') || resolveModule('midway-mirror'); export const mm = Object.assign({}, mock, { container: mockContainer, }) as MidwayMock; mm.app = (options = {}): MidwayMockApplication => { - if (process.env.MIDWAY_BASE_DIR && !options.baseDir) { options.baseDir = process.env.MIDWAY_BASE_DIR; } - if (process.env.MIDWAY_FRAMEWORK_PATH && !options.framework) { options.framework = process.env.MIDWAY_FRAMEWORK_PATH; } - // @ts-ignore - return mock.app(Object.assign({ - framework: options.framework || getDefaultFramework(), - typescript: isTypeScriptEnvironment(), - plugins: { - 'midway-mock': { - enable: true, - path: join(__dirname, '../') + if (process.env.MIDWAY_BASE_DIR && !options.baseDir) { + options.baseDir = process.env.MIDWAY_BASE_DIR; + } + if (process.env.MIDWAY_FRAMEWORK_PATH && !options.framework) { + options.framework = process.env.MIDWAY_FRAMEWORK_PATH; + } + return (mock as any).app( + Object.assign( + { + framework: options.framework || getDefaultFramework(), + typescript: isTypeScriptEnvironment(), + plugins: { + 'midway-mock': { + enable: true, + path: join(__dirname, '../'), + }, + watcher: false, + development: false, + }, }, - watcher: false, - development: false, - } - }, options)); + options + ) + ); }; mm.cluster = (options = {}) => { - if (process.env.MIDWAY_BASE_DIR && !options.baseDir) { options.baseDir = process.env.MIDWAY_BASE_DIR; } - if (process.env.MIDWAY_FRAMEWORK_PATH && !options.framework) { options.framework = process.env.MIDWAY_FRAMEWORK_PATH; } - // @ts-ignore - return mock.cluster(Object.assign({ - framework: options.framework || getDefaultFramework(), - typescript: isTypeScriptEnvironment(), - plugins: { - 'midway-mock': { - enable: true, - path: join(__dirname, '../') + if (process.env.MIDWAY_BASE_DIR && !options.baseDir) { + options.baseDir = process.env.MIDWAY_BASE_DIR; + } + if (process.env.MIDWAY_FRAMEWORK_PATH && !options.framework) { + options.framework = process.env.MIDWAY_FRAMEWORK_PATH; + } + return (mock as any).cluster( + Object.assign( + { + framework: options.framework || getDefaultFramework(), + typescript: isTypeScriptEnvironment(), + plugins: { + 'midway-mock': { + enable: true, + path: join(__dirname, '../'), + }, + watcher: false, + development: false, + }, }, - watcher: false, - development: false, - } - }, options)); + options + ) + ); }; export class MockContainer { - app: MidwayMockApplication; constructor(options: MidwayApplicationOptions = {}) { diff --git a/packages/mock/src/resolve.ts b/packages/mock/src/resolve.ts index b5b857b1934..d4e44642f6d 100644 --- a/packages/mock/src/resolve.ts +++ b/packages/mock/src/resolve.ts @@ -24,6 +24,7 @@ export function resolveModule(moduleName) { * @return {string} path */ export function retrieveModulePath(moduleName) { + // eslint-disable-next-line node/no-unsupported-features/node-builtins const paths = require.resolve.paths(moduleName); const moduleDir = paths.find(dir => { diff --git a/packages/mock/src/utils.ts b/packages/mock/src/utils.ts index 706defd7b59..0bb973c2316 100644 --- a/packages/mock/src/utils.ts +++ b/packages/mock/src/utils.ts @@ -1,5 +1,9 @@ import { BootstrapStarter } from '@midwayjs/bootstrap'; -import { IMidwayApplication, IMidwayFramework, MidwayFrameworkType } from '@midwayjs/core'; +import { + IMidwayApplication, + IMidwayFramework, + MidwayFrameworkType, +} from '@midwayjs/core'; import { isAbsolute, join } from 'path'; import { remove } from 'fs-extra'; import { clearAllModule } from '@midwayjs/decorator'; @@ -18,7 +22,14 @@ function getIncludeFramework(dependencies): string { } } -export async function create, U = T['configurationOptions']>(baseDir: string = process.cwd(), options?: U, customFrameworkName?: string | MidwayFrameworkType | object): Promise { +export async function create< + T extends IMidwayFramework, + U = T['configurationOptions'] +>( + baseDir: string = process.cwd(), + options?: U, + customFrameworkName?: string | MidwayFrameworkType | object +): Promise { clearAllModule(); let framework: T = null; let DefaultFramework = null; @@ -48,11 +59,11 @@ export async function create, U = T['configuration plugins: { 'egg-mock': { enable: true, - package: 'egg-mock' + package: 'egg-mock', }, watcher: false, development: false, - } + }, }) as any; } framework.configure(options); @@ -68,7 +79,7 @@ export async function create, U = T['configuration starter .configure({ - baseDir + baseDir, }) .load(framework); @@ -80,9 +91,21 @@ export async function create, U = T['configuration return framework; } -export async function createApp, U = T['configurationOptions'], Y = ReturnType>(baseDir: string = process.cwd(), options?: U, customFrameworkName?: string | MidwayFrameworkType | object): Promise { - const framework: T = await create(baseDir, options, customFrameworkName); - return framework.getApplication() as unknown as Y; +export async function createApp< + T extends IMidwayFramework, + U = T['configurationOptions'], + Y = ReturnType +>( + baseDir: string = process.cwd(), + options?: U, + customFrameworkName?: string | MidwayFrameworkType | object +): Promise { + const framework: T = await create( + baseDir, + options, + customFrameworkName + ); + return (framework.getApplication() as unknown) as Y; } export async function close(app: IMidwayApplication | IMidwayFramework) { diff --git a/packages/socketio/src/framework.ts b/packages/socketio/src/framework.ts index 03037df8f2b..dbd3b912d56 100644 --- a/packages/socketio/src/framework.ts +++ b/packages/socketio/src/framework.ts @@ -11,11 +11,23 @@ import { PRIVATE_META_DATA_KEY, } from '@midwayjs/core'; -import { IMidwaySocketIOApplication, IMidwaySocketIOConfigurationOptions, IMidwaySocketIOContext } from './interface'; +import { + IMidwaySocketIOApplication, + IMidwaySocketIOConfigurationOptions, + IMidwaySocketIOContext, +} from './interface'; import * as SocketIO from 'socket.io'; -import { WS_CONTROLLER_KEY, WS_EVENT_KEY, WSControllerOption, WSEventInfo, WSEventTypeEnum } from '@midwayjs/decorator'; +import { + WS_CONTROLLER_KEY, + WS_EVENT_KEY, + WSControllerOption, + WSEventInfo, + WSEventTypeEnum, +} from '@midwayjs/decorator'; -export class MidwaySocketIOFramework extends BaseFramework { +export class MidwaySocketIOFramework extends BaseFramework< + IMidwaySocketIOConfigurationOptions +> { protected app: IMidwaySocketIOApplication; public configure( @@ -25,16 +37,26 @@ export class MidwaySocketIOFramework extends BaseFramework) { + protected async afterDirectoryLoad( + options: Partial + ) { if (this.configurationOptions.webServer) { - this.app = SocketIO(this.configurationOptions.webServer, this.configurationOptions) as unknown as IMidwaySocketIOApplication; + this.app = (SocketIO( + this.configurationOptions.webServer, + this.configurationOptions + ) as unknown) as IMidwaySocketIOApplication; } else { - this.app = SocketIO(this.configurationOptions) as unknown as IMidwaySocketIOApplication; + this.app = (SocketIO( + this.configurationOptions + ) as unknown) as IMidwaySocketIOApplication; } this.defineApplicationProperties(this.app); this.app.use((socket, next) => { - socket.requestContext = new MidwayRequestContainer(socket, this.getApplicationContext()); + socket.requestContext = new MidwayRequestContainer( + socket, + this.getApplicationContext() + ); socket.requestContext.registerObject('socket', socket); next(); }); @@ -50,15 +72,18 @@ export class MidwaySocketIOFramework extends BaseFramework { - this.app.listen(this.configurationOptions.port, this.configurationOptions); + new Promise(resolve => { + this.app.listen( + this.configurationOptions.port, + this.configurationOptions + ); }); } } } protected async beforeStop(): Promise { - return new Promise((resolve) => { + return new Promise(resolve => { this.app.close(() => { resolve(); }); @@ -73,7 +98,9 @@ export class MidwaySocketIOFramework extends BaseFramework { return this.baseDir; @@ -129,7 +156,6 @@ export class MidwaySocketIOFramework extends BaseFramework { - const wsEventInfos: WSEventInfo[] = getClassMetadata( WS_EVENT_KEY, target @@ -139,43 +165,86 @@ export class MidwaySocketIOFramework extends BaseFramework { - const result = await controller[wsEventInfo.propertyName].apply(controller, args); - await this.bindSocketResponse(result, socket, wsEventInfo.propertyName, methodMap); + // eslint-disable-next-line prefer-spread + const result = await controller[wsEventInfo.propertyName].apply( + controller, + args + ); + await this.bindSocketResponse( + result, + socket, + wsEventInfo.propertyName, + methodMap + ); }); - } else if (wsEventInfo.eventType === WSEventTypeEnum.ON_DISCONNECTION) { + } else if ( + wsEventInfo.eventType === WSEventTypeEnum.ON_DISCONNECTION + ) { // on socket disconnect socket.on('disconnect', async (reason: string) => { - const result = await controller[wsEventInfo.propertyName].apply(controller, [reason]); - await this.bindSocketResponse(result, socket, wsEventInfo.propertyName, methodMap); + const result = await controller[ + wsEventInfo.propertyName + ].apply(controller, [reason]); + await this.bindSocketResponse( + result, + socket, + wsEventInfo.propertyName, + methodMap + ); }); - } else if (wsEventInfo.eventType === WSEventTypeEnum.ON_SOCKET_ERROR) { + } else if ( + wsEventInfo.eventType === WSEventTypeEnum.ON_SOCKET_ERROR + ) { // on socket error - socket.on('error', async (err) => { - const result = await controller[wsEventInfo.propertyName].apply(controller, [err]); - await this.bindSocketResponse(result, socket, wsEventInfo.propertyName, methodMap); + socket.on('error', async err => { + const result = await controller[ + wsEventInfo.propertyName + ].apply(controller, [err]); + await this.bindSocketResponse( + result, + socket, + wsEventInfo.propertyName, + methodMap + ); }); } else { // 存储每个方法对应的后置响应处理,供后续快速匹配 - methodMap[wsEventInfo.propertyName].responseEvents.push(wsEventInfo); + methodMap[wsEventInfo.propertyName].responseEvents.push( + wsEventInfo + ); } } } }); } - private async bindSocketResponse(result: any, socket: IMidwaySocketIOContext, propertyName: string, methodMap: { - responseEvents?: WSEventInfo[] - }) { + private async bindSocketResponse( + result: any, + socket: IMidwaySocketIOContext, + propertyName: string, + methodMap: { + responseEvents?: WSEventInfo[]; + } + ) { if (result && methodMap[propertyName]) { for (const wsEventInfo of methodMap[propertyName].responseEvents) { if (wsEventInfo.eventType === WSEventTypeEnum.EMIT) { @@ -184,8 +253,13 @@ export class MidwaySocketIOFramework extends BaseFramework { +export class MidwayExpressFramework extends BaseFramework< + IMidwayExpressConfigurationOptions +> { protected app: IMidwayExpressApplication; private controllerIds: string[] = []; public prioritySortRouters: Array<{ @@ -53,11 +56,16 @@ export class MidwayExpressFramework extends BaseFramework) { - this.app = express() as unknown as IMidwayExpressApplication; + protected async afterDirectoryLoad( + options: Partial + ) { + this.app = (express() as unknown) as IMidwayExpressApplication; this.defineApplicationProperties(this.app); this.app.use((req: IMidwayExpressRequest, res, next) => { - req.requestContext = new MidwayRequestContainer(req, this.getApplicationContext()); + req.requestContext = new MidwayRequestContainer( + req, + this.getApplicationContext() + ); req.requestContext.registerObject('req', req); req.requestContext.registerObject('res', res); req.requestContext.ready(); @@ -73,7 +81,7 @@ export class MidwayExpressFramework extends BaseFramework { if (this.configurationOptions.port) { - new Promise((resolve) => { + new Promise(resolve => { this.app.listen(this.configurationOptions.port, () => { resolve(); }); @@ -98,7 +106,7 @@ export class MidwayExpressFramework extends BaseFramework { const [controllerId, methodName] = controllerMapping.split('.'); return async (req, res, next) => { @@ -106,11 +114,16 @@ export class MidwayExpressFramework extends BaseFramework { - args[index] = await extractExpressLikeValue(type, propertyData)(req, res, next); + args[index] = await extractExpressLikeValue(type, propertyData)( + req, + res, + next + ); }) ); } const controller = await req.requestContext.getAsync(controllerId); + // eslint-disable-next-line prefer-spread const result = await controller[methodName].apply(controller, args); // implement response decorator @@ -170,7 +183,9 @@ export class MidwayExpressFramework extends BaseFramework(middlewareId); + const mwIns = await this.getApplicationContext().getAsync( + middlewareId + ); return mwIns.resolve(); } @@ -186,8 +201,8 @@ export class MidwayExpressFramework extends BaseFramework { @@ -207,7 +222,7 @@ export class MidwayExpressFramework extends BaseFramework { return this.baseDir; @@ -323,7 +341,7 @@ export class MidwayExpressFramework extends BaseFramework { return this.generateMiddleware(middlewareId); - } + }, }); } } diff --git a/packages/web-koa/src/framework.ts b/packages/web-koa/src/framework.ts index 1ea21070584..5ed4126333a 100644 --- a/packages/web-koa/src/framework.ts +++ b/packages/web-koa/src/framework.ts @@ -26,7 +26,7 @@ import { WEB_RESPONSE_KEY, WEB_RESPONSE_REDIRECT, WEB_ROUTER_KEY, - WEB_ROUTER_PARAM_KEY + WEB_ROUTER_PARAM_KEY, } from '@midwayjs/decorator'; import { IMidwayKoaApplication, @@ -34,13 +34,17 @@ import { IMidwayKoaConfigurationOptions, WebMiddleware, IMidwayKoaContext, - MiddlewareParamArray + MiddlewareParamArray, } from './interface'; import * as Router from 'koa-router'; import type { DefaultState, Middleware } from 'koa'; import * as koa from 'koa'; -export abstract class MidwayKoaBaseFramework extends BaseFramework { +export abstract class MidwayKoaBaseFramework< + T, + U extends IMidwayApplication & IMidwayKoaApplicationPlus, + CustomContext +> extends BaseFramework { protected app: U; private controllerIds: string[] = []; public prioritySortRouters: Array<{ @@ -61,19 +65,23 @@ export abstract class MidwayKoaBaseFramework { const [controllerId, methodName] = controllerMapping.split('.'); return async (ctx, next) => { const args = [ctx, next]; if (Array.isArray(routeArgsInfo)) { await Promise.all( - routeArgsInfo.map(async ({index, type, propertyData}) => { - args[index] = await extractKoaLikeValue(type, propertyData)(ctx, next); + routeArgsInfo.map(async ({ index, type, propertyData }) => { + args[index] = await extractKoaLikeValue(type, propertyData)( + ctx, + next + ); }) ); } const controller = await ctx.requestContext.getAsync(controllerId); + // eslint-disable-next-line prefer-spread const result = await controller[methodName].apply(controller, args); if (result) { ctx.body = result; @@ -102,7 +110,9 @@ export abstract class MidwayKoaBaseFramework(middlewareId); + const mwIns = await this.getApplicationContext().getAsync( + middlewareId + ); return mwIns.resolve(); } @@ -151,7 +161,8 @@ export abstract class MidwayKoaBaseFramework { @@ -190,11 +201,8 @@ export abstract class MidwayKoaBaseFramework { +export class MidwayKoaFramework extends MidwayKoaBaseFramework< + IMidwayKoaConfigurationOptions, + IMidwayKoaApplication, + IMidwayKoaContext +> { public configure( options: IMidwayKoaConfigurationOptions ): MidwayKoaFramework { @@ -269,10 +282,18 @@ export class MidwayKoaFramework extends MidwayKoaBaseFramework) { - this.app = new koa() as IMidwayKoaApplication; + protected async afterDirectoryLoad( + options: Partial + ) { + this.app = new koa< + DefaultState, + IMidwayKoaContext + >() as IMidwayKoaApplication; this.app.use(async (ctx, next) => { - ctx.requestContext = new MidwayRequestContainer(ctx, this.getApplicationContext()); + ctx.requestContext = new MidwayRequestContainer( + ctx, + this.getApplicationContext() + ); await ctx.requestContext.ready(); await next(); }); @@ -288,7 +309,7 @@ export class MidwayKoaFramework extends MidwayKoaBaseFramework { if (this.configurationOptions.port) { - new Promise((resolve) => { + new Promise(resolve => { this.app.listen(this.configurationOptions.port, () => { resolve(); }); @@ -300,7 +321,9 @@ export class MidwayKoaFramework extends MidwayKoaBaseFramework { return this.baseDir; @@ -336,7 +359,7 @@ export class MidwayKoaFramework extends MidwayKoaBaseFramework { return this.generateMiddleware(middlewareId); - } + }, }); } } diff --git a/packages/web-koa/src/index.ts b/packages/web-koa/src/index.ts index be15f766ac0..f55e61b0cc0 100644 --- a/packages/web-koa/src/index.ts +++ b/packages/web-koa/src/index.ts @@ -1,2 +1,5 @@ -export { MidwayKoaFramework as Framework, MidwayKoaBaseFramework } from './framework'; +export { + MidwayKoaFramework as Framework, + MidwayKoaBaseFramework, +} from './framework'; export * from './interface'; diff --git a/packages/web-koa/test/fixtures/base-app/src/controller/api.ts b/packages/web-koa/test/fixtures/base-app/src/controller/api.ts index a9d247f5445..8097d54cc50 100644 --- a/packages/web-koa/test/fixtures/base-app/src/controller/api.ts +++ b/packages/web-koa/test/fixtures/base-app/src/controller/api.ts @@ -34,7 +34,5 @@ export class APIController { @Get('/login') @Redirect('/') - async redirect() { - } - + async redirect() {} } diff --git a/packages/web/package.json b/packages/web/package.json index 29c0580ea3f..c516ce89c41 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -38,6 +38,8 @@ "@midwayjs/decorator": "^2.2.5", "@midwayjs/koa": "^2.2.5", "debug": "^4.1.1", + "egg-logger": "^2.4.2", + "mkdirp": "^1.0.4", "egg": "^2.28.0", "extend2": "^1.0.0" }, diff --git a/packages/web/src/agent.ts b/packages/web/src/agent.ts index a7acfbd511b..e00cd82f431 100644 --- a/packages/web/src/agent.ts +++ b/packages/web/src/agent.ts @@ -15,7 +15,7 @@ class AppBootHook { if (this.app.options['isClusterMode'] !== false) { this.framework = new Framework().configure({ processType: 'agent', - app: this.app + app: this.app, }); this.bootstrap = new BootstrapStarter(); this.bootstrap @@ -28,9 +28,7 @@ class AppBootHook { } } - async willReady() { - } - + async willReady() {} } module.exports = AppBootHook; diff --git a/packages/web/src/app.ts b/packages/web/src/app.ts index b038fb34456..d4bffc53a40 100644 --- a/packages/web/src/app.ts +++ b/packages/web/src/app.ts @@ -22,13 +22,11 @@ class AppBootHook { if (this.app.options['isClusterMode'] !== false) { this.framework = new Framework().configure({ processType: 'application', - app: this.app + app: this.app, }); - Bootstrap - .configure({ - baseDir: this.app.appDir, - }) - .load(this.framework); + Bootstrap.configure({ + baseDir: this.app.appDir, + }).load(this.framework); await Bootstrap.run(); this.app.options['webFramework'] = this.framework; } @@ -43,12 +41,9 @@ class AppBootHook { this.app.use(this.app.middlewares[name](this.app.config[name])); } } - - } - - async willReady() { } + async willReady() {} } module.exports = AppBootHook; diff --git a/packages/web/src/application.ts b/packages/web/src/application.ts index 3ac3fdba851..d4f466fae1a 100644 --- a/packages/web/src/application.ts +++ b/packages/web/src/application.ts @@ -20,12 +20,11 @@ const EGG_PATH = Symbol.for('egg#eggPath'); export const createAppWorkerLoader = AppWorkerLoader => { class EggAppWorkerLoader extends (AppWorkerLoader as any) { - app: IMidwayWebApplication & { appOptions: { typescript?: boolean; isTsMode?: boolean; - }, + }; appDir: string; baseDir: string; middlewares: []; @@ -37,7 +36,10 @@ export const createAppWorkerLoader = AppWorkerLoader => { if (this.app.appOptions.typescript || this.app.appOptions.isTsMode) { process.env.EGG_TYPESCRIPT = 'true'; } - const result = parseNormalDir(this.app.appOptions['baseDir'], this.app.appOptions.isTsMode); + const result = parseNormalDir( + this.app.appOptions['baseDir'], + this.app.appOptions.isTsMode + ); this.baseDir = result.baseDir; this.options.baseDir = this.baseDir; this.appDir = this.app.appDir = result.appDir; @@ -113,13 +115,15 @@ export const createAppWorkerLoader = AppWorkerLoader => { const appInfo: EggAppInfo | undefined = super.getAppInfo(); // ROOT == HOME in prod env this.appInfo = extend(true, appInfo, { - root: appInfo.env === 'local' || appInfo.env === 'unittest' ? this.appDir : appInfo.root, + root: + appInfo.env === 'local' || appInfo.env === 'unittest' + ? this.appDir + : appInfo.root, appDir: this.appDir, }); } return this.appInfo; } - } return EggAppWorkerLoader as any; @@ -127,13 +131,15 @@ export const createAppWorkerLoader = AppWorkerLoader => { export const createAgentWorkerLoader = AppWorkerLoader => { class EggAppWorkerLoader extends (AppWorkerLoader as any) { - getEggPaths() { if (!this.appDir) { if (this.app.appOptions.typescript || this.app.appOptions.isTsMode) { process.env.EGG_TYPESCRIPT = 'true'; } - const result = parseNormalDir(this.app.appOptions['baseDir'], this.app.appOptions.isTsMode); + const result = parseNormalDir( + this.app.appOptions['baseDir'], + this.app.appOptions.isTsMode + ); this.baseDir = result.baseDir; this.options.baseDir = this.baseDir; this.appDir = this.app.appDir = result.appDir; @@ -150,7 +156,10 @@ export const createAgentWorkerLoader = AppWorkerLoader => { const appInfo: EggAppInfo | undefined = super.getAppInfo(); // ROOT == HOME in prod env this.appInfo = extend(true, appInfo, { - root: appInfo.env === 'local' || appInfo.env === 'unittest' ? this.appDir : appInfo.root, + root: + appInfo.env === 'local' || appInfo.env === 'unittest' + ? this.appDir + : appInfo.root, appDir: this.appDir, }); } @@ -164,6 +173,7 @@ export const createAgentWorkerLoader = AppWorkerLoader => { export const createEggApplication = Application => { class EggApplication extends (Application as any) { constructor(options) { + // eslint-disable-next-line constructor-super super(options); } @@ -191,10 +201,16 @@ export const createEggApplication = Application => { return this.applicationContext; } - generateController(controllerMapping: string, - routeArgsInfo?: RouterParamValue[], - routerResponseData?: any []) { - return this.midwayWebFramework.generateController(controllerMapping, routeArgsInfo, routerResponseData); + generateController( + controllerMapping: string, + routeArgsInfo?: RouterParamValue[], + routerResponseData?: any[] + ) { + return this.midwayWebFramework.generateController( + controllerMapping, + routeArgsInfo, + routerResponseData + ); } async generateMiddleware(middlewareId: string) { @@ -204,7 +220,6 @@ export const createEggApplication = Application => { get baseDir() { return this.loader.baseDir; } - } return EggApplication as any; @@ -213,6 +228,7 @@ export const createEggApplication = Application => { export const createEggAgent = Agent => { class EggAgent extends (Agent as any) { constructor(options) { + // eslint-disable-next-line constructor-super super(options); } @@ -257,7 +273,6 @@ const EggAgentWorkerLoader = createAgentWorkerLoader(AgentWorkerLoader); const BaseEggAgent = createEggAgent(Agent); export class EggApplication extends BaseEggApplication { - get [EGG_LOADER]() { return EggAppWorkerLoader; } @@ -268,7 +283,6 @@ export class EggApplication extends BaseEggApplication { } export class EggAgent extends BaseEggAgent { - get [EGG_LOADER]() { return EggAgentWorkerLoader; } diff --git a/packages/web/src/config/config.default.ts b/packages/web/src/config/config.default.ts index f4ec75df514..1344f61174b 100644 --- a/packages/web/src/config/config.default.ts +++ b/packages/web/src/config/config.default.ts @@ -1,4 +1,3 @@ - const path = require('path'); const mkdirp = require('mkdirp'); const os = require('os'); @@ -13,7 +12,7 @@ module.exports = (appInfo: EggAppInfo) => { // 修改默认的日志名 exports.logger = { - appLogName: `midway-web.log`, + appLogName: 'midway-web.log', coreLogName: 'midway-core.log', agentLogName: 'midway-agent.log', }; @@ -23,7 +22,7 @@ module.exports = (appInfo: EggAppInfo) => { exports.security = { csrf: { ignoreJSON: false, - } + }, }; // alinode runtime 写入的日志策略是: 如果 NODE_LOG_DIR 有设置,写入 NODE_LOG_DIR 设置的目录;否则为 /tmp @@ -40,9 +39,7 @@ module.exports = (appInfo: EggAppInfo) => { path.join(appInfo.root, `logs/${appInfo.pkg.name}/common-error.log`), path.join(appInfo.root, 'logs/stderr.log'), ], - packages: [ - path.join(appInfo.appDir, 'package.json'), - ] + packages: [path.join(appInfo.appDir, 'package.json')], }; return exports; diff --git a/packages/web/src/config/plugin.ts b/packages/web/src/config/plugin.ts index 6d916df147b..ff8b4c56321 100644 --- a/packages/web/src/config/plugin.ts +++ b/packages/web/src/config/plugin.ts @@ -1,3 +1 @@ -export default { - -}; +export default {}; diff --git a/packages/web/src/framework.ts b/packages/web/src/framework.ts index 7a2a7290e69..37ab36c93d3 100644 --- a/packages/web/src/framework.ts +++ b/packages/web/src/framework.ts @@ -1,12 +1,26 @@ -import { IMidwayBootstrapOptions, MidwayFrameworkType, MidwayProcessTypeEnum, safelyGet } from '@midwayjs/core'; -import { CONFIG_KEY, ControllerOption, LOGGER_KEY, PLUGIN_KEY, } from '@midwayjs/decorator'; -import { IMidwayWebConfigurationOptions, } from './interface'; +import { + IMidwayBootstrapOptions, + MidwayFrameworkType, + MidwayProcessTypeEnum, + safelyGet, +} from '@midwayjs/core'; +import { + CONFIG_KEY, + ControllerOption, + LOGGER_KEY, + PLUGIN_KEY, +} from '@midwayjs/decorator'; +import { IMidwayWebConfigurationOptions } from './interface'; import { MidwayKoaBaseFramework } from '@midwayjs/koa'; import { EggRouter } from '@eggjs/router'; import { resolve } from 'path'; import { Application, Router, Context } from 'egg'; -export class MidwayWebFramework extends MidwayKoaBaseFramework { +export class MidwayWebFramework extends MidwayKoaBaseFramework< + IMidwayWebConfigurationOptions, + Application, + Context +> { protected app: Application; public configurationOptions: IMidwayWebConfigurationOptions; public prioritySortRouters: Array<{ @@ -28,14 +42,14 @@ export class MidwayWebFramework extends MidwayKoaBaseFramework - ) { + protected async beforeInitialize(options: Partial) { options.ignore = options.ignore || []; options.ignore.push('**/app/extend/**'); } - protected async afterDirectoryLoad(options: Partial) { + protected async afterDirectoryLoad( + options: Partial + ) { if (this.isTsMode) { process.env.EGG_TYPESCRIPT = 'true'; } @@ -95,7 +109,7 @@ export class MidwayWebFramework extends MidwayKoaBaseFramework { if (this.configurationOptions.port) { - new Promise((resolve) => { + new Promise(resolve => { this.app.listen(this.configurationOptions.port, () => { resolve(); }); @@ -159,8 +173,7 @@ export class MidwayWebFramework extends MidwayKoaBaseFramework { if (isTypeScriptEnv) { return { baseDir: join(baseDir, 'src'), - appDir: baseDir + appDir: baseDir, }; } else { return { baseDir: join(baseDir, 'dist'), - appDir: baseDir + appDir: baseDir, }; } } else { // js baseDir return { baseDir, - appDir: baseDir + appDir: baseDir, }; } };