From 7611c1b2bf4144e24373102211b0701608cf6683 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Thu, 30 Jul 2020 08:17:49 -0500 Subject: [PATCH] Add support for deepmatch routes --- TODO.txt | 25 +++++++++++++++ app/http/controllers/Api.controller.ts | 2 +- lib/src/http/ApiController.ts | 8 ++--- lib/src/http/routing/ComplexRoute.ts | 2 +- lib/src/http/routing/DeepmatchRoute.ts | 43 ++++++++++++++++++++++++++ lib/src/unit/Routing.ts | 5 +-- 6 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 TODO.txt create mode 100644 lib/src/http/routing/DeepmatchRoute.ts diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..536cad3 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,25 @@ +deepmatch route, regex match route +static assets +middleware +view engine +user-defined services +internationalization +uploads & universal path +CLI - view routes, template generation, start server, directives, output, args +request level error handler +develop/prod/debug modes +logger scope (e.g. logger.verbose()) +favicon +utility - root, path, is_windows, is_linux, is_mac +authentication - user/session, oauth, jwt, &c. +orm relations, subqueries, enum/bit fields, json handlers, scopes +redis - redis client, redis rehydrated classes, redis sessions +less/scss +notifications - gotify/push/other mechanisms +forms +job queue - redis/db backed? +comment all the things +unit tests +integration tests +documentation & docs site +events and observables? diff --git a/app/http/controllers/Api.controller.ts b/app/http/controllers/Api.controller.ts index 3fe2254..9908d19 100644 --- a/app/http/controllers/Api.controller.ts +++ b/app/http/controllers/Api.controller.ts @@ -15,7 +15,7 @@ export default class ApiController extends BaseApiController { } get_msg(request: Request) { - return 'Hello, world!' + return request.route.params } get_redirect(request: Request) { diff --git a/lib/src/http/ApiController.ts b/lib/src/http/ApiController.ts index 5419ff9..1ff1ce3 100644 --- a/lib/src/http/ApiController.ts +++ b/lib/src/http/ApiController.ts @@ -1,8 +1,8 @@ -import Controller from "./Controller.ts"; -import {Request} from "./Request.ts"; -import ResponseFactory from "./response/ResponseFactory.ts"; +import Controller from './Controller.ts' +import {Request} from './Request.ts' +import ResponseFactory from './response/ResponseFactory.ts' import * as api from '../support/api.ts' -import JSONResponseFactory from "./response/JSONResponseFactory.ts"; +import JSONResponseFactory from './response/JSONResponseFactory.ts' export default class ApiController extends Controller { public get_bound_method(method_name: string): (...args: any[]) => any { diff --git a/lib/src/http/routing/ComplexRoute.ts b/lib/src/http/routing/ComplexRoute.ts index d1bbb95..31cea51 100644 --- a/lib/src/http/routing/ComplexRoute.ts +++ b/lib/src/http/routing/ComplexRoute.ts @@ -22,7 +22,7 @@ export class ComplexRoute extends Route { let current_wildcard: number = 1 this.zip(incoming).forEach((segment: RouteSegment) => { - if ( segment.base.indexOf('*') >= 0 ) { + if ( segment.base === '*' ) { params[`$${current_wildcard}`] = utility.infer(segment.match) current_wildcard += 1 } else if ( segment.base.startsWith(':') && segment.base.length > 1 ) { diff --git a/lib/src/http/routing/DeepmatchRoute.ts b/lib/src/http/routing/DeepmatchRoute.ts new file mode 100644 index 0000000..f1120ac --- /dev/null +++ b/lib/src/http/routing/DeepmatchRoute.ts @@ -0,0 +1,43 @@ +import {Route, RouteParameters} from './Route.ts' + +export class DeepmatchRoute extends Route { + protected base_regex: RegExp + + constructor( + protected base: string + ) { + super(base) + this.base_regex = this.build_regex(this.split(base)) + } + + public match(incoming: string): boolean { + return this.base_regex.test(incoming.toLowerCase()) + } + + public build_parameters(incoming: string): RouteParameters { + const results = this.base_regex.exec(incoming.toLowerCase()) + if ( !results ) return {} + + const [match, ...wildcards] = results + const params: RouteParameters = {} + let current_wildcard: number = 1 + + for ( const wild of wildcards ) { + params[`$${current_wildcard}`] = wild + current_wildcard += 1 + } + + return params + } + + protected build_regex(base_parts: string[]) { + const deepmatch_group = '([a-zA-Z0-9\\-\\_\\.\\/]+)' // allows for alphanum, -, _, ., and / + const shallowmatch_group = '([a-zA-Z0-9\\-\\.\\_]+)' // allows for alphanum, -, ., and _ + + const regex = base_parts.map(part => { + return part.split('**').join(deepmatch_group).split('*').join(shallowmatch_group) + }).join('\\/') + + return new RegExp(regex) + } +} diff --git a/lib/src/unit/Routing.ts b/lib/src/unit/Routing.ts index bb4834e..cf7987e 100644 --- a/lib/src/unit/Routing.ts +++ b/lib/src/unit/Routing.ts @@ -13,6 +13,7 @@ import {Canonical} from './Canonical.ts' import {Logging} from '../service/logging/Logging.ts' import {Canon} from './Canon.ts' import {isBindable} from '../lifecycle/AppClass.ts' +import {DeepmatchRoute} from "../http/routing/DeepmatchRoute.ts"; export type RouteHandler = (request: Request) => Request | Promise | ResponseFactory | Promise | void | Promise export type RouteHandlers = RouteHandler[] @@ -138,11 +139,11 @@ export default class Routing extends LifecycleUnit { public build_route(base: string): Route { if ( !base.includes(':') && !base.includes('*') ) { return new SimpleRoute(base) + } else if ( base.includes('**') ) { + return new DeepmatchRoute(base) } else { return new ComplexRoute(base) } - - // TODO deep-match route } public match(incoming: string): Route | undefined {