@stefanobalocco/jdamnsmallmrouter
v3.0.0
Published
Damn small hash router
Maintainers
Readme
jDamnSmallRouter
A small JavaScript/TypeScript library for hash-based URL routing (#). It supports routes with parameters, special error routes (403, 404, 500), and asynchronous functions. The default export is the singleton router instance.
Installation
npm / bundler:
npm install @stefanobalocco/jdamnsmallmrouterBrowser (CDN):
<script type="module">
import router from 'https://cdn.jsdelivr.net/npm/@stefanobalocco/jdamnsmallmrouter/dist/jDamnSmallRouter.min.js';
router.routeAdd( '/home', async ( routePath, hashPath, params ) => {
console.log( 'Home page' );
} );
</script>Quick Start
import router from '@stefanobalocco/jdamnsmallmrouter';
router.routeAdd( '/home', async () => {
console.log( 'Home page' );
} );
router.routeSpecialAdd( 404, async ( routePath, hashPath ) => {
console.warn( 'Not found:', routePath, hashPath );
} );API Reference
router.routeSpecialAdd(code: number, routeFunction: RouteFunction): boolean
Adds a callback function to handle special routes like 403 (Forbidden) or 404 (Not Found).
code: The status code to handle (supports403,404, and500). Any other code throws aRangeError.routeFunction: The function to execute when the error occurs. It must conform to theRouteFunctiontype ((routePath: string, hashPath: string, params?: { [ key: string ]: string }) => ( void | Promise<void> )).Returns
trueif the code is supported and the function was added successfully.Throws a
RangeErrorif the code is not 403, 404, or 500.
router.routeAdd(path: string, routeFunction: RouteFunction, available?: CheckAvailability, routeFunction403?: RouteFunction): boolean
Adds a new route to the router.
path: The path string to match against (see Path Syntax).routeFunction: The function to execute when the path matches. It must conform to theRouteFunctiontype.available(optional): A function to check if the route is available. It must conform to theCheckAvailabilitytype ((routePath: string, hashPath: string, params?: { [ key: string ]: string }) => ( boolean | Promise<boolean> )). If this function returnsfalse(or a Promise resolving tofalse), the mainrouteFunctionwill not be executed.routeFunction403(optional): A function specific to this route to execute if theavailablecheck fails (returnsfalse). This takes precedence over the global 403 function defined withrouteSpecialAdd. It must conform to theRouteFunctiontype.Returns
trueif the route was added successfully,falseif a route with the same "reduced path" (path with typed parameters normalized) already exists.Throws a
SyntaxErrorif the path contains duplicate parameter IDs (e.g.,/users/:id/orders/:id).
Routes are sorted based on a calculated "weight": routes with more static segments have a higher weight and are checked first.
router.routeDel(path: string): boolean
Removes a previously added route.
path: The path string to remove. Removes the first registered route equivalent to the supplied normalized path. An untyped parameter path (defaulting toAZ09) may therefore select a registered typed route with an overlapping parameter class (AZor09).Returns
trueif the route was found and removed,falseotherwise.Throws a
SyntaxErrorif the path contains duplicate parameter IDs (for consistency withrouteAdd).
router.trigger(path: string): void
Changes the URL hash in the browser window. The browser fires a hashchange event that the router's checkHash handler picks up and routes. Equivalent to setting window.location.hash = '#' + path; when the path differs from the current hash.
path: The path string to navigate to (without the '#').
router.route(path: string): Promise<void>
Performs the route matching logic and callback function execution. Called automatically by checkHash on hashchange events. You should not need to call this directly unless you want to force routing for a specific path without changing the URL hash.
Direct route() calls execute immediately, not through the queue. Multiple direct calls may run concurrently; they do not wait for one another.
path: The path string to match against (without the '#').
router.checkHash(): Promise<void>
Bound to the window's hashchange event. It executes automatically whenever the URL hash changes. It reads the current hash and invokes router.route() only when the hash is nonempty. If routing is already in progress (e.g., an async route handler is pending), the hash is queued and processed after the current route completes.
Path Syntax
Route paths can contain static segments and dynamic parameters.
Static Segments: Any part of the path that does not start with
:. Static segments form part of a regular expression — characters with special regex meaning (e.g.,.) match as regex metacharacters. For example,/a.bmatches both/a.band/axb.Dynamic Parameters: Start with
:followed by a name (e.g.,:id). They can include type hints in square brackets./:nameand/:name[AZ09]: Matches one or more characters in the seta-zA-Z0-9. E.g.,/users/:username./:name[09]: Matches one or more digits (\d). E.g.,/products/:id[09]./:name[AZ]: Matches one or more characters in the seta-zA-Z. E.g.,/language/:code[AZ].
Example path: /blog/:year[09]/:month[09]/:slug. This would match /blog/2023/10/myArticle.
Restriction: You cannot use the same parameter ID multiple times within the same path (e.g., /users/:id/orders/:id throws a SyntaxError).
Parameters of RouteFunction and CheckAvailability
The routeFunction, available, and routeFunction403 functions receive three arguments:
routePath: string: The registered path in its normalized form — parameter names are discarded and retained parameter classes are represented (e.g.,/users/:id[09]becomes/users/:09, and/users/:idbecomes/users/:AZ09). Useful for identifying which route matched.hashPath: string: The actual path string from the URL hash (without the '#'). This is the path that was matched against.params?: { [ key: string ]: string }: An object containing the values extracted from the dynamic path parameters. Keys are the parameter names defined in the path (e.g.,id), values are the corresponding strings from thehashPath.
Example with /users/:id[09] and URL #/users/123:
routePath:/users/:09hashPath:/users/123params:{ id: "123" }
Special Routes (403, 404, and 500)
You can define handlers for common errors:
404 Not Found: The function registered with
routeSpecialAdd(404, ...)is called if no route matches the URL hash, or if a matched route'savailablefunction returnsfalseand no callable 403 handler (route-specific or global) exists.403 Forbidden: A 403 function is called if a route matches, but its
availablefunction returnsfalse. The precedence for the 403 function is:The
routeFunction403defined specifically for the route that matched (if truthy).The global 403 function defined with
routeSpecialAdd(403, ...)(if set).
500 Error: A 500 function registered with
routeSpecialAdd(500, ...)is called when no callable handler could be resolved: no route matches and no callable 404 handler exists, or the matched route'savailablecheck denied and neither a route-specific nor a global callable 403 handler exists and no callable 404 handler exists.
Async Functions
routeFunction, available, and routeFunction403 can be asynchronous functions (async). The router awaits every callback result regardless of whether the function is declared async. A non-async callback that returns a Promise is also awaited.
Routing Queue
checkHash() queues hash changes while _routing is true. The route() method drains that queue recursively when it reaches its drain step, ensuring no hash change is lost.
Direct calls to route() execute immediately and may run concurrently with other route() calls. They are not added to the queue and do not wait for one another.
