This commit is contained in:
crusader 2017-12-28 22:51:04 +09:00
parent b1ec678681
commit b0df948bc4
15 changed files with 218 additions and 53 deletions

View File

@ -45,15 +45,22 @@ export class Application {
private findRunner(): Method { private findRunner(): Method {
let clazz: Class = Class.forClass(this._primaryClass); let clazz: Class = Class.forClass(this._primaryClass);
let methods = clazz.getMethods(); let methods = clazz.getOwnMethods();
for (let i = 0; i < methods.length; i++) { if (null === methods || 0 === methods.size) {
const method = methods[i]; return null;
}
for (const key in methods.keys()) {
if (methods.hasOwnProperty(key)) {
const method = methods[key];
let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation); let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation);
if (undefined === runnerAnnotation) { if (undefined === runnerAnnotation) {
continue; continue;
} }
return method; return method;
} }
}
return null; return null;
} }
@ -94,8 +101,12 @@ export class Application {
if (undefined === configAnnotation) { if (undefined === configAnnotation) {
throw new Error(`Class is not Configuration type. add @Configuration annotation to class[${configurationType.name}]`); throw new Error(`Class is not Configuration type. add @Configuration annotation to class[${configurationType.name}]`);
} }
let methods = clazz.getOwnMethods();
if (null === methods) {
return;
}
let instance = instanceFactory.getInstance(null, configurationType); let instance = instanceFactory.getInstance(null, configurationType);
clazz.getMethods().forEach(method => { methods.forEach(method => {
let instanceAnnotation = method.getOwnAnnotation(InstanceAnnotation); let instanceAnnotation = method.getOwnAnnotation(InstanceAnnotation);
if (undefined === instanceAnnotation) { if (undefined === instanceAnnotation) {
return; return;

View File

@ -21,7 +21,7 @@ export abstract class AccessibleObject implements AnnotatedElement {
return null !== this.getAnnotation(annotationClass); return null !== this.getAnnotation(annotationClass);
} }
public getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType { public getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType | undefined {
return <AnnotationType>this._annotations.get(annotationClass); return <AnnotationType>this._annotations.get(annotationClass);
} }
@ -29,7 +29,7 @@ export abstract class AccessibleObject implements AnnotatedElement {
return this._annotations; return this._annotations;
} }
public getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType { public getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType | undefined {
return this.getOwnAnnotation(annotationClass); return this.getOwnAnnotation(annotationClass);
} }

View File

@ -8,8 +8,8 @@ export interface AnnotatedElement {
_addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void; _addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void;
isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): boolean; isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): boolean;
getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType; getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType | undefined;
getOwnAnnotations(): Map<ClassType, Annotation>; getOwnAnnotations(): Map<ClassType, Annotation>;
getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType; getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType | undefined;
getAnnotations(): Map<ClassType, Annotation>; getAnnotations(): Map<ClassType, Annotation>;
} }

View File

@ -1,10 +1,12 @@
import { import {
ClassType, ClassType,
PropertyKeyType,
Metadata, Metadata,
PropertyKeyType,
TypeUtil,
} from '@overflow/commons/core/type'; } from '@overflow/commons/core/type';
import {AccessibleObject} from './accessible_object'; import {AccessibleObject} from './accessible_object';
import {Annotation} from './annotation';
import {systemClassRegistry} from './class_registry'; import {systemClassRegistry} from './class_registry';
import {Constructor} from './constructor'; import {Constructor} from './constructor';
import {Field} from './field'; import {Field} from './field';
@ -21,7 +23,7 @@ export class Class extends AccessibleObject {
/** /**
* forClass * forClass
*/ */
public static forClass(clazzType: ClassType): Class { public static forClass(clazzType: ClassType): Class | undefined {
return systemClassRegistry.get(clazzType); return systemClassRegistry.get(clazzType);
} }
@ -97,7 +99,7 @@ export class Class extends AccessibleObject {
return this._constructor; return this._constructor;
} }
public getOwnField(propertyKey: PropertyKeyType): Field { public getOwnField(propertyKey: PropertyKeyType): Field | undefined {
return this._fields.get(propertyKey); return this._fields.get(propertyKey);
} }
@ -105,15 +107,35 @@ export class Class extends AccessibleObject {
return this._fields; return this._fields;
} }
public getField(propertyKey: PropertyKeyType): Field { public getField(propertyKey: PropertyKeyType): Field | undefined {
return null; let fields = this.getFields();
return fields.get(propertyKey);
} }
public getFields(): Field[] { public getFields(): Map<PropertyKeyType, Field> {
return null; let fields: Map<PropertyKeyType, Field> = new Map();
let clazzTypes = TypeUtil.ancestorsOf(this._clazzType);
if (null === clazzTypes || 0 === clazzTypes.length) {
return fields;
}
for (let i = 0; i < clazzTypes.length; i++) {
const tClazzType = clazzTypes[i];
let tClazz = Class.forClass(tClazzType);
if (undefined === tClazz) {
continue;
} }
public getOwnMethod(propertyKey: PropertyKeyType): Method { tClazz.getOwnFields().forEach((value: Field, key: PropertyKeyType, map: Map<PropertyKeyType, Field>): void => {
fields.set(key, value);
});
}
return fields;
}
public getOwnMethod(propertyKey: PropertyKeyType): Method | undefined {
return this._methods.get(propertyKey); return this._methods.get(propertyKey);
} }
@ -121,15 +143,64 @@ export class Class extends AccessibleObject {
return this._methods; return this._methods;
} }
public getMethod(propertyKey: PropertyKeyType): Method { public getMethod(propertyKey: PropertyKeyType): Method | undefined {
return null; let methods = this.getMethods();
return methods.get(propertyKey);
} }
public getMethods(): Method[] { public getMethods(): Map<PropertyKeyType, Method> {
return null; let methods: Map<PropertyKeyType, Method> = new Map();
let clazzTypes = TypeUtil.ancestorsOf(this._clazzType);
if (null === clazzTypes || 0 === clazzTypes.length) {
return methods;
} }
for (let i = 0; i < clazzTypes.length; i++) {
const tClazzType = clazzTypes[i];
let tClazz = Class.forClass(tClazzType);
if (undefined === tClazz) {
continue;
}
tClazz.getOwnMethods().forEach((value: Method, key: PropertyKeyType, map: Map<PropertyKeyType, Method>): void => {
methods.set(key, value);
});
}
return methods;
}
public getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType | undefined {
let annotations = this.getAnnotations();
return <AnnotationType>annotations.get(annotationClass);
}
public getAnnotations(): Map<ClassType, Annotation> {
let annotations: Map<ClassType, Annotation> = new Map();
let clazzTypes = TypeUtil.ancestorsOf(this._clazzType);
if (null === clazzTypes || 0 === clazzTypes.length) {
return annotations;
}
for (let i = 0; i < clazzTypes.length; i++) {
const tClazzType = clazzTypes[i];
let tClazz = Class.forClass(tClazzType);
if (undefined === tClazz) {
continue;
}
tClazz.getOwnAnnotations().forEach((value: Annotation, key: ClassType, map: Map<ClassType, Annotation>): void => {
annotations.set(key, value);
});
}
return annotations;
}
public getName(): string { public getName(): string {
return null; return this._clazzType.name;
} }
} }

View File

@ -54,18 +54,18 @@ export abstract class Executable extends AccessibleObject implements Member {
/** /**
* getParameters * getParameters
*/ */
public getParameters(): Parameter[] { public getParameters(): Parameter[] | undefined {
return this._parameters; return this._parameters;
} }
/** /**
* getParameter * getParameter
*/ */
public getParameter(index: number): Parameter { public getParameter(index: number): Parameter | undefined {
if (null === this._parameters) { if (null === this._parameters) {
return null; return undefined;
} }
if (0 > index || this._parameters.length <= index) { if (0 > index || this._parameters.length <= index) {
return null; return undefined;
} }
return this._parameters[index]; return this._parameters[index];
} }

View File

@ -315,7 +315,7 @@ export class TypeUtil {
* @param target * @param target
* @returns {any} * @returns {any}
*/ */
public static getInheritedClass(target: any): any { public static getInheritedClass(target: ClassType): ClassType {
return Object.getPrototypeOf(target); return Object.getPrototypeOf(target);
} }
@ -388,8 +388,8 @@ export class TypeUtil {
* @param target * @param target
* @returns {Array} * @returns {Array}
*/ */
public static ancestorsOf(target: any): any[] { public static ancestorsOf(target: ClassType): ClassType[] {
const classes = []; const classes: ClassType[] = [];
let currentTarget = TypeUtil.getClass(target); let currentTarget = TypeUtil.getClass(target);

View File

@ -7,7 +7,7 @@ export abstract class Registry<K, V> {
this._map = new Map<K, V>(); this._map = new Map<K, V>();
} }
public get parent(): Registry<K, V> { public get parent(): Registry<K, V> | undefined {
return this._parent; return this._parent;
} }

View File

@ -4,21 +4,47 @@ import {
import { import {
InstanceNameType, InstanceNameType,
InstanceFactoryType,
} from '@overflow/commons/di/type'; } from '@overflow/commons/di/type';
import {InstanceDefinitionRegistry} from './instance_definition_registry'; import {InstanceDefinitionRegistry} from './instance_definition_registry';
import {InstanceDefinition} from './instance_definition'; import {InstanceDefinition} from './instance_definition';
export class InstanceFactory implements InstanceDefinitionRegistry { export class InstanceFactory implements InstanceDefinitionRegistry {
private singletonObjects: Map<InstanceNameType, any> = new Map();
private singletonFactories: Map<InstanceNameType, InstanceFactoryType> = new Map();
private instanceDefinitionMap: Map<InstanceNameType, InstanceDefinition> = new Map();
private instanceDefinitionNames: Set<InstanceNameType> = new Set();
/** /**
* getInstance * getInstance
*/ */
public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any { public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any {
if (null === name) {
return this.getInstanceByType(requiredType);
}
let sharedInstance = this.getSingleton(name);
if (undefined !== sharedInstance) {
return sharedInstance;
}
return null; return null;
} }
private getInstanceByName(requiredType: ClassType): any {
}
private getInstanceByType(requiredType: ClassType): any {
}
private getSingleton(name: InstanceNameType): any | undefined {
let singletonObject = this.singletonObjects.get(name);
}
/** /**
* containsInstance * containsInstance
*/ */
@ -35,31 +61,40 @@ export class InstanceFactory implements InstanceDefinitionRegistry {
} }
public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void { public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
// let oldInstanceDefinition = this.instanceDefinitionMap.get(name);
if (undefined !== oldInstanceDefinition) {
throw new Error(`InstanceDefinition[${name}] is already exist.`);
}
this.instanceDefinitionNames.add(name);
this.instanceDefinitionMap.set(name, instanceDefinition);
} }
public removeInstanceDefinition(name: InstanceNameType): void { public removeInstanceDefinition(name: InstanceNameType): void {
// if (!this.instanceDefinitionMap.has(name)) {
throw new Error(`InstanceDefinition[${name}] is not exist.`);
}
this.instanceDefinitionNames.delete(name);
this.instanceDefinitionMap.delete(name);
} }
public getInstanceDefinition(name: InstanceNameType): InstanceDefinition { public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined {
// return this.instanceDefinitionMap.get(name);
} }
public containsInstanceDefinition(name: InstanceNameType): boolean { public containsInstanceDefinition(name: InstanceNameType): boolean {
// return this.instanceDefinitionMap.has(name);
} }
public getInstanceDefinitionNames(): InstanceNameType[] { public getInstanceDefinitionNames(): Set<InstanceNameType> {
// return this.instanceDefinitionNames;
} }
public getInstanceDefinitionCount(): number { public getInstanceDefinitionCount(): number {
// return this.instanceDefinitionMap.size;
} }
public isInstanceNameInUse(name: InstanceNameType): boolean { public isInstanceNameInUse(name: InstanceNameType): boolean {
// return false;
} }
} }

View File

@ -3,3 +3,4 @@ import {
} from '@overflow/commons/core/type'; } from '@overflow/commons/core/type';
export type InstanceNameType = IdentityType<string>; export type InstanceNameType = IdentityType<string>;
export type InstanceFactoryType = (...args: any[]) => any;

View File

@ -1,4 +1,5 @@
export * from './injectables'; export * from './injectables';
export * from './json_sources';
export * from './reducer_configuration'; export * from './reducer_configuration';
export * from './rest_api_configuration'; export * from './rest_api_configuration';
export * from './rpc_api_configuration'; export * from './rpc_api_configuration';

View File

@ -0,0 +1,6 @@
import * as webapp from './jsons/webapp.json';
export const jsonSources: any[] = [
webapp,
];

View File

@ -0,0 +1,7 @@
{
"html": {
"container": {
"id": "appContainer"
}
}
}

View File

@ -2,14 +2,26 @@ import {
Configuration, Configuration,
Instance, Instance,
} from '@overflow/commons/application/decorators'; } from '@overflow/commons/application/decorators';
import { Value } from '@overflow/commons/di/decorators';
@Configuration() @Configuration()
export class WebAppConfiguration { export class WebAppConfiguration {
@Value('html.container.id')
private htmlContainerID: string;
/** /**
* container * container
*/ */
@Instance() @Instance()
public container(): HTMLElement { public container(): Promise<HTMLElement> {
return null; function getContainer(containerID: string): Promise<HTMLElement> {
return new Promise<HTMLElement>(resolve => {
document.addEventListener('DOMContentLoaded', () => {
resolve(document.getElementById(containerID));
});
});
}
return getContainer(this.htmlContainerID);
} }
} }

View File

@ -36,10 +36,12 @@ import {
import { import {
Inject, Inject,
Resource, Resource,
Value,
} from '@overflow/commons/di/decorators'; } from '@overflow/commons/di/decorators';
import config, { import config, {
injectables, injectables,
jsonSources,
ReducerConfiguration, ReducerConfiguration,
RestAPIConfiguration, RestAPIConfiguration,
RpcAPIConfiguration, RpcAPIConfiguration,
@ -58,8 +60,14 @@ declare global {
const module: { hot: any }; const module: { hot: any };
} }
class A {
}
class B extends A {
}
@WebApplication({ @WebApplication({
injectables: injectables, injectables: injectables,
jsonSources: jsonSources,
configurations: [ configurations: [
ReducerConfiguration, ReducerConfiguration,
RestAPIConfiguration, RestAPIConfiguration,
@ -67,11 +75,12 @@ declare global {
WebAppConfiguration, WebAppConfiguration,
], ],
}) })
class WebAppApplication { class WebAppApplication extends B {
private static isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false; private static isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
private static useReduxDevTools:boolean = window.devToolsExtension && !WebAppApplication.isProduction ? true : false; private static useReduxDevTools:boolean = window.devToolsExtension && !WebAppApplication.isProduction ? true : false;
@Resource() @Value('html.container.id')
private htmlContainerID: string;
private container: HTMLElement; private container: HTMLElement;
@Inject() @Inject()
@ -81,14 +90,10 @@ class WebAppApplication {
@Inject() @Inject()
private dispatcherReducer: WebAppDispatcherReducer; private dispatcherReducer: WebAppDispatcherReducer;
public constructor() {
this.container = document.getElementById('appContainer');
this.history = createHashHistory();
}
@Runner() @Runner()
public async run(): Promise<void> { public async run(): Promise<void> {
try { try {
this.container = await this.getContainer();
this.renderLoading(); this.renderLoading();
let reducer: WebAppDispatcherReducer = new WebAppDispatcherReducer(); let reducer: WebAppDispatcherReducer = new WebAppDispatcherReducer();
reducer.registerReducers(config.redux.reducers); reducer.registerReducers(config.redux.reducers);
@ -100,6 +105,18 @@ class WebAppApplication {
} }
} }
private getContainer(): Promise<HTMLElement> {
function getContainer(containerID: string): Promise<HTMLElement> {
return new Promise<HTMLElement>(resolve => {
document.addEventListener('DOMContentLoaded', () => {
resolve(document.getElementById(containerID));
});
});
}
return getContainer(this.htmlContainerID);
}
private renderLoading(): void { private renderLoading(): void {
ReactDOM.render( ReactDOM.render(
<div style={{ <div style={{

4
src/ts/typings.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module '*.json' {
const value: any;
export default value;
}