This commit is contained in:
crusader 2017-08-01 14:23:34 +09:00
parent 6a9cc22a06
commit c5358742ce
21 changed files with 199 additions and 120 deletions

View File

@ -15,7 +15,7 @@ const Configuration = (qualifier?: string | symbol ) => createDecorator('Configu
throw new Error('Cannot apply @Injectable or @Injectable stereotype decorator multiple times.');
}
configurationDefinition = getConfigurationDefinition(target, true);
configurationDefinition = getConfigurationDefinition(target.prototype, true);
configurationDefinition.Stereotype = InjectableSterotype.CONFIGURATION;
configurationDefinition.Qualifier = validateQualifier(target.prototype, qualifier);

View File

@ -1,6 +1,8 @@
import { ClassType, PropertyType } from '@loafer/core/constants';
interface PouchConfig {
qualifier?: string | symbol;
type?: any;
qualifier?: PropertyType;
type?: ClassType;
}
export default PouchConfig;

View File

@ -15,7 +15,7 @@ const Service = (qualifier?: string | symbol ) => createDecorator('Service', {
throw new Error('Cannot apply @Injectable or @Injectable stereotype decorator multiple times.');
}
injectableDefinition = getInjectableDefinition(target, true);
injectableDefinition = getInjectableDefinition(target.prototype, true);
injectableDefinition.Stereotype = InjectableSterotype.SERVICE;
injectableDefinition.Qualifier = validateQualifier(target.prototype, qualifier);

View File

@ -1,20 +1,20 @@
import { DESIGN_RETURNTYPE } from '@loafer/core/constants';
import { ClassType, DESIGN_RETURNTYPE, PropertyType } from '@loafer/core/constants';
import InjectableDefinition from '@loafer/context/definition/InjectableDefinition';
import PouchConfig from '@loafer/context/decorator/PouchConfig';
class ConfigurationDefinition extends InjectableDefinition {
protected _qualifier: string | symbol = undefined;
protected _qualifier: PropertyType = undefined;
protected _pouchMap: Map<string, PouchConfig>;
public constructor(type: Object) {
super(type);
public constructor(clazz: ClassType) {
super(clazz);
}
public addPouch(propertyKey: string, pouchConfig: PouchConfig): void {
if (undefined === this._pouchMap) {
this._pouchMap = new Map();
}
let returnType: any = Reflect.getMetadata(DESIGN_RETURNTYPE, this._type, propertyKey);
let returnType: any = Reflect.getMetadata(DESIGN_RETURNTYPE, this._clazz, propertyKey);
if (undefined === pouchConfig.type) {
pouchConfig.type = returnType;

View File

@ -1,21 +1,22 @@
import { ClassType, PropertyType } from '@loafer/core/constants';
import PouchDefinition from '@loafer/pouches/factory/config/PouchDefinition';
import { InjectableSterotype, PouchScope } from '@loafer/pouches/constants';
class InjectableDefinition implements PouchDefinition {
protected _type: Object;
protected _clazz: ClassType;
protected _stereotype: InjectableSterotype;
protected _scope: PouchScope = PouchScope.SINGLETON;
protected _qualifier: string | symbol = undefined;
protected _qualifier: PropertyType = undefined;
protected _postConstruct: Set<string> = undefined;
protected _preDestroy: Set<string> = undefined;
public constructor(type: Object) {
this._type = type;
public constructor(clazz: ClassType) {
this._clazz = clazz;
this._stereotype = InjectableSterotype.INJECTABLE;
}
public get Type(): Object {
return this._type;
public get Clazz(): ClassType {
return this._clazz;
}
public get Stereotype(): InjectableSterotype {
@ -34,11 +35,11 @@ class InjectableDefinition implements PouchDefinition {
this._scope = scope;
}
public get Qualifier(): string | symbol {
public get Qualifier(): PropertyType {
return this._qualifier;
}
public set Qualifier(qualifier: string | symbol) {
public set Qualifier(qualifier: PropertyType) {
this._qualifier = qualifier;
}

View File

@ -1,5 +1,6 @@
import {
Construtorable,
ClassType,
PropertyType,
} from '@loafer/core/constants';
import AppContext from '@loafer/context/AppContext';
@ -17,12 +18,11 @@ class DefaultAppContext implements AppContext {
return this.pouchFactory;
}
public getPouch<T>(type: Construtorable<T>, ...args: any[]): T {
return this.pouchFactory.getPouch(type, args);
public getPouch(qualifier: PropertyType, clazz: ClassType, ...args: any[]): any {
return this.pouchFactory.getPouch(qualifier, clazz, args);
}
public getPouchByQualifier<T>(type: Construtorable<T>, qualifier: string | symbol, ...args: any[]): T {
return this.pouchFactory.getPouchByQualifier(type, qualifier, args);
public getPouchByType(clazz: ClassType, qualifier: PropertyType, ...args: any[]): any {
return this.pouchFactory.getPouchByType(clazz, qualifier, args);
}
}

View File

@ -1,6 +1,7 @@
import { ClassType } from '@loafer/core/constants';
import getClassMetadata from '@loafer/core/util/metadata/getClassMetadata';
import { CONTEXT_INJECTABLE_DEFINITION } from '@loafer/context/constants';
import ConfigurationDefinition from '@loafer/context/definition/ConfigurationDefinition';
export const getConfigurationDefinition = (target: Object, isCreate: boolean = false) =>
getClassMetadata(target, CONTEXT_INJECTABLE_DEFINITION, ConfigurationDefinition, isCreate);
export const getConfigurationDefinition = (clazz: ClassType, isCreate: boolean = false) =>
getClassMetadata(clazz, CONTEXT_INJECTABLE_DEFINITION, ConfigurationDefinition, isCreate);

View File

@ -1,6 +1,7 @@
import { ClassType } from '@loafer/core/constants';
import getClassMetadata from '@loafer/core/util/metadata/getClassMetadata';
import { CONTEXT_INJECTABLE_DEFINITION } from '@loafer/context/constants';
import InjectableDefinition from '@loafer/context/definition/InjectableDefinition';
export const getInjectableDefinition = (target: Object, isCreate: boolean = false) =>
getClassMetadata(target, CONTEXT_INJECTABLE_DEFINITION, InjectableDefinition, isCreate);
export const getInjectableDefinition = (clazz: ClassType, isCreate: boolean = false) =>
getClassMetadata(clazz, CONTEXT_INJECTABLE_DEFINITION, InjectableDefinition, isCreate);

View File

@ -1,4 +1,6 @@
export type Construtorable<T> = {new(...args: any[]): T};
export type ClassType = Object;
export type PropertyType = string | symbol;
export enum DecoratorType {
CLASS,

View File

@ -1,21 +1,25 @@
export type MetadataDefinable<T> = {new(target: Function): T};
import {
ClassType,
} from '@loafer/core/constants';
const getClassMetadata = <DefinitionType>(target: Object,
export type MetadataDefinable<T> = {new(clazz: ClassType): T};
const getClassMetadata = <DefinitionType>(clazz: ClassType,
metadataKey: any,
definitionType: MetadataDefinable<DefinitionType>,
isCreate: boolean = false): DefinitionType => {
let definition: DefinitionType;
if (Reflect.hasOwnMetadata(metadataKey, target) !== true) {
if (Reflect.hasOwnMetadata(metadataKey, clazz) !== true) {
if (!isCreate) {
return undefined;
}
definition = Object.create(definitionType.prototype);
definition.constructor.call(definition, target);
definition.constructor.call(definition, clazz);
Reflect.defineMetadata(metadataKey, definition, target);
Reflect.defineMetadata(metadataKey, definition, clazz);
} else {
definition = Reflect.getMetadata(metadataKey, target);
definition = Reflect.getMetadata(metadataKey, clazz);
}
return definition;
};

View File

@ -1,7 +1,9 @@
import { ClassType, PropertyType } from '@loafer/core/constants';
interface InjectConfig {
qualifier?: string | symbol;
qualifier?: PropertyType;
required?: boolean;
type?: any;
clazz?: ClassType;
}
export default InjectConfig;

View File

@ -1,33 +1,39 @@
import {
ClassType,
DecoratorType,
DESIGN_PARAMTYPES,
DESIGN_TYPE,
PropertyType,
} from '@loafer/core/constants';
import { InjectSterotype } from '@loafer/pouches/constants';
import { validateQualifier } from '@loafer/pouches/util/qualifier';
import InjectConfig from '@loafer/pouches/decorator/InjectConfig';
import * as CoreConstants from '@loafer/core/constants';
export interface InjectItem {
stereotype: InjectSterotype;
decoratorType: CoreConstants.DecoratorType;
decoratorType: DecoratorType;
propertyConfig?: InjectConfig;
parameterConfigMap?: Map<number, InjectConfig>;
}
class InjectDefinition {
protected target: Object;
protected injectMap: Map<string | symbol, InjectItem>;
protected clazz: ClassType;
protected injectMap: Map<PropertyType, InjectItem>;
public constructor(target: Object) {
this.target = target;
public constructor(clazz: ClassType) {
this.clazz = clazz;
this.injectMap = new Map();
}
public get injectors(): Map<string | symbol, InjectItem> {
public get injectors(): Map<PropertyType, InjectItem> {
return this.injectMap;
}
/**
* addInject
*/
public addInject(injectConfig: InjectConfig, propertyKey: string | symbol, parameterIndex?: number): void {
injectConfig.qualifier = validateQualifier(this.target, injectConfig.qualifier);
public addInject(injectConfig: InjectConfig, propertyKey: PropertyType, parameterIndex?: number): void {
injectConfig.qualifier = validateQualifier(this.clazz, injectConfig.qualifier);
if (undefined === injectConfig.required) {
injectConfig.required = false;
}
@ -42,7 +48,7 @@ class InjectDefinition {
/**
* addValue
*/
public addValue(value: string, propertyKey: string | symbol, parameterIndex?: number): void {
public addValue(value: string, propertyKey: PropertyType, parameterIndex?: number): void {
if(typeof parameterIndex === 'number') {
this.addValueParameter(value, propertyKey, parameterIndex);
} else {
@ -50,22 +56,22 @@ class InjectDefinition {
}
}
private addValueProperty(value: string, propertyKey: string | symbol): void {
private addValueProperty(value: string, propertyKey: PropertyType): void {
return;
}
private addValueParameter(value: string, propertyKey: string | symbol, parameterIndex: number): void {
private addValueParameter(value: string, propertyKey: PropertyType, parameterIndex: number): void {
return;
}
private addInjectParameter(injectConfig: InjectConfig,
propertyKey: string | symbol, parameterIndex: number): void {
propertyKey: PropertyType, parameterIndex: number): void {
let injectItem: InjectItem;
let parameterTypes: any[] = Reflect.getMetadata(CoreConstants.DESIGN_PARAMTYPES, this.target, propertyKey);
let parameterTypes: any[] = Reflect.getMetadata(DESIGN_PARAMTYPES, this.clazz, propertyKey);
if (undefined === injectConfig.type) {
injectConfig.type = parameterTypes[parameterIndex];
if (undefined === injectConfig.clazz) {
injectConfig.clazz = parameterTypes[parameterIndex];
}
if (this.injectMap.has(propertyKey)) {
@ -73,7 +79,7 @@ class InjectDefinition {
} else {
injectItem = {
stereotype: InjectSterotype.INJECT,
decoratorType: CoreConstants.DecoratorType.PARAMETER,
decoratorType: DecoratorType.PARAMETER,
};
this.injectMap.set(propertyKey, injectItem);
}
@ -90,20 +96,20 @@ class InjectDefinition {
}
private addInjectProperty(injectConfig: InjectConfig, propertyKey: string | symbol): void {
private addInjectProperty(injectConfig: InjectConfig, propertyKey: PropertyType): void {
if (this.injectMap.has(propertyKey)) {
throw new Error(`Cannot apply @inject decorator on one property[${propertyKey}] multiple times.`);
}
let propertyType: any = Reflect.getMetadata(CoreConstants.DESIGN_TYPE, this.target, propertyKey);
let propertyType: any = Reflect.getMetadata(DESIGN_TYPE, this.clazz, propertyKey);
if (undefined === injectConfig.type) {
injectConfig.type = propertyType;
if (undefined === injectConfig.clazz) {
injectConfig.clazz = propertyType;
}
let injectItem: InjectItem = {
stereotype: InjectSterotype.INJECT,
decoratorType: CoreConstants.DecoratorType.PROPERTY,
decoratorType: DecoratorType.PROPERTY,
propertyConfig: injectConfig,
};

View File

@ -1,8 +1,23 @@
import { Construtorable } from '@loafer/core/constants';
import {
ClassType,
PropertyType,
} from '@loafer/core/constants';
interface PouchFactory {
getPouch<T>(type: Construtorable<T>, ...args: any[]): T;
getPouchByQualifier<T>(type: Construtorable<T>, qualifier: string | symbol, ...args: any[]): T;
/**
* @param qualifier is identity of pouch
* @param clazz is type of pouch (if clazz is not specified, set the undefined)
* @param args are argument of target constructor
* @returns an instance of pouch
*/
getPouch(qualifier: PropertyType, clazz: ClassType, ...args: any[]): any;
/**
* @param clazz is type of pouch
* @param qualifier is identity of pouch (if qualifier is not specified, set the undefined)
* @param args are argument of target constructor
* @returns an instance of pouch
*/
getPouchByType(clazz: ClassType, qualifier: PropertyType, ...args: any[]): any;
}

View File

@ -1,10 +1,11 @@
import { ClassType, PropertyType } from '@loafer/core/constants';
import { InjectableSterotype, PouchScope } from '@loafer/pouches/constants';
interface PouchDefinition {
readonly Type: Object;
readonly Clazz: ClassType;
Stereotype: InjectableSterotype;
Scope: PouchScope;
Qualifier: string | symbol;
Qualifier: PropertyType;
readonly PostConstruct: Set<string>;
readonly PreDestroy: Set<string>;
addPostConstruct(postConstruct: string): void;

View File

@ -1,11 +1,14 @@
import {
Construtorable,
ClassType,
PropertyType,
} from '@loafer/core/constants';
interface SingletonPouchRegistry {
registerSingleton(pouch: any, qualifier?: string | symbol): void;
getSingleton<T>(type: Construtorable<T>, qualifier?: string | symbol): T;
hasSingleton<T>(type: Construtorable<T>, qualifier?: string | symbol): boolean;
registerSingleton(pouch: any, qualifier?: PropertyType): void;
getSingleton(qualifier: PropertyType, clazz?: ClassType): any;
getSingletonByClass(clazz: ClassType, qualifier?: PropertyType): any;
hasSingleton(qualifier: PropertyType, clazz?: ClassType): boolean;
hasSingletonByClass(clazz: ClassType, qualifier?: PropertyType): boolean;
}
export default SingletonPouchRegistry;

View File

@ -1,3 +1,8 @@
import {
ClassType,
PropertyType,
} from '@loafer/core/constants';
import {
validateQualifier,
} from '@loafer/pouches/util/qualifier';
@ -9,46 +14,46 @@ import DefaultSingletonPouchRegistry from '@loafer/pouches/factory/implement/Def
abstract class AbstractPouchFactory extends DefaultSingletonPouchRegistry implements PouchDefinitionRegistry {
protected pouchDefinitionMap: Map<string | symbol, Map<Object, PouchDefinition>>;
protected pouchDefinitionMap: Map<PropertyType, Map<ClassType, PouchDefinition>>;
public constructor() {
super();
this.pouchDefinitionMap = new Map();
}
public registerPouchDefinition(pouchDefinition: PouchDefinition): void {
let type = pouchDefinition.Type;
let qualifier = validateQualifier(type, pouchDefinition.Qualifier);
let clazz = pouchDefinition.Clazz;
let qualifier = validateQualifier(clazz, pouchDefinition.Qualifier);
if (this.hasPouchDefinition(type, qualifier)) {
throw new Error(`Pouch Definition[${type.constructor.name}:${qualifier}] is exist already`);
if (this.hasPouchDefinition(clazz, qualifier)) {
throw new Error(`Pouch Definition[${clazz.constructor.name}:${qualifier}] is exist already`);
}
let map = this.pouchDefinitionMap.get(qualifier);
if (undefined === map) {
map = new Map();
this.pouchDefinitionMap.set(qualifier, map);
}
map.set(type, pouchDefinition);
map.set(clazz, pouchDefinition);
}
public removePouchDefinition(type: Object, qualifier?: string | symbol): void {
const _qualifier = validateQualifier(type, qualifier);
if (!this.hasPouchDefinition(type, _qualifier)) {
throw new Error(`Pouch Definition[${type.constructor.name}:${qualifier}] is not exist`);
public removePouchDefinition(clazz: ClassType, qualifier?: PropertyType): void {
const _qualifier = validateQualifier(clazz, qualifier);
if (!this.hasPouchDefinition(clazz, _qualifier)) {
throw new Error(`Pouch Definition[${clazz.constructor.name}:${qualifier}] is not exist`);
}
this.pouchDefinitionMap.get(_qualifier).delete(type);
this.pouchDefinitionMap.get(_qualifier).delete(clazz);
if (0 === this.pouchDefinitionMap.get(_qualifier).size) {
this.pouchDefinitionMap.delete(_qualifier);
}
}
public getPouchDefinition(type: Object, qualifier?: string | symbol): PouchDefinition {
const _qualifier = validateQualifier(type, qualifier);
public getPouchDefinition(clazz: ClassType, qualifier?: PropertyType): PouchDefinition {
const _qualifier = validateQualifier(clazz, qualifier);
if (!this.pouchDefinitionMap.has(_qualifier)) {
return undefined;
}
return this.pouchDefinitionMap.get(_qualifier).get(type);
return this.pouchDefinitionMap.get(_qualifier).get(clazz);
}
public hasPouchDefinition(type: Object, qualifier?: string | symbol): boolean {
return undefined === this.getPouchDefinition(type, qualifier) ? false : true;
public hasPouchDefinition(clazz: ClassType, qualifier?: PropertyType): boolean {
return undefined === this.getPouchDefinition(clazz, qualifier) ? false : true;
}

View File

@ -1,6 +1,7 @@
import {
Construtorable,
ClassType,
DecoratorType,
PropertyType,
} from '@loafer/core/constants';
import {
@ -19,19 +20,16 @@ class DefaultPouchFactory extends AbstractPouchFactory implements PouchFactory,
public constructor() {
super();
}
public getPouch(qualifier: PropertyType, clazz: ClassType, ...args: any[]): any {
public getPouch<T>(type: Construtorable<T>, ...args: any[]): T {
let qualifier = validateQualifier(type.prototype, undefined);
return this.getPouchByQualifier(type, qualifier, args);
return null;
}
public getPouchByType(clazz: ClassType, qualifier: PropertyType, ...args: any[]): any {
let _qualifier = validateQualifier(clazz, qualifier);
public getPouchByQualifier<T>(type: Construtorable<T>, qualifier: string | symbol, ...args: any[]): T {
let clazz: Function = type.prototype;
let instance: T;
return instance;
return null;
}
}
export default DefaultPouchFactory;

View File

@ -1,5 +1,6 @@
import {
Construtorable,
ClassType,
PropertyType,
} from '@loafer/core/constants';
import SingletonPouchRegistry from '@loafer/pouches/factory/config/SingletonPouchRegistry';
@ -9,44 +10,71 @@ import {
} from '@loafer/pouches/util/qualifier';
class DefaultSingletonPouchRegistry implements SingletonPouchRegistry {
protected singletonInstanceMap: Map<string | symbol, Map<Object, any>>;
protected singletonInstanceMap: Map<PropertyType, Map<ClassType, any>>;
protected constructor() {
}
public registerSingleton(pouch: any, qualifier?: string | symbol): void {
let type: Object = Object.getPrototypeOf(pouch);
const _qualifier = validateQualifier(type, qualifier);
public registerSingleton(pouch: any, qualifier?: PropertyType): void {
let clazz: ClassType = Object.getPrototypeOf(pouch);
const _qualifier = validateQualifier(clazz, qualifier);
if (this._hasSingleton(type, _qualifier)) {
throw new Error(`Pouch Definition[${type.constructor.name}:${qualifier}] is exist already`);
if (this._hasSingleton(_qualifier, clazz)) {
throw new Error(`Pouch Definition[${clazz.constructor.name}:${qualifier}] is exist already`);
}
let map = this.singletonInstanceMap.get(_qualifier);
if (undefined === map) {
map = new Map();
this.singletonInstanceMap.set(_qualifier, map);
}
map.set(type, pouch);
}
public getSingleton<T>(target: Construtorable<T>, qualifier?: string | symbol): T {
let type = target.prototype;
return this._getSingleton(type, qualifier);
}
public hasSingleton<T>(target: Construtorable<T>, qualifier?: string | symbol): boolean {
return this._hasSingleton(target.prototype, qualifier);
map.set(clazz, pouch);
}
private _getSingleton<T>(type: Object, qualifier?: string | symbol): T {
const _qualifier = validateQualifier(type, qualifier);
public getSingleton(qualifier: PropertyType, clazz?: ClassType): any {
return this._getSingleton(qualifier, clazz);
}
public getSingletonByClass(clazz: ClassType, qualifier?: PropertyType): any {
const _qualifier = validateQualifier(clazz, qualifier);
return this._getSingleton(_qualifier, clazz);
}
public hasSingleton(qualifier: PropertyType, clazz?: ClassType): boolean {
return this._hasSingleton(qualifier, clazz);
}
public hasSingletonByClass(clazz: ClassType, qualifier?: PropertyType): boolean {
const _qualifier = validateQualifier(clazz, qualifier);
return this._hasSingleton(_qualifier, clazz);
}
if (!this.singletonInstanceMap.has(_qualifier)) {
private _getSingleton<T>(qualifier: PropertyType, clazz?: ClassType): T {
if (!this.singletonInstanceMap.has(qualifier)) {
return undefined;
}
return this.singletonInstanceMap.get(_qualifier).get(type);
let map = this.singletonInstanceMap.get(qualifier);
let instance;
try {
instance = this._getInstance(map, clazz);
} catch(e) {
throw new Error(`Type of Pouch[${qualifier}] cannot be specified(count is ${map.size}).`);
}
return instance;
}
private _hasSingleton(type: Object, qualifier?: string | symbol): boolean {
return undefined === this._getSingleton(type, qualifier) ? false : true;
private _hasSingleton(qualifier: PropertyType, clazz?: ClassType): boolean {
return undefined === this._getSingleton(qualifier, clazz) ? false : true;
}
private _getInstance(map: Map<ClassType, any>, clazz?: ClassType): any {
if (undefined !== clazz) {
return map.get(clazz);
}
const count = map.size;
if (1 < count) {
throw new Error(`Type of Pouch cannot be specified(count is ${count}).`);
}
for (let value of Array.from(map.values())) {
return value;
}
}
}

View File

@ -1,11 +1,15 @@
import { Construtorable } from '@loafer/core/constants';
import {
ClassType,
PropertyType,
} from '@loafer/core/constants';
import PouchDefinition from '@loafer/pouches/factory/config/PouchDefinition';
interface PouchDefinitionRegistry {
registerPouchDefinition(pouchDefinition: PouchDefinition): void;
removePouchDefinition(type: Object, qualifier?: string | symbol): void;
getPouchDefinition(type: Object, qualifier?: string | symbol): PouchDefinition;
hasPouchDefinition(type: Object, qualifier?: string | symbol): boolean;
removePouchDefinition(clazz: ClassType, qualifier?: PropertyType): void;
getPouchDefinition(clazz: ClassType, qualifier?: PropertyType): PouchDefinition;
hasPouchDefinition(clazz: ClassType, qualifier?: PropertyType): boolean;
}
export default PouchDefinitionRegistry;

View File

@ -1,8 +1,9 @@
import { ClassType } from '@loafer/core/constants';
import getClassMetadata from '@loafer/core/util/metadata/getClassMetadata';
import { POUCH_INJECT_DEFINITION } from '@loafer/pouches/constants';
import InjectDefinition from '@loafer/pouches/definition/InjectDefinition';
export const getInjectDefinition =
(target: Object, isCreate: boolean = false) =>
getClassMetadata(target, POUCH_INJECT_DEFINITION, InjectDefinition, isCreate);
(clazz: ClassType, isCreate: boolean = false) =>
getClassMetadata(clazz, POUCH_INJECT_DEFINITION, InjectDefinition, isCreate);

View File

@ -1,3 +1,8 @@
export const validateQualifier = (type: Object, qualifier: string | symbol) => {
return undefined === qualifier ? type.constructor.name : qualifier;
import {
ClassType,
PropertyType,
} from '@loafer/core/constants';
export const validateQualifier = (clazz: ClassType, qualifier: PropertyType) => {
return undefined === qualifier ? clazz.constructor.name : qualifier;
};