ing
This commit is contained in:
parent
a38b472a1e
commit
471a3a6ccc
75
package-lock.json
generated
75
package-lock.json
generated
|
@ -204,6 +204,55 @@
|
||||||
"tslib": "1.9.0"
|
"tslib": "1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@loafer/core": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@loafer/core/-/core-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-t0Nio5E4l/jqkstQYE4rYqrsnPIgTOWpoxuX6s4UwUvNfAsOnVWxeZ6cSg2ontSZYeEPaObFVfp7IjPiblhX0A==",
|
||||||
|
"requires": {
|
||||||
|
"reflect-metadata": "0.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@loafer/decorator": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@loafer/decorator/-/decorator-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-vN6NX2D3dS5wRevWtznqYSdCteaKpzR7X6YQ25LXXoGEljh5dbAqyBnMBLiULPGmshKV2zp762lZYlrGM5qW0Q==",
|
||||||
|
"requires": {
|
||||||
|
"@loafer/core": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@loafer/ng-logger": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@loafer/ng-logger/-/ng-logger-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-9z7gCg/Fj2QaeDI5Hg6jIHDkbcS25D8LLyS4+tTHETSOoqJA3lzostSOACTeKtZFpewD/mXQWmyNoazJp9v6cw==",
|
||||||
|
"requires": {
|
||||||
|
"@angular/common": "5.2.10",
|
||||||
|
"@angular/core": "5.2.10",
|
||||||
|
"rxjs": "5.5.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@loafer/ng-rest": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@loafer/ng-rest/-/ng-rest-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-ApMSTQWTVEJwPU1ib8UPcr/9+IIfwxe03VmLY9gd9rznzWlm1tW44zlRIQwVqlt2Y15Oc6iqhF3o0AvIDwAfiA==",
|
||||||
|
"requires": {
|
||||||
|
"@angular/common": "5.2.10",
|
||||||
|
"@angular/core": "5.2.10",
|
||||||
|
"rxjs": "5.5.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@loafer/ng-rpc": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@loafer/ng-rpc/-/ng-rpc-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-qVYe/RJGfpQ70l7MSGoCfCDsOEQo+onj3FOojSyQkhZ6L/19zy/ZpFBVNAayJmV4dh8mSuK9FeeL58uGwDxCcg==",
|
||||||
|
"requires": {
|
||||||
|
"@angular/common": "5.2.10",
|
||||||
|
"@angular/core": "5.2.10",
|
||||||
|
"@loafer/core": "0.0.1",
|
||||||
|
"@loafer/decorator": "0.0.1",
|
||||||
|
"@ngrx/store": "5.2.0",
|
||||||
|
"rxjs": "5.5.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ngrx/core": {
|
"@ngrx/core": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ngrx/core/-/core-1.2.0.tgz",
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@ngrx/core/-/core-1.2.0.tgz",
|
||||||
|
@ -259,7 +308,7 @@
|
||||||
"@overflow/commons-typescript": {
|
"@overflow/commons-typescript": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@overflow/commons-typescript/-/commons-typescript-0.0.3.tgz",
|
"resolved": "https://nexus.loafle.net/repository/npm-all/@overflow/commons-typescript/-/commons-typescript-0.0.3.tgz",
|
||||||
"integrity": "sha512-dLKMAZCABAVYVjAe1VXvyx2XocS3kwmzSuu5AeFvg0EgH4nqaAC+FCQtBzzKvDPDg9dFaXWQb9SIL4Jy/6EjQQ=="
|
"integrity": "sha512-CMPT43+Qvrc0IM5tXvJDeNoBajc82jk0l5CAfHd8u+ua3/j8+lB9ZYbnjY3LJpTcqQTe9dHbuBiBiUM9wNA7kg=="
|
||||||
},
|
},
|
||||||
"@schematics/angular": {
|
"@schematics/angular": {
|
||||||
"version": "0.1.17",
|
"version": "0.1.17",
|
||||||
|
@ -1595,7 +1644,7 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"anymatch": "1.3.2",
|
"anymatch": "1.3.2",
|
||||||
"async-each": "1.0.1",
|
"async-each": "1.0.1",
|
||||||
"fsevents": "1.2.3",
|
"fsevents": "1.2.4",
|
||||||
"glob-parent": "2.0.0",
|
"glob-parent": "2.0.0",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"is-binary-path": "1.0.1",
|
"is-binary-path": "1.0.1",
|
||||||
|
@ -3874,14 +3923,14 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.4",
|
||||||
"resolved": "https://nexus.loafle.net/repository/npm-all/fsevents/-/fsevents-1.2.3.tgz",
|
"resolved": "https://nexus.loafle.net/repository/npm-all/fsevents/-/fsevents-1.2.4.tgz",
|
||||||
"integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==",
|
"integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"nan": "2.10.0",
|
"nan": "2.10.0",
|
||||||
"node-pre-gyp": "0.9.1"
|
"node-pre-gyp": "0.10.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abbrev": {
|
"abbrev": {
|
||||||
|
@ -3962,7 +4011,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"deep-extend": {
|
"deep-extend": {
|
||||||
"version": "0.4.2",
|
"version": "0.5.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
|
@ -4140,7 +4189,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-pre-gyp": {
|
"node-pre-gyp": {
|
||||||
"version": "0.9.1",
|
"version": "0.10.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
@ -4151,7 +4200,7 @@
|
||||||
"nopt": "4.0.1",
|
"nopt": "4.0.1",
|
||||||
"npm-packlist": "1.1.10",
|
"npm-packlist": "1.1.10",
|
||||||
"npmlog": "4.1.2",
|
"npmlog": "4.1.2",
|
||||||
"rc": "1.2.6",
|
"rc": "1.2.7",
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"semver": "5.5.0",
|
"semver": "5.5.0",
|
||||||
"tar": "4.4.1"
|
"tar": "4.4.1"
|
||||||
|
@ -4249,12 +4298,12 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"rc": {
|
"rc": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.7",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"deep-extend": "0.4.2",
|
"deep-extend": "0.5.1",
|
||||||
"ini": "1.3.5",
|
"ini": "1.3.5",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"strip-json-comments": "2.0.1"
|
"strip-json-comments": "2.0.1"
|
||||||
|
@ -12894,7 +12943,7 @@
|
||||||
"anymatch": "2.0.0",
|
"anymatch": "2.0.0",
|
||||||
"async-each": "1.0.1",
|
"async-each": "1.0.1",
|
||||||
"braces": "2.3.2",
|
"braces": "2.3.2",
|
||||||
"fsevents": "1.2.3",
|
"fsevents": "1.2.4",
|
||||||
"glob-parent": "3.1.0",
|
"glob-parent": "3.1.0",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"is-binary-path": "1.0.1",
|
"is-binary-path": "1.0.1",
|
||||||
|
@ -13665,7 +13714,7 @@
|
||||||
"anymatch": "2.0.0",
|
"anymatch": "2.0.0",
|
||||||
"async-each": "1.0.1",
|
"async-each": "1.0.1",
|
||||||
"braces": "2.3.2",
|
"braces": "2.3.2",
|
||||||
"fsevents": "1.2.3",
|
"fsevents": "1.2.4",
|
||||||
"glob-parent": "3.1.0",
|
"glob-parent": "3.1.0",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"is-binary-path": "1.0.1",
|
"is-binary-path": "1.0.1",
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
"@angular/platform-browser": "^5.2.9",
|
"@angular/platform-browser": "^5.2.9",
|
||||||
"@angular/platform-browser-dynamic": "^5.2.9",
|
"@angular/platform-browser-dynamic": "^5.2.9",
|
||||||
"@angular/router": "^5.2.0",
|
"@angular/router": "^5.2.0",
|
||||||
|
"@loafer/core": "^0.0.1",
|
||||||
|
"@loafer/decorator": "^0.0.1",
|
||||||
|
"@loafer/ng-logger": "^0.0.1",
|
||||||
|
"@loafer/ng-rest": "^0.0.1",
|
||||||
|
"@loafer/ng-rpc": "^0.0.1",
|
||||||
"@ngrx/core": "^1.2.0",
|
"@ngrx/core": "^1.2.0",
|
||||||
"@ngrx/effects": "^5.2.0",
|
"@ngrx/effects": "^5.2.0",
|
||||||
"@ngrx/entity": "^5.2.0",
|
"@ngrx/entity": "^5.2.0",
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
export class IllegalArgumentError extends Error {
|
|
||||||
public constructor(message?: string) {
|
|
||||||
super(message);
|
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './type';
|
|
|
@ -1,64 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '../util/TypeUtil';
|
|
||||||
|
|
||||||
import { AnnotatedElement } from './AnnotatedElement';
|
|
||||||
import { Annotation } from './Annotation';
|
|
||||||
|
|
||||||
export abstract class AccessibleObject implements AnnotatedElement {
|
|
||||||
private _annotations: Map<Type<any>, Annotation>;
|
|
||||||
|
|
||||||
protected constructor() {
|
|
||||||
this._annotations = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
public _addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void {
|
|
||||||
this._annotations.set(TypeUtil.getType(annotation), annotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): boolean {
|
|
||||||
return null !== this.getAnnotation(annotationClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType | undefined {
|
|
||||||
return <AnnotationType>this._annotations.get(annotationClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnAnnotations(): Map<Type<any>, Annotation> {
|
|
||||||
return this._annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>)
|
|
||||||
: AnnotationType[] | undefined {
|
|
||||||
if (0 === this._annotations.size) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const results: AnnotationType[] = [];
|
|
||||||
for (const classType of Array.from(this._annotations.keys())) {
|
|
||||||
if (classType === annotationClass) {
|
|
||||||
results.push(<AnnotationType>this._annotations.get(classType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (0 === results.length) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAnnotation<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType | undefined {
|
|
||||||
return this.getOwnAnnotation(annotationClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAnnotations(): Map<Type<any>, Annotation> {
|
|
||||||
return this.getOwnAnnotations();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>)
|
|
||||||
: AnnotationType[] | undefined {
|
|
||||||
return this.getOwnAnnotationsByType(annotationClass);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import { Annotation } from './Annotation';
|
|
||||||
|
|
||||||
export interface AnnotatedElement {
|
|
||||||
_addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void;
|
|
||||||
|
|
||||||
isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): boolean;
|
|
||||||
getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType | undefined;
|
|
||||||
getOwnAnnotations(): Map<Type<any>, Annotation>;
|
|
||||||
getOwnAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType[] | undefined;
|
|
||||||
getAnnotation<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType | undefined;
|
|
||||||
getAnnotations(): Map<Type<any>, Annotation>;
|
|
||||||
getAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType[] | undefined;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
export abstract class Annotation<Attribute = {}> {
|
|
||||||
public readonly attribute: Attribute;
|
|
||||||
|
|
||||||
public constructor(attribute?: Attribute) {
|
|
||||||
this.attribute = attribute;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,228 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '../util/TypeUtil';
|
|
||||||
|
|
||||||
import { AccessibleObject } from './AccessibleObject';
|
|
||||||
import { Annotation } from './Annotation';
|
|
||||||
import { SystemClassRegistry } from './ClassRegistry';
|
|
||||||
import { Constructor } from './Constructor';
|
|
||||||
import { Field } from './Field';
|
|
||||||
import { Method } from './Method';
|
|
||||||
import { Metadata } from './Metadata';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Class extends AccessibleObject {
|
|
||||||
private _type: Type<any>;
|
|
||||||
private _constructor: Constructor;
|
|
||||||
private _fields: Map<PropertyKeyType, Field>;
|
|
||||||
private _methods: Map<PropertyKeyType, Method>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* forClass
|
|
||||||
*/
|
|
||||||
public static forType(type: Type<any>): Class | undefined {
|
|
||||||
return SystemClassRegistry.get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _defineClass
|
|
||||||
*/
|
|
||||||
public static _defineClass(type: Type<any>): Class {
|
|
||||||
let clazz: Class = Class.forType(type);
|
|
||||||
if (undefined === clazz) {
|
|
||||||
clazz = new Class(type);
|
|
||||||
SystemClassRegistry.set(type, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === clazz._constructor) {
|
|
||||||
const parameterTypes = Metadata.getOwnParamTypes(type);
|
|
||||||
if (undefined !== parameterTypes) {
|
|
||||||
clazz._constructor = new Constructor(clazz, parameterTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
private constructor(type: Type<any>) {
|
|
||||||
super();
|
|
||||||
this._type = type;
|
|
||||||
this._fields = new Map();
|
|
||||||
this._methods = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _defineField
|
|
||||||
*/
|
|
||||||
public _defineConstructor(parameterTypes: any[]): Constructor {
|
|
||||||
let cons: Constructor = this._constructor;
|
|
||||||
if (undefined === cons) {
|
|
||||||
cons = new Constructor(this, parameterTypes);
|
|
||||||
this._constructor = cons;
|
|
||||||
}
|
|
||||||
return cons;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _defineField
|
|
||||||
*/
|
|
||||||
public _defineField(propertyKey: PropertyKeyType, propertyType: any): Field {
|
|
||||||
let field: Field = this._fields.get(propertyKey);
|
|
||||||
if (undefined === field) {
|
|
||||||
field = new Field(this, propertyKey, propertyType);
|
|
||||||
this._fields.set(propertyKey, field);
|
|
||||||
}
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _defineMethod
|
|
||||||
*/
|
|
||||||
public _defineMethod(propertyKey: PropertyKeyType, parameterTypes: any[], returnType: any): Method {
|
|
||||||
let method: Method = this._methods.get(propertyKey);
|
|
||||||
if (undefined === method) {
|
|
||||||
method = new Method(this, propertyKey, parameterTypes, returnType);
|
|
||||||
this._methods.set(propertyKey, method);
|
|
||||||
}
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getType(): Type<any> {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConstructor(): Constructor {
|
|
||||||
if (undefined === this._constructor) {
|
|
||||||
this._constructor = new Constructor(this, undefined);
|
|
||||||
}
|
|
||||||
return this._constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnField(propertyKey: PropertyKeyType): Field | undefined {
|
|
||||||
return this._fields.get(propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnFields(): Map<PropertyKeyType, Field> {
|
|
||||||
return this._fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getField(propertyKey: PropertyKeyType): Field | undefined {
|
|
||||||
const fields = this.getFields();
|
|
||||||
|
|
||||||
return fields.get(propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFields(): Map<PropertyKeyType, Field> {
|
|
||||||
const fields: Map<PropertyKeyType, Field> = new Map();
|
|
||||||
|
|
||||||
const types = TypeUtil.ancestorsOf(this._type);
|
|
||||||
if (null === types || 0 === types.length) {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < types.length; i++) {
|
|
||||||
const tType = types[i];
|
|
||||||
const tClazz = Class.forType(tType);
|
|
||||||
if (undefined === tClazz) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOwnMethods(): Map<PropertyKeyType, Method> {
|
|
||||||
return this._methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMethod(propertyKey: PropertyKeyType): Method | undefined {
|
|
||||||
const methods = this.getMethods();
|
|
||||||
|
|
||||||
return methods.get(propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMethods(): Map<PropertyKeyType, Method> {
|
|
||||||
const methods: Map<PropertyKeyType, Method> = new Map();
|
|
||||||
|
|
||||||
const types = TypeUtil.ancestorsOf(this._type);
|
|
||||||
if (null === types || 0 === types.length) {
|
|
||||||
return methods;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < types.length; i++) {
|
|
||||||
const tClazzType = types[i];
|
|
||||||
const tClazz = Class.forType(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: Type<AnnotationType>): AnnotationType | undefined {
|
|
||||||
const annotations = this.getAnnotations();
|
|
||||||
|
|
||||||
return <AnnotationType>annotations.get(annotationClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAnnotations(): Map<Type<any>, Annotation> {
|
|
||||||
const annotations: Map<Type<any>, Annotation> = new Map();
|
|
||||||
|
|
||||||
const types = TypeUtil.ancestorsOf(this._type);
|
|
||||||
if (null === types || 0 === types.length) {
|
|
||||||
return annotations;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < types.length; i++) {
|
|
||||||
const tClazzType = types[i];
|
|
||||||
const tClazz = Class.forType(tClazzType);
|
|
||||||
if (undefined === tClazz) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tClazz.getOwnAnnotations().forEach((value: Annotation, key: Type<any>, map: Map<Type<any>, Annotation>): void => {
|
|
||||||
annotations.set(key, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>)
|
|
||||||
: AnnotationType[] | undefined {
|
|
||||||
const annotations = this.getAnnotations();
|
|
||||||
if (0 === annotations.size) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const results: AnnotationType[] = [];
|
|
||||||
for (const classType of Array.from(annotations.keys())) {
|
|
||||||
if (classType === annotationClass) {
|
|
||||||
results.push(<AnnotationType>annotations.get(classType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (0 === results.length) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getName(): string {
|
|
||||||
return this._type.name;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { Type } from '../type';
|
|
||||||
import { Registry } from '../util/Registry';
|
|
||||||
|
|
||||||
import { Class } from './Class';
|
|
||||||
|
|
||||||
export class ClassRegistry extends Registry<Type<any>, Class> {
|
|
||||||
public constructor(parent?: ClassRegistry) {
|
|
||||||
super(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SystemClassRegistry = new ClassRegistry();
|
|
|
@ -1,26 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '../util/TypeUtil';
|
|
||||||
|
|
||||||
import { Class } from './Class';
|
|
||||||
import { Executable } from './Executable';
|
|
||||||
|
|
||||||
export class Constructor extends Executable {
|
|
||||||
private _rawConstructor: Function;
|
|
||||||
|
|
||||||
public constructor(declaringClazz: Class, parameterTypes?: any[]) {
|
|
||||||
super(declaringClazz, CONSTRUCTOR_NAME, parameterTypes);
|
|
||||||
this._rawConstructor = TypeUtil.getPrototype(declaringClazz.getType())[CONSTRUCTOR_NAME];
|
|
||||||
}
|
|
||||||
|
|
||||||
public newInstance(...args: any[]): any {
|
|
||||||
const ctor = this.getDeclaringClass().getType();
|
|
||||||
return new (ctor.bind.apply(ctor, [null].concat(args)))();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONSTRUCTOR_NAME = 'constructor';
|
|
|
@ -1,75 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '../util/TypeUtil';
|
|
||||||
|
|
||||||
import { AccessibleObject } from './AccessibleObject';
|
|
||||||
import { Class } from './Class';
|
|
||||||
import { Member } from './Member';
|
|
||||||
import { Parameter } from './Parameter';
|
|
||||||
|
|
||||||
export abstract class Executable extends AccessibleObject implements Member {
|
|
||||||
private _clazz: Class;
|
|
||||||
private _name: PropertyKeyType;
|
|
||||||
private _parameters: Parameter[];
|
|
||||||
|
|
||||||
protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes?: any[]) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._clazz = declaringClazz;
|
|
||||||
this._name = name;
|
|
||||||
|
|
||||||
if (undefined === parameterTypes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parameterNames = TypeUtil.getParameterNames(declaringClazz.getType(), name);
|
|
||||||
this._parameters = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < parameterTypes.length; i++) {
|
|
||||||
const parameterType = parameterTypes[i];
|
|
||||||
const parameterName = parameterNames[i];
|
|
||||||
const parameter: Parameter = new Parameter(this, parameterType, parameterName, i);
|
|
||||||
this._parameters.push(parameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDeclaringClass(): Class {
|
|
||||||
return this._clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getName(): PropertyKeyType {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getParameterCount
|
|
||||||
*/
|
|
||||||
public getParameterCount(): number {
|
|
||||||
if (null === this._parameters) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return this._parameters.length;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* getParameters
|
|
||||||
*/
|
|
||||||
public getParameters(): Parameter[] | undefined {
|
|
||||||
return this._parameters;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* getParameter
|
|
||||||
*/
|
|
||||||
public getParameter(index: number): Parameter | undefined {
|
|
||||||
if (null === this._parameters) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (0 > index || this._parameters.length <= index) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return this._parameters[index];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import { AccessibleObject } from './AccessibleObject';
|
|
||||||
import { Class } from './Class';
|
|
||||||
import { Member } from './Member';
|
|
||||||
|
|
||||||
export class Field extends AccessibleObject implements Member {
|
|
||||||
private _clazz: Class;
|
|
||||||
private _name: PropertyKeyType;
|
|
||||||
private _type: any;
|
|
||||||
|
|
||||||
public constructor(declaringClazz: Class, name: PropertyKeyType, fieldType: any) {
|
|
||||||
super();
|
|
||||||
this._clazz = declaringClazz;
|
|
||||||
this._name = name;
|
|
||||||
this._type = fieldType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDeclaringClass(): Class {
|
|
||||||
return this._clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getName(): PropertyKeyType {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getType(): any {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import { Class } from './Class';
|
|
||||||
|
|
||||||
export interface Member {
|
|
||||||
getDeclaringClass(): Class;
|
|
||||||
getName(): PropertyKeyType;
|
|
||||||
}
|
|
|
@ -1,521 +0,0 @@
|
||||||
import {
|
|
||||||
MetadataKeyType,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import { TypeUtil } from '../util/TypeUtil';
|
|
||||||
|
|
||||||
|
|
||||||
export class Metadata {
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata key on the target object or its prototype chain.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* result = Metadata.get("custom:annotation", Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.get("custom:annotation", Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.get("custom:annotation", Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.get("custom:annotation", Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.get("custom:annotation", Example.prototype, "method");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static get(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata key on the target object or its prototype chain.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* result = Metadata.getOwn("custom:annotation", Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getOwn("custom:annotation", Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.getOwn("custom:annotation", Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getOwn("custom:annotation", Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.getOwn("custom:annotation", Example.prototype, "method");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getOwnMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getType(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getType(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getType(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getType(target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getOwnType(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getOwnType(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getOwnType(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getOwnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getReturnType(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getReturnType(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getReturnType(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getReturnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getMetadata(DESIGN_RETURN_TYPE, target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getOwnReturnType(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getOwnReturnType(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getOwnReturnType(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getOwnReturnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
||||||
return Reflect.getOwnMetadata(DESIGN_RETURN_TYPE, target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* result = Metadata.has("custom:annotation", Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.has("custom:annotation", Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.has("custom:annotation", Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.has("custom:annotation", Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.has("custom:annotation", Example.prototype, "method");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static has(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
||||||
return Reflect.hasMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* result = Metadata.has("custom:annotation", Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.hasOwn("custom:annotation", Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.hasOwn("custom:annotation", Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.hasOwn("custom:annotation", Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.hasOwn("custom:annotation", Example.prototype, "method");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static hasOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
||||||
return Reflect.hasOwnMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the metadata entry from the target object with the provided key.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns `true` if the metadata entry was found and deleted; otherwise, false.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* result = Metadata.delete("custom:annotation", Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.delete("custom:annotation", Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.delete("custom:annotation", Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.delete("custom:annotation", Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.delete("custom:annotation", Example.prototype, "method");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static delete(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
||||||
return Reflect.deleteMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @param value A value that contains attached metadata.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.setParamTypes(Example, undefined, [Object]);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.setParamTypes(Example, "staticProperty", [Object]);
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* result = Metadata.setParamTypes(Example.prototype, "property", [Object]);
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.setParamTypes(Example, "staticMethod", [Object]);
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* result = Metadata.setParamTypes(Example.prototype, "method", [Object]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static setParamTypes(target: any, propertyKey: PropertyKeyType, value: any): void {
|
|
||||||
return this.set(DESIGN_PARAM_TYPES, value, target.prototype, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all metadata for a metadataKey.
|
|
||||||
* @param metadataKey
|
|
||||||
*/
|
|
||||||
public static getTargetsFromPropertyKey = (metadataKey: MetadataKeyType): any[] =>
|
|
||||||
PROPERTIES.has(metadataKey) ? PROPERTIES.get(metadataKey) || [] : []
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define a unique metadata entry on the target.
|
|
||||||
* @param key A key used to store and retrieve metadata.
|
|
||||||
* @param value A value that contains attached metadata.
|
|
||||||
* @param target The target object on which to define metadata.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // constructor
|
|
||||||
* Reflect.defineMetadata("custom:annotation", options, Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* Reflect.defineMetadata("custom:annotation", Number, Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // property (on prototype)
|
|
||||||
* Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "property");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* Reflect.defineMetadata("custom:annotation", Number, Example, "staticMethod");
|
|
||||||
*
|
|
||||||
* // method (on prototype)
|
|
||||||
* Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "method");
|
|
||||||
*
|
|
||||||
* // decorator factory as metadata-producing annotation.
|
|
||||||
* function MyAnnotation(options): PropertyDecorator {
|
|
||||||
* return (target, key) => Reflect.defineMetadata("custom:annotation", options, target, key);
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static set(key: MetadataKeyType, value: any, target: any, propertyKey?: PropertyKeyType): void {
|
|
||||||
|
|
||||||
const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : [];
|
|
||||||
const classConstructor = TypeUtil.getType(target);
|
|
||||||
|
|
||||||
if (targets.indexOf(classConstructor) === -1) {
|
|
||||||
targets.push(classConstructor);
|
|
||||||
PROPERTIES.set(key, targets);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reflect.defineMetadata(key, value, TypeUtil.getType(target), propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getParamTypes(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getParamTypes(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getParamTypes(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
|
|
||||||
return Reflect.getMetadata(DESIGN_PARAM_TYPES, target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
||||||
* @param target The target object on which the metadata is defined.
|
|
||||||
* @param propertyKey The property key for the target.
|
|
||||||
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class Example {
|
|
||||||
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
||||||
* // static staticProperty;
|
|
||||||
* // property;
|
|
||||||
*
|
|
||||||
* static staticMethod(p) { }
|
|
||||||
* method(p) { }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // on contructor
|
|
||||||
* result = Metadata.getParamTypes(Example);
|
|
||||||
*
|
|
||||||
* // property (on constructor)
|
|
||||||
* result = Metadata.getParamTypes(Example, "staticProperty");
|
|
||||||
*
|
|
||||||
* // method (on constructor)
|
|
||||||
* result = Metadata.getParamTypes(Example, "staticMethod");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static getOwnParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
|
|
||||||
return Reflect.getOwnMetadata(DESIGN_PARAM_TYPES, target, propertyKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata key
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const DESIGN_PARAM_TYPES = 'design:paramtypes';
|
|
||||||
/**
|
|
||||||
* Metadata key
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const DESIGN_TYPE = 'design:type';
|
|
||||||
/**
|
|
||||||
* Metadata key
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const DESIGN_RETURN_TYPE = 'design:returntype';
|
|
||||||
/**
|
|
||||||
* Properties collections
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const PROPERTIES: Map<MetadataKeyType, any[]> = new Map<MetadataKeyType, any[]>();
|
|
|
@ -1,29 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '../util/TypeUtil';
|
|
||||||
|
|
||||||
import { Class } from './Class';
|
|
||||||
import { Executable } from './Executable';
|
|
||||||
|
|
||||||
export class Method extends Executable {
|
|
||||||
private _returnType: any;
|
|
||||||
private _rawMethod: Function;
|
|
||||||
|
|
||||||
public constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes: any[], returnType: any) {
|
|
||||||
super(declaringClazz, name, parameterTypes);
|
|
||||||
this._returnType = returnType;
|
|
||||||
this._rawMethod = TypeUtil.getPrototype(declaringClazz.getType())[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getReturnType(): any {
|
|
||||||
return this._returnType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public invoke(instance: Object, ...args: any[]): any {
|
|
||||||
return this._rawMethod.apply(instance, args);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { AccessibleObject } from './AccessibleObject';
|
|
||||||
import { Executable } from './Executable';
|
|
||||||
|
|
||||||
export class Parameter extends AccessibleObject {
|
|
||||||
private _executable: Executable;
|
|
||||||
private _type: any;
|
|
||||||
private _index: number;
|
|
||||||
private _name: string;
|
|
||||||
|
|
||||||
public constructor(executable: Executable, parameterType: any, name: string, index: number) {
|
|
||||||
super();
|
|
||||||
this._executable = executable;
|
|
||||||
this._type = parameterType;
|
|
||||||
this._name = name;
|
|
||||||
this._index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDeclaringExecutable(): Executable {
|
|
||||||
return this._executable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getType(): any {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getName(): string {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getIndex(): number {
|
|
||||||
return this._index;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
export * from './AccessibleObject';
|
|
||||||
export * from './AnnotatedElement';
|
|
||||||
export * from './Annotation';
|
|
||||||
export * from './Class';
|
|
||||||
export * from './Constructor';
|
|
||||||
|
|
||||||
export * from './Executable';
|
|
||||||
export * from './Field';
|
|
||||||
export * from './Member';
|
|
||||||
export * from './Metadata';
|
|
||||||
export * from './Method';
|
|
||||||
export * from './Parameter';
|
|
|
@ -1,16 +0,0 @@
|
||||||
export declare const Type: FunctionConstructor;
|
|
||||||
export declare function isType(v: any): v is Type<any>;
|
|
||||||
export interface Type<T> extends Function {
|
|
||||||
new (...args: any[]): T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export declare type IdentityType<T> = T | symbol;
|
|
||||||
export declare type PropertyKeyType = IdentityType<string>;
|
|
||||||
export declare type MetadataKeyType = IdentityType<string>;
|
|
||||||
|
|
||||||
export enum PrimitiveType {
|
|
||||||
ANY = 'any',
|
|
||||||
STRING = 'string',
|
|
||||||
NUMBER = 'number',
|
|
||||||
BOOLEAN = 'boolean',
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { Class, Annotation } from '../reflect';
|
|
||||||
import { Type } from '../type';
|
|
||||||
|
|
||||||
export abstract class AnnotationUtils {
|
|
||||||
public static hasAnnotation<T extends Annotation>(type: Type<any>, annotationClass: Type<T>): boolean {
|
|
||||||
const annotation = AnnotationUtils.getAnnotation(type, annotationClass);
|
|
||||||
if (undefined !== annotation) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getAnnotation<T extends Annotation>(type: Type<any>, annotationClass: Type<T>): T | undefined {
|
|
||||||
const clazz = Class.forType(type);
|
|
||||||
if (undefined === clazz) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const annotations = clazz.getAnnotations();
|
|
||||||
if (0 === annotations.size) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const annonClassType of Array.from(annotations.keys())) {
|
|
||||||
if (annonClassType === annotationClass) {
|
|
||||||
return <T>annotations.get(annonClassType);
|
|
||||||
}
|
|
||||||
const annotation = AnnotationUtils.getAnnotation(annonClassType, annotationClass);
|
|
||||||
if (undefined !== annotation) {
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
export abstract class Registry<K, V> {
|
|
||||||
private _parent: Registry<K, V>;
|
|
||||||
private _map: Map<K, V>;
|
|
||||||
|
|
||||||
protected constructor(parent?: Registry<K, V>) {
|
|
||||||
this._parent = parent;
|
|
||||||
this._map = new Map<K, V>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get parent(): Registry<K, V> | undefined {
|
|
||||||
return this._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get size(): number {
|
|
||||||
return this._map.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: K): V | undefined {
|
|
||||||
let v = this._map.get(key);
|
|
||||||
if (undefined === v && undefined !== this._parent) {
|
|
||||||
v = this._parent.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public has(key: K): boolean {
|
|
||||||
let exist = this._map.has(key);
|
|
||||||
if (!exist && undefined !== this._parent) {
|
|
||||||
exist = this._parent.has(key);
|
|
||||||
}
|
|
||||||
return exist;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(key: K, value: V): void {
|
|
||||||
this._map.set(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public entries(): IterableIterator<[K, V]> {
|
|
||||||
return this._map.entries();
|
|
||||||
}
|
|
||||||
|
|
||||||
public keys(): IterableIterator<K> {
|
|
||||||
return this._map.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public values(): IterableIterator<V> {
|
|
||||||
return this._map.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(): void {
|
|
||||||
this._map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(key: K): boolean {
|
|
||||||
let result = this._map.delete(key);
|
|
||||||
if (!result && undefined !== this._parent) {
|
|
||||||
result = this._parent.delete(key);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(callback: (vlaue: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
|
|
||||||
this._map.forEach(callback, thisArg);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,407 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
PrimitiveType,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '../type';
|
|
||||||
|
|
||||||
|
|
||||||
export class TypeUtil {
|
|
||||||
/**
|
|
||||||
* Get the provide constructor.
|
|
||||||
* @param target
|
|
||||||
*/
|
|
||||||
public static getContructor<T>(target: any): Type<T> {
|
|
||||||
return typeof target === 'function' ? target : target.constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the provide constructor if target is an instance.
|
|
||||||
* @param target
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
public static getType<T>(target: any): Type<T> {
|
|
||||||
return target.prototype ? target : target.constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the provide prototype if target is an instance.
|
|
||||||
* @param target
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
public static getPrototype(target: any): Object {
|
|
||||||
return typeof target === 'function' ? target.prototype : target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {symbol}
|
|
||||||
*/
|
|
||||||
public static getTypeOrSymbol(target: any): any {
|
|
||||||
return typeof target === 'symbol' ? target : TypeUtil.getType(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the given obj is a primitive.
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isPrimitiveOrPrimitiveType(target: any): boolean {
|
|
||||||
return TypeUtil.isString(target)
|
|
||||||
|| TypeUtil.isNumber(target)
|
|
||||||
|| TypeUtil.isBoolean(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {PrimitiveType}
|
|
||||||
*/
|
|
||||||
public static primitiveOf(target: any): PrimitiveType {
|
|
||||||
if (TypeUtil.isString(target)) {
|
|
||||||
return PrimitiveType.STRING;
|
|
||||||
}
|
|
||||||
if (TypeUtil.isNumber(target)) {
|
|
||||||
return PrimitiveType.NUMBER;
|
|
||||||
}
|
|
||||||
if (TypeUtil.isBoolean(target)) {
|
|
||||||
return PrimitiveType.BOOLEAN;
|
|
||||||
}
|
|
||||||
return PrimitiveType.ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isString(target: any): boolean {
|
|
||||||
return typeof target === 'string' || target instanceof String || target === String;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isNumber(target: any): boolean {
|
|
||||||
return typeof target === 'number' || target instanceof Number || target === Number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isBoolean(target: any): boolean {
|
|
||||||
return typeof target === 'boolean' || target instanceof Boolean || target === Boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
public static isArray(target: any): boolean {
|
|
||||||
return Array.isArray(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the clazz is an array.
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isArrayOrArrayType(target: any): boolean {
|
|
||||||
if (target === Array) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return TypeUtil.isArray(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the target.
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isCollection(target: any): boolean {
|
|
||||||
return TypeUtil.isArrayOrArrayType(target)
|
|
||||||
|| target === Map
|
|
||||||
|| target instanceof Map
|
|
||||||
|| target === Set
|
|
||||||
|| target instanceof Set
|
|
||||||
|| target === WeakMap
|
|
||||||
|| target instanceof WeakMap
|
|
||||||
|| target === WeakSet
|
|
||||||
|| target instanceof WeakSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isDate(target: any): boolean {
|
|
||||||
return target === Date || target instanceof Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isMethod(target: any, propertyKey: PropertyKeyType): boolean {
|
|
||||||
if (typeof(target[propertyKey]) === undefined) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return typeof target[propertyKey] === 'function';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isObject(target: any): boolean {
|
|
||||||
return target === Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isType(target: any): boolean {
|
|
||||||
return !TypeUtil.isPrimitiveOrPrimitiveType(target)
|
|
||||||
&& !TypeUtil.isObject(target)
|
|
||||||
&& !TypeUtil.isDate(target)
|
|
||||||
&& target !== undefined
|
|
||||||
&& !TypeUtil.isPromise(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the value is an empty string, null or undefined.
|
|
||||||
* @param value
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isEmpty(value: any): boolean {
|
|
||||||
return value === '' || value === null || value === undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get object name
|
|
||||||
*/
|
|
||||||
public static nameOf(obj: any): string {
|
|
||||||
switch (typeof obj) {
|
|
||||||
default:
|
|
||||||
return '' + obj;
|
|
||||||
case 'symbol':
|
|
||||||
return TypeUtil.nameOfSymbol(obj);
|
|
||||||
case 'function':
|
|
||||||
return TypeUtil.nameOfType(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the provide name.
|
|
||||||
* @param target
|
|
||||||
*/
|
|
||||||
public static nameOfType(target: any): string {
|
|
||||||
return typeof target === 'function'
|
|
||||||
? target.name
|
|
||||||
: target.constructor.name;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get symbol name.
|
|
||||||
* @param sym
|
|
||||||
*/
|
|
||||||
public static nameOfSymbol(sym: symbol): string {
|
|
||||||
return sym.toString().replace('Symbol(', '').replace(')', '');
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param out
|
|
||||||
* @param obj
|
|
||||||
* @param {{[p: string]: (collection: any[], value: any) => any}} reducers
|
|
||||||
* @returns {any}
|
|
||||||
*/
|
|
||||||
public static deepExtends(out: any, obj: any, reducers: { [key: string]: (collection: any[], value: any) => any } = {}): any {
|
|
||||||
|
|
||||||
if (obj === undefined || obj === null) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeUtil.isPrimitiveOrPrimitiveType(obj) || typeof obj === 'symbol' || typeof obj === 'function') {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeUtil.isArrayOrArrayType(obj)) {
|
|
||||||
out = out || [];
|
|
||||||
} else {
|
|
||||||
out = out || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultReducer = reducers.default ? reducers.default : (collection: any[], value: any) => {
|
|
||||||
collection.push(value);
|
|
||||||
return collection;
|
|
||||||
};
|
|
||||||
const set = (key: string | number, value: any) => {
|
|
||||||
if (TypeUtil.isArrayOrArrayType(obj)) {
|
|
||||||
out.push(value);
|
|
||||||
} else {
|
|
||||||
out[key] = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(obj).forEach(key => {
|
|
||||||
let value = obj[key];
|
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === '' && out[key] !== '') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeUtil.isPrimitiveOrPrimitiveType(value) || typeof value === 'function') {
|
|
||||||
set(key, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeUtil.isArrayOrArrayType(value)) {
|
|
||||||
|
|
||||||
value = value.map((v: any) => TypeUtil.deepExtends(undefined, v));
|
|
||||||
|
|
||||||
set(key, []
|
|
||||||
.concat(out[key] || [], value)
|
|
||||||
.reduce((collection: any[], v: any) =>
|
|
||||||
reducers[key] ? reducers[key](collection, v) : defaultReducer(collection, v),
|
|
||||||
[]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object
|
|
||||||
if (TypeUtil.isArrayOrArrayType(obj)) {
|
|
||||||
set(key, TypeUtil.deepExtends(undefined, value, reducers));
|
|
||||||
} else {
|
|
||||||
set(key, TypeUtil.deepExtends(out[key], value, reducers));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (TypeUtil.isArrayOrArrayType(out)) {
|
|
||||||
out.reduce((collection: any[], value: any) => defaultReducer(collection, value), []);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
public static isPromise(target: any): boolean {
|
|
||||||
return target === Promise || target instanceof Promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {any}
|
|
||||||
*/
|
|
||||||
public static getInheritedType(target: Type<any>): Type<any> {
|
|
||||||
return Object.getPrototypeOf(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @param {PropertyKeyType} propertyKey
|
|
||||||
* @returns {PropertyDescriptor}
|
|
||||||
*/
|
|
||||||
public static descriptorOf(target: any, propertyKey: PropertyKeyType): PropertyDescriptor {
|
|
||||||
return Object.getOwnPropertyDescriptor(target && target.prototype || target, propertyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @param {PropertyKeyType} propertyKey
|
|
||||||
* @returns {string[]}
|
|
||||||
*/
|
|
||||||
public static getParameterNames(target: any, propertyKey: PropertyKeyType): string[] {
|
|
||||||
const rawType = TypeUtil.getPrototype(target);
|
|
||||||
const fn: Function = rawType[propertyKey];
|
|
||||||
|
|
||||||
const code = fn.toString()
|
|
||||||
.replace(COMMENTS, '')
|
|
||||||
.replace(FAT_ARROWS, '')
|
|
||||||
.replace(DEFAULT_PARAMS, '');
|
|
||||||
|
|
||||||
const result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
|
|
||||||
|
|
||||||
return result === null
|
|
||||||
? []
|
|
||||||
: result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
public static ancestorsOf(target: Type<any>): Type<any>[] {
|
|
||||||
const classes: Type<any>[] = [];
|
|
||||||
|
|
||||||
let currentTarget = TypeUtil.getType(target);
|
|
||||||
|
|
||||||
while (TypeUtil.nameOf(currentTarget) !== '') {
|
|
||||||
classes.unshift(currentTarget);
|
|
||||||
currentTarget = TypeUtil.getInheritedType(currentTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @param {string} name
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
public static applyBefore(target: any, name: string, callback: Function): void {
|
|
||||||
const original = target[name];
|
|
||||||
target[name] = function (...args: any[]): any {
|
|
||||||
callback(...args);
|
|
||||||
return original.apply(this, args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {Promise<any>} promise
|
|
||||||
* @param {number} time
|
|
||||||
* @returns {Promise<any>}
|
|
||||||
*/
|
|
||||||
public static promiseTimeout(promise: Promise<any>, time: number = 1000): Promise<{ ok: boolean, response: any }> {
|
|
||||||
const timeout = (p: Promise<any>, t: number) => new Promise((resolve) => {
|
|
||||||
p.then((response) => {
|
|
||||||
resolve();
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
setTimeout(() => resolve({ok: false}), t);
|
|
||||||
});
|
|
||||||
|
|
||||||
promise = promise.then((response) => ({ok: true, response}));
|
|
||||||
|
|
||||||
return Promise.race([
|
|
||||||
promise,
|
|
||||||
timeout(promise, time),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
|
||||||
const DEFAULT_PARAMS = /=[^,]+/mg;
|
|
||||||
const FAT_ARROWS = /=>.*$/mg;
|
|
|
@ -1,22 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '@loafer/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Annotation,
|
|
||||||
} from '@loafer/core/reflect';
|
|
||||||
|
|
||||||
export interface Decorator<Attribute = {}> {
|
|
||||||
classDecorator?: <TFunction extends Function>(target: TFunction) => TFunction | void;
|
|
||||||
propertyDecorator?: (target: Object, propertyKey: PropertyKeyType) => void;
|
|
||||||
methodDecorator?: <T>(target: Object, propertyKey: PropertyKeyType,
|
|
||||||
descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
|
|
||||||
parameterDecorator?: (target: Object, propertyKey: PropertyKeyType, parameterIndex: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class Decorator<Attribute = {}> extends Annotation<Attribute> {
|
|
||||||
public constructor(attribute?: Attribute) {
|
|
||||||
super(attribute);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
MetadataKeyType,
|
|
||||||
} from '@loafer/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Annotation,
|
|
||||||
Class,
|
|
||||||
Constructor,
|
|
||||||
Field,
|
|
||||||
Method,
|
|
||||||
Parameter,
|
|
||||||
Metadata,
|
|
||||||
} from '@loafer/core/reflect';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '@loafer/core/util/TypeUtil';
|
|
||||||
|
|
||||||
import { Decorator } from './Decorator';
|
|
||||||
import { DecoratorUtil } from './util';
|
|
||||||
import { DecoratorType } from './type';
|
|
||||||
import { NotSupportedDecoratorError } from './error';
|
|
||||||
|
|
||||||
|
|
||||||
export class DecoratorFactory {
|
|
||||||
public static create = <Attribute = {}>(DecoratorClass: Type<Decorator<Attribute>>) => {
|
|
||||||
return (attribute: Attribute) => {
|
|
||||||
const annotation: Decorator<Attribute> = new DecoratorClass(attribute);
|
|
||||||
const name: string = DecoratorClass.name;
|
|
||||||
|
|
||||||
return (...decoratorArgs: any[]) => {
|
|
||||||
const decoratorType: DecoratorType = DecoratorUtil.getDecoratorType(decoratorArgs);
|
|
||||||
|
|
||||||
const [target, propertyKey, descriptorOrParameterIndex] = decoratorArgs;
|
|
||||||
|
|
||||||
const clazz: Class = Class._defineClass(TypeUtil.getType(target));
|
|
||||||
let field: Field = null;
|
|
||||||
let method: Method = null;
|
|
||||||
let parameter: Parameter = null;
|
|
||||||
let cons: Constructor = null;
|
|
||||||
|
|
||||||
switch (decoratorType) {
|
|
||||||
case DecoratorType.CLASS:
|
|
||||||
try {
|
|
||||||
cons = clazz._defineConstructor(Metadata.getOwnParamTypes(target));
|
|
||||||
clazz._addAnnotation(annotation);
|
|
||||||
return annotation.classDecorator.call(annotation, target);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof NotSupportedDecoratorError) {
|
|
||||||
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Class.`);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
case DecoratorType.PROPERTY:
|
|
||||||
try {
|
|
||||||
field = clazz._defineField(propertyKey, Metadata.getOwnType(target, propertyKey));
|
|
||||||
field._addAnnotation(annotation);
|
|
||||||
return annotation.propertyDecorator.call(annotation, target, propertyKey);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof NotSupportedDecoratorError) {
|
|
||||||
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Property.`);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
case DecoratorType.METHOD:
|
|
||||||
try {
|
|
||||||
method = clazz._defineMethod(propertyKey,
|
|
||||||
Metadata.getOwnParamTypes(target, propertyKey),
|
|
||||||
Metadata.getOwnReturnType(target, propertyKey));
|
|
||||||
method._addAnnotation(annotation);
|
|
||||||
|
|
||||||
return annotation.methodDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof NotSupportedDecoratorError) {
|
|
||||||
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Method.`);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
case DecoratorType.PARAMETER:
|
|
||||||
try {
|
|
||||||
if (undefined === propertyKey) {
|
|
||||||
cons = clazz.getConstructor();
|
|
||||||
parameter = cons.getParameter(descriptorOrParameterIndex);
|
|
||||||
} else {
|
|
||||||
method = clazz._defineMethod(propertyKey,
|
|
||||||
Metadata.getOwnParamTypes(target, propertyKey),
|
|
||||||
Metadata.getOwnReturnType(target, propertyKey));
|
|
||||||
parameter = method.getParameter(descriptorOrParameterIndex);
|
|
||||||
}
|
|
||||||
parameter._addAnnotation(annotation);
|
|
||||||
|
|
||||||
return annotation.parameterDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof NotSupportedDecoratorError) {
|
|
||||||
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Parameter.`);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotSupportedDecoratorError(`Cannot determine decorator[@${name}] type.`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
export class NotSupportedDecoratorError extends Error {
|
|
||||||
public constructor(message?: string) {
|
|
||||||
super(message);
|
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotDecoratedClassError extends Error {
|
|
||||||
public constructor(message?: string) {
|
|
||||||
super(message);
|
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
export * from './Decorator';
|
|
||||||
export * from './DecoratorFactory';
|
|
||||||
export * from './error';
|
|
||||||
export * from './type';
|
|
||||||
export * from './util';
|
|
|
@ -1,8 +0,0 @@
|
||||||
export enum DecoratorType {
|
|
||||||
CLASS = 'Clazz',
|
|
||||||
PROPERTY = 'Property',
|
|
||||||
METHOD = 'Method',
|
|
||||||
PARAMETER = 'Parameter',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DecoratorParametersType = [any, string | symbol, number | PropertyDescriptor];
|
|
|
@ -1,48 +0,0 @@
|
||||||
import {
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '@loafer/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TypeUtil,
|
|
||||||
} from '@loafer/core/util/TypeUtil';
|
|
||||||
|
|
||||||
|
|
||||||
import {
|
|
||||||
DecoratorType,
|
|
||||||
DecoratorParametersType,
|
|
||||||
} from './type';
|
|
||||||
|
|
||||||
export class DecoratorUtil {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {any[]} args
|
|
||||||
* @returns {DecoratorType}
|
|
||||||
*/
|
|
||||||
public static getDecoratorType(args: any[]): DecoratorType {
|
|
||||||
const [, propertyKey, descriptor] = args;
|
|
||||||
|
|
||||||
if (typeof descriptor === 'number') {
|
|
||||||
return DecoratorType.PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyKey && descriptor === undefined || descriptor && (descriptor.get || descriptor.set)) {
|
|
||||||
return DecoratorType.PROPERTY;
|
|
||||||
}
|
|
||||||
return (descriptor && descriptor.value) ? DecoratorType.METHOD : DecoratorType.CLASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* @param {string} propertyKey
|
|
||||||
* @returns {DecoratorParametersType}
|
|
||||||
*/
|
|
||||||
public static decoratorArgs(target: any, propertyKey: PropertyKeyType): DecoratorParametersType {
|
|
||||||
return [
|
|
||||||
target,
|
|
||||||
propertyKey,
|
|
||||||
TypeUtil.descriptorOf(target, propertyKey),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { LoggerLevel } from './type';
|
|
||||||
|
|
||||||
export interface LoggerConfig {
|
|
||||||
level: LoggerLevel;
|
|
||||||
serverLogLevel?: LoggerLevel;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export * from './config';
|
|
||||||
export * from './token';
|
|
||||||
export * from './type';
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { InjectionToken } from '@angular/core';
|
|
||||||
|
|
||||||
export const _LOGGER_CONFIG = new InjectionToken('@loafer/ng-logger Internal Logger config');
|
|
|
@ -1,26 +0,0 @@
|
||||||
export enum LoggerLevel {
|
|
||||||
TRACE = 0,
|
|
||||||
DEBUG,
|
|
||||||
INFO,
|
|
||||||
LOG,
|
|
||||||
WARN,
|
|
||||||
ERROR,
|
|
||||||
OFF,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LoggerLevelName = [
|
|
||||||
'TRACE',
|
|
||||||
'DEBUG',
|
|
||||||
'INFO',
|
|
||||||
'LOG',
|
|
||||||
'WARN',
|
|
||||||
'ERROR',
|
|
||||||
'OFF'
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface ServerLoggingParameter {
|
|
||||||
level: string;
|
|
||||||
message: string;
|
|
||||||
addtional?: string;
|
|
||||||
timestamp: Date;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './ng-logger.module';
|
|
|
@ -1,65 +0,0 @@
|
||||||
import {
|
|
||||||
NgModule,
|
|
||||||
ModuleWithProviders,
|
|
||||||
Type,
|
|
||||||
Inject,
|
|
||||||
InjectionToken,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
_LOGGER_CONFIG,
|
|
||||||
LoggerConfig,
|
|
||||||
} from './core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SERVICES, LoggerService,
|
|
||||||
} from './service';
|
|
||||||
|
|
||||||
export interface LoggerFeatureModuleConfig {
|
|
||||||
url?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoggerRootModuleConfig {
|
|
||||||
config: LoggerConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class LoggerRootModule {
|
|
||||||
constructor(
|
|
||||||
private loggerService: LoggerService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class LoggerFeatureModule {
|
|
||||||
constructor(
|
|
||||||
private loggerService: LoggerService,
|
|
||||||
private root: LoggerRootModule,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class LoggerModule {
|
|
||||||
static forRoot(config: LoggerRootModuleConfig): ModuleWithProviders {
|
|
||||||
return {
|
|
||||||
ngModule: LoggerRootModule,
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: _LOGGER_CONFIG,
|
|
||||||
useValue: config.config,
|
|
||||||
},
|
|
||||||
SERVICES,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static forFeature(config: LoggerFeatureModuleConfig): ModuleWithProviders {
|
|
||||||
return {
|
|
||||||
ngModule: LoggerFeatureModule,
|
|
||||||
providers: [
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './logger.service';
|
|
||||||
|
|
||||||
import { LoggerService } from './logger.service';
|
|
||||||
|
|
||||||
export const SERVICES = [
|
|
||||||
LoggerService,
|
|
||||||
];
|
|
|
@ -1,158 +0,0 @@
|
||||||
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
|
|
||||||
import { isPlatformBrowser } from '@angular/common';
|
|
||||||
|
|
||||||
import {
|
|
||||||
LoggerConfig,
|
|
||||||
LoggerLevel,
|
|
||||||
LoggerLevelName,
|
|
||||||
_LOGGER_CONFIG,
|
|
||||||
} from '../core';
|
|
||||||
|
|
||||||
export type ConsoleFunc = (message?: any, ...optionalParams: any[]) => void;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class LoggerService {
|
|
||||||
private _isIE: boolean;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
@Inject(_LOGGER_CONFIG) private readonly config: LoggerConfig,
|
|
||||||
@Inject(PLATFORM_ID) private readonly platformId,
|
|
||||||
) {
|
|
||||||
this._isIE = isPlatformBrowser(platformId) &&
|
|
||||||
!!(navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.match(/Trident\//) || navigator.userAgent.match(/Edge\//));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public get trace(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.TRACE);
|
|
||||||
}
|
|
||||||
public get debug(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.DEBUG);
|
|
||||||
}
|
|
||||||
public get info(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.INFO);
|
|
||||||
}
|
|
||||||
public get log(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.LOG);
|
|
||||||
}
|
|
||||||
public get warn(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.WARN);
|
|
||||||
}
|
|
||||||
public get error(): ConsoleFunc {
|
|
||||||
return this.getConsoleMethod(LoggerLevel.ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _console_log: ConsoleFunc;
|
|
||||||
|
|
||||||
private getConsoleMethod(level: LoggerLevel): ConsoleFunc {
|
|
||||||
if (level < this.config.level) {
|
|
||||||
return (message, ...additional: any[]) => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._isIE) {
|
|
||||||
switch (level) {
|
|
||||||
case LoggerLevel.WARN:
|
|
||||||
return console.warn.bind(console, ...this.getLogHeader(level));
|
|
||||||
case LoggerLevel.ERROR:
|
|
||||||
return console.error.bind(console, ...this.getLogHeader(level));
|
|
||||||
case LoggerLevel.INFO:
|
|
||||||
return console.info.bind(console, ...this.getLogHeader(level));
|
|
||||||
default:
|
|
||||||
return console.log.bind(console, ...this.getLogHeader(level));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return console.log.bind(console, ...this.getLogHeader(level));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getLogHeader(level: LoggerLevel): any[] {
|
|
||||||
const params: any[] = [];
|
|
||||||
params.push(`%c${this._timestamp()} [${LoggerLevelName[level]}]`);
|
|
||||||
if (!this._isIE) {
|
|
||||||
const color = this._getColor(level);
|
|
||||||
params.push(`color:${color}`);
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _timestamp(): string {
|
|
||||||
return new Date().toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _log(level: LoggerLevel, message, additional: any[] = []): void {
|
|
||||||
if (!message) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow logging on server even if client log level is off
|
|
||||||
// if (logOnServer) {
|
|
||||||
// this._logOnServer(level, message, additional);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if no message or the log level is less than the environ
|
|
||||||
if (level < this.config.level) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
message = typeof message === 'string' ? message : JSON.stringify(message, null, 2);
|
|
||||||
} catch (e) {
|
|
||||||
additional = [message, ...additional];
|
|
||||||
message = 'The provided "message" value could not be parsed with JSON.stringify().';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coloring doesn't work in IE
|
|
||||||
if (this._isIE) {
|
|
||||||
return this._logIE(level, message, additional);
|
|
||||||
}
|
|
||||||
|
|
||||||
const color = this._getColor(level);
|
|
||||||
|
|
||||||
const params: any[] = [];
|
|
||||||
params.push(`%c${this._timestamp()} [${LoggerLevelName[level]}]`);
|
|
||||||
params.push(`color:${color}`);
|
|
||||||
params.push(message);
|
|
||||||
params.push(...additional);
|
|
||||||
|
|
||||||
console.log.apply(console, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _logIE(level: LoggerLevel, message: string, additional: any[] = []): void {
|
|
||||||
const params: any[] = [];
|
|
||||||
params.push(`${this._timestamp()} [${LoggerLevelName[level]}] `);
|
|
||||||
params.push(message);
|
|
||||||
params.push(...additional);
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case LoggerLevel.WARN:
|
|
||||||
console.warn.apply(console, params);
|
|
||||||
break;
|
|
||||||
case LoggerLevel.ERROR:
|
|
||||||
console.error.apply(console, params);
|
|
||||||
break;
|
|
||||||
case LoggerLevel.INFO:
|
|
||||||
console.info.apply(console, params);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log.apply(console, params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getColor(level: LoggerLevel): 'blue' | 'teal' | 'gray' | 'red' | undefined {
|
|
||||||
switch (level) {
|
|
||||||
case LoggerLevel.TRACE:
|
|
||||||
return 'blue';
|
|
||||||
case LoggerLevel.DEBUG:
|
|
||||||
return 'teal';
|
|
||||||
case LoggerLevel.INFO:
|
|
||||||
case LoggerLevel.LOG:
|
|
||||||
return 'gray';
|
|
||||||
case LoggerLevel.WARN:
|
|
||||||
case LoggerLevel.ERROR:
|
|
||||||
return 'red';
|
|
||||||
case LoggerLevel.OFF:
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
import { Injectable, Inject } from '@angular/core';
|
|
||||||
import { Location } from '@angular/common';
|
|
||||||
import { HttpClient, HttpHeaders, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import 'rxjs/add/operator/do';
|
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
import 'rxjs/add/operator/catch';
|
|
||||||
import 'rxjs/add/operator/timeout';
|
|
||||||
import 'rxjs/add/observable/throw';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RESTError,
|
|
||||||
RESTClientError,
|
|
||||||
} from '../protocol';
|
|
||||||
|
|
||||||
export class RESTClient {
|
|
||||||
constructor(
|
|
||||||
private _baseURL: string,
|
|
||||||
private _httpClient: HttpClient,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public get httpClient(): HttpClient {
|
|
||||||
return this._httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public request<T>(method: string, entry: string, options?: {
|
|
||||||
body?: any;
|
|
||||||
headers?: HttpHeaders | {
|
|
||||||
[header: string]: string | string[];
|
|
||||||
};
|
|
||||||
observe?: 'body';
|
|
||||||
params?: HttpParams | {
|
|
||||||
[param: string]: string | string[];
|
|
||||||
};
|
|
||||||
responseType?: 'json';
|
|
||||||
reportProgress?: boolean;
|
|
||||||
withCredentials?: boolean;
|
|
||||||
}): Observable<T> {
|
|
||||||
return this._httpClient
|
|
||||||
.request<T>(method, Location.joinWithSlash(this._baseURL, entry), options)
|
|
||||||
.map(response => response)
|
|
||||||
.catch((error: HttpErrorResponse) => {
|
|
||||||
const restClientError: RESTClientError = {
|
|
||||||
request: {
|
|
||||||
method: method,
|
|
||||||
entry: entry,
|
|
||||||
options: options,
|
|
||||||
},
|
|
||||||
response: error.error,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.error(restClientError);
|
|
||||||
// const aryMsg = error.error.message.split('|');
|
|
||||||
// const resError: RESTError = {
|
|
||||||
// code: error.error.code,
|
|
||||||
// message: aryMsg[0],
|
|
||||||
// data: aryMsg[1] === 'null' ? '' : aryMsg[1],
|
|
||||||
// };
|
|
||||||
return Observable.throw(restClientError);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './RESTClient';
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './token';
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { InjectionToken } from '@angular/core';
|
|
||||||
|
|
||||||
export const _REST_BASE_URL = new InjectionToken('@loafer/ng-rest Internal Base URL');
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './ng-rest.module';
|
|
|
@ -1,64 +0,0 @@
|
||||||
import {
|
|
||||||
NgModule,
|
|
||||||
ModuleWithProviders,
|
|
||||||
Type,
|
|
||||||
Inject,
|
|
||||||
InjectionToken,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
_REST_BASE_URL,
|
|
||||||
} from './core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SERVICES, RESTService,
|
|
||||||
} from './service';
|
|
||||||
|
|
||||||
export interface RESTFeatureModuleConfig {
|
|
||||||
url?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RESTRootModuleConfig {
|
|
||||||
baseURL: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RESTRootModule {
|
|
||||||
constructor(
|
|
||||||
private restService: RESTService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RESTFeatureModule {
|
|
||||||
constructor(
|
|
||||||
private restService: RESTService,
|
|
||||||
private root: RESTRootModule,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RESTModule {
|
|
||||||
static forRoot(config: RESTRootModuleConfig): ModuleWithProviders {
|
|
||||||
return {
|
|
||||||
ngModule: RESTRootModule,
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: _REST_BASE_URL,
|
|
||||||
useValue: config.baseURL,
|
|
||||||
},
|
|
||||||
SERVICES,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static forFeature(config: RESTFeatureModuleConfig): ModuleWithProviders {
|
|
||||||
return {
|
|
||||||
ngModule: RESTFeatureModule,
|
|
||||||
providers: [
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
export interface RESTClientError {
|
|
||||||
request: {
|
|
||||||
method: string;
|
|
||||||
entry: string;
|
|
||||||
options?: any;
|
|
||||||
};
|
|
||||||
response: RESTError;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RESTError {
|
|
||||||
code: number;
|
|
||||||
message: string;
|
|
||||||
data?: any;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './RESTError';
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './rest.service';
|
|
||||||
|
|
||||||
import { RESTService } from './rest.service';
|
|
||||||
|
|
||||||
export const SERVICES = [
|
|
||||||
RESTService,
|
|
||||||
];
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { TestBed, inject } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { RESTService } from './rest.service';
|
|
||||||
|
|
||||||
describe('RESTService', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [RESTService]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', inject([RESTService], (service: RESTService) => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
}));
|
|
||||||
});
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { Injectable, Inject } from '@angular/core';
|
|
||||||
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
|
|
||||||
import { Location } from '@angular/common';
|
|
||||||
|
|
||||||
import 'rxjs/add/operator/do';
|
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
import 'rxjs/add/operator/catch';
|
|
||||||
import 'rxjs/add/operator/timeout';
|
|
||||||
import 'rxjs/add/observable/throw';
|
|
||||||
|
|
||||||
import { _REST_BASE_URL } from '../core';
|
|
||||||
import { RESTClient } from '../client';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RESTService extends RESTClient {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(_REST_BASE_URL) _baseURL: string,
|
|
||||||
@Inject(HttpClient) _httpClient: HttpClient,
|
|
||||||
) {
|
|
||||||
super(_baseURL, _httpClient);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import { Subject } from 'rxjs/Subject';
|
|
||||||
|
|
||||||
import { RPCClientError } from '../protocol/RPCError';
|
|
||||||
import { RPCClientRWC } from './RPCClientRWC';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClientCodec,
|
|
||||||
RPCClientResponseCodec,
|
|
||||||
RPCClientNotificationCodec,
|
|
||||||
} from '../protocol/RPCClientCodec';
|
|
||||||
|
|
||||||
export interface RPCRequestState {
|
|
||||||
subject: Subject<any>;
|
|
||||||
request: {
|
|
||||||
method: string;
|
|
||||||
params: any[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class RPCClient {
|
|
||||||
private _requestID: number;
|
|
||||||
|
|
||||||
private _pendingRequestsCount: number;
|
|
||||||
private _pendingRequests: Map<number, RPCRequestState>;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private _codec: RPCClientCodec,
|
|
||||||
private _rwc: RPCClientRWC,
|
|
||||||
) {
|
|
||||||
this._requestID = 0;
|
|
||||||
this._pendingRequestsCount = 0;
|
|
||||||
this._pendingRequests = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getRequestID(): number {
|
|
||||||
return ++this._requestID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* connect
|
|
||||||
*/
|
|
||||||
public connect(queryString?: string): void {
|
|
||||||
this._rwc.connect(queryString);
|
|
||||||
this._rwc.readResponse().subscribe(
|
|
||||||
(value: Object) => {
|
|
||||||
this.onMessage(value);
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
console.error(error);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* close
|
|
||||||
*/
|
|
||||||
public disconnect() {
|
|
||||||
this._rwc.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* notify
|
|
||||||
*/
|
|
||||||
public send(method: string, ...args: any[]): void {
|
|
||||||
this.sendInternal(false, method, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* call
|
|
||||||
*/
|
|
||||||
public call<T>(method: string, ...args: any[]): Observable<T> {
|
|
||||||
return this.sendInternal<T>(true, method, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* callTimeout
|
|
||||||
*/
|
|
||||||
public callTimeout<T>(ms: number, method: string, ...args: any[]): Observable<T> {
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private sendInternal<T>(hasResponse: boolean, method: string, args?: any[]): Observable<T> | undefined {
|
|
||||||
let id: number;
|
|
||||||
let resSubject: Subject<T>;
|
|
||||||
if (hasResponse) {
|
|
||||||
id = this.getRequestID();
|
|
||||||
resSubject = new Subject<T>();
|
|
||||||
const reqState: RPCRequestState = {
|
|
||||||
subject: resSubject,
|
|
||||||
request: {
|
|
||||||
method: method,
|
|
||||||
params: args,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this._pendingRequests.set(id, reqState);
|
|
||||||
this._pendingRequestsCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const req = this._codec.request(method, args, id);
|
|
||||||
this._rwc.writeRequest(req);
|
|
||||||
|
|
||||||
if (undefined !== resSubject) {
|
|
||||||
return resSubject.asObservable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMessage(message: Object): void {
|
|
||||||
const resCodec = this._codec.response(message);
|
|
||||||
|
|
||||||
if (resCodec.isNotification()) {
|
|
||||||
this.onNotification(resCodec.notification());
|
|
||||||
} else {
|
|
||||||
this.onResponse(resCodec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onResponse(resCodec: RPCClientResponseCodec): void {
|
|
||||||
const id = resCodec.id();
|
|
||||||
const result = resCodec.result();
|
|
||||||
const error = resCodec.error();
|
|
||||||
|
|
||||||
const reqState: RPCRequestState = this._pendingRequests.get(id);
|
|
||||||
|
|
||||||
this._pendingRequests.delete(id);
|
|
||||||
this._pendingRequestsCount--;
|
|
||||||
|
|
||||||
if (undefined !== result) {
|
|
||||||
reqState.subject.next(result);
|
|
||||||
} else if (undefined !== error) {
|
|
||||||
const rpcClientError: RPCClientError = {
|
|
||||||
request: reqState.request,
|
|
||||||
response: error,
|
|
||||||
};
|
|
||||||
console.error(rpcClientError);
|
|
||||||
reqState.subject.error(rpcClientError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract onNotification(notiCodec: RPCClientNotificationCodec): void;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { InjectionToken } from '@angular/core';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
|
|
||||||
export interface RPCClientRWC {
|
|
||||||
connect(queryString?: string): void;
|
|
||||||
readResponse(): Observable<Object>;
|
|
||||||
writeRequest(data: any): void;
|
|
||||||
disconnect(): void;
|
|
||||||
connectionStatus(): Observable<boolean>;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './RPCClient';
|
|
||||||
export * from './RPCClientRWC';
|
|
|
@ -1,62 +0,0 @@
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import { Subject } from 'rxjs/Subject';
|
|
||||||
import { map } from 'rxjs/operator/map';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RxWebsocketSubject,
|
|
||||||
RxWebsocketSubjectConfig,
|
|
||||||
} from './RxWebsocketSubject';
|
|
||||||
|
|
||||||
import { RPCClientRWC } from '../../RPCClientRWC';
|
|
||||||
|
|
||||||
export class RPCClientWebsocketRWC implements RPCClientRWC {
|
|
||||||
private _wsSocketSubject: RxWebsocketSubject<Object>;
|
|
||||||
private _responseSubject: Subject<Object>;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private _config: RxWebsocketSubjectConfig,
|
|
||||||
) {
|
|
||||||
this._wsSocketSubject = new RxWebsocketSubject<Object>(this._config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public connect(queryString?: string): void {
|
|
||||||
if (undefined !== queryString) {
|
|
||||||
this._wsSocketSubject.queryString = queryString;
|
|
||||||
}
|
|
||||||
this._wsSocketSubject.connect();
|
|
||||||
this._wsSocketSubject.subscribe(
|
|
||||||
(value: Object) => {
|
|
||||||
if (undefined !== this._responseSubject) {
|
|
||||||
this._responseSubject.next(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
if (undefined !== this._responseSubject) {
|
|
||||||
this._responseSubject.error(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
console.log('sss');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public disconnect(): void {
|
|
||||||
this._wsSocketSubject.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public connectionStatus(): Observable<boolean> {
|
|
||||||
return this._wsSocketSubject.connectionStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readResponse(): Observable<Object> {
|
|
||||||
if (undefined === this._responseSubject) {
|
|
||||||
this._responseSubject = new Subject<Object>();
|
|
||||||
}
|
|
||||||
return this._responseSubject.asObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public writeRequest(data: any): void {
|
|
||||||
this._wsSocketSubject.write(data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import { Observer } from 'rxjs/Observer';
|
|
||||||
import { Subject } from 'rxjs/Subject';
|
|
||||||
import {
|
|
||||||
WebSocketSubject,
|
|
||||||
WebSocketSubjectConfig
|
|
||||||
} from 'rxjs/observable/dom/WebSocketSubject';
|
|
||||||
|
|
||||||
import 'rxjs/add/operator/distinctUntilChanged';
|
|
||||||
import 'rxjs/add/operator/share';
|
|
||||||
import 'rxjs/add/operator/takeWhile';
|
|
||||||
import 'rxjs/add/observable/interval';
|
|
||||||
|
|
||||||
export interface RxWebsocketSubjectConfig {
|
|
||||||
url: string;
|
|
||||||
protocol?: string | Array<string>;
|
|
||||||
reconnectInterval?: 5000;
|
|
||||||
reconnectRetry?: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RxWebsocketSubject<T> extends Subject<T> {
|
|
||||||
private _reconnectionObservable: Observable<number>;
|
|
||||||
private _wsSubjectConfig: WebSocketSubjectConfig;
|
|
||||||
private _socket: WebSocketSubject<any>;
|
|
||||||
private _connectionObserver: Observer<boolean>;
|
|
||||||
private _connectionStatus: Observable<boolean>;
|
|
||||||
private _queryString: string;
|
|
||||||
|
|
||||||
public constructor(private _config: RxWebsocketSubjectConfig) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._connectionStatus = new Observable<boolean>((observer) => {
|
|
||||||
this._connectionObserver = observer;
|
|
||||||
}).share().distinctUntilChanged();
|
|
||||||
|
|
||||||
this._wsSubjectConfig = {
|
|
||||||
url: _config.url,
|
|
||||||
protocol: _config.protocol,
|
|
||||||
closeObserver: {
|
|
||||||
next: (e: CloseEvent) => {
|
|
||||||
this._socket = null;
|
|
||||||
this._connectionObserver.next(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openObserver: {
|
|
||||||
next: (e: Event) => {
|
|
||||||
this._connectionObserver.next(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this._connectionStatus.subscribe((isConnected: boolean) => {
|
|
||||||
if (!this._reconnectionObservable && typeof(isConnected) === 'boolean' && !isConnected) {
|
|
||||||
this.reconnect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public set queryString(query: string) {
|
|
||||||
this._queryString = query;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get queryString(): string | undefined {
|
|
||||||
return this._queryString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get connectionStatus(): Observable<boolean> {
|
|
||||||
return this._connectionStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public connect(): void {
|
|
||||||
const wsSubjectConfig = Object.assign({}, this._wsSubjectConfig);
|
|
||||||
if (undefined !== this._queryString) {
|
|
||||||
wsSubjectConfig.url = wsSubjectConfig.url + '?' + this._queryString;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._socket = new WebSocketSubject(wsSubjectConfig);
|
|
||||||
this._socket.subscribe(
|
|
||||||
(m) => {
|
|
||||||
this.next(m);
|
|
||||||
},
|
|
||||||
(error: Event) => {
|
|
||||||
if (!this._socket) {
|
|
||||||
this.reconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public disconnect(): void {
|
|
||||||
this._socket.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private reconnect(): void {
|
|
||||||
this._reconnectionObservable = Observable.interval(this._config.reconnectInterval)
|
|
||||||
.takeWhile((v, index) => {
|
|
||||||
return index < this._config.reconnectRetry && !this._socket;
|
|
||||||
});
|
|
||||||
this._reconnectionObservable.subscribe(
|
|
||||||
() => {
|
|
||||||
this.connect();
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
() => {
|
|
||||||
this._reconnectionObservable = null;
|
|
||||||
if (!this._socket) {
|
|
||||||
this.complete();
|
|
||||||
this._connectionObserver.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public write(data: any): void {
|
|
||||||
this._socket.next(data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './RPCClientWebsocketRWC';
|
|
||||||
export * from './RxWebsocketSubject';
|
|
|
@ -1,6 +0,0 @@
|
||||||
export class SubscriberParameterError extends Error {
|
|
||||||
public constructor(message?: string) {
|
|
||||||
super(message);
|
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './error';
|
|
||||||
export * from './token';
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { InjectionToken } from '@angular/core';
|
|
||||||
|
|
||||||
export const RPC_CODEC = new InjectionToken('@loafer/ng-rpc RPC codec');
|
|
||||||
export const RPC_RWC = new InjectionToken('@loafer/ng-rpc RPC rwc');
|
|
||||||
|
|
||||||
export const _ROOT_SUBSCRIBERS = new InjectionToken('@loafer/ng-rpc RPC root subscribers');
|
|
||||||
export const _FEATURE_SUBSCRIBERS = new InjectionToken('@loafer/ng-rpc RPC feature subscribers');
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './rpc-subscriber.decorator';
|
|
|
@ -1,26 +0,0 @@
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '@loafer/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Decorator,
|
|
||||||
DecoratorFactory,
|
|
||||||
} from '@loafer/decorator';
|
|
||||||
|
|
||||||
export interface RPCSubscriberDecoratorAttribute {
|
|
||||||
method: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RPCSubscriberDecorator extends Decorator<RPCSubscriberDecoratorAttribute> {
|
|
||||||
public constructor(config: RPCSubscriberDecoratorAttribute) {
|
|
||||||
super(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public methodDecorator = <T>(target: Object, propertyKey: PropertyKeyType,
|
|
||||||
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void => {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RPCSubscriber = DecoratorFactory.create<RPCSubscriberDecoratorAttribute>(RPCSubscriberDecorator);
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './ng-rpc.module';
|
|
|
@ -1,109 +0,0 @@
|
||||||
import {
|
|
||||||
NgModule,
|
|
||||||
ModuleWithProviders,
|
|
||||||
Type,
|
|
||||||
Inject,
|
|
||||||
InjectionToken,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPC_CODEC,
|
|
||||||
RPC_RWC,
|
|
||||||
|
|
||||||
_ROOT_SUBSCRIBERS,
|
|
||||||
_FEATURE_SUBSCRIBERS,
|
|
||||||
} from './core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClientRWC,
|
|
||||||
} from './client/RPCClientRWC';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClientCodec,
|
|
||||||
} from './protocol';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SERVICES, RPCService,
|
|
||||||
} from './service';
|
|
||||||
|
|
||||||
import {
|
|
||||||
SUBSCRIBERS, RPCSubscribeService,
|
|
||||||
} from './subscribe';
|
|
||||||
|
|
||||||
export interface RPCFeatureModuleConfig {
|
|
||||||
subscribers?: Type<any>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RPCRootModuleConfig {
|
|
||||||
subscribers?: Type<any>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RPCRootModule {
|
|
||||||
constructor(
|
|
||||||
private rpcService: RPCService,
|
|
||||||
private rpcSubscribeService: RPCSubscribeService,
|
|
||||||
@Inject(_ROOT_SUBSCRIBERS) rootSubscribers: any[],
|
|
||||||
) {
|
|
||||||
rootSubscribers.forEach((subscriber) => {
|
|
||||||
rpcSubscribeService.addSubscriber(subscriber);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RPCFeatureModule {
|
|
||||||
constructor(
|
|
||||||
private rpcService: RPCService,
|
|
||||||
private rpcSubscribeService: RPCSubscribeService,
|
|
||||||
@Inject(_FEATURE_SUBSCRIBERS) featureSubscribersGroups: any[][],
|
|
||||||
private root: RPCRootModule,
|
|
||||||
) {
|
|
||||||
featureSubscribersGroups.forEach((featureSubscribers) => {
|
|
||||||
featureSubscribers.forEach((subscriber) => {
|
|
||||||
rpcSubscribeService.addSubscriber(subscriber);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({})
|
|
||||||
export class RPCModule {
|
|
||||||
static forRoot(config: RPCRootModuleConfig): ModuleWithProviders {
|
|
||||||
const subscribers = undefined === config.subscribers ? [] : config.subscribers;
|
|
||||||
return {
|
|
||||||
ngModule: RPCRootModule,
|
|
||||||
providers: [
|
|
||||||
subscribers,
|
|
||||||
{
|
|
||||||
provide: _ROOT_SUBSCRIBERS,
|
|
||||||
deps: subscribers,
|
|
||||||
useFactory: createSourceInstances,
|
|
||||||
},
|
|
||||||
SERVICES,
|
|
||||||
SUBSCRIBERS,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static forFeature(config: RPCFeatureModuleConfig): ModuleWithProviders {
|
|
||||||
const subscribers = undefined === config.subscribers ? [] : config.subscribers;
|
|
||||||
|
|
||||||
return {
|
|
||||||
ngModule: RPCFeatureModule,
|
|
||||||
providers: [
|
|
||||||
subscribers,
|
|
||||||
{
|
|
||||||
provide: _FEATURE_SUBSCRIBERS,
|
|
||||||
multi: true,
|
|
||||||
deps: subscribers,
|
|
||||||
useFactory: createSourceInstances,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSourceInstances(...instances: any[]) {
|
|
||||||
return instances;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { RPCError } from './RPCError';
|
|
||||||
|
|
||||||
export interface RPCClientCodec {
|
|
||||||
request(method: string, args: any[], id: number): any;
|
|
||||||
response(res: any): RPCClientResponseCodec;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RPCClientResponseCodec {
|
|
||||||
id(): number | undefined;
|
|
||||||
error(): RPCError | undefined;
|
|
||||||
result(): any | undefined;
|
|
||||||
|
|
||||||
isNotification(): boolean;
|
|
||||||
notification(): RPCClientNotificationCodec | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RPCClientNotificationCodec {
|
|
||||||
method(): string;
|
|
||||||
params(): any | undefined;
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
export interface RPCClientError {
|
|
||||||
request: {
|
|
||||||
method: string,
|
|
||||||
params: any[],
|
|
||||||
};
|
|
||||||
response: RPCError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error object representation when a method invocation fails.
|
|
||||||
*/
|
|
||||||
export interface RPCError {
|
|
||||||
/** Indicates the error type that occurred. */
|
|
||||||
code: RPCErrorCode;
|
|
||||||
|
|
||||||
/** A short description of the error. */
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
/** Additional information about the error */
|
|
||||||
data?: any;
|
|
||||||
}/*
|
|
||||||
|
|
||||||
/** Error codes are same as xml-rpc codes. See http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php */
|
|
||||||
export const enum RPCErrorCode {
|
|
||||||
/** Parse error Invalid JSON was received by the Server. */
|
|
||||||
ParseError = -32700,
|
|
||||||
|
|
||||||
/** Invalid Request The JSON sent is not a valid Request object. */
|
|
||||||
InvalidRequest = -32600,
|
|
||||||
|
|
||||||
/** The method does not exist / is not available. */
|
|
||||||
MethodNotFound = -32601,
|
|
||||||
|
|
||||||
/** Invalid method parameter(s). */
|
|
||||||
InvalidParams = - -32602,
|
|
||||||
|
|
||||||
/** Internal JSON-RPC error. */
|
|
||||||
InternalError = -32603
|
|
||||||
|
|
||||||
/** -32000 to -32099: Reserved for implementation-defined Server errors. */
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './RPCClientCodec';
|
|
||||||
export * from './RPCError';
|
|
|
@ -1,125 +0,0 @@
|
||||||
import {
|
|
||||||
RPCClientCodec,
|
|
||||||
RPCClientResponseCodec,
|
|
||||||
RPCClientNotificationCodec,
|
|
||||||
} from '../RPCClientCodec';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCError,
|
|
||||||
} from '../RPCError';
|
|
||||||
|
|
||||||
export interface ClientNotification {
|
|
||||||
method: string;
|
|
||||||
params?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientRequest {
|
|
||||||
jsonrpc: string;
|
|
||||||
method: string;
|
|
||||||
params?: string[];
|
|
||||||
id?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientResponse {
|
|
||||||
jsonrpc: string;
|
|
||||||
result?: any;
|
|
||||||
error?: RPCError;
|
|
||||||
id?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class JSONRPCClientCodec implements RPCClientCodec {
|
|
||||||
public request(method: string, args: any[], id?: number): any {
|
|
||||||
const params = convertParamsToStringArray(args);
|
|
||||||
|
|
||||||
const req: ClientRequest = {
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
method: method,
|
|
||||||
params: 0 === params.length ? null : params,
|
|
||||||
id: id,
|
|
||||||
};
|
|
||||||
return JSON.stringify(req);
|
|
||||||
}
|
|
||||||
public response(res: any): RPCClientResponseCodec {
|
|
||||||
const _res: ClientResponse = {
|
|
||||||
id: res.id,
|
|
||||||
jsonrpc: res.jsonrpc,
|
|
||||||
result: res.result,
|
|
||||||
error: res.error,
|
|
||||||
};
|
|
||||||
return new JSONRPCClientResponseCodec(_res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertParamsToStringArray(args: any[]): string[] | undefined {
|
|
||||||
const values: string[] = [];
|
|
||||||
|
|
||||||
if (undefined === args || null === args || 0 === args.length) {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let indexI = 0; indexI < args.length; indexI++) {
|
|
||||||
const arg = args[indexI];
|
|
||||||
|
|
||||||
switch (typeof arg) {
|
|
||||||
case 'boolean':
|
|
||||||
case 'number': // enum
|
|
||||||
values.push(String(arg));
|
|
||||||
break;
|
|
||||||
case 'string':
|
|
||||||
values.push(arg);
|
|
||||||
break;
|
|
||||||
case 'object': // array, map
|
|
||||||
values.push(JSON.stringify(arg));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`Not supported type[${typeof arg}]`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class JSONRPCClientResponseCodec implements RPCClientResponseCodec {
|
|
||||||
public constructor(private _res: ClientResponse) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public id(): number | undefined {
|
|
||||||
return this._res.id;
|
|
||||||
}
|
|
||||||
public error(): RPCError | undefined {
|
|
||||||
return this._res.error;
|
|
||||||
}
|
|
||||||
public result(): any | undefined {
|
|
||||||
return this._res.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isNotification(): boolean {
|
|
||||||
if (undefined !== this.id() || undefined === this.result()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public notification(): RPCClientNotificationCodec | undefined {
|
|
||||||
if (undefined !== this.id() || undefined === this.result()) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const _noti: ClientNotification = {
|
|
||||||
method: this._res.result.method,
|
|
||||||
params: this._res.result.params,
|
|
||||||
};
|
|
||||||
return new JSONRPCClientNotificationCodec(_noti);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class JSONRPCClientNotificationCodec implements RPCClientNotificationCodec {
|
|
||||||
public constructor(private _noti: ClientNotification) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public method(): string {
|
|
||||||
return this._noti.method;
|
|
||||||
}
|
|
||||||
public params(): any[] | undefined {
|
|
||||||
return this._noti.params;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './JSONRPCClientCodec';
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './rpc.service';
|
|
||||||
|
|
||||||
import { RPCService } from './rpc.service';
|
|
||||||
|
|
||||||
export const SERVICES = [
|
|
||||||
RPCService,
|
|
||||||
];
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { Injectable, Inject } from '@angular/core';
|
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import { Subject } from 'rxjs/Subject';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPC_CODEC,
|
|
||||||
RPC_RWC,
|
|
||||||
} from '../core';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClient,
|
|
||||||
RPCClientRWC,
|
|
||||||
} from '../client';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClientCodec,
|
|
||||||
RPCClientNotificationCodec,
|
|
||||||
} from '../protocol';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCSubscribeService,
|
|
||||||
} from '../subscribe';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RPCService extends RPCClient {
|
|
||||||
constructor(
|
|
||||||
@Inject(RPC_CODEC) rpcClientCodec: RPCClientCodec,
|
|
||||||
@Inject(RPC_RWC) rpcClientRWC: RPCClientRWC,
|
|
||||||
private rpcSubscribeService: RPCSubscribeService,
|
|
||||||
) {
|
|
||||||
super(rpcClientCodec, rpcClientRWC);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onNotification(notiCodec: RPCClientNotificationCodec): void {
|
|
||||||
this.rpcSubscribeService.notify(notiCodec);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './subscribe.service';
|
|
||||||
|
|
||||||
import { RPCSubscribeService } from './subscribe.service';
|
|
||||||
|
|
||||||
export const SUBSCRIBERS = [
|
|
||||||
RPCSubscribeService,
|
|
||||||
];
|
|
|
@ -1,161 +0,0 @@
|
||||||
import { Injectable, Inject } from '@angular/core';
|
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Type,
|
|
||||||
PropertyKeyType,
|
|
||||||
} from '@loafer/core';
|
|
||||||
|
|
||||||
import { TypeUtil } from '@loafer/core/util/TypeUtil';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Class,
|
|
||||||
Method,
|
|
||||||
Metadata,
|
|
||||||
} from '@loafer/core/reflect';
|
|
||||||
|
|
||||||
import { RPCSubscriberDecorator } from '../decorator';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RPCClientNotificationCodec,
|
|
||||||
} from '../protocol';
|
|
||||||
import { SubscriberParameterError } from '../core';
|
|
||||||
|
|
||||||
export interface SubscriberMethod {
|
|
||||||
className: PropertyKeyType;
|
|
||||||
methodName: PropertyKeyType;
|
|
||||||
parameterTypes: string[];
|
|
||||||
|
|
||||||
method: Method;
|
|
||||||
instance: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RPCSubscribeService {
|
|
||||||
private subscriberTypes: Set<Type<any>>;
|
|
||||||
private subscribers: Set<any>;
|
|
||||||
private subscriberMethodMap: Map<string, SubscriberMethod[]>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
) {
|
|
||||||
this.subscriberTypes = new Set();
|
|
||||||
this.subscribers = new Set();
|
|
||||||
this.subscriberMethodMap = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addSubscriber(subscriber: Type<any>): void {
|
|
||||||
const type = TypeUtil.getType(subscriber);
|
|
||||||
|
|
||||||
if (this.subscriberTypes.has(type)) {
|
|
||||||
// console.log(`Subscriber[${type.name}] has been added`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.subscriberTypes.add(type);
|
|
||||||
|
|
||||||
const clazz = Class.forType(type);
|
|
||||||
if (undefined === clazz) {
|
|
||||||
console.log(`Type[${subscriber.name}] is not decorated type`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const methods = clazz.getMethods();
|
|
||||||
methods.forEach((method, propertyKey) => {
|
|
||||||
const annon = method.getAnnotation(RPCSubscriberDecorator);
|
|
||||||
if (undefined === annon) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subscriberMethodName = annon.attribute.method;
|
|
||||||
let subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(subscriberMethodName);
|
|
||||||
if (undefined === subscriberMethods) {
|
|
||||||
subscriberMethods = [];
|
|
||||||
this.subscriberMethodMap.set(subscriberMethodName, subscriberMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
const paramTypes = this.getParamTypes(method);
|
|
||||||
|
|
||||||
const subscriberMethod: SubscriberMethod = {
|
|
||||||
className: clazz.getName(),
|
|
||||||
methodName: method.getName(),
|
|
||||||
parameterTypes: paramTypes,
|
|
||||||
method: method,
|
|
||||||
instance: subscriber,
|
|
||||||
};
|
|
||||||
|
|
||||||
subscriberMethods.push(subscriberMethod);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public notify(codec: RPCClientNotificationCodec): void {
|
|
||||||
const method = codec.method();
|
|
||||||
const params = codec.params();
|
|
||||||
|
|
||||||
const subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(method);
|
|
||||||
if (undefined === subscriberMethods) {
|
|
||||||
console.warn(`Subscriber for method[${method}] is not exist`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
subscriberMethods.forEach((subscriberMethod) => {
|
|
||||||
try {
|
|
||||||
const args = this.converParams(params, subscriberMethod.parameterTypes);
|
|
||||||
subscriberMethod.method.invoke(subscriberMethod.instance, ...args);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private getParamTypes(method: Method): string[] {
|
|
||||||
if (undefined === method || null === method || 0 === method.getParameterCount()) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const parameters = method.getParameters();
|
|
||||||
const results: string[] = [];
|
|
||||||
for (let indexI = 0; indexI < parameters.length; indexI++) {
|
|
||||||
const paramType = parameters[indexI].getType();
|
|
||||||
results.push(paramType.name);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private converParams(params: string[], paramTypes: string[]): any[] {
|
|
||||||
const results: any[] = [];
|
|
||||||
|
|
||||||
if (undefined === params || null === params || 0 === params.length) {
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
if (undefined === paramTypes || null === paramTypes || 0 === paramTypes.length) {
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
if (params.length !== paramTypes.length) {
|
|
||||||
throw new SubscriberParameterError(`Count is not same from server[${params.length}] and method[${paramTypes.length}]`);
|
|
||||||
}
|
|
||||||
for (let indexI = 0; indexI < params.length; indexI++) {
|
|
||||||
const param = params[indexI];
|
|
||||||
const type = paramTypes[indexI];
|
|
||||||
switch (type) {
|
|
||||||
case 'Object':
|
|
||||||
case 'Array':
|
|
||||||
case 'Map':
|
|
||||||
results.push(JSON.parse(param));
|
|
||||||
break;
|
|
||||||
case 'String':
|
|
||||||
results.push(param);
|
|
||||||
break;
|
|
||||||
case 'Number':
|
|
||||||
results.push(Number(param));
|
|
||||||
break;
|
|
||||||
case 'Boolean':
|
|
||||||
results.push(Boolean(param));
|
|
||||||
break;
|
|
||||||
case 'Function':
|
|
||||||
throw new SubscriberParameterError(`Function type [${indexI}] is not allowed`);
|
|
||||||
default:
|
|
||||||
throw new SubscriberParameterError(`${type} type parameter[${indexI}] is not allowed`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import * as ResetPasswordStore from '../../store/reset-password';
|
import * as ResetPasswordStore from '../../store/reset-password';
|
||||||
import {select, Store} from '@ngrx/store';
|
import {select, Store} from '@ngrx/store';
|
||||||
import { ResetPasswordSelector } from '../../store';
|
import { ResetPasswordSelector } from '../../store';
|
||||||
import {RPCClientError} from '../../../../@loafer/ng-rpc/protocol';
|
import {RPCClientError} from '@loafer/ng-rpc/protocol';
|
||||||
import {Member} from '@overflow/commons-typescript/model/member/index';
|
import {Member} from '@overflow/commons-typescript/model/member/index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
|
@ -14,7 +14,7 @@ import * as TotpStore from 'packages/member/store/totp';
|
||||||
import { AuthSelector } from 'packages/member/store';
|
import { AuthSelector } from 'packages/member/store';
|
||||||
import { TotpSelector } from 'packages/member/store';
|
import { TotpSelector } from 'packages/member/store';
|
||||||
import { Member } from '@overflow/commons-typescript/model/member';
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
import {RPCClientError} from '../../../../../../@loafer/ng-rpc/protocol';
|
import {RPCClientError} from '@loafer/ng-rpc/protocol';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-config-setting',
|
selector: 'of-config-setting',
|
||||||
|
|
|
@ -16,7 +16,7 @@ export class ProbeHostService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public readByProbe(probe: Probe): Observable<Probe> {
|
public readByProbe(probe: Probe): Observable<Probe> {
|
||||||
return this.rpcService.call<ProbeHost>('ProbeHostService.readByProbe', probe);
|
return this.rpcService.call<Probe>('ProbeHostService.readByProbe', probe);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readAllByDomain(domain: Domain): Observable<ProbeHost[]> {
|
public readAllByDomain(domain: Domain): Observable<ProbeHost[]> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user