From 4f68a64a8841d0e1dbb60fdb6eb494715f0363f2 Mon Sep 17 00:00:00 2001 From: Andy Burke Date: Wed, 25 Jun 2025 20:07:08 -0700 Subject: [PATCH] feature: sort imports to try to ensure parameter paths are less specific --- deno.json | 2 +- handlers/typescript.ts | 37 ++++++++++++++++++++++------- tests/07_test_route_sorting.test.ts | 35 +++++++++++++++++++++++++++ tests/www/echo/hi/index.ts | 8 +++++++ 4 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 tests/07_test_route_sorting.test.ts create mode 100644 tests/www/echo/hi/index.ts diff --git a/deno.json b/deno.json index eb034a6..389eed6 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,7 @@ { "name": "@andyburke/serverus", "description": "A flexible HTTP server for mixed content. Throw static files, markdown, Typescript and (hopefully, eventually) more into a directory and serverus can serve it up a bit more like old-school CGI.", - "version": "0.3.0", + "version": "0.4.0", "license": "MIT", "exports": { ".": "./serverus.ts", diff --git a/handlers/typescript.ts b/handlers/typescript.ts index 97d7171..d240818 100644 --- a/handlers/typescript.ts +++ b/handlers/typescript.ts @@ -53,6 +53,11 @@ export default async function handle_typescript(request: Request): Promise rhs.route_path.localeCompare(lhs.route_path)); + for (const import_info of sorted_imports) { + try { + const module: ROUTE_HANDLER = await import(import_info.import_path) as ROUTE_HANDLER; - if (Deno.env.get('SERVERUS_TYPESCRIPT_IMPORT_LOGGING')) { - console.log(`imported: ${import_path}`); - } + const pattern = new URLPattern({ pathname: import_info.route_path }); - routes.set(pattern, module); - } catch (error) { - console.error(`Error mounting module ${import_path} at ${route_path}\n\n${error}\n`); + if (Deno.env.get('SERVERUS_TYPESCRIPT_IMPORT_LOGGING')) { + console.log(`imported: ${import_info.import_path}`); } + + routes.set(pattern, module); + } catch (error) { + console.error(`Error mounting module ${import_info.import_path} at ${import_info.route_path}\n\n${error}\n`); } } diff --git a/tests/07_test_route_sorting.test.ts b/tests/07_test_route_sorting.test.ts new file mode 100644 index 0000000..e10e2da --- /dev/null +++ b/tests/07_test_route_sorting.test.ts @@ -0,0 +1,35 @@ +import * as asserts from '@std/assert'; +import { EPHEMERAL_SERVER, get_ephemeral_listen_server } from './helpers.ts'; + +Deno.test({ + name: 'test that routes are sorted most to least specific', + permissions: { + env: true, + read: true, + write: true, + net: true + }, + fn: async () => { + let test_server_info: EPHEMERAL_SERVER | null = null; + + try { + Deno.env.set('SERVERUS_ROOT', './tests/www'); + test_server_info = await get_ephemeral_listen_server(); + + const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/hi`, { + method: 'GET' + }); + + const body = await response.text(); + + asserts.assert(response.ok); + asserts.assert(body); + asserts.assertEquals(body, 'hello'); + } finally { + Deno.env.delete('SERVERUS_ROOT'); + if (test_server_info) { + await test_server_info?.server?.stop(); + } + } + } +}); diff --git a/tests/www/echo/hi/index.ts b/tests/www/echo/hi/index.ts new file mode 100644 index 0000000..e97f859 --- /dev/null +++ b/tests/www/echo/hi/index.ts @@ -0,0 +1,8 @@ +export function GET(_req: Request, _meta: Record): Response { + return new Response('hello', { + status: 200, + headers: { + 'Content-Type': 'text/plain' + } + }); +}