Create links from a route config with type-safe route IDs, params, and query arguments.
This package is distributed through the JSR registry: https://jsr.io/@kokomi/link-generator
npx jsr add @kokomi/link-generatorimport{link_generator,typeRouteConfig}from"@kokomi/link-generator";constroute_config={home: {path: "/"},users: {path: "/users",children: {user: {path: "/:id"},},},posts: {path: "/posts?page"},}asconstsatisfiesRouteConfig;constlink=link_generator(route_config);link("home");// "/"link("users");// "/users"link("users/user",{id: "alice"});// "/users/alice"link("posts",undefined,{page: 2});// "/posts?page=2"You can pass multiple query objects. They are merged in order.
undefined values are ignored.
constroute_config={products: {path: "/products?color&page"},}asconstsatisfiesRouteConfig;constlink=link_generator(route_config);link("products",undefined,{color: "red"},{page: 2});// "/products?color=red&page=2"Repeated keys are kept.
link("products",undefined,{color: "red"},{color: "blue"});// "/products?color=red&color=blue"The final URL is built in the following order:
Resolve route
- The route ID is mapped to a path template.
- Example:
"users/user"→"/users/:id"
Create context
RouteContextis created with:pathparamsquery
Apply transforms
- Each function in
transformsruns in order. - You can mutate
ctx.path,ctx.params, andctx.query.
- Each function in
Replace path params
replace_params_fn(ctx)is called.- Default: replaces
:paramwith encoded values.
Format query string
format_qs_fn(ctx)is called.- Returns a string like
"a=1&b=2"(without?).
Combine
- If the query string is not empty,
"?"is added. - Final result:
path + "?" + query
- If the query string is not empty,
link("users/user",{id: "alice"},{tab: "profile"});Flow:
"/users/:id"
→ (transform)
→ "/users/:id"
→ (replace params)
→ "/users/alice"
→ (format query)
→ "tab=profile"
→ "/users/alice?tab=profile"
transforms is a list of functions that run before the final URL is built.
Each transform receives a RouteContext. You can mutate ctx.path,
ctx.params, or ctx.query.
constroute_config={user: {path: "/users/:id"},}asconstsatisfiesRouteConfig;constlink=link_generator(route_config,{transforms: [(ctx)=>{if(ctx.id==="user"){ctx.path="/members/:id";}},(ctx)=>{if(ctx.id==="user"){ctx.params.set("id",String(ctx.params.get("id")).toUpperCase());}},],});link("user",{id: "alice"});// "/members/ALICE"Use transforms when you want small, reusable changes before parameter
replacement and query formatting.
replace_params_fn replaces path parameters such as :id.
By default, the library uses replace_params(ctx).
import{link_generator,replace_params,typeRouteConfig,}from"@kokomi/link-generator";constroute_config={user: {path: "/users/:id"},}asconstsatisfiesRouteConfig;constlink=link_generator(route_config,{replace_params_fn: (ctx)=>{if(ctx.id==="user"){returnctx.path.replace(":id","bob");}returnreplace_params(ctx);},});link("user",{id: "alice"});// "/users/bob"Use this when you want full control over how path params are resolved.
format_qs_fn returns the final query string without the leading ?.
By default, the library uses format_qs(ctx).
import{format_qs,link_generator,typeRouteConfig,}from"@kokomi/link-generator";constroute_config={products: {path: "/products?color"},}asconstsatisfiesRouteConfig;constlink=link_generator(route_config,{format_qs_fn: (ctx)=>{if(ctx.id==="products"){constqs=newURLSearchParams(ctx.query);constcolor=qs.get("color");if(color){qs.set("color",color.toUpperCase());}qs.set("custom","YES");returnqs.toString();}returnformat_qs(ctx);},});link("products",undefined,{color: "red"});// "/products?color=RED&custom=YES"Use this when you want custom query-string rules.
ParamsContext is a Map<string, DefaultParamValue> for path params.
constparams=newParamsContext({id: "alice"});params.get("id");// "alice"QueryContext is a URLSearchParams instance for query params.
It merges multiple query objects and stringifies values. undefined values are
skipped.
constquery=newQueryContext({lang: "en"},{page: 2});query.get("lang");// "en"query.get("page");// "2"query.toString();// "lang=en&page=2"RouteContext is passed to transforms, replace_params_fn, and
format_qs_fn.
It has these properties:
id: flattened route ID such as"users/user"path: current path templateparams:ParamsContextquery:URLSearchParams
constctx=newRouteContext("users/user",{path: "/users/:id",params: newParamsContext({id: "alice"}),query: newQueryContext({tab: "profile"}),});Nested routes are flattened into slash-separated route IDs.
constroute_config={home: {path: "/"},users: {path: "/users",children: {user: {path: "/:id"},},},}asconstsatisfiesRouteConfig;flatten_route_config(route_config);// {// home: "/",// users: "/users",// "users/user": "/users/:id",// }- Query parts written in route paths are used only as a declaration hint. They are removed from the stored path before link generation.
- Constraint sections in paths are also removed before parameter replacement.
- Path params are URL-encoded by the default
replace_paramsfunction. - Query params are stringified by the default
format_qsfunction.
MIT