From f540335c2498730912d0e471094d481df8514767 Mon Sep 17 00:00:00 2001 From: lengfangbing Date: Mon, 21 Sep 2020 15:01:42 +0800 Subject: [PATCH 1/4] feat: update router path split function --- router.ts | 22 +++++++++++----------- router_test.ts | 23 +++++++++++------------ utils/parse/url.ts | 4 ++-- utils/test/url_test.ts | 29 +---------------------------- 4 files changed, 25 insertions(+), 53 deletions(-) diff --git a/router.ts b/router.ts index 2d9bed1..3e80795 100644 --- a/router.ts +++ b/router.ts @@ -59,7 +59,7 @@ export class Router { if (!us.length) throw new Error('router.add first argument path is invalid, use /path instead'); let p: NewRoute | null = null; let pm: NewRoute['paramsNames'] = {}; - us.forEach((value: string | { paramsName: string }, index: number) => { + us.forEach((value: string | { key: string, paramsName: string }, index: number) => { if (typeof value === 'string') { if (p) { if (p.next) { @@ -85,27 +85,27 @@ export class Router { } } else { if (p === null) { - if (fM['']) { - p = fM['']; + if (fM[value.key]) { + p = fM[value.key]; } else { - fM[''] = this.#initRoute(); - p = fM['']; + fM[value.key] = this.#initRoute(); + p = fM[value.key]; } pm[index] = value.paramsName; } else { if (p.next) { - if (p.next['']) { - p = p.next['']; + if (p.next[value.key]) { + p = p.next[value.key]; } else { - p.next[''] = this.#initRoute(); - p = p.next['']; + p.next[value.key] = this.#initRoute(); + p = p.next[value.key]; } pm[index] = value.paramsName; } else { p.next = { - '': this.#initRoute() + [value.key]: this.#initRoute() } - p = p.next['']; + p = p.next[value.key]; pm[index] = value.paramsName; } } diff --git a/router_test.ts b/router_test.ts index b396dc7..3832482 100644 --- a/router_test.ts +++ b/router_test.ts @@ -1,7 +1,6 @@ import { parseUrlQuery, splitPath, - splitNewPath, splitUrl } from './utils/test/url_test.ts'; @@ -141,7 +140,7 @@ export class Router { // p理解为一个查找路由这个数据结构的指针 let p: NewRoute | null = null; let params: NewRoute['paramsNames'] = {}; - urls.forEach((value: string | { paramsName: string }, index: number) => { + urls.forEach((value: string | { key: string, paramsName: string }, index: number) => { // 静态路由 if (typeof value === 'string') { // 如果p代表了有值了, 就代表funcMap有匹配项了 @@ -174,27 +173,27 @@ export class Router { // 把所有动态路由都改成''(空字符串)索引的形式构造树 // 第一个就是动态路由 if (p === null) { - if (funcMap['']) { - p = funcMap['']; + if (funcMap[value.key]) { + p = funcMap[value.key]; } else { - funcMap[''] = this.#initRoute(); - p = funcMap['']; + funcMap[value.key] = this.#initRoute(); + p = funcMap[value.key]; } params[index] = value.paramsName; } else { if (p.next) { - if (p.next['']) { - p = p.next['']; + if (p.next[value.key]) { + p = p.next[value.key]; } else { - p.next[''] = this.#initRoute(); - p = p.next['']; + p.next[value.key] = this.#initRoute(); + p = p.next[value.key]; } params[index] = value.paramsName; } else { p.next = { - '': this.#initRoute() + [value.key]: this.#initRoute() } - p = p.next['']; + p = p.next[value.key]; params[index] = value.paramsName; } } diff --git a/utils/parse/url.ts b/utils/parse/url.ts index 0539c2a..3d702c1 100644 --- a/utils/parse/url.ts +++ b/utils/parse/url.ts @@ -83,7 +83,7 @@ export function splitPath(path: string){ const v = url.substring(0, i); let j = 0; if((j = v.indexOf(':')) >= 0){ - res.push({paramsName: v.substring(j+1)}); + res.push({key: '', paramsName: v.substring(j+1)}); }else{ res.push(`/${v}`); } @@ -91,7 +91,7 @@ export function splitPath(path: string){ } if(url.length){ if((i = url.indexOf(':')) >= 0){ - res.push({paramsName: url.substring(i+1)}); + res.push({key: '', paramsName: url.substring(i+1)}); }else{ res.push(`/${url}`); } diff --git a/utils/test/url_test.ts b/utils/test/url_test.ts index f6ce41a..7964207 100644 --- a/utils/test/url_test.ts +++ b/utils/test/url_test.ts @@ -69,29 +69,6 @@ export function splitUrl(url: string){ } export function splitPath(path: string){ - const res = []; - let url = path.substring(1) || '/'; - let i = 0; - while((i = url.indexOf('/')) >= 0){ - const v = url.substring(0, i); - let j = 0; - if((j = v.indexOf(':')) >= 0){ - res.push({paramsName: v.substring(j+1)}); - }else{ - res.push(`/${v}`); - } - url = url.substring(i+1); - } - if(url.length){ - if((i = url.indexOf(':')) >= 0){ - res.push({paramsName: url.substring(i+1)}); - }else{ - res.push(`/${url}`); - } - } - return res; -} -export function splitNewPath(path: string){ const res = []; let url = path.substring(1) || '/'; let i = 0; @@ -100,8 +77,6 @@ export function splitNewPath(path: string){ let j = 0; if((j = v.indexOf(':')) >= 0){ res.push({key: '', paramsName: v.substring(j+1)}); - }else if((j = v.indexOf('*')) >= 0){ - res.push({key: '#', paramsName: v.substring(j+1)}); }else{ res.push(`/${v}`); } @@ -110,8 +85,6 @@ export function splitNewPath(path: string){ if(url.length){ if((i = url.indexOf(':')) >= 0){ res.push({key: '', paramsName: url.substring(i+1)}); - }else if((i = url.indexOf('*')) >= 0){ - res.push({key: '#', paramsName: url.substring(i+1)}); }else{ res.push(`/${url}`); } @@ -154,5 +127,5 @@ export function parseResponseCookie(options?: Record){ return res.join(';'); } assertEquals('domain=.foo.com;Path=/;secure;httpOnly', parseResponseCookie({domain: '.foo.com', Path: '/', secure: true, httpOnly: true})); -assertEquals(['/name', {paramsName: 'id'}, '/v1'], splitPath('/name/:id/v1')); +assertEquals(['/name', {key: '', paramsName: 'id'}, '/v1'], splitPath('/name/:id/v1')); assertEquals(['/name', '/fangbing', '/v1'], splitUrl('/name/fangbing/v1')); From 8700d482aa964447e523d479ff2557fcb7599dfe Mon Sep 17 00:00:00 2001 From: lengfangbing Date: Mon, 21 Sep 2020 15:17:31 +0800 Subject: [PATCH 2/4] feat: add entity property --- decorator/decorator.type.ts | 1 + decorator/entity.ts | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/decorator/decorator.type.ts b/decorator/decorator.type.ts index 55c1109..9a439b8 100644 --- a/decorator/decorator.type.ts +++ b/decorator/decorator.type.ts @@ -16,4 +16,5 @@ export declare type Entity = { middleware: Function[], handler: Function, }>; + middlewares: Array; }; diff --git a/decorator/entity.ts b/decorator/entity.ts index ff2d821..7e8628f 100644 --- a/decorator/entity.ts +++ b/decorator/entity.ts @@ -1,4 +1,4 @@ -import {Entity} from "./decorator.type.ts"; +import {Entity, MiddlewareFunc} from "./decorator.type.ts"; import {Middleware} from "./middleware.ts"; import {Router} from "./router.ts"; import {DecorationApplication} from "./application.ts"; @@ -15,6 +15,7 @@ const entity: Entity = { server: defaultServer, middleware: null, routes: [], + middlewares: [], }; export function getAppInitial(): DecorationApplication { @@ -69,3 +70,15 @@ export function setRoutes(routes: Entity['routes'][number]) { export function clearRoutes() { entity.routes = []; } + +export function getMiddlewares() { + return entity.middlewares; +} + +export function setMiddlewares(func: MiddlewareFunc) { + entity.middlewares.push(func); +} + +export function clearMiddlewares() { + entity.middlewares = []; +} From c7d9e7e97eafe655686e00fbfb5ae28d1092b55c Mon Sep 17 00:00:00 2001 From: lengfangbing Date: Mon, 21 Sep 2020 15:29:08 +0800 Subject: [PATCH 3/4] feat: update middleware works for scope Route --- decorator/decorator.ts | 32 ++++++++++++++++++++++++-------- decorator/decorator.type.ts | 6 ++---- decorator/entity.ts | 4 ++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/decorator/decorator.ts b/decorator/decorator.ts index 19abc3a..f2568ee 100644 --- a/decorator/decorator.ts +++ b/decorator/decorator.ts @@ -5,24 +5,42 @@ import { setRoutes, clearRoutes, setServer, - getMiddlewareInitial + getMiddlewareInitial, + getMiddlewares, + setMiddlewares, + clearMiddlewares, } from "./entity.ts"; import {App} from "./app.ts"; import {DecorationApplication} from "./application.ts"; import {ListenOptions, MethodFuncArgument} from "../model.ts"; -const consumeRoutes: ClassDecorator = (target: Function) => { +const consumeApplication: ClassDecorator = (target: Function) => { + const middleware = getMiddlewareInitial(); const router = getRouterInitial(); const path = target.prototype.decorator_prefix_min || ''; + getMiddlewares().forEach(val => { + middleware.push(val); + }); getRoutes().forEach(val => { router[val.method](path + val.path, val.handler, val.middleware); }); + clearMiddlewares(); + clearRoutes(); +} + +const consumeRoutes: ClassDecorator = (target: Function) => { + const router = getRouterInitial(); + const path = target.prototype.decorator_prefix_min || ''; + getRoutes().forEach(val => { + router[val.method](path + val.path, val.handler, val.middleware.concat(getMiddlewares())); + }); + clearMiddlewares(); clearRoutes(); } const StartApplication: ClassDecorator = target => { setApp(new DecorationApplication()); - consumeRoutes(target); + consumeApplication(target); return target; } @@ -39,16 +57,14 @@ const Prefix = (path: string): ClassDecorator => { } const Middleware: MethodDecorator = (target, propertyKey, descriptor: TypedPropertyDescriptor) => { - const middleware = getMiddlewareInitial(); - middleware.push(descriptor.value); + setMiddlewares(descriptor.value); return descriptor; } const ApplyMiddleware = (args: MethodFuncArgument): MethodDecorator => { - const middleware = getMiddlewareInitial(); args.forEach(val => { - middleware.push(val); - }) + setMiddlewares(val); + }); return (target, propertyKey, descriptor) => { return descriptor; } diff --git a/decorator/decorator.type.ts b/decorator/decorator.type.ts index 9a439b8..6d7850c 100644 --- a/decorator/decorator.type.ts +++ b/decorator/decorator.type.ts @@ -1,9 +1,7 @@ import {Middleware} from "./middleware.ts"; import {DecorationApplication} from "./application.ts"; import {Router} from "./router.ts"; -import {ListenOptions, Req, ReqMethod, Res} from "../model.ts"; - -export declare type MiddlewareFunc = (req: Req, res: Res, next?: Function) => Promise | unknown; +import {ListenOptions, ReqMethod, MethodFuncArgument} from "../model.ts"; export declare type Entity = { app: DecorationApplication | null, @@ -16,5 +14,5 @@ export declare type Entity = { middleware: Function[], handler: Function, }>; - middlewares: Array; + middlewares: MethodFuncArgument; }; diff --git a/decorator/entity.ts b/decorator/entity.ts index 7e8628f..ce63ca5 100644 --- a/decorator/entity.ts +++ b/decorator/entity.ts @@ -1,8 +1,8 @@ -import {Entity, MiddlewareFunc} from "./decorator.type.ts"; +import {Entity} from "./decorator.type.ts"; import {Middleware} from "./middleware.ts"; import {Router} from "./router.ts"; import {DecorationApplication} from "./application.ts"; -import {ListenOptions} from "../model.ts"; +import {ListenOptions, MiddlewareFunc} from "../model.ts"; const defaultServer = { port: 8000, From b03d145cd20a19b5dcb4d0c63dd8e3edc3a22fe7 Mon Sep 17 00:00:00 2001 From: lengfangbing Date: Mon, 21 Sep 2020 15:43:03 +0800 Subject: [PATCH 4/4] feat: add middleware comment --- examples/decorator/demo2/index.ts | 3 +++ examples/decorator/demo2/routes/route1.ts | 1 + examples/decorator/demo2/routes/route2.ts | 1 + 3 files changed, 5 insertions(+) diff --git a/examples/decorator/demo2/index.ts b/examples/decorator/demo2/index.ts index ccab699..7a57c64 100644 --- a/examples/decorator/demo2/index.ts +++ b/examples/decorator/demo2/index.ts @@ -34,6 +34,9 @@ export class TestClass extends App { console.log('middle2 end'); } + // in @StartApplication class middleware will work for global + // but in @Route class , it will only work for that Route + @Get('/id/:id/info', [async (req: Req, res: Res, next: Function) => { console.log(`I am a middleware func in ${req.url}`); await next(); diff --git a/examples/decorator/demo2/routes/route1.ts b/examples/decorator/demo2/routes/route1.ts index 6ec73ef..25a06e9 100644 --- a/examples/decorator/demo2/routes/route1.ts +++ b/examples/decorator/demo2/routes/route1.ts @@ -4,6 +4,7 @@ import {Get, Route, Middleware, Req, Res} from "../deps.ts"; @Route class Route1 { @Middleware + // this middleware will only work for this Route async middle3(req: Req, res: Res, next: Function) { console.log('route1 middle'); await next(); diff --git a/examples/decorator/demo2/routes/route2.ts b/examples/decorator/demo2/routes/route2.ts index 1a39297..a9d77d3 100644 --- a/examples/decorator/demo2/routes/route2.ts +++ b/examples/decorator/demo2/routes/route2.ts @@ -6,6 +6,7 @@ import {Get, Route, Prefix, Middleware, Req, Res} from "../deps.ts"; @Prefix('/route2') class Route2 { @Middleware + // this middleware will only work for this Route async middle (req: Req, res: Res, next: Function) { console.log('route2 middle'); await next();