Skip to content

Commit

Permalink
feat: add namespace feature (#386)
Browse files Browse the repository at this point in the history
* add namespace feature

* modified

* remove only

* fix bug

* add sub package load
  • Loading branch information
kurten authored Feb 15, 2020
1 parent 78d74d0 commit bb2a8c8
Show file tree
Hide file tree
Showing 30 changed files with 271 additions and 91 deletions.
29 changes: 28 additions & 1 deletion packages/midway-core/src/common/util.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { dirname, resolve, sep } from 'path';
import { MAIN_MODULE_KEY } from '../interface';

export const safeRequire = p => {
if (p.startsWith(`.${sep}`) || p.startsWith(`..${sep}`)) {
p = resolve(dirname(module.parent.filename), p);
}

try {
return require(p);
} catch (err) {
Expand Down Expand Up @@ -49,3 +49,30 @@ export function safelyGet(list: string | string[], obj?: object): any {

return willReturn;
}
/**
* 生成带 namespace 的 provideId
* @param provideId provideId
* @param namespace namespace
*/
export function generateProvideId(provideId: string, namespace?: string) {
if (namespace && namespace !== MAIN_MODULE_KEY) {
if (provideId.includes('@')) {
return provideId.substr(1);
}
if (provideId.includes(':')) {
return provideId;
}
return namespace + ':' + provideId;
}
return provideId;
}
/**
* 剔除 @ 符号
* @param provideId provideId
*/
export function parsePrefix(provideId: string) {
if (provideId.includes('@')) {
return provideId.substr(1);
}
return provideId;
}
7 changes: 5 additions & 2 deletions packages/midway-core/src/context/applicationContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ManagedResolverFactory } from './managedResolverFactory';
import { NotFoundError } from '../common/notFoundError';

import assert = require('assert');
import { parsePrefix } from '../common/util';

export const ContextEvent = {
START: 'start',
Expand Down Expand Up @@ -203,6 +204,7 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto

get<T>(identifier: ObjectIdentifier, args?: any): T {
// 因为在这里拿不到类名, NotFoundError 类的错误信息在 ManagedResolverFactory.ts createAsync 方法中增加错误类名
identifier = parsePrefix(identifier);

if (this.registry.hasObject(identifier)) {
return this.registry.getObject(identifier);
Expand All @@ -223,11 +225,12 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto
if (!definition) {
throw new NotFoundError(identifier);
}
return this.getManagedResolverFactory().create(definition, args);
return this.getManagedResolverFactory().create({ definition, args });
}

async getAsync<T>(identifier: ObjectIdentifier, args?: any): Promise<T> {
// 因为在这里拿不到类名, NotFoundError 类的错误信息在 ManagedResolverFactory.ts createAsync 方法中增加错误类名
identifier = parsePrefix(identifier);

if (this.registry.hasObject(identifier)) {
return this.registry.getObject(identifier);
Expand All @@ -242,7 +245,7 @@ export class BaseApplicationContext implements IApplicationContext, IObjectFacto
throw new NotFoundError(identifier);
}

return this.getManagedResolverFactory().createAsync(definition, args);
return this.getManagedResolverFactory().createAsync({ definition, args });
}

addLifeCycle(lifeCycle: ILifeCycle): void {
Expand Down
94 changes: 58 additions & 36 deletions packages/midway-core/src/context/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import { CONFIGURATION_KEY, InjectionConfigurationOptions, getClassMetadata } from '@midwayjs/decorator';
import * as is from 'is-type-of';
import { dirname, isAbsolute, join } from 'path';
import { IContainerConfiguration, IMidwayContainer } from '../interface';
import { IContainerConfiguration, IMidwayContainer, MAIN_MODULE_KEY } from '../interface';
import { isPath, safeRequire } from '../common/util';

const debug = require('debug')('midway:container:configuration');

export class ContainerConfiguration implements IContainerConfiguration {
container: IMidwayContainer;
importDirectory = [];
imports: string[] = [];
namespace: string;
loadDirs: string[] = [];
importObjects: object = new Map();

constructor(container) {
this.container = container;
}

addLoadDir(dir: string) {
this.loadDirs.push(dir);
}

addImports(imports: string[] = [], baseDir?: string) {
// 处理 imports
for (let importPackage of imports) {
// 把相对路径转为绝对路径
if (isPath(importPackage)) {
if (!isAbsolute(importPackage)) {
importPackage = join(baseDir || this.container.baseDir, importPackage);
}
} else {
// for package
importPackage = this.resolvePackageBaseDir(importPackage);
}
this.imports.push(importPackage);
this.load(importPackage);
for (const importPackage of imports) {
// for package
const subContainerConfiguration = this.container.createConfiguration();
const subPackageDir = this.resolvePackageBaseDir(importPackage);
debug('import package => %s dir => %s.', importPackage, subPackageDir);
subContainerConfiguration.addLoadDir(subPackageDir);
subContainerConfiguration.load(subPackageDir);
}
}

Expand All @@ -38,40 +39,58 @@ export class ContainerConfiguration implements IContainerConfiguration {
}

addImportConfigs(importConfigs: string[], baseDir: string) {
debug('import configs %j baseDir => %s.', importConfigs, baseDir);
if (importConfigs && importConfigs.length) {
this.container.getConfigService().add(importConfigs.map(importConfigPath => {
return join(baseDir || this.container.baseDir, importConfigPath);
}));
}
}

private resolvePackageBaseDir(packageName: string) {
return dirname(require.resolve(packageName));
private resolvePackageBaseDir(packageName: string, baseDir?: string) {
// 把相对路径转为绝对路径
if (isPath(packageName)) {
if (!isAbsolute(packageName)) {
packageName = join(baseDir || this.container.baseDir, packageName);
}
return packageName;
}
try {
return dirname(require.resolve(packageName));
} catch (e) { /* ignore */ }
return join(baseDir || this.container.baseDir, '../node_modules', packageName);
}

load(packageName: string) {
let configuration;
let baseDir = packageName;
if (isPath(packageName)) {
const pkg = safeRequire(join(packageName, 'package.json'));
if (pkg && pkg.main) {
// 找到 package.json 中的 main 指定的文件目录
baseDir = dirname(join(packageName, pkg.main));
configuration = safeRequire(join(baseDir, 'configuration'));
const packageBaseDir = this.resolvePackageBaseDir(packageName);
debug('load %s => %s.', packageName, packageBaseDir);
let pkg = safeRequire(join(packageBaseDir, 'package.json'));
if (!pkg) {
pkg = safeRequire(join(packageBaseDir, '../', 'package.json'));
}
debug('safeRequire pkg.name => %s, from %s.', pkg ? pkg.name : undefined, packageBaseDir);

if (pkg) {
if (this.namespace !== MAIN_MODULE_KEY) {
this.namespace = pkg.midwayNamespace ? pkg.midwayNamespace : pkg.name;
}
if (!configuration) {
// 找外层目录
configuration = safeRequire(join(packageName, 'configuration'));
let cfgFile;
if (pkg.main) {
const cfgFileDir = dirname(join(packageBaseDir, pkg.main));
cfgFile = join(cfgFileDir, 'configuration');
configuration = safeRequire(cfgFile);
debug('configuration file path one => %s.', cfgFile);
}
} else {
// 查找包中的文件
baseDir = this.resolvePackageBaseDir(packageName);
configuration = safeRequire(join(baseDir, 'configuration'));
if (!configuration) {
configuration = safeRequire(`${packageName}/configuration`);
cfgFile = `${packageBaseDir}/configuration`;
configuration = safeRequire(cfgFile);
debug('configuration file path two => %s.', cfgFile);
}
}
this.loadConfiguration(configuration, baseDir);
debug('packageName => %s namespace => %s configuration file => %s.',
packageName, this.namespace, configuration ? true : false);
this.loadConfiguration(configuration, packageBaseDir);
}

loadConfiguration(configuration, baseDir) {
Expand All @@ -83,9 +102,12 @@ export class ContainerConfiguration implements IContainerConfiguration {
CONFIGURATION_KEY,
configurationExport
);

debug('configuration export %j.', configurationOptions);
if (configurationOptions) {
this.addImports(configurationOptions.imports, baseDir);
if (this.namespace !== MAIN_MODULE_KEY && configurationOptions.namespace) {
this.namespace = configurationOptions.namespace;
}
this.addImports(configurationOptions.imports);
this.addImportObjects(configurationOptions.importObjects);
this.addImportConfigs(configurationOptions.importConfigs, baseDir);
}
Expand All @@ -94,7 +116,7 @@ export class ContainerConfiguration implements IContainerConfiguration {
}

getImportDirectory() {
return this.imports;
return this.loadDirs;
}

private getConfigurationExport(exports): any[] {
Expand Down
10 changes: 6 additions & 4 deletions packages/midway-core/src/context/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { ManagedReference, ManagedValue } from './managed';
import { FunctionDefinition } from '../definitions/functionDefinition';
import { BaseApplicationContext } from './applicationContext';
import { recursiveGetMetadata } from '../common/reflectTool';
import { generateProvideId } from '../common/util';

const is = require('is-type-of');
const debug = require('debug')(`injection:Container:${process.pid}`);
const debug = require('debug')(`midway:container:${process.pid}`);

export class Container extends BaseApplicationContext implements IContainer {
id = '';
Expand All @@ -23,7 +24,7 @@ export class Container extends BaseApplicationContext implements IContainer {
bind<T>(identifier: ObjectIdentifier, target: T, options?: ObjectDefinitionOptions): void;
bind<T>(identifier: ObjectIdentifier, target: T, options?: ObjectDefinitionOptions): void {
let definition;
// definition.autowire = true;

if (is.class(identifier) || is.function(identifier)) {
options = target;
target = identifier as any;
Expand All @@ -39,6 +40,7 @@ export class Container extends BaseApplicationContext implements IContainer {

definition.path = target;
definition.id = identifier;
definition.namespace = options ? options.namespace : '';

debug(`=> bind and build definition, id = [${definition.id}]`);

Expand All @@ -51,7 +53,7 @@ export class Container extends BaseApplicationContext implements IContainer {
const propertyMeta = constructorMetaData[ i ];
if (propertyMeta) {
const refManagedIns = new ManagedReference();
refManagedIns.name = propertyMeta[ 0 ].value;
refManagedIns.name = generateProvideId(propertyMeta[ 0 ].value, definition.namespace);
definition.constructorArgs.push(refManagedIns);
} else {
// inject empty value
Expand All @@ -69,7 +71,7 @@ export class Container extends BaseApplicationContext implements IContainer {
for (const metaKey in metaData) {
for (const propertyMeta of metaData[ metaKey ]) {
const refManaged = new ManagedReference();
refManaged.name = propertyMeta.value;
refManaged.name = generateProvideId(propertyMeta.value, definition.namespace);
definition.properties.set(metaKey, refManaged);
}
}
Expand Down
13 changes: 8 additions & 5 deletions packages/midway-core/src/context/managedResolverFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {
IManagedResolver,
IObjectDefinition,
REQUEST_CTX_KEY,
REQUEST_OBJ_CTX_KEY
REQUEST_OBJ_CTX_KEY,
IManagedResolverFactoryCreateOptions
} from '../interface';
import { ObjectProperties } from '../definitions/properties';
import { NotFoundError } from '../common/notFoundError';
Expand Down Expand Up @@ -278,12 +279,12 @@ class ObjectResolver extends BaseManagedResolver {

resolve(managed: IManagedInstance): any {
const mo = managed as ManagedObject;
return this._factory.create(mo.definition, null);
return this._factory.create({ definition: mo.definition });
}

async resolveAsync(managed: IManagedInstance): Promise<any> {
const mo = managed as ManagedObject;
return this._factory.createAsync(mo.definition, null);
return this._factory.createAsync({ definition: mo.definition });
}
}

Expand Down Expand Up @@ -364,7 +365,8 @@ export class ManagedResolverFactory {
* @param definition 对象定义
* @param args 参数
*/
create(definition: IObjectDefinition, args: any): any {
create(opt: IManagedResolverFactoryCreateOptions): any {
const { definition, args } = opt;
if (definition.isSingletonScope() &&
this.singletonCache.has(definition.id)) {
return this.singletonCache.get(definition.id);
Expand Down Expand Up @@ -453,7 +455,8 @@ export class ManagedResolverFactory {
* @param definition 对象定义
* @param args 参数
*/
async createAsync(definition: IObjectDefinition, args: any): Promise<any> {
async createAsync(opt: IManagedResolverFactoryCreateOptions): Promise<any> {
const { definition, args } = opt;
if (definition.isSingletonScope() &&
this.singletonCache.has(definition.id)) {
return this.singletonCache.get(definition.id);
Expand Down
Loading

0 comments on commit bb2a8c8

Please sign in to comment.