feat: add cc-server-binding

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2019-06-20 18:24:23 +08:00
parent 8e56d471a7
commit 6c61f14907
10 changed files with 240 additions and 0 deletions

4
packages/cc-server-binding/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules
/dist
/package-lock.json
/yarn.lock

View File

@ -0,0 +1,11 @@
# `cc-server-binding`
> TODO: description
## Usage
```
const ccServerBinding = require('cc-server-binding');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,33 @@
{
"name": "cc-server-binding",
"version": "0.2.5",
"description": "> TODO: description",
"author": "MiaoWoo <admin@yumc.pw>",
"homepage": "https://github.com/502647092/cc-server-parent#readme",
"license": "ISC",
"main": "dist/index.js",
"publishConfig": {
"registry": "https://repo.yumc.pw/repository/npm/"
},
"repository": {
"type": "git",
"url": "git+https://github.com/502647092/cc-server-parent.git"
},
"scripts": {
"dev": "npx ts-node src/index.ts",
"build": "rimraf dist && npx tsc",
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"express": "^4.17.1",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
"mocha": "^6.1.4",
"rimraf": "^2.6.3",
"typescript": "^3.5.1"
},
"bugs": {
"url": "https://github.com/502647092/cc-server-parent/issues"
}
}

View File

@ -0,0 +1,69 @@
import { Container, interfaces as inversify_interfaces } from 'inversify'
import { TYPE, interfaces as express_interfaces } from 'inversify-express-utils'
import { METADATA_KEY, VAILD_TYPE } from './constants'
import { interfaces } from './interfaces'
import { getVaildMethodMetadata, getVaildControllerMetadata, getVaildModelMetadata } from './utils'
let handler = {
apply: function(target: Function, thisArgument: Object, argumentsList: any[]) {
let methodParams = getVaildMethodMetadata(target);
let [req, res, next] = [...argumentsList.slice(-3)];
try {
// loop @Valid params
for (const param of methodParams) {
// get function argument value
let origin = argumentsList[param.index]
let props = getVaildModelMetadata(param.type);
for (const prop of props) {
let propValue = origin[prop.name];
switch (prop.type) {
case VAILD_TYPE.NOT_BLANK:
if (!propValue) {
throw new Error(prop.message);
}
break;
case VAILD_TYPE.NOT_NULL:
if (propValue == undefined) {
throw new Error(prop.message);
}
break;
default:
throw new Error('Unkonw Vaild Type!')
}
}
}
return target.apply(thisArgument, argumentsList);
} catch (ex) {
res.status(400).json({
status: 400,
message: ex.message
})
}
}
}
function rebuildServer(container: Container) {
// get all controller
let controllers = container.getAll<express_interfaces.Controller>(TYPE.Controller)
// for loop controllers and inject proxy to each method
for (const controller of controllers) {
container.rebind(TYPE.Controller)
.to(controller.constructor as any)
.inSingletonScope()
.whenTargetNamed(controller.constructor.name)
.onActivation((ctx: inversify_interfaces.Context, controller: express_interfaces.Controller) => {
let prop = controller.constructor.prototype
// funcs => { create: [ { index: 0, type: [Function: ExampleModel] } ] }
let funcs = getVaildControllerMetadata(controller.constructor);
//Reflect.getMetadata(METADATA_KEY.controllerParameter, controller.constructor);
for (const func in funcs) {
Reflect.defineMetadata(METADATA_KEY.vaildMethod, funcs[func], prop[func])
// Define Proxy handle model vaild
Reflect.defineProperty(prop, func, { value: new Proxy(prop[func], handler) })
}
return controller;
});
}
}
export { rebuildServer }

View File

@ -0,0 +1,10 @@
export const METADATA_KEY = {
vaildModel: "cc-server-binding:vaild-model",
vaildMethod: "cc-server-binding:vaild-method",
vaildController: "cc-server-binding:vaild-controller"
};
export enum VAILD_TYPE {
NOT_BLANK,
NOT_NULL
}

View File

@ -0,0 +1,50 @@
import 'reflect-metadata'
import { METADATA_KEY, VAILD_TYPE } from './constants';
import { getVaildControllerMetadata, getVaildModelMetadata } from './utils'
import { interfaces } from './interfaces'
/**
* ParameterVaild
*/
export function Vaild(): ParameterDecorator {
return (controller: Object, methodName: string, index: number): void => {
var type = Reflect.getMetadata("design:paramtypes", controller, methodName)[index];
let metadataList = getVaildControllerMetadata(controller.constructor);
let parameterMetadataList = metadataList[methodName] || [];
let parameterMetadata: interfaces.ParameterMetadata = {
index: index,
type: type
};
parameterMetadataList.unshift(parameterMetadata);
metadataList[methodName] = parameterMetadataList;
Reflect.defineMetadata(METADATA_KEY.vaildController, metadataList, controller.constructor);
}
}
/**
* Vaild Blank String
* @param message Error Message
*/
export const NotBlank: (message?: string) => PropertyDecorator = vaildDecoratorFactory(VAILD_TYPE.NOT_BLANK);
/**
* Vaild Null Param
* @param message Error Message
*/
export const NotNull: (message?: string) => PropertyDecorator = vaildDecoratorFactory(VAILD_TYPE.NOT_NULL);
function vaildDecoratorFactory(type: VAILD_TYPE): () => PropertyDecorator {
return function(message?: string): PropertyDecorator {
return vaildProperty(type, message);
};
}
function vaildProperty(type: VAILD_TYPE, message?: string): PropertyDecorator {
return (model: Object, propertyKey: string) => {
let metadataList: interfaces.PropertyMetadata[] = getVaildModelMetadata(model.constructor);
metadataList.push({
name: propertyKey,
message: message || `model ${model.constructor.name} property ${propertyKey} vaild failed => ${VAILD_TYPE[type]}`,
type: type
})
Reflect.defineMetadata(METADATA_KEY.vaildModel, metadataList, model.constructor);
}
}

View File

@ -0,0 +1,4 @@
export * from './decorators'
export * from './constants';
export * from './utils'
export * from './activation'

View File

@ -0,0 +1,20 @@
import { VAILD_TYPE } from './constants'
namespace interfaces {
export interface MethodMetadata {
[methodName: string]: ParameterMetadata[];
}
export interface ParameterMetadata {
index: number;
type: NewableFunction;
}
export interface PropertyMetadata {
name: string;
message: string;
type: VAILD_TYPE;
}
}
export { interfaces };

View File

@ -0,0 +1,32 @@
import { METADATA_KEY } from './constants'
import { interfaces } from './interfaces'
function getVaildControllerMetadata(model: Object) {
let controllerMetadata: interfaces.MethodMetadata = Reflect.getMetadata(
METADATA_KEY.vaildController,
model
) || {};
return controllerMetadata;
}
function getVaildMethodMetadata(constructor: any) {
let parameterMetadata: interfaces.ParameterMetadata[] = Reflect.getMetadata(
METADATA_KEY.vaildMethod,
constructor
) || [];
return parameterMetadata;
}
function getVaildModelMetadata(model: Object) {
let propertyMetadata: interfaces.PropertyMetadata[] = Reflect.getMetadata(
METADATA_KEY.vaildModel,
model
) || [];
return propertyMetadata;
}
export {
getVaildControllerMetadata,
getVaildMethodMetadata,
getVaildModelMetadata
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}