{"_id":"unrouting","_rev":"10-e402bc678952fbe23a329131c794b8e1","name":"unrouting","dist-tags":{"latest":"0.2.3"},"versions":{"0.0.0":{"name":"unrouting","version":"0.0.0","author":{"name":"Daniel Roe","email":"daniel@roe.dev"},"_id":"unrouting@0.0.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"dist":{"shasum":"7301f81958a60461e25c29e509623d293929e81c","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.0.0.tgz","fileCount":2,"integrity":"sha512-/zF2b5FTzyDB353NO6cvL94TSKFX7roiKLTLC/ipkB7el5C3o0iUjEL1Qyr5VjzskwNVJfqT/maHWSNnX3fW/Q==","signatures":[{"sig":"MEYCIQDwPR5Jeah2RIkq59Aii+W/JpRoBZG3Tl/Q+MRpQIOE8wIhAICzgGHv9m/3LwBhx/Qtone2zr09mRx9KtFtoDWloiud","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":119},"gitHead":"fd8425b8bdc158ba00894cfaeed3d885d344b97f","_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_npmVersion":"10.2.3","directories":{},"_nodeVersion":"18.19.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.0.0_1706633309768_0.4119757529337291","host":"s3://npm-registry-packages"}},"0.0.1":{"name":"unrouting","version":"0.0.1","license":"MIT","_id":"unrouting@0.0.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"6fca13386d71aa27d26724614e72da834702c952","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.0.1.tgz","fileCount":5,"integrity":"sha512-N9SkOgBoJPo7/MgllxlF3CaE6Flyi2OVjuE06rQ3c3tAdvYjL5b/nKB3t46S91NTJkr+V50wHnXFQawZHiIwIQ==","signatures":[{"sig":"MEQCICH6E2j+JG/G/rLBG47N0arPngVWF6DCENWgNdzKeYepAiBNnd2LTQHEaFZb0+AyLbVRUOtXkGtsHZIZ6A700tlglg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":11136},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":"./dist/index.js"},"gitHead":"051ba2832cf8fd88e0ae8fb6552314213d23fa6b","scripts":{"dev":"vitest dev","lint":"eslint . --fix","test":"pnpm test:unit && pnpm test:types","build":"unbuild","prepack":"pnpm build","prepare":"simple-git-hooks","release":"pnpm test && bumpp && npm publish","test:unit":"vitest","test:types":"tsc --noEmit","prepublishOnly":"pnpm lint && pnpm test"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"10.5.0","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"resolutions":{"unrouting":"link:."},"sideEffects":false,"_nodeVersion":"20.12.2","dependencies":{"ufo":"^1.3.2","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.0.6","devDependencies":{"vite":"latest","bumpp":"^9.4.1","eslint":"latest","radix3":"1.1.2","vitest":"latest","unbuild":"latest","typescript":"latest","vue-router":"4.3.2","@types/node":"20.12.7","lint-staged":"latest","simple-git-hooks":"latest","@vitest/coverage-v8":"latest","@antfu/eslint-config":"latest"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.0.1_1715193441979_0.31796014756526114","host":"s3://npm-registry-packages"}},"0.1.3":{"name":"unrouting","version":"0.1.3","license":"MIT","_id":"unrouting@0.1.3","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"a2bc2b5c401caf2376e193c887b39c53c63089e8","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.1.3.tgz","fileCount":5,"integrity":"sha512-/cYt6OnDziX5k/cOBcbIVCNq9tG4wYNCf5rHdoZzs2+ph+w/p/pJWN0FScpAaTUVndVQOh5JeoMHZq/Vz83yAw==","signatures":[{"sig":"MEYCIQDLqv05LLOk5ecJTiOGnjgt8+MLPeIytvheplAi/1s4swIhAOD3P6JpusqNkJBovNzu5ILES9FrMRQ4YpdF/KKZzJuP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":43031},"main":"./dist/index.mjs","type":"module","_from":"file:unrouting-0.1.3.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp && npm publish","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4d55f99a-7f10-442e-9575-ad3cb3853873"}},"_resolved":"/tmp/2500fe2580eef22ea7f9c389ee78b30b/unrouting-0.1.3.tgz","_integrity":"sha512-/cYt6OnDziX5k/cOBcbIVCNq9tG4wYNCf5rHdoZzs2+ph+w/p/pJWN0FScpAaTUVndVQOh5JeoMHZq/Vz83yAw==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"11.6.2","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"resolutions":{"unrouting":"link:."},"sideEffects":false,"_nodeVersion":"24.13.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.7.12","vite":"7.3.1","bumpp":"10.4.1","eslint":"10.0.0","tsdown":"0.20.3","vitest":"4.0.18","pkg-pr-new":"0.0.63","typescript":"5.9.3","vue-router":"5.0.2","@types/node":"22.19.11","lint-staged":"16.2.7","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.0.18","@antfu/eslint-config":"7.4.3"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.1.3_1770940857347_0.6036443218165815","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"unrouting","version":"0.1.4","license":"MIT","_id":"unrouting@0.1.4","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"8e1249c6d05d52f2c9f38f4e7cedac487c422a71","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.1.4.tgz","fileCount":5,"integrity":"sha512-INBm5DI5W0akn98ZkoqDDMvF2CpYi3Thp+/dGqvizkkDK7xbFuM94P0jdMRc2yUAVNjdQdpWsiGEkgwu7uL4Dg==","signatures":[{"sig":"MEYCIQCT/JUOrchGZTaTeX6gTnz+cXaUbYuZiKZj2LmNZzyy0gIhAMTdHYzqsrNjYDgmjiISVyujePnv7jUXs8vucQhvD+Za","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":50599},"main":"./dist/index.mjs","type":"module","_from":"file:unrouting-0.1.4.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4d55f99a-7f10-442e-9575-ad3cb3853873"}},"_resolved":"/tmp/663a5cbbd37e4d40b7ca108e1f84e9b5/unrouting-0.1.4.tgz","_integrity":"sha512-INBm5DI5W0akn98ZkoqDDMvF2CpYi3Thp+/dGqvizkkDK7xbFuM94P0jdMRc2yUAVNjdQdpWsiGEkgwu7uL4Dg==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"11.6.2","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"resolutions":{"unrouting":"link:."},"sideEffects":false,"_nodeVersion":"24.13.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.7.12","vite":"7.3.1","bumpp":"10.4.1","eslint":"10.0.0","tsdown":"0.20.3","vitest":"4.0.18","pkg-pr-new":"0.0.63","typescript":"5.9.3","vue-router":"5.0.2","@types/node":"24.10.13","lint-staged":"16.2.7","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.0.18","@antfu/eslint-config":"7.4.3"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.1.4_1770976237117_0.6834050758247472","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"unrouting","version":"0.1.5","license":"MIT","_id":"unrouting@0.1.5","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"ba2c508c82c148223d5109e5dc530b7898f972b1","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.1.5.tgz","fileCount":5,"integrity":"sha512-Z9QCdWmf2dqrlcJ5KMgSRm5sEhhhSS2D7iOh/t3k0bnAKp5K8+AMf6eqfGGZAQCPn3IcM7ABixxy+FBjOvATBQ==","signatures":[{"sig":"MEUCIQCpCN1D7YFq0w0XtQSD6X2K2xJhI76EdDsLlHasyq5lsAIgNorNRRdTKYJ6YLm3E3UYLebLqm9eRuKMEm5RAwyob5g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.1.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":51325},"main":"./dist/index.mjs","type":"module","_from":"file:unrouting-0.1.5.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4d55f99a-7f10-442e-9575-ad3cb3853873"}},"_resolved":"/tmp/749dc1919448e63f24ff5fd7d77d9c8e/unrouting-0.1.5.tgz","_integrity":"sha512-Z9QCdWmf2dqrlcJ5KMgSRm5sEhhhSS2D7iOh/t3k0bnAKp5K8+AMf6eqfGGZAQCPn3IcM7ABixxy+FBjOvATBQ==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"11.6.2","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"resolutions":{"unrouting":"link:."},"sideEffects":false,"_nodeVersion":"24.13.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.7.12","vite":"7.3.1","bumpp":"10.4.1","eslint":"10.0.0","tsdown":"0.20.3","vitest":"4.0.18","pkg-pr-new":"0.0.63","typescript":"5.9.3","vue-router":"5.0.2","@types/node":"24.10.13","lint-staged":"16.2.7","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.0.18","@antfu/eslint-config":"7.4.3"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.1.5_1770979269351_0.8049143040303548","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"unrouting","version":"0.1.7","license":"MIT","_id":"unrouting@0.1.7","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"a4754c81c5270093118734dbf0d90a367b211a27","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.1.7.tgz","fileCount":5,"integrity":"sha512-+0hfD+CVWtD636rc5Fn9VEjjTEDhdqgMpbwAuVoUmydSHDaMNiFW93SJG4LV++RoGSEAyvQN5uABAscYpDphpQ==","signatures":[{"sig":"MEQCIHnN+6rfP69mOYOeHP5/oguYW4RJfDamstvLJPWjahKuAiBbcQjZbtl8InRwuY0oFM8cOKUzbKRZrgAoBtMnS845nQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.1.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":51302},"main":"./dist/index.mjs","type":"module","_from":"file:unrouting-0.1.7.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4d55f99a-7f10-442e-9575-ad3cb3853873"}},"_resolved":"/tmp/52edddef2c9f2dd5eb7530789c83c65d/unrouting-0.1.7.tgz","_integrity":"sha512-+0hfD+CVWtD636rc5Fn9VEjjTEDhdqgMpbwAuVoUmydSHDaMNiFW93SJG4LV++RoGSEAyvQN5uABAscYpDphpQ==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"11.9.0","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"resolutions":{"unrouting":"link:."},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.7.12","vite":"7.3.1","bumpp":"10.4.1","eslint":"10.0.1","tsdown":"0.21.0","vitest":"4.0.18","pkg-pr-new":"0.0.65","typescript":"5.9.3","vue-router":"5.0.3","@types/node":"24.11.0","lint-staged":"16.3.2","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.0.18","@antfu/eslint-config":"7.6.1"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.1.7_1773402263029_0.9712664484664582","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"unrouting","version":"0.2.0","license":"MIT","_id":"unrouting@0.2.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"838edaa24c17ae3804f0a114a921cb7b730461ef","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.2.0.tgz","fileCount":5,"integrity":"sha512-/0DyKV3NShmnCWNcU2BEYD0//GTqG36i6YldpYTXV5Rs+FRqs7sFfxUHTuT76dV5f+N1eHIQvnFKtxkB9HMV8g==","signatures":[{"sig":"MEUCIAgQXOcafbxo6gAZS5d0dUn63WExJw92W+7egMFCat1sAiEA7dDwKDQj+dDRFA3TenJ+8MPieCWligZPL6NsPrHGoI4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":76255},"main":"./dist/index.mjs","type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.0.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:4575029b-8dbb-4d98-b671-21a952eb8533"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.0.tgz","_integrity":"sha512-/0DyKV3NShmnCWNcU2BEYD0//GTqG36i6YldpYTXV5Rs+FRqs7sFfxUHTuT76dV5f+N1eHIQvnFKtxkB9HMV8g==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"12.0.1","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.9.1","vite":"8.1.5","bumpp":"11.1.0","eslint":"10.7.0","tsdown":"0.22.13","vitest":"4.1.10","pkg-pr-new":"0.0.79","typescript":"6.0.3","vue-router":"5.2.0","@types/node":"24.13.3","lint-staged":"17.1.1","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.10","@antfu/eslint-config":"9.2.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.2.0_1784741770777_0.7607105637984661","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"unrouting","version":"0.2.1","license":"MIT","_id":"unrouting@0.2.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"64ccdfa0cdbda06b7eba76377461171678075e0b","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.2.1.tgz","fileCount":5,"integrity":"sha512-6PPgRNT60lViebJUD/eRdbOd4lS5x+RK5z7IHzAzlYwPqRLFySlzwmoyvvVvpQwrxyyphJ2fSzuWKoCnklilqQ==","signatures":[{"sig":"MEUCIQCIPfQ4nz2OHQuy6xVnt7D8VFeTCqgYpoAqsDiiV5cArwIgUY0e57Vs7R0HhWOy1ybHIUaMXiwgqFWAs3bfFD3D90o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":77814},"main":"./dist/index.mjs","type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.1.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:4575029b-8dbb-4d98-b671-21a952eb8533"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.1.tgz","_integrity":"sha512-6PPgRNT60lViebJUD/eRdbOd4lS5x+RK5z7IHzAzlYwPqRLFySlzwmoyvvVvpQwrxyyphJ2fSzuWKoCnklilqQ==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"12.0.1","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.9.1","vite":"8.1.5","bumpp":"11.1.0","eslint":"10.7.0","tsdown":"0.22.13","vitest":"4.1.10","pkg-pr-new":"0.0.79","typescript":"6.0.3","vue-router":"5.2.0","@types/node":"24.13.3","lint-staged":"17.1.1","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.10","@antfu/eslint-config":"9.2.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.2.1_1784744244803_0.4123262678386479","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"unrouting","version":"0.2.2","license":"MIT","_id":"unrouting@0.2.2","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/unrouting#readme","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"db9c0c890b6d32d746f72dee170b775b240f3c95","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.2.2.tgz","fileCount":5,"integrity":"sha512-EoCab68s1o9AWFq9fjKsMEsmjKrPO11SAsvopikks2eEm/KLXgZMCof4cgpVgdy0Vz71OFBJw6DoDqu1oOSFGw==","signatures":[{"sig":"MEUCIGiC8iMu55O9OoHr4XPcnBI47cIkINUWznKvjdd/kEajAiEArgy4YNVWwfjtxlMngCdk7rEeFQmzClBoC8j83SqFws0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":77943},"main":"./dist/index.mjs","type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.2.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:4575029b-8dbb-4d98-b671-21a952eb8533"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.2.tgz","_integrity":"sha512-EoCab68s1o9AWFq9fjKsMEsmjKrPO11SAsvopikks2eEm/KLXgZMCof4cgpVgdy0Vz71OFBJw6DoDqu1oOSFGw==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"12.0.1","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rou3":"0.9.1","vite":"8.1.5","bumpp":"11.1.0","eslint":"10.7.0","tsdown":"0.22.13","vitest":"4.1.10","pkg-pr-new":"0.0.79","typescript":"6.0.3","vue-router":"5.2.0","@types/node":"24.13.3","lint-staged":"17.1.1","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.10","@antfu/eslint-config":"9.2.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/unrouting_0.2.2_1784799541635_0.08931429005044556","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"_id":"unrouting@0.2.3","bugs":{"url":"https://github.com/unjs/unrouting/issues"},"dist":{"shasum":"16c7d9326c7251fc73269decc683a65597cc0f1f","tarball":"https://registry.npmjs.org/unrouting/-/unrouting-0.2.3.tgz","integrity":"sha512-8wOFT/fBh8YeeDr1aVmkXCqYVTMbQ6vzfNzwzybKmSfXdRhGCq1Y2B1e9YeB0JEf85gbvSwJHAMu3D2IEcLGKA==","fileCount":5,"unpackedSize":78666,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/unrouting@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCNF8wZklgh1yGCMyCpbyeTg+4dce0UyzF93WwkFNs92gIgZIt96p/dD2Xydp7u0C7z/fHjPqu5paOAjYXGnZW5E+o="}]},"main":"./dist/index.mjs","name":"unrouting","type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.3.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"license":"MIT","scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"tsdown","release":"pnpm test && bumpp","test:unit":"vitest run","test:types":"tsc --noEmit"},"version":"0.2.3","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4575029b-8dbb-4d98-b671-21a952eb8533"},"approver":{"name":"danielroe","email":"daniel@roe.dev"}},"homepage":"https://github.com/unjs/unrouting#readme","_resolved":"/home/runner/work/_temp/uppt-tarballs/unrouting-0.2.3.tgz","_integrity":"sha512-8wOFT/fBh8YeeDr1aVmkXCqYVTMbQ6vzfNzwzybKmSfXdRhGCq1Y2B1e9YeB0JEf85gbvSwJHAMu3D2IEcLGKA==","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"_npmVersion":"12.0.2","description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["pnpm eslint --fix"]},"maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"ufo":"^1.6.3","escape-string-regexp":"^5.0.0"},"devDependencies":{"rou3":"0.9.2","vite":"8.2.1","bumpp":"12.2.0","eslint":"10.8.1","tsdown":"0.22.14","vitest":"4.1.10","pkg-pr-new":"0.0.87","typescript":"6.0.3","vue-router":"5.2.0","@types/node":"24.13.3","lint-staged":"17.3.0","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.10","@antfu/eslint-config":"9.3.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/unrouting_0.2.3_1786547246469_0.5370323848369778"},"_hasShrinkwrap":false}},"time":{"created":"2024-01-30T16:48:29.652Z","modified":"2026-08-12T15:07:26.890Z","0.0.0":"2024-01-30T16:48:29.914Z","0.0.1":"2024-05-08T18:37:22.170Z","0.1.3":"2026-02-13T00:00:57.494Z","0.1.4":"2026-02-13T09:50:37.288Z","0.1.5":"2026-02-13T10:41:09.504Z","0.1.7":"2026-03-13T11:44:23.212Z","0.2.0":"2026-07-22T17:36:10.859Z","0.2.1":"2026-07-22T18:17:24.886Z","0.2.2":"2026-07-23T09:39:01.713Z","0.2.3":"2026-08-12T15:07:26.557Z"},"bugs":{"url":"https://github.com/unjs/unrouting/issues"},"license":"MIT","homepage":"https://github.com/unjs/unrouting#readme","repository":{"url":"git+https://github.com/unjs/unrouting.git","type":"git"},"description":"[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![bundle][bundle-src]][bundle-href] [![Codecov][codecov-src]][codecov-href] [![License][license-src]][license-href] [![JSDocs][jsdocs-src]][jsdo","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"readme":"# 📍 unrouting\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![bundle][bundle-src]][bundle-href]\n[![Codecov][codecov-src]][codecov-href]\n[![License][license-src]][license-href]\n[![JSDocs][jsdocs-src]][jsdocs-href]\n\n> Universal filesystem routing\n\n`unrouting` parses file paths into a route tree and emits route definitions for any framework router. It handles nested routes, dynamic params, catchalls, optional segments, route groups, layer merging, and more – as a standalone, framework-agnostic library.\n\n## Status\n\nIn active development. The core pipeline (parse, tree, emit) is functional and used by Nuxt.\n\n- [x] Generic route parsing covering major filesystem routing patterns\n  - [x] [Nuxt](https://github.com/nuxt/nuxt) / [unplugin-vue-router](https://github.com/posva/unplugin-vue-router)\n  - [ ] [SvelteKit](https://kit.svelte.dev/docs/routing)\n  - [ ] [Next.js](https://nextjs.org/docs/app/building-your-application/routing)\n- [x] Route tree with nesting, layer merging, group transparency\n- [x] Layer priority (multiple roots with configurable file precedence)\n- [x] Incremental tree updates (`addFile`/`removeFile` for dev server HMR)\n- [x] Pluggable route name generation\n- [x] Route ordering by segment priority (static > dynamic > optional > catchall)\n- [x] Named view support (`@viewName` convention)\n- [x] Mode variant support (`.client`, `.server`, configurable)\n- [x] Duplicate route name detection\n- [x] Emit to framework routers\n  - [x] [`vue-router`](https://router.vuejs.org/) (nested routes, names, files, children, meta, components, modes)\n  - [x] [rou3](http://github.com/h3js/rou3)/[Nitro](https://nitro.unjs.io/)\n  - [x] RegExp patterns\n  - [ ] [SolidStart](https://start.solidjs.com/core-concepts/routing)\n  - [ ] [SvelteKit](https://kit.svelte.dev/docs/routing)\n\n## Install\n\n```sh\n# npm\nnpm install unrouting\n\n# pnpm\npnpm install unrouting\n```\n\n## Usage\n\nThe library has a three-phase pipeline: **parse** file paths into tokens, **build** a route tree, and **emit** to a target format. For most use cases you only need two function calls.\n\n### Quick start\n\n```js\nimport { buildTree, toVueRouter4 } from 'unrouting'\n\nconst tree = buildTree([\n  'pages/index.vue',\n  'pages/about.vue',\n  'pages/users/[id].vue',\n  'pages/users.vue',\n  'pages/[...slug].vue',\n], { roots: ['pages/'] })\n\nconst routes = toVueRouter4(tree)\n// [\n//   { name: 'index', path: '/', file: 'pages/index.vue', children: [] },\n//   { name: 'about', path: '/about', file: 'pages/about.vue', children: [] },\n//   { name: 'users', path: '/users', file: 'pages/users.vue', children: [\n//     { name: 'users-id', path: ':id()', file: 'pages/users/[id].vue', children: [] },\n//   ]},\n//   { name: 'slug', path: '/:slug(.*)*', file: 'pages/[...slug].vue', children: [] },\n// ]\n```\n\n### Nuxt-like usage with layers\n\n```js\nimport { buildTree, toVueRouter4 } from 'unrouting'\n\n// Files from app + layer directories with priority\nconst tree = buildTree([\n  { path: 'pages/index.vue', priority: 0 }, // app layer (wins on collision)\n  { path: 'pages/dashboard.vue', priority: 0 },\n  { path: 'pages/dashboard/settings.vue', priority: 0 },\n  { path: 'layer/pages/dashboard/analytics.vue', priority: 1 }, // extending layer\n  { path: 'layer/pages/index.vue', priority: 1 }, // overridden by app layer\n], {\n  roots: ['pages/', 'layer/pages/'],\n  extensions: ['.vue'],\n  modes: ['client', 'server'],\n  warn: msg => console.warn(msg),\n})\n\nconst routes = toVueRouter4(tree, {\n  onDuplicateRouteName: (name, file, existingFile) => {\n    console.warn(`Duplicate route name \"${name}\": ${file} and ${existingFile}`)\n  },\n})\n```\n\n### Emitting to different formats\n\nAll emitters accept a `RouteTree`:\n\n```js\nimport { buildTree, toRegExp, toRou3, toVueRouter4 } from 'unrouting'\n\nconst tree = buildTree(['users/[id]/posts/[slug].vue'])\n\n// Vue Router 4 – nested routes with names, files, children\nconst vueRoutes = toVueRouter4(tree)\n// [{ name: 'users-id-posts-slug', path: '/users/:id()/posts/:slug()', file: '...', children: [] }]\n\n// rou3/Nitro – flat route patterns\nconst rou3Routes = toRou3(tree)\n// [{ path: '/users/:id/posts/:slug', file: '...' }]\n\n// RegExp – matcher patterns with named groups\nconst regexpRoutes = toRegExp(tree)\n// [{ pattern: /^\\/users\\/(?<id>[^/]+)\\/posts\\/(?<slug>[^/]+)\\/?$/, keys: ['id', 'slug'], file: '...' }]\n```\n\n### Incremental updates (dev server)\n\nThe route tree is mutable. Instead of rebuilding everything when a file changes, use `addFile` and `removeFile` to update the tree in place – avoiding the cost of re-parsing all files and reconstructing the tree from scratch on every change.\n\n```js\nimport { addFile, buildTree, removeFile, toVueRouter4 } from 'unrouting'\n\nconst opts = { roots: ['pages/'], extensions: ['.vue'] }\n\n// Build once at startup\nconst tree = buildTree(initialFiles, opts)\nlet routes = toVueRouter4(tree)\n\n// On file add/remove (e.g., from a watcher callback)\naddFile(tree, 'pages/new-page.vue', opts)\nroutes = toVueRouter4(tree)\n\nremoveFile(tree, 'pages/old-page.vue')\nroutes = toVueRouter4(tree)\n\n// Rename = remove + add\nremoveFile(tree, 'pages/old-name.vue')\naddFile(tree, 'pages/new-name.vue', opts)\nroutes = toVueRouter4(tree)\n```\n\n`addFile` supports the same `InputFile` format as `buildTree` for layer priority:\n\n```js\naddFile(tree, { path: 'layer/pages/about.vue', priority: 1 }, opts)\n```\n\n### Standalone parsing and segment conversion\n\nIf you don't need the full tree pipeline – e.g., you already have resolved routes and only need to convert individual path segments or strings to Vue Router syntax – you can use the parse + convert functions directly:\n\n```js\nimport { parsePath, parseSegment, toVueRouterPath, toVueRouterSegment } from 'unrouting'\n\n// Parse a full file path\nconst [result] = parsePath(['users/[id]/profile.vue'])\n// {\n//   file: 'users/[id]/profile.vue',\n//   segments: [\n//     [{ type: 'static', value: 'users' }],\n//     [{ type: 'dynamic', value: 'id' }],\n//     [{ type: 'static', value: 'profile' }],\n//   ],\n// }\n\n// Convert parsed segments to a Vue Router path\ntoVueRouterPath(result.segments) // => '/users/:id()/profile'\n\n// Parse and convert a single segment (e.g., i18n per-locale route path)\nconst tokens = parseSegment('[...slug]')\n// [{ type: 'catchall', value: 'slug' }]\ntoVueRouterSegment(tokens) // => ':slug(.*)*'\n```\n\n## Supported patterns\n\n| Pattern | Example | Description |\n|---|---|---|\n| Static | `about.vue` | Static route segment |\n| Index | `index.vue` | Index page (maps to `/`) |\n| Dynamic | `[slug].vue` | Required parameter |\n| Optional | `[[slug]].vue` | Optional parameter |\n| Catchall | `[...slug].vue` | Catch-all (zero or more segments) |\n| Repeatable | `[slug]+.vue` | One or more segments |\n| Optional repeatable | `[[slug]]+.vue` | Zero or more segments |\n| Group | `(admin)/dashboard.vue` | Route group (transparent to path, stored in meta) |\n| Mixed | `prefix-[slug]-suffix.vue` | Static and dynamic in one segment |\n| Nested | `parent.vue` + `parent/child.vue` | Parent layout with child routes |\n| Named views | `index@sidebar.vue` | Vue Router named view slots |\n| Modes | `page.client.vue` | Mode variants (configurable suffixes) |\n\n## API\n\n### `buildTree(input, options?)`\n\nBuild a route tree from file paths. Accepts raw strings, `InputFile[]` (with priority), or pre-parsed `ParsedPath[]`.\n\n```ts\nfunction buildTree(\n  input: string[] | InputFile[] | ParsedPath[],\n  options?: BuildTreeOptions\n): RouteTree\n\ninterface InputFile {\n  path: string\n  /** Lower number = higher priority. Default: 0 */\n  priority?: number\n}\n```\n\n**Options** (extends `ParsePathOptions`):\n\n| Option | Type | Description |\n|---|---|---|\n| `roots` | `string[]` | Root paths to strip (e.g., `['pages/', 'layer/pages/']`) |\n| `extensions` | `string[]` | File extensions to strip (default: strip all) |\n| `modes` | `string[]` | Mode suffixes to detect (e.g., `['client', 'server']`) |\n| `warn` | `(msg: string) => void` | Warning callback for invalid characters in dynamic params |\n| `duplicateStrategy` | `'first-wins' \\| 'last-wins' \\| 'error'` | How to handle duplicate paths (default: `'first-wins'`) |\n\nWhen files from different layers collide at the same tree position, the file with the lowest `priority` number wins regardless of insertion order.\n\n### `addFile(tree, filePath, options?)`\n\nAdd a single file to an existing route tree in place. Parses the file and inserts it, avoiding a full rebuild. Accepts a plain string or `InputFile` with priority.\n\n```ts\nfunction addFile(\n  tree: RouteTree,\n  filePath: string | InputFile,\n  options?: BuildTreeOptions\n): void\n```\n\n### `removeFile(tree, filePath)`\n\nRemove a file from an existing route tree by its original file path. Prunes empty structural nodes left behind. Returns `true` if the file was found and removed.\n\n```ts\nfunction removeFile(tree: RouteTree, filePath: string): boolean\n```\n\n### `toVueRouter4(tree, options?)`\n\nEmit Vue Router 4 route definitions from a tree. Handles nested routes, names, index promotion, structural collapse, groups, catchall optimisation, route ordering, named views, and mode variants.\n\n```ts\nfunction toVueRouter4(tree: RouteTree, options?: VueRouterEmitOptions): VueRoute[]\n\ninterface VueRoute {\n  name?: string\n  path: string\n  file?: string\n  /** Named view components. Only present when multiple views exist. */\n  components?: Record<string, string>\n  /** Mode variants. Only present when mode files exist. */\n  modes?: string[]\n  children: VueRoute[]\n  meta?: Record<string, unknown>\n}\n\ninterface VueRouterEmitOptions {\n  /** Custom name generator. Receives raw `/`-separated name, returns final name. */\n  getRouteName?: (rawName: string) => string\n  /** Called when two routes produce the same name. */\n  onDuplicateRouteName?: (name: string, file: string, existingFile: string) => void\n}\n```\n\nRoutes are sorted by segment priority within each level: static segments first, then dynamic, optional, and catchall last.\n\n### `toRou3(tree)`\n\nEmit rou3/Nitro route patterns from a tree.\n\n```ts\nfunction toRou3(tree: RouteTree): Rou3Route[]\n\ninterface Rou3Route {\n  path: string\n  file: string\n}\n```\n\n### `vueRouterToRou3(path, options?)`\n\nConvert a compiled Vue Router path string (e.g. a route definition's `path`) into one or more rou3 patterns. Useful when you already have resolved Vue Router routes (not files) and need to feed them to rou3/Nitro, for example when a module rewrites paths at runtime.\n\n```ts\nfunction vueRouterToRou3(path: string, options?: VueRouterToRou3Options): VueRouterToRou3Result\n\ninterface VueRouterToRou3Options {\n  /** Expand finite alternation params (`:locale(de|fr)`) into concrete paths. @default true */\n  expand?: boolean\n  /** Max paths a single input may expand to before falling back to a dynamic param. Must be a positive integer or a TypeError is thrown. @default 100 */\n  maxExpansions?: number\n  /** Collapse each result into a glob using only `*` and `**` wildcards. @default false */\n  collapse?: boolean\n}\n\ninterface VueRouterToRou3Result {\n  /** The converted rou3 patterns. */\n  patterns: string[]\n  /** One entry per lossy or widening conversion step; empty when the conversion is faithful. */\n  issues: VueRouterToRou3Issue[]\n}\n```\n\nParams carrying a finite alternation regexp are expanded into concrete paths; other custom regexps are preserved as rou3 param constraints where rou3 enforces them (plain and optional params). They are dropped on repeatable params (rou3 ignores them there) and when the regexp contains `/` (rou3 splits patterns on slashes and cannot represent it).\n\n```ts\nimport { vueRouterToRou3 } from 'unrouting'\n\nvueRouterToRou3('/:locale(de|fr)/account/verify').patterns\n// => ['/de/account/verify', '/fr/account/verify']\n\nvueRouterToRou3('/users/:id(\\\\d+)').patterns\n// => ['/users/:id(\\\\d+)']\n\nvueRouterToRou3('/:pathMatch(.*)*').patterns\n// => ['/:pathMatch*']\n```\n\nWith `collapse: true`, each path becomes a glob built from `*` and `**` wildcards. This exists because some targets (route-rule keys, hosting provider config exports) only understand static prefixes and wildcard globs, not `:param` matchers. A bare whole-segment param (`:id`) maps exactly to a single-segment `*` wildcard, so no issue is reported and later segments stay intact. A bare optional param (`:id?`) becomes a trailing `*` (optional in rou3) or, mid-path, expands into both variants (with and without the segment). Anything a wildcard cannot represent exactly (a regexp constraint, a partial segment like `prefix-:id`, a repeatable param) collapses into a `**` catch-all from that segment onwards, with a `collapsed` issue. Enumerable params are still expanded first, so the glob stays as narrow as possible.\n\n```ts\nvueRouterToRou3('/products/:id/edit', { collapse: true }).patterns\n// => ['/products/*/edit']\n\nvueRouterToRou3('/users/:id(\\\\d+)/edit', { collapse: true }).patterns\n// => ['/users/**']\n\nvueRouterToRou3('/:locale(de|fr)/account/:id', { collapse: true }).patterns\n// => ['/de/account/*', '/fr/account/*']\n\nvueRouterToRou3('/static/path', { collapse: true }).patterns\n// => ['/static/path']\n```\n\nConversions are best-effort: a collapsed catch-all matches more than the original path, repeatable params lose their regexp constraint (rou3 does not enforce them) and huge alternations fall back to plain dynamic params. Every such step is recorded in `issues` so callers can surface them to their users:\n\n```ts\nconst { patterns, issues } = vueRouterToRou3('/products/:id(\\\\d+)', { collapse: true })\n// patterns => ['/products/**']\n// issues => [{ type: 'collapsed', message: 'Collapsed \"/products/:id(\\\\d+)\" at segment \":id(\\\\d+)\" into a `**` catch-all, ...' }]\n```\n\n### `toRegExp(tree)`\n\nEmit RegExp matchers from a tree.\n\n```ts\nfunction toRegExp(tree: RouteTree): RegExpRoute[]\n\ninterface RegExpRoute {\n  pattern: RegExp\n  keys: string[]\n  file: string\n}\n```\n\n### `rou3PatternToURLPattern(pattern, options?)`\n\nConvert a single rou3/Nitro route pattern into a URLPattern pathname pattern (e.g. for a [Speculation Rules](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API) `href_matches` rule, or `new URLPattern({ pathname })`). rou3 describes its syntax as URLPattern-compatible, so most tokens (`:name`, `:name(regex)`, `:name?`, `:name+`, `(regex)`, `{...}`) pass through unchanged. Only `*` and `**` genuinely differ and are translated: rou3 `*` (single segment) becomes `([^/]*)`, and rou3 `**`/`**:name` (catch-all) becomes `*`.\n\n```ts\nfunction rou3PatternToURLPattern(pattern: string, options?: { segment?: 'strict' | 'loose' }): {\n  pattern: string\n  issues: Rou3ToURLPatternIssue[]\n}\n\nrou3PatternToURLPattern('/blog/**').pattern // => '/blog/*'\nrou3PatternToURLPattern('/users/:id').pattern // => '/users/:id'\nrou3PatternToURLPattern('/users/:id(\\\\d+)').pattern // => '/users/:id(\\\\d+)'\n```\n\nPass `{ segment: 'loose' }` to collapse single-segment tokens (`:name`, `*`) to `*` instead, matching Nuxt's historical inline conversion. This over-matches (a single `*` matches across `/`), so each collapse is recorded in `issues`:\n\n```ts\nconst { pattern, issues } = rou3PatternToURLPattern('/users/:id', { segment: 'loose' })\n// pattern => '/users/*'\n// issues => [{ type: 'widened', param: 'id', message: 'Widened \":id\" ...' }]\n```\n\n### `toVueRouterSegment(tokens, options?)`\n\nConvert a single parsed segment (an array of tokens returned by `parseSegment`) into a Vue Router 4 path segment string. Useful for modules that already have resolved routes and only need segment-level path conversion (e.g., `@nuxtjs/i18n` converting per-locale custom paths).\n\n```ts\nfunction toVueRouterSegment(\n  tokens: ParsedPathSegmentToken[],\n  options?: ToVueRouterSegmentOptions\n): string\n\ninterface ToVueRouterSegmentOptions {\n  /**\n   * Whether non-index segments follow this one.\n   * When true, catchall uses ([^/]*)*; when false (default), uses (.*)*\n   */\n  hasSucceeding?: boolean\n}\n```\n\n```js\nimport { parseSegment, toVueRouterSegment } from 'unrouting'\n\ntoVueRouterSegment(parseSegment('[id]')) // => ':id()'\ntoVueRouterSegment(parseSegment('[[opt]]')) // => ':opt?'\ntoVueRouterSegment(parseSegment('[...slug]')) // => ':slug(.*)*'\ntoVueRouterSegment(parseSegment('prefix-[slug]')) // => 'prefix-:slug()'\n\n// i18n use case – parse a custom locale path segment\nconst tokens = parseSegment('[foo]_[bar]:[...buz]_buz_[[qux]]')\nconst path = `/${toVueRouterSegment(tokens)}`\n// => '/:foo()_:bar()\\::buz(.*)*_buz_:qux?'\n```\n\n### `toVueRouterPath(segments)`\n\nConvert an array of parsed path segments into a full Vue Router 4 path string. Automatically determines `hasSucceeding` per segment so that mid-path catchalls use the restrictive `([^/]*)*` pattern and terminal catchalls use `(.*)*`.\n\n```ts\nfunction toVueRouterPath(segments: ParsedPathSegment[]): string\n```\n\n```js\nimport { parsePath, toVueRouterPath } from 'unrouting'\n\ntoVueRouterPath(parsePath(['users/[id]/posts.vue'])[0].segments)\n// => '/users/:id()/posts'\n\ntoVueRouterPath(parsePath(['[...slug]/suffix.vue'])[0].segments)\n// => '/:slug([^/]*)*/suffix'  (mid-path catchall auto-detected)\n\ntoVueRouterPath(parsePath(['prefix/[...slug].vue'])[0].segments)\n// => '/prefix/:slug(.*)*'     (terminal catchall)\n```\n\n### `parsePath(filePaths, options?)`\n\nParse file paths into segments. Standalone – does not build a tree.\n\n```ts\nfunction parsePath(filePaths: string[], options?: ParsePathOptions): ParsedPath[]\n\ninterface ParsedPath {\n  file: string\n  segments: ParsedPathSegment[]\n  meta?: { modes?: string[], name?: string }\n}\n```\n\n### `compileParsePath(options?)`\n\nPre-compile parsing options into a reusable function. Useful in hot paths (e.g., dev server file watchers) where `parsePath` would otherwise reconstruct the same regexes on every call.\n\n```ts\nfunction compileParsePath(options?: ParsePathOptions): CompiledParsePath\n\ninterface CompiledParsePath {\n  (filePaths: string[]): ParsedPath[]\n}\n```\n\nReturns a callable with the same signature as `parsePath` (minus the options argument). The regexes for root stripping, extension matching, and mode detection are built once at compile time.\n\n```js\nimport { addFile, buildTree, compileParsePath, toVueRouter4 } from 'unrouting'\n\nconst opts = { roots: ['pages/'], modes: ['client', 'server'] }\n\n// Compile once at startup\nconst parse = compileParsePath(opts)\nconst tree = buildTree(initialFiles, opts)\n\n// In a file watcher callback — no regex re-compilation\naddFile(tree, 'pages/new-page.vue', parse)\nconst routes = toVueRouter4(tree)\n```\n\nThe compiled function can be passed directly to `addFile` as the options argument:\n\n```js\n// These are equivalent, but the compiled version avoids re-building regexes:\naddFile(tree, file, parse) // pre-compiled (fast)\naddFile(tree, file, opts) // raw options (re-compiles each call)\n```\n\n### `parseSegment(segment, absolutePath?, warn?)`\n\nParse a single filesystem segment into typed tokens. Useful for modules that need to parse custom paths (e.g., i18n locale-specific routes).\n\n```ts\nfunction parseSegment(\n  segment: string,\n  absolutePath?: string,\n  warn?: (message: string) => void\n): ParsedPathSegmentToken[]\n\n// Token types: 'static' | 'dynamic' | 'optional' | 'catchall' |\n//              'repeatable' | 'optional-repeatable' | 'group'\n```\n\n### `walkTree(tree, visitor)`\n\nWalk all nodes depth-first.\n\n```ts\nfunction walkTree(\n  tree: RouteTree,\n  visitor: (node: RouteNode, depth: number, parent: RouteNode | null) => void\n): void\n```\n\n### `isPageNode(node)`\n\nCheck if a node has files attached (page node vs structural node).\n\n```ts\nfunction isPageNode(node: RouteNode): boolean\n```\n\n## How nesting works\n\nThe tree distinguishes between **page nodes** (have files) and **structural nodes** (directory-only, no files):\n\n- **Page nodes** create nesting boundaries – children get relative paths\n- **Structural nodes** collapse – their path segment is prepended to descendants\n\n```text\nparent.vue + parent/child.vue\n  → { path: '/parent', children: [{ path: 'child' }] }\n\nparent/child.vue  (no parent.vue)\n  → { path: '/parent/child' }  (structural 'parent' collapses)\n```\n\n`index.vue` promotes a structural directory into a page node:\n\n```text\nusers/index.vue + users/[id].vue\n  → { path: '/users', file: 'users/index.vue', children: [{ path: ':id()' }] }\n```\n\nRoute groups `(name)` are transparent – they don't affect paths or nesting, but are stored in `meta.groups`.\n\n## Development\n\n- Clone this repository\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n## License\n\nMade with ❤️\n\nPublished under [MIT License](./LICENCE).\n\n<!-- Badges -->\n\n[npm-version-src]: https://npmx.dev/api/registry/badge/version/unrouting\n[npm-version-href]: https://npmx.dev/package/unrouting\n[npm-downloads-src]: https://npmx.dev/api/registry/badge/downloads/unrouting\n[npm-downloads-href]: https://npmx.dev/package/unrouting\n[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/unrouting/main?style=flat&colorA=18181B&colorB=F0DB4F\n[codecov-href]: https://codecov.io/gh/unjs/unrouting\n[bundle-src]: https://img.shields.io/bundlephobia/minzip/unrouting?style=flat&colorA=18181B&colorB=F0DB4F\n[bundle-href]: https://bundlephobia.com/result?p=unrouting\n[license-src]: https://img.shields.io/github/license/unjs/unrouting.svg?style=flat&colorA=18181B&colorB=F0DB4F\n[license-href]: https://github.com/unjs/unrouting/blob/main/LICENSE\n[jsdocs-src]: https://img.shields.io/badge/jsDocs.io-reference-18181B?style=flat&colorA=18181B&colorB=F0DB4F\n[jsdocs-href]: https://www.jsdocs.io/package/unrouting\n","readmeFilename":"README.md"}