npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

router-uri-convert

v2.0.3

Published

convert uri-template replace :varname with {+varname} to make it RFC 6570 compatible

Readme

router-uri-convert

將 Router URI 語法(:varname,源自 Express.js / Octokit)與 RFC 6570 URI Template 之間進行雙向轉換的工具模組。

Converts between Router URI syntax (:varname, from Express.js / Octokit) and RFC 6570 URI Template.


Installation

yarn add router-uri-convert
pnpm add router-uri-convert

API

routerToRfc6570(url: string): string

將 Router 語法轉換為 RFC 6570 相容格式。

:varname 替換為 {+varname}

import { routerToRfc6570 } from 'router-uri-convert';

// 基本用法 / Basic usage
routerToRfc6570('/users/:user');
// → '/users/{+user}'

routerToRfc6570('/api/v1/:resource/:id');
// → '/api/v1/{+resource}/{+id}'

rfc6570ToRouter(url: string, opts?: IRfc6570ToRouterOptions): string

將 RFC 6570 格式轉換回 Router 語法。

{varname} / {+varname} 替換回 :varname

import { rfc6570ToRouter } from 'router-uri-convert';

// 基本用法 / Basic usage
rfc6570ToRouter('/users/{+user}');
// → '/users/:user'

rfc6570ToRouter('/api/v1/{+resource}/{+id}');
// → '/api/v1/:resource/:id'

opts.ignoreUnSupport

Router URI 格式是 RFC 6570 的真子集(proper subset),僅能表達簡單路徑參數。當遇到不支援的 RFC 6570 語法(如運算子 ? # / ; & .、逗號多變數 {x,y}、修飾詞 * :N)時:

| ignoreUnSupport | 行為 | |---|---| | false (預設) | 拋出 TypeError | | true | 保留原 {...} 不轉換 |

// 預設:不支援語法拋錯 / Default: throws on unsupported syntax
rfc6570ToRouter('/api/{?query,number}');
// → TypeError: only can convert base rule, but got {?query,number}

// ignoreUnSupport: true → 保留原樣 / keep original
rfc6570ToRouter('/api/{?query,number}', { ignoreUnSupport: true });
// → '/api/{?query,number}'(原樣保留 / kept as-is)

_notSupport(w: string, throwError?: boolean): boolean | void

檢查變數名稱是否包含不支援的規則。僅檢查純符號類型的變數(如 {?}{#})。

import { _notSupport } from 'router-uri-convert';

_notSupport('?query,number'); // → false(含有字元,不觸發此舊檢查,但實際仍不支援)
_notSupport('?');             // → true(純符號,不支援)
_notSupport('+');             // → true

注意:此函數僅檢查「全非單字字元」這種極端情況。更全面的支援性檢查由 rfc6570ToRouter 內部的 _isSupportedRouterVar 處理。


expandRfc6570(url: string, data: Record<string, unknown>): ExpandResult

展開 RFC 6570 URI 模板,並自動將展開結果分離為路徑參數一般資料參數

Expands an RFC 6570 URI template and automatically separates the result into path parameters and data parameters.

import { expandRfc6570 } from 'router-uri-convert/parser';

const result = expandRfc6570('/users/{+user}', { user: 'foo/bar' });
// →
// {
//   router: '/users/{+user}',
//   url: '/users/foo/bar',
//   paths: { user: 'foo/bar' },
//   data: {}
// }
// 完整 RFC 6570 語法支援(運算子、多變數、修飾詞)
// Full RFC 6570 syntax support (operators, multi-variables, modifiers)
expandRfc6570('http://{domain}/~{user}/foo{?query,number}', {
  domain: 'example.com',
  user: 'fred',
  query: 'mycelium',
  number: 3,
});
// →
// {
//   router: 'http://{domain}/~{user}/foo{?query,number}',
//   url: 'http://example.com/~fred/foo?query=mycelium&number=3',
//   paths: { domain: 'example.com', user: 'fred' },
//   data: { query: 'mycelium', number: 3 }
// }

已知上游限制:底層依賴 uri-template-lite,存在數項已知行為差異(如 Reserved Expansion 雙重編碼、boolean 處理、無效模板不拋錯等)。詳見 docs/known-upstream-limitations.md

Known upstream limitations: The underlying uri-template-lite library has several known behavioral differences (e.g., double-encoding in Reserved Expansion, boolean handling, non-throwing for invalid templates, etc.). See docs/known-upstream-limitations.md.


matchRfc6570(template: string, uri: string): Record<string, string> | undefined

將 URI 與 RFC 6570 模板進行匹配,提取變數值(已解碼)。

Matches a URI against an RFC 6570 template and extracts decoded variable values.

import { matchRfc6570 } from 'router-uri-convert/parser';

// 基礎匹配 / Basic matching
matchRfc6570('/users/{+user}', '/users/foo/bar');
// → { user: 'foo/bar' }

// 多變數匹配 / Multi-variable matching
matchRfc6570('/api{/version}/users{?page,limit}', '/api/v1/users?page=1&limit=10');
// → { version: 'v1', page: '1', limit: '10' }

// 不匹配 → undefined / No match → undefined
matchRfc6570('/users/{+user}', '/other/path');
// → undefined

已知上游限制:match 層亦有已知限制(explode list* 回傳錯誤陣列、query 多變數 round-trip 不對稱性)。詳見 docs/known-upstream-limitations.md

Known upstream limitations: The match layer also has known limitations (wrong array for explode list*, query multi-variable round-trip asymmetry). See docs/known-upstream-limitations.md.

matchRouter(template: string, uri: string): Record<string, string> | undefined

將 URI 與 Router 格式模板(:varname)進行匹配。

Matches a URI against a Router-format template (:varname).

import { matchRouter } from 'router-uri-convert/parser';

// 基礎匹配 / Basic matching
matchRouter('/users/:user', '/users/foo/bar');
// → { user: 'foo/bar' }

// 不匹配 → undefined / No match → undefined
matchRouter('/users/:user', '/other/path');
// → undefined

注意matchRouter 內部先呼叫 routerToRfc6570 轉換為 RFC 6570 格式後再進行匹配,因此支援與 routerToRfc6570 相同的變數語法(:varname{+varname})。


使用範例

雙向轉換 / Bidirectional conversion

import { routerToRfc6570, rfc6570ToRouter } from 'router-uri-convert';

const source = '/users/:user';

const rfc6570 = routerToRfc6570(source);
// → '/users/{+user}'

const back = rfc6570ToRouter(rfc6570);
// → '/users/:user'

// Round-trip 成立
expect(back).toBe(source);

使用 expandRfc6570 展開模板

import { expandRfc6570 } from 'router-uri-convert/parser';

// 直接使用 RFC 6570 語法展開 / Expand directly with RFC 6570 syntax
const result = expandRfc6570('/users/{+user}', { user: 'foo/bar' });
// → { router: '/users/{+user}', url: '/users/foo/bar', ... }

配合 matchRfc6570 進行 round-trip

import { expandRfc6570, matchRfc6570 } from 'router-uri-convert/parser';

// 先展開 / Expand first
const expanded = expandRfc6570('/users/{+user}', { user: 'foo/bar' });
// expanded.url → '/users/foo/bar'

// 再匹配還原 / Then match back
const matched = matchRfc6570('/users/{+user}', expanded.url);
// matched → { user: 'foo/bar' }

匯出路徑

| 函數 | 匯出路徑 | |------|---------| | routerToRfc6570 | router-uri-convert | | rfc6570ToRouter | router-uri-convert | | _notSupport | router-uri-convert | | expandRfc6570 | router-uri-convert/parser | | matchRfc6570 | router-uri-convert/parser | | matchRouter | router-uri-convert/parser | | parseRouterVars | router-uri-convert/parser |


RFC 6570 語法支援度

支援轉換(Router ↔ RFC 6570)

| 語法 | Router | RFC 6570 | 說明 | |------|--------|----------|------| | 簡單變數 | :user | {+user} | Round-trip 完全支援 |

不支援轉換(僅 RFC 6570 端)

以下 RFC 6570 語法沒有Router URI 對應,無法進行 rfc6570ToRouter 的雙向轉換:

| 類別 | 範例 | 說明 | |------|------|------| | 運算子 | {?query,number} {#frag} {/path} {;x,y} {&x,y} {.sub} | 表達式類型 | | 多變數 | {x,y} {?x,y} | 逗號分隔多個變數 | | Explode 修飾詞 | {keys*} | * 展開運算 | | Prefix-length | {var:3} | :N 截斷運算 |

若需要使用這些語法,請傳入 { ignoreUnSupport: true }{...} 保留原樣通過轉換:

const url = '/api/{?query,number}/items';
const router = rfc6570ToRouter(url, { ignoreUnSupport: true });
// → '/api/{?query,number}/items'(不轉換 `{?query,number}`,因為無 Router 對應)

// 再轉回 RFC 6570 時亦維持原樣 / Back to RFC 6570 unchanged
routerToRfc6570(router);
// → '/api/{?query,number}/items'

測試

pnpm run test:snapshot

內部使用 vitest + snapshot testing。新增功能時請確保 pnpm run test:snapshot 通過。

指定單一測試檔:

pnpm run test:snapshot test/match-syntax.test.ts
pnpm run test:snapshot test/expand-syntax.test.ts
pnpm run test:snapshot test/uritemplate-test.test.ts

參考文件

| 文件 | 說明 | |------|------| | docs/rfc-6570-syntax-support.md | RFC 6570 語法完整支援度參照表 | | docs/known-upstream-limitations.md | uri-template-lite 已知上游限制與行為差異 |


相關連結