From c9246d5c7e727080ab429d7ea1cfe8ed6f3d1293 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Sun, 19 Jun 2022 10:28:08 +0200 Subject: [PATCH 1/9] Update RouterList.ts --- routers/RouterList.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/routers/RouterList.ts b/routers/RouterList.ts index 6ea20a9..054b43b 100644 --- a/routers/RouterList.ts +++ b/routers/RouterList.ts @@ -50,14 +50,6 @@ export class RouterList implements IRouter { } - /** - * @deprecated Use `add` method instead. - */ - addRouter(router: IRouter): void { - this.add(router); - } - - startsWith(path: string): RouterList { const searchString = Router.cleanPathname(path); @@ -102,6 +94,15 @@ export class RouterList implements IRouter { } + // #region — Routers + /** + * @deprecated Use `add` method instead. + */ + addRouter(router: IRouter): void { + this.add(router); + } + + /** * Add route or router to list. * @@ -157,6 +158,7 @@ export class RouterList implements IRouter { const router = new RegExpRouter(regexp, serveResponse, this.#options); return this.#addRouter(router); } + // #endregion async match(req: Request): Promise { @@ -190,6 +192,7 @@ export class RouterList implements IRouter { } + // #region — Errors setError(serveResponse: ServeResponseType): void { this.#errorServeResponse = serveResponse; } @@ -213,4 +216,5 @@ export class RouterList implements IRouter { }); } } + // #endregion } From 5ac85a90719c7277a714a2aece5f4c0e567de3d2 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Sun, 19 Jun 2022 10:34:46 +0200 Subject: [PATCH 2/9] Update ParsedParamValues.ts --- routers/MaskRouter.ts | 8 ++++---- types/{ParamValuesType.ts => ParsedParamValues.ts} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename types/{ParamValuesType.ts => ParsedParamValues.ts} (78%) diff --git a/routers/MaskRouter.ts b/routers/MaskRouter.ts index b373d0e..c2c87d9 100644 --- a/routers/MaskRouter.ts +++ b/routers/MaskRouter.ts @@ -8,7 +8,7 @@ import { Router } from "./Router.ts"; import { type ServeResponseType } from "../types/ServeResponseType.ts"; import { type RouterOptions, createRequiredOptions } from "../helpers/RouterOptions.ts"; import { type ParamDeclarationsType } from "../types/ParamDeclarationsType.ts"; -import { type ParamValuesType } from "../types/ParamValuesType.ts"; +import { type ParsedParamValues } from "../types/ParsedParamValues.ts"; import { RouterMalformedException } from "./RouterMalformedException.ts"; @@ -45,7 +45,7 @@ export class MaskRouter extends Router implements IRouter { readonly #matchCache = new Cache(); readonly #paramParserCache = new Cache(); readonly #paramDeclarationCache = new Cache(); - readonly #paramValuesCache = new Cache(); + readonly #paramValuesCache = new Cache(); constructor(mask: string, serveResponse: ServeResponseType, options?: RouterOptions) { @@ -174,7 +174,7 @@ export class MaskRouter extends Router implements IRouter { } - #parseParamValues(primaryMask: string, matchedMask: string, pathname: string): ParamValuesType | null { + #parseParamValues(primaryMask: string, matchedMask: string, pathname: string): ParsedParamValues | null { const isValid = (value: string | null, expression: RegExp | null): boolean => { if (expression === null) return true; if (value === null) return false; @@ -185,7 +185,7 @@ export class MaskRouter extends Router implements IRouter { const parse = (primaryMask: string, matchedMask: string, pathname: string) => { const paramParser = this.#createParamParser(matchedMask); - const paramValues: ParamValuesType = new Map(); + const paramValues: ParsedParamValues = new Map(); const paramDeclarations = this.#parseParamDeclarations(primaryMask); if (paramDeclarations === null) return paramValues; diff --git a/types/ParamValuesType.ts b/types/ParsedParamValues.ts similarity index 78% rename from types/ParamValuesType.ts rename to types/ParsedParamValues.ts index 696f663..1230941 100644 --- a/types/ParamValuesType.ts +++ b/types/ParsedParamValues.ts @@ -6,7 +6,7 @@ /** * @internal */ -export type ParamValuesType = Map Date: Sun, 19 Jun 2022 10:42:55 +0200 Subject: [PATCH 3/9] Add doc comments --- routers/MaskRouter.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/routers/MaskRouter.ts b/routers/MaskRouter.ts index c2c87d9..2c1c4ea 100644 --- a/routers/MaskRouter.ts +++ b/routers/MaskRouter.ts @@ -58,17 +58,22 @@ export class MaskRouter extends Router implements IRouter { } + /** + * Return `true` if `pathname` of request matches `mask`. + */ match(req: Request): boolean { const pathname = this.#computePathname(req); - return this.#match(pathname) } + /** + * Return Response. + */ async serveResponse(req: Request): Promise { const pathname = this.#computePathname(req); - const matchedMask = this.#getMatchedMask(pathname); + const matchedMask = this.#getMatchedMaskVariant(pathname); if (matchedMask === null || !this.#match(pathname)) throw new Error("No mask matched"); const params: Record = {}; @@ -88,6 +93,9 @@ export class MaskRouter extends Router implements IRouter { } + /** + * Return `true` if `pathname` matches some of `mask` variants. + */ #match(pathname: string): boolean { const result = this.#maskVariants.some(mask => { return this.#matchMask(mask, pathname); @@ -97,7 +105,10 @@ export class MaskRouter extends Router implements IRouter { } - #getMatchedMask(pathname: string): string | null { + /** + * Return matched mask variant or `null` if no mask matched. + */ + #getMatchedMaskVariant(pathname: string): string | null { const result = this.#maskVariants.find(mask => { return this.#matchMask(mask, pathname); }) ?? null; From c07d0a73d92391edf52fa230693e34117844ff85 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 27 Jun 2022 20:02:57 +0200 Subject: [PATCH 4/9] Add test --- routers/MaskRouter.ts | 17 +++++++++++++++-- tests/MaskRouter.test.ts | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/routers/MaskRouter.ts b/routers/MaskRouter.ts index 2c1c4ea..7ab3d64 100644 --- a/routers/MaskRouter.ts +++ b/routers/MaskRouter.ts @@ -51,7 +51,7 @@ export class MaskRouter extends Router implements IRouter { constructor(mask: string, serveResponse: ServeResponseType, options?: RouterOptions) { super(); - this.#mask = this.#parseMask(mask); + this.#mask = this.#normalizeMask(mask); this.#maskVariants = this.#parseVariants(mask); this.#serveResponse = serveResponse; this.#options = createRequiredOptions(options); @@ -335,7 +335,7 @@ export class MaskRouter extends Router implements IRouter { } - #parseMask(mask: string): string { + #normalizeMask(mask: string): string { const parse = (mask: string): string => { const openChar = this.#varibleOpenChar; const closeChar = this.#varibleCloseChar; @@ -355,4 +355,17 @@ export class MaskRouter extends Router implements IRouter { return Router.cleanPathname(pathname); } + + + recontructPathname(params: Record): string { + const variants = [...this.#maskVariants]; + + variants.forEach(mask => { + this. + }) + + + + return ""; + } } diff --git a/tests/MaskRouter.test.ts b/tests/MaskRouter.test.ts index 465745e..d043437 100644 --- a/tests/MaskRouter.test.ts +++ b/tests/MaskRouter.test.ts @@ -163,3 +163,18 @@ Deno.test("MaskRouter::parseParams", async () => { await test(task); } }); + + +Deno.test("MaskRouter::recontructPathname", () => { + const mask = "//"; + const serveResponse = () => new Response(); + const router = new MaskRouter(mask, serveResponse); + + const urlPath = router.recontructPathname({ + controller: "product", + action: "detail", + id: "abc123", + }) + + assertEquals(urlPath, "product/detail/abc123"); +}); From d6e75b07c2ce7a69eaff2ea11d585d5d8ee39e65 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 27 Jun 2022 20:57:21 +0200 Subject: [PATCH 5/9] Update MaskRouter.ts --- routers/MaskRouter.ts | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/routers/MaskRouter.ts b/routers/MaskRouter.ts index 7ab3d64..180e77a 100644 --- a/routers/MaskRouter.ts +++ b/routers/MaskRouter.ts @@ -358,14 +358,36 @@ export class MaskRouter extends Router implements IRouter { recontructPathname(params: Record): string { - const variants = [...this.#maskVariants]; + const paramNames = Object.keys(params); - variants.forEach(mask => { - this. - }) + // Find matching mask + const mask = this.#maskVariants.find(mask => { + const declaration = this.#parseParamDeclarations(mask); + if (declaration === null) return false; + for (const [name, properties] of declaration.entries()) { + // Missing param + if (!paramNames.includes(name) && properties.defaultValue === null) return false; + } + + return true; + }); + + // If mask not found, creates url query + if (!mask) { + const query = new URLSearchParams(params); + return query.toString(); + } + + const declaration = this.#parseParamDeclarations(mask); + + this.#maskParser.lastIndex = 0; + const pathname = mask.replace(this.#maskParser, (_substring, _g1, _g2, _g3, _g4, _g5, _offset, _source, groups) => { + const name = groups.name; + + return params[name] ?? declaration?.get(name)?.defaultValue ?? ''; + }); - - return ""; + return pathname; } } From aea7a814c7f130ddcdd385b8989471230d793fb8 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 27 Jun 2022 21:01:39 +0200 Subject: [PATCH 6/9] Update MaskRouter.test.ts --- tests/MaskRouter.test.ts | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/tests/MaskRouter.test.ts b/tests/MaskRouter.test.ts index d043437..cc69342 100644 --- a/tests/MaskRouter.test.ts +++ b/tests/MaskRouter.test.ts @@ -166,15 +166,28 @@ Deno.test("MaskRouter::parseParams", async () => { Deno.test("MaskRouter::recontructPathname", () => { - const mask = "//"; - const serveResponse = () => new Response(); - const router = new MaskRouter(mask, serveResponse); + const tasks: { + mask: string, + params: Record, + expectation: string, + }[] = [ + { + expectation: 'product/detail/abc123', + mask: '//', + params: { + controller: "product", + action: "detail", + id: "abc123", + } + } + ]; + - const urlPath = router.recontructPathname({ - controller: "product", - action: "detail", - id: "abc123", - }) + tasks.forEach(({ mask, params, expectation }) => { + const serveResponse = () => new Response(); + const router = new MaskRouter(mask, serveResponse); + const urlPath = router.recontructPathname(params) - assertEquals(urlPath, "product/detail/abc123"); + assertEquals(urlPath, expectation); + }); }); From 89e446cc3dae04f873e2069eb0fbf25c43b17386 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 27 Jun 2022 21:02:04 +0200 Subject: [PATCH 7/9] Update MaskRouter.test.ts --- tests/MaskRouter.test.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/MaskRouter.test.ts b/tests/MaskRouter.test.ts index cc69342..89957bd 100644 --- a/tests/MaskRouter.test.ts +++ b/tests/MaskRouter.test.ts @@ -166,21 +166,23 @@ Deno.test("MaskRouter::parseParams", async () => { Deno.test("MaskRouter::recontructPathname", () => { - const tasks: { + type Task = { mask: string, params: Record, expectation: string, - }[] = [ - { - expectation: 'product/detail/abc123', - mask: '//', - params: { - controller: "product", - action: "detail", - id: "abc123", - } + } + + const tasks: Task[] = [ + { + expectation: 'product/detail/abc123', + mask: '//', + params: { + controller: "product", + action: "detail", + id: "abc123", } - ]; + } + ]; tasks.forEach(({ mask, params, expectation }) => { From b1b18e253d8386a7049697c66ab07966056593a9 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 28 Jun 2022 08:08:10 +0200 Subject: [PATCH 8/9] Update MaskRouter.ts --- routers/MaskRouter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/MaskRouter.ts b/routers/MaskRouter.ts index 180e77a..3765d47 100644 --- a/routers/MaskRouter.ts +++ b/routers/MaskRouter.ts @@ -38,7 +38,7 @@ export class MaskRouter extends Router implements IRouter { readonly #varibleOpenChar = '['; readonly #varibleCloseChar = ']'; - readonly #maskParser = /\<(?[a-z][A-z0-9]*)(=(?.+?))?\s*(\s+(?.+?))?\>/g; + readonly #maskParser = /\<(?[a-z][A-z0-9-]*)(=(?.+?))?\s*(\s+(?.+?))?\>/g; readonly #maskCache = new Cache(); readonly #variantCache = new Cache(); From 9f4da3db42e8459822ba9810772f346fff4286d9 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 28 Jun 2022 08:08:12 +0200 Subject: [PATCH 9/9] Update MaskRouter.test.ts --- tests/MaskRouter.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/MaskRouter.test.ts b/tests/MaskRouter.test.ts index 89957bd..61f92f9 100644 --- a/tests/MaskRouter.test.ts +++ b/tests/MaskRouter.test.ts @@ -181,7 +181,14 @@ Deno.test("MaskRouter::recontructPathname", () => { action: "detail", id: "abc123", } - } + }, + { + expectation: 'mrkev', + mask: '', + params: { + "vegetable-name": "mrkev", + } + }, ];