[
  {
    "path": ".eslintignore",
    "content": "e2e/public/assets\ne2e/components/Import.svelte\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"env\": {\n    \"es6\": true,\n    \"browser\": true\n  },\n  \"extends\": \"airbnb-base\",\n  \"plugins\": [\n    \"svelte3\"\n  ],\n  \"overrides\": [\n    {\n      \"files\": [\"*.svelte\"],\n      \"processor\": \"svelte3/svelte3\"\n    }\n  ],\n  \"parserOptions\": {\n    \"ecmaVersion\": 2019,\n    \"sourceType\": \"module\"\n  },\n  \"rules\" : {\n    \"max-len\": [\"error\", {\n      \"code\": 150\n    }],\n    \"arrow-parens\": [\"error\", \"as-needed\"],\n    \"indent\": 0,\n    \"strict\": 0,\n    \"prefer-const\": 0,\n    \"no-console\": 0,\n    \"no-labels\": 0,\n    \"no-unused-labels\": 0,\n    \"no-restricted-syntax\": 0,\n    \"no-multi-assign\": 0,\n    \"prefer-destructuring\": 0,\n    \"function-paren-newline\": 0,\n    \"global-require\": 0,\n    \"prefer-spread\": 0,\n    \"prefer-rest-params\": 0,\n    \"prefer-arrow-callback\": 0,\n    \"arrow-body-style\": 0,\n    \"no-restricted-globals\": 0,\n    \"consistent-return\": 0,\n    \"no-param-reassign\": 0,\n    \"no-underscore-dangle\": 0,\n    \"no-multiple-empty-lines\": 0,\n    \"import/first\": 0,\n    \"import/extensions\": 0,\n    \"import/no-unresolved\": 0,\n    \"import/no-dynamic-require\": 0,\n    \"import/no-mutable-exports\": 0,\n    \"import/no-extraneous-dependencies\": 0,\n    \"import/prefer-default-export\": 0\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "package-lock.json -diff\ndist/* -diff\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  Release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v1\n        with:\n          persist-credentials: false\n          fetch-depth: 0\n\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 14\n\n      - run: npm i\n      - run: npm test\n      - run: HASHCHANGE=true npm test\n\n      - run: |\n          git config --local user.name \"Release Bot\"\n          git config --local user.email \"41898282+github-actions[bot]@users.noreply.github.com\"\n\n      - run: npm run release\n\n      - name: Push Changes\n        uses: ad-m/github-push-action@master\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          branch: ${{ github.ref }}\n          tags: true\n\n      - name: Publish\n        run: make release && npm publish\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/testing.yml",
    "content": "name: build\n\non:\n  pull_request:\n    branches:\n    - master\n\njobs:\n  build-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n\n      - uses: tacoss/nodejs@v2\n        with:\n          args: make ci\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.todo\ndist\nbuild\ncache.json\nnode_modules\ne2e/public/assets\npackage-lock.json\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### [0.0.57](https://github.com/pateketrueke/yrv/compare/v0.0.56...v0.0.57) (2022-06-26)\n\n\n### Bug Fixes\n\n* use actions/setup-node instead ([7106391](https://github.com/pateketrueke/yrv/commit/7106391a64783c514c9578147e129021c201087b))\n\n### [0.0.56](https://github.com/pateketrueke/yrv/compare/v0.0.55...v0.0.56) (2022-06-26)\n\n### [0.0.55](https://github.com/pateketrueke/yrv/compare/v0.0.52...v0.0.55) (2022-06-26)\n\n\n### Bug Fixes\n\n* revert alias support ([8e1b907](https://github.com/pateketrueke/yrv/commit/8e1b9072f1b0bc462018c19ddcac3f5b53b896c7))\n* run tests before releasing ([77e30d8](https://github.com/pateketrueke/yrv/commit/77e30d840cc73acdf49a084da55b147b33accd18))\n\n### [0.0.54](https://github.com/pateketrueke/yrv/compare/v0.0.52...v0.0.54) (2022-06-26)\n\n\n### Bug Fixes\n\n* revert alias support ([8e1b907](https://github.com/pateketrueke/yrv/commit/8e1b9072f1b0bc462018c19ddcac3f5b53b896c7))\n* run tests before releasing ([77e30d8](https://github.com/pateketrueke/yrv/commit/77e30d840cc73acdf49a084da55b147b33accd18))\n\n### [0.0.52](https://github.com/pateketrueke/yrv/compare/v0.0.51...v0.0.52) (2022-01-21)\n\n### [0.0.51](https://github.com/pateketrueke/yrv/compare/v0.0.50...v0.0.51) (2022-01-16)\n\n### [0.0.50](https://github.com/pateketrueke/yrv/compare/v0.0.49...v0.0.50) (2021-08-13)\n\n\n### Bug Fixes\n\n* make sure vendor.js is bundled ([b863696](https://github.com/pateketrueke/yrv/commit/b8636962b82bb5488c2ec5286c2c9c3097165104))\n\n### [0.0.49](https://github.com/pateketrueke/yrv/compare/v0.0.48...v0.0.49) (2021-08-13)\n\n### [0.0.48](https://github.com/pateketrueke/yrv/compare/v0.0.47...v0.0.48) (2021-08-11)\n\n### [0.0.47](https://github.com/pateketrueke/yrv/compare/v0.0.46...v0.0.47) (2021-06-30)\n\n### [0.0.46](https://github.com/pateketrueke/yrv/compare/v0.0.45...v0.0.46) (2021-06-27)\n\n\n### Bug Fixes\n\n* run tests on CI for PRs only, master is for release ([c5ad7a4](https://github.com/pateketrueke/yrv/commit/c5ad7a4c66cab235cd09970f6f9bffe13560701a))\n* setup NPM token before releasing ([258dbe2](https://github.com/pateketrueke/yrv/commit/258dbe2211514c4d544470e8b00e6c8011e7fdae))\n\n### [0.0.45](https://github.com/pateketrueke/yrv/compare/v0.0.44...v0.0.45) (2021-06-27)\n\n\n### Bug Fixes\n\n* move release step outside npm scripts ([40a870c](https://github.com/pateketrueke/yrv/commit/40a870cbe99a7dc05cdb4a633083914011c4fac4))\n\n### [0.0.44](https://github.com/pateketrueke/yrv/compare/v0.0.43...v0.0.44) (2021-06-27)\n\n\n### Bug Fixes\n\n* debug entry-point ([e500aad](https://github.com/pateketrueke/yrv/commit/e500aad01fb3314f2a84cdf7079b5f194b5015ad))\n* enable DEBUG while on dev and CI ([2bddc76](https://github.com/pateketrueke/yrv/commit/2bddc761be5e791005b345d97e43b0b06e10a084))\n* rebuild before tests to enable cross-env changes ([6aea3f8](https://github.com/pateketrueke/yrv/commit/6aea3f8d9cc5daac53e97127d56901ae33362ed2))\n* use ...activeProps for active Route components ([cf41085](https://github.com/pateketrueke/yrv/commit/cf41085c3aaa20bd4d25d76f9e1b6650a997e808))\n\n### [0.0.43](https://github.com/pateketrueke/yrv/compare/v0.0.42...v0.0.43) (2021-06-27)\n\n### [0.0.42](https://github.com/pateketrueke/yrv/compare/v0.0.41...v0.0.42) (2021-05-09)\n\n### [0.0.41](https://github.com/pateketrueke/yrv/compare/v0.0.40...v0.0.41) (2021-05-09)\n\n### [0.0.40](https://github.com/pateketrueke/yrv/compare/v0.0.39...v0.0.40) (2021-05-09)\n\n### [0.0.39](https://github.com/pateketrueke/yrv/compare/v0.0.38...v0.0.39) (2021-03-31)\n\n### [0.0.38](https://github.com/pateketrueke/yrv/compare/v0.0.37...v0.0.38) (2021-03-10)\n\n\n### Bug Fixes\n\n* make sure types are included on the package; closes [#72](https://github.com/pateketrueke/yrv/issues/72) ([72c07f2](https://github.com/pateketrueke/yrv/commit/72c07f2fa57aefef23af093fab58430e318231a9))\n\n### [0.0.37](https://github.com/pateketrueke/yrv/compare/v0.0.35...v0.0.37) (2021-03-10)\n\n\n### Features\n\n* adds in auto release and auto-publishing ([f587f9b](https://github.com/pateketrueke/yrv/commit/f587f9b35c48586b05bcc08f645021ed801c073b))\n* Adds in Standard Version ([af0a5e4](https://github.com/pateketrueke/yrv/commit/af0a5e4d6b9f25480a5b3b88ed3151c00516792c)), closes [#28](https://github.com/pateketrueke/yrv/issues/28)\n* Adds in TypeScript definitions for the repository ([4273f09](https://github.com/pateketrueke/yrv/commit/4273f09a778ff38b7c11eb0ef108209ac5f12749))\n\n\n### Bug Fixes\n\n* Adds changes to move to ubuntu runner instead of self-hosted ([83f605c](https://github.com/pateketrueke/yrv/commit/83f605ce8f0eedc58de761af1b9ee8901a0dda8c))\n* patch top-level pending component on routers, thanks to [@jhechtf](https://github.com/jhechtf) - closes [#34](https://github.com/pateketrueke/yrv/issues/34) ([83f74bc](https://github.com/pateketrueke/yrv/commit/83f74bcae474ba122c5dacc8c4aeb0625b2645ea))\n\n### [0.0.36](https://github.com/pateketrueke/yrv/compare/v0.0.35...v0.0.36) (2021-03-09)\n\n\n### Features\n\n* adds in auto release and auto-publishing ([f587f9b](https://github.com/pateketrueke/yrv/commit/f587f9b35c48586b05bcc08f645021ed801c073b))\n* Adds in Standard Version ([af0a5e4](https://github.com/pateketrueke/yrv/commit/af0a5e4d6b9f25480a5b3b88ed3151c00516792c)), closes [#28](https://github.com/pateketrueke/yrv/issues/28)\n* Adds in TypeScript definitions for the repository ([4273f09](https://github.com/pateketrueke/yrv/commit/4273f09a778ff38b7c11eb0ef108209ac5f12749))\n\n\n### Bug Fixes\n\n* Adds changes to move to ubuntu runner instead of self-hosted ([83f605c](https://github.com/pateketrueke/yrv/commit/83f605ce8f0eedc58de761af1b9ee8901a0dda8c))\n* patch top-level pending component on routers, thanks to [@jhechtf](https://github.com/jhechtf) - closes [#34](https://github.com/pateketrueke/yrv/issues/34) ([83f74bc](https://github.com/pateketrueke/yrv/commit/83f74bcae474ba122c5dacc8c4aeb0625b2645ea))\n\n### [0.0.35](https://github.com/pateketrueke/yrv/compare/v0.0.34...v0.0.35) (2020-11-13)\n\n### [0.0.34](https://github.com/pateketrueke/yrv/compare/v0.0.33...v0.0.34) (2020-11-13)\n\n\n### Bug Fixes\n\n* skip :headless ([1e4d0eb](https://github.com/pateketrueke/yrv/commit/1e4d0eb426945635c48c150a8b26dbf970dc2841))\n* wait 1sec before check ([a6479cf](https://github.com/pateketrueke/yrv/commit/a6479cfd12d49350e14189d21e58d70bd60e5132))\n\n### [0.0.33](https://github.com/pateketrueke/yrv/compare/v0.0.32...v0.0.33) (2020-09-24)\n\n\n### Bug Fixes\n\n* clean ./build before test ([60fc680](https://github.com/pateketrueke/yrv/commit/60fc6800e9bd952d14fa6cb98cc8267c106aeb3f))\n* dev, test and build ready; lock deps ([1dfe683](https://github.com/pateketrueke/yrv/commit/1dfe683e5e03b8cd0f7b6ed91d86585aee384200))\n* disable DEBUG on dist, include src/ files ([eea9b5a](https://github.com/pateketrueke/yrv/commit/eea9b5a15704e660a3d2b070f6f73b4363d783b7))\n* enable DEBUG for whole testing ([64a21cf](https://github.com/pateketrueke/yrv/commit/64a21cfd48065bdeb582f38f76af10f52ff9d46d))\n* import from ./src during development ([6616e98](https://github.com/pateketrueke/yrv/commit/6616e986483731ba443fb675482583a1b369e918))\n* print fallback branch when missing DEBUG ([d34b6ab](https://github.com/pateketrueke/yrv/commit/d34b6abb8d291bc0e749abaf310c844cbf02071f))\n* remove cache too ([a438b4e](https://github.com/pateketrueke/yrv/commit/a438b4e2080e0849298d38c1b6b36a2e7088dc1e))\n* right setup for DEBUG mode ([7f247fd](https://github.com/pateketrueke/yrv/commit/7f247fd259702149982f20674f3265c7e1ac352d))\n* split sub tasks ([7fca020](https://github.com/pateketrueke/yrv/commit/7fca020283f955b8826923323029199bd98ba8b3))\n\n### [0.0.32](https://github.com/pateketrueke/yrv/compare/v0.0.31...v0.0.32) (2020-09-23)\n\n\n### Bug Fixes\n\n* package built files, not sources ([610f016](https://github.com/pateketrueke/yrv/commit/610f0169d7c1dc38c11ca68efaa15a976c5596f1))\n\n### [0.0.31](https://github.com/pateketrueke/yrv/compare/v0.0.30...v0.0.31) (2020-09-23)\n\n### [0.0.30](https://github.com/pateketrueke/yrv/compare/v0.0.29...v0.0.30) (2020-04-11)\n\n### [0.0.29](https://github.com/pateketrueke/yrv/compare/v0.0.28...v0.0.29) (2020-04-10)\n\n### [0.0.28](https://github.com/pateketrueke/yrv/compare/v0.0.27...v0.0.28) (2020-04-10)\n\n### [0.0.27](https://github.com/pateketrueke/yrv/compare/v0.0.26...v0.0.27) (2020-03-25)\n\n### [0.0.26](https://github.com/pateketrueke/yrv/compare/v0.0.25...v0.0.26) (2020-03-15)\n\n### [0.0.25](https://github.com/pateketrueke/yrv/compare/v0.0.24...v0.0.25) (2020-03-06)\n\n### [0.0.24](https://github.com/pateketrueke/yrv/compare/v0.0.23...v0.0.24) (2020-02-29)\n\n### [0.0.23](https://github.com/pateketrueke/yrv/compare/v0.0.22...v0.0.23) (2020-02-29)\n\n### [0.0.22](https://github.com/pateketrueke/yrv/compare/v0.0.21...v0.0.22) (2020-02-29)\n\n### [0.0.21](https://github.com/pateketrueke/yrv/compare/v0.0.20...v0.0.21) (2020-02-29)\n\n### [0.0.20](https://github.com/pateketrueke/yrv/compare/v0.0.19...v0.0.20) (2020-02-29)\n\n### [0.0.19](https://github.com/pateketrueke/yrv/compare/v0.0.18...v0.0.19) (2020-02-20)\n\n### [0.0.18](https://github.com/pateketrueke/yrv/compare/v0.0.17...v0.0.18) (2020-01-25)\n\n### [0.0.17](https://github.com/pateketrueke/yrv/compare/v0.0.16...v0.0.17) (2020-01-20)\n\n### [0.0.16](https://github.com/pateketrueke/yrv/compare/v0.0.15...v0.0.16) (2019-12-14)\n\n### [0.0.15](https://github.com/pateketrueke/yrv/compare/v0.0.14...v0.0.15) (2019-12-07)\n\n### [0.0.14](https://github.com/pateketrueke/yrv/compare/v0.0.13...v0.0.14) (2019-11-19)\n\n### [0.0.13](https://github.com/pateketrueke/yrv/compare/v0.0.12...v0.0.13) (2019-11-16)\n\n### [0.0.12](https://github.com/pateketrueke/yrv/compare/v0.0.10...v0.0.12) (2019-11-08)\n\n### [0.0.10](https://github.com/pateketrueke/yrv/compare/v0.0.9...v0.0.10) (2019-11-04)\n\n### [0.0.9](https://github.com/pateketrueke/yrv/compare/v0.0.8...v0.0.9) (2019-11-01)\n\n### [0.0.8](https://github.com/pateketrueke/yrv/compare/v0.0.7...v0.0.8) (2019-10-28)\n\n### [0.0.7](https://github.com/pateketrueke/yrv/compare/v0.0.6...v0.0.7) (2019-10-26)\n\n### [0.0.6](https://github.com/pateketrueke/yrv/compare/v0.0.5...v0.0.6) (2019-10-18)\n\n### [0.0.5](https://github.com/pateketrueke/yrv/compare/v0.0.4...v0.0.5) (2019-10-18)\n\n### [0.0.4](https://github.com/pateketrueke/yrv/compare/v0.0.3...v0.0.4) (2019-10-18)\n\n### [0.0.3](https://github.com/pateketrueke/yrv/compare/v0.0.2...v0.0.3) (2019-10-17)\n\n### [0.0.2](https://github.com/pateketrueke/yrv/compare/v0.0.1...v0.0.2) (2019-10-17)\n"
  },
  {
    "path": "Makefile",
    "content": "ifneq ($(DEBUG),)\n\tE2E_FLAGS=--debug-on-fail\nendif\n\nhelp: Makefile\n\t@awk -F':.*?##' '/^[a-z0-9\\\\%!:-]+:.*##/{gsub(\"%\",\"*\",$$1);gsub(\"\\\\\\\\\",\":*\",$$1);printf \"\\033[36m%8s\\033[0m %s\\n\",$$1,$$2}' $<\n\nci: src deps clean ## Run CI scripts\n\t@npm test -- --color $(E2E_FLAGS)\n\t@HASHCHANGE=true npm test -- --color $(E2E_FLAGS)\n\ndev: src deps ## Start dev tasks\n\t@npm run dev\n\ne2e: src deps ## Run E2E tests locally\n\t@npm run test:e2e -- e2e/cases $(E2E_FLAGS)\n\ntest: src deps clean\n\t@npm test\n\ndeps: package*.json\n\t@(((ls node_modules | grep .) > /dev/null 2>&1) || npm i) || true\n\nclean:\n\t@rm -f cache.json\n\t@rm -rf build/*\n\nrelease: clean\n\t@NODE_ENV=production npm run build\nifneq ($(CI),)\n\t@echo '//registry.npmjs.org/:_authToken=$${NODE_AUTH_TOKEN}' > .npmrc\nendif\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n\n![yrv](Japan_road_sign_201-D.svg)\n\n![Build status](https://github.com/pateketrueke/yrv/workflows/build/badge.svg)\n[![NPM version](https://img.shields.io/npm/v/yrv)](https://www.npmjs.com/package/yrv)\n[![Known Vulnerabilities](https://snyk.io/test/npm/yrv/badge.svg)](https://snyk.io/test/npm/yrv)\n[![donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8MXLRJ7QQXGYY)\n\n</div>\n\n> The `v` is for Svelte\n\nBuilt on top of [abstract-nested-router](https://www.npmjs.com/package/abstract-nested-router), so you can use nested routers, also:\n\n- Advanced parameters can be used, e.g. `/:id<\\d+>` &mdash; [see docs](https://www.npmjs.com/package/abstract-nested-router#params)\n- ARIA-compliant, sets `[aria-current=\"page\"]` on active links\n- Seamless `<base href=\"...\" />` integration\n- Conditionals and redirection through props\n- Fallback `<Route />` handlers\n- Hash and URI-based routes\n- Support for [query-string](https://www.npmjs.com/package/query-string)\n- [REPL ready!](https://svelte.dev/repl/0f07c6134b16432591a9a3a0095a80de?version=3.12.1)\n\n> `yrv` will use any _base-href_ found on the current page to rewrite links and routes.\n\n## Usage\n\nInstall `yrv` through NPM or Yarn:\n\n```html\n<script>\n  import { Router, Route, Link } from 'yrv';\n</script>\n\n<Link href=\"/\">Home</Link>\n| <Link href=\"/World\">Hello</Link>\n| <Link href=\"/not/found\">NotFound</Link>\n\n<p>\n  <Router>\n    <Route exact>Hello World</Route>\n    <Route fallback>Not found</Route>\n    <Route exact path=\"/:name\" let:router>Hey {router.params.name}!</Route>\n  </Router>\n</p>\n```\n\n> Notice `fallback` routes can’t be placed at the beginning, otherwise further routes will not be mounted. :bomb:\n\n## Components\n\n> You MUST declare at least, one top-level `Router` to setup the bindings.\n\n### `<Router {path} {pending} {disabled} {condition} {nofallback} />`\n\nThis component will hold any given routes as children, `path` is always derived from parent routes.\n\nAvailable props:\n\n- `{path}` &mdash; Any segment to derive a fullpath from, defaults to `/`\n- `{pending}` &mdash; Svelte-component or String; top-level `pending` support\n- `{disabled}` &mdash; Boolean; Similar to condition, but for bound props\n- `{condition}` &mdash; Function; if given, render only if evaluates to true\n- `{nofallback}` &mdash; If set, non-matched routes will never raise a failure\n\n> Nested routers does not need the same path to be declared inside, e.g. if the router for `/top` has a `/sub` router inside, inner router will use the route `/top/sub`, (the same as declaring `/top/sub` route outside the parent router).\n\n### `<Route {key} {path} {exact} {pending} {fallback} {component} {disabled} {condition} {redirect} let:router />`\n\nMain container for routing, they can hold any component or children.\n\nAvailable props:\n\n- `{key}` &mdash; The route identity, not its path; defaults to random pseudo-hash\n- `{path}` &mdash; Any segment to derive a fullpath from, default to `/`\n- `{exact}` &mdash; If set, the route will render only if the route exactly matches\n- `{pending}` &mdash; Svelte-component or String; rendered during the loading of dynamic components\n- `{fallback}` &mdash; If set, the route will render only if no more routes were matched\n- `{component}` &mdash; Accepts either a valid svelte-component, a promise, or a dynamic import function\n- `{disabled}` &mdash; Boolean; Similar to `condition`, but for bound props\n- `{condition}` &mdash; Function; if given, the route will render only if evaluates to `true`\n- `{redirect}` &mdash; Alternate redirection location, only if the previous condition was `true`\n- `let:router` &mdash; Injects the `router` context, it also provides `failure` in case of errors\n\n> If you omit `exact`, then `/x` would match both `/` and `/x` routes &mdash; [see docs](https://www.npmjs.com/package/abstract-nested-router#params)\n\nWhen `yrv` adds a new route, it'll use any given `key` from its props &mdash; once routes are detached they're also removed from the router registry, due to that, the next time the same route is mounted a new key is generated (if isn't present already).\n\n```html\n<script>\n  import SvelteComponent from 'path/to/svelte-component.svelte';\n</script>\n\n<Link href=\"/\">Home</Link>\n| <Link href=\"/svelte-component\">Svelte component</Link>\n| <Link href=\"/promise\">Promised component</Link>\n| <Link href=\"/lazy\">Lazy component</Link>\n\n<p>\n  <Router>\n    <Route exact>Hello World</Route>\n    <Route exact path=\"/svelte-component\" component={SvelteComponent}/>\n    <Route exact path=\"/promise\" component=\"{import('path/to/other-component.svelte')}\"/>\n    <Route exact path=\"/lazy\" component=\"{() => import('path/to/another-component.svelte')}\"/>\n  </Router>\n</p>\n```\n\n> Behind the scenes, for making dynamic-imports work, the bundler _should_ inline them or just write-out the required chunks to make it work natively (`<script type=\"module\" />`) or through `shimport`, etc.\n\n### `<Link {go} {href} {open} {title} {exact} {reload} {replace} {class} />`\n\nIn order to navigate, you can use `Link` components, or regular links, etc.\n\n> All `href` values MUST be absolute, only links starting with `/` or `#` are allowed.\n\nAvailable props:\n\n- `{go}` &mdash; History shortcut (see below)\n- `{href}` &mdash; New location, default to `/`\n- `{open}` &mdash; Same behavior as `<a target=\"_blank\">`\n- `{title}` &mdash; HTML title-attribute value\n- `{button}` &mdash; If set, will use button-tag instead\n- `{exact}` &mdash; Determine if link should match exactly to be set as active\n- `{reload}` &mdash; Use `location.href` instead\n- `{replace}` &mdash; Use `history.replaceState()` instead\n- `{class}` &mdash; Custom class-name for the mounted anchor\n\n> The value for `open` can be a string including the window specs, e.g. `width=400,height=200` &mdash; a `on:close` event will be fired once the opened window is closed.\n\nNormal `on:click` events are still allowed, so you can use:\n\n```html\n<Link on:click={() => location.reload()}>Reload</Link>\n```\n\n> Active _links_ will gain the `[aria-current]` attribute, and `[disabled]` if they're buttons.\n\nAditionally, you can setup  `go` to move around:\n\n- `\"back\"` &mdash; String; if given, will invoke `history.back()`\n- `\"fwd\"` &mdash; String; if given, will invoke `history.fwd()`\n- `n` &mdash; Number; if given, it'll be used to invoke `history.go(n)`\n\n> If navigating through `history` is not possible a normal redirection will run. :anchor:\n\n## Public API\n\n- `navigateTo(path[, options])` &mdash; Change the location, supported options are:\n  - `reload` &mdash; If true, it will use `document.location.href` instead\n  - `replace` &mdash; If true, it will use `history.replaceState()` instead\n  - `params` &mdash; Used to replace `:placeholders` from given path\n  - `queryParams` &mdash; Additional search-params for the new location\n- `$router` &mdash; Store with shared routeInfo details, similar to `let:router`\n\n> `yrv` gracefully degrades to `location.hash` on environments where `history` is not suitable, also it can be forced through `router.hashchange = true`.\n\n### Route Info\n\nRoute changes are propagated through stores, if you want to listen too just subscribe, e.g.\n\n```js\nimport { router } from 'yrv';\n\nrouter.subscribe(e => {\n  if (!e.initial) console.log(e);\n});\n```\n\nUsing this technique you gain access to the same detail object as `let:router` does.\n\n> Notice the `initial` property is present as soon the store is initialized, consecutive changes will not have it anymore.\n\n### IE11 support\n\nSupport for IE11 is _granted_ if you include, at least, the following polyfills before your application:\n\n```html\n<script>if (!!window.MSInputMethodContext && !!document.documentMode)\n  document.write('<script src=\"https://polyfill.io/v3/polyfill.min.js?features=default,Promise,Object.getOwnPropertyDescriptors\"><\\/script>');</script>\n<script src=\"your-app.js\"></script>\n```\n\n> `document.write()` is used because conditional comments were dropped in IE10, so this way you can conditionally load polyfills anyway.\n\nAlso, you MUST [enable either `buble` or `babel`](https://github.com/sveltejs/svelte/issues/2621) within your build pipeline to transpile down to ES5.\n\n### Frequently Asked Questions\n\n**How to conditionally render a `<Router />` component?**\n\nBoth Route/Router components support the `disabled` and `condition` props, but:\n\n- Use `condition` to allow/disallow route-dispatching dynamically\n- Use `disabled` to skip from rendering, it will add/remove the route\n\nThis new `disabled` prop would work as you're expecting:\n\n```html\n<Router disabled={!showNavBar}>\n  ...\n</Router>\n```\n\n**What means the `exact` property and how it works?**\n\nSay you have three routes:\n\n- `/a` (exact)\n- `/a/b` (non-exact)\n- `/a/b/c` (exact)\n\nNow, you navigate from `/a` to `/a/b/c`:\n\n- Since `/a` was active, and it was exact, `yrv` clears out the `routeInfo` for that route.\n- Since `/a/b` is not exact, `yrv` activate this route because is half-way to the final route.\n\n> If you plan to have more routes nested, then the route will never be `exact` (at least at top-levels).\n\nThis is also true for `<Link />` components &mdash; as soon as they match the `[aria-current]` attribute will be added on them to denote _active_ links.\n\nIf the link for `/a` were also `exact`, then it'll be _active_ if the matching route is `/a` only.\n\n**Why `path` can't be an empty string like other routers does?**\n\nEven if browsers treat `http://localhost:8080` and `http://localhost:8080/` as the same thing I wanted to keep paths clear as possible.\n\nInternally `yrv` normalizes any given URI to keep a trailing slash, so `/foo` is `/foo/` for matching purposes.\n\nAlso, the default path is usually `/` so there's no point on having to declare anything else:\n\n```html\n<Route>OK</Route>\n<Route path=\"/\">OK</Route>\n```\n\n**What is `routeInfo` and how can I access it outside routes?**\n\nThis object is very similar to what you get with `let:router` inside components.\n\nUse the `$router` store to access it, e.g.\n\n```html\n<script>\n  import { router } from 'yrv';\n</script>\n<pre>{JSON.stringify($router, null, 2)}</pre>\n```\n\n**Why does Yrv not work with Parcel or webpack/snowpack?**\n\nIf you're getting any of the errors below:\n\n- store.subscribe is not a function\n- Class constructor SvelteComponent cannot be invoked without 'new'\n- 'on_outro' is not exported by [...]\n- 'target' is a required option\n\nMake sure you're using the right settings:\n\n1. Add mainFields into resolve config, e.g. `mainFields: ['svelte', 'browser', 'module', 'main']`\n2. Remove `exclude: /node_modules/` from `svelte-loader` config\n\n> If you're using an online tool that is not the official Svelte REPL the behavior is unexpected and no further support will be granted.\n\n**Can I use hash-based routes _à la_ Gmail? e.g. `index.html#/profile`, `index.html#/book/42`?**\n\nYes, URIs like that are suitable for embedded apps like Electron, where normal URLs would fail.\n\nAlso this mode is the default used on the Svelte REPL, because is not an iframe, nor a regular webpage... it's a weird thing!\n\n> If you enable `router.hashchange = true` all your regular links will be automatically rewritten to hash-based URIs instead, see how it works in our test suite.\n\n**Why I'm getting `<Component> was created with unknown prop 'router'` in the browser's console?**\n\nIf you're not using the `router` prop inside your route-components then just add:\n\n```html\n<script>\n  export const router = null;\n</script>\n```\n\nThat will remove the warning and also will make `eslint-plugin-svelte3` in your workflow happy.\n\n**Why `router.subscribe` is called two times when I first open the page?**\n\nAny subscription to stores will fire twice as they have an initial value, once the router resolves (e.g. the initial route) then a second event is fired.\n\n> In this case, and additional property `initial` is added to identify such event.\n\n**Is there any method that allows me to detect route change?**\n\nYes, you can subscribe to the router store, e.g. `router.subscribe(...)` &mdash; [see above](#route-info).\n\n**Is there a way to reduce the bundle size of yrv?**\n\nSince `v0.0.46` you'll be getting the most reduced version we can ship, however it comes without development warnings.\n\n> Consume it as `import { ... } from 'yrv/debug'` right away and you'll get a more complete version with included DEBUG information.\n"
  },
  {
    "path": "components.js",
    "content": "export { default as Router } from './src/lib/Router.svelte';\nexport { default as Route } from './src/lib/Route.svelte';\nexport { default as Link } from './src/lib/Link.svelte';\n\nexport { navigateTo, router } from './src/lib/utils';\n"
  },
  {
    "path": "debug.js",
    "content": "export * from './build/dev/index.js';\n"
  },
  {
    "path": "e2e/app/import.esm.js",
    "content": "import App from '../components/Import.svelte';\n\nnew App({ target: document.body }); // eslint-disable-line\n"
  },
  {
    "path": "e2e/app/routers.js",
    "content": "import App from '../components/nested-routers/App.svelte';\n\nnew App({ target: document.body }); // eslint-disable-line\n"
  },
  {
    "path": "e2e/app/testing.js",
    "content": "import App from '../components/Main.svelte';\n\n/* global USE_HASH_CHANGE */\nlet hashchange;\nif (typeof USE_HASH_CHANGE !== 'undefined' && USE_HASH_CHANGE) {\n  hashchange = USE_HASH_CHANGE;\n}\n\nnew App({ target: document.body, props: { hashchange } }); // eslint-disable-line\n"
  },
  {
    "path": "e2e/cases/main.test.js",
    "content": "import { Selector } from 'testcafe';\nimport { url, href } from '../helpers';\n\n/* global fixture, test */\n\nfixture('yrv (dsl)')\n  .page(url('/'));\n\ntest('it just loads!', async t => {\n  await t.expect(Selector('h1').withText('Example page').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n  await t.expect(Selector('a').withText('Home').getAttribute('href')).eql(href('/'));\n  await t.expect(Selector('a').withText('Home').hasAttribute('aria-current')).ok();\n});\n\ntest('it would mount Route-less content', async t => {\n  await t.expect(Selector('p[data-test=routeless]').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest('it should mount from slot-content nodes', async t => {\n  await t.click(Selector('a').withText('Test page'));\n  await t.expect(Selector('h2').withText('Testing features').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n});\n\ntest('it should allow to bind <Link {href} /> and such', async t => {\n  await t.typeText(Selector('[data-test=custominput]'), 'success');\n  await t.expect(Selector('[data-test=customhref]').getAttribute('href')).contains('/success');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\nfixture('yrv (example)')\n  .page(url('/example'));\n\ntest('it should mount \"Hello World\"', async t => {\n  await t.expect(Selector('[data-test=example]').withText('Hello World').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest('it should mount nested content', async t => {\n  await t.click(Selector('a').withText('Link'));\n  await t.expect(Selector('[data-test=example]').withText('Hello a').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n  await t.expect(Selector('[data-test=unordered]').innerText).notContains('III');\n\n  await t.click(Selector('a').withText('List'));\n  await t.expect(Selector('[data-test=unordered]').innerText).eql('III');\n\n  await t.click(Selector('a').withText('Show'));\n  await t.expect(Selector('[data-test=unordered]').innerText).eql('II III');\n\n  await t.click(Selector('a').withText('Edit'));\n  await t.expect(Selector('[data-test=unordered]').innerText).eql('I II III');\n});\n\ntest('it should fallback on unmatched routes', async t => {\n  await t.click(Selector('a').withText('Broken link'));\n  await t.expect(Selector('[data-test=example]').withText('Not found').visible).ok();\n  await t.expect(Selector('[data-test=example]').innerText).notContains('Hello a');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n});\n\nfixture('yrv (fallback)')\n  .page(url('/e'));\n\ntest('should not mount any fallback et all', async t => {\n  await t.expect(Selector('h2[data-test=fallback]').exists).notOk();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest.page(url('/e/im_not_exists'))('should handle non-matched routes as fallback', async t => {\n  await t.expect(Selector('h2').withText('NOT FOUND').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\nfixture('yrv (buttons)')\n  .page(url('/test'));\n\ntest('it should disable Link buttons if they are active', async t => {\n  const UndoButton = Selector('button').withText('Undo');\n  const Parameters = Selector('[data-test=parameters]');\n\n  await t.expect(UndoButton.visible).ok();\n  await t.expect(UndoButton.hasAttribute('disabled')).ok();\n  await t.click(Selector('a').withText('Test props'));\n\n  await t.expect(Parameters.visible).ok();\n  await t.expect(UndoButton.hasAttribute('disabled')).notOk();\n\n  await t.click(UndoButton);\n  await t.expect(Parameters.exists).notOk();\n  await t.expect(UndoButton.hasAttribute('disabled')).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(3);\n});\n\nfixture('yrv (query params)')\n  .page(url('/test/props'));\n\ntest('it should parse from location.search', async t => {\n  await t.expect(Selector('li').withText('query: {}').exists).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n\n  await t.expect(Selector('a').withText('Test page').getAttribute('href')).eql(href('/test'));\n  await t.expect(Selector('a').withText('Test page').hasAttribute('aria-current')).ok();\n\n  await t.expect(Selector('a').withText('Test props').getAttribute('href')).eql(href('/test/props'));\n  await t.expect(Selector('a').withText('Test props').hasAttribute('aria-current')).ok();\n});\n\ntest('it should take queryParams from navigateTo()', async t => {\n  await t.click(Selector('a').withText('Do not click!'));\n  await t.expect(Selector('li').withText('query: {\"truth\":\"42\"}').exists).ok();\n\n  await t.typeText(Selector('[data-test=key]'), 'x');\n  await t.typeText(Selector('[data-test=value]'), 'y');\n  await t.click(Selector('[data-test=append]'));\n\n  await t.expect(Selector('li').withText('query: {\"truth\":\"42\",\"x\":\"y\"}').exists).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(3);\n});\n\nfixture('yrv (middleware)')\n  .page(url('/test/props'));\n\ntest('it should redirect if the given route matches', async t => {\n  await t.click(Selector('a').withText('Redirect'));\n  await t.expect(Selector('button').withText('Undo').hasAttribute('disabled')).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(3);\n});\n\ntest('it should mount or redirect based on given condition', async t => {\n  await t.setNativeDialogHandler(() => false);\n  await t.click(Selector('a').withText('Protected'));\n  await t.expect(Selector('[data-test=redirect]').innerText).contains('Wrong!');\n\n  await t.setNativeDialogHandler(() => true);\n  await t.click(Selector('a').withText('Protected'));\n  await t.expect(Selector('[data-test=redirect]').innerText).contains('Yay!');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(4);\n});\n\nfixture('yrv (nested params)')\n  .page(url('/test/props'));\n\ntest('it should inject params from resolved routes', async t => {\n  await t.click(Selector('a').withText('Hello World.'));\n  await t.expect(Selector('p').withText('Value: Hello World').visible).ok();\n  await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n});\n\nif (!process.env.HASHCHANGE) {\n  fixture('yrv (anchored routes)')\n    .page(url('/sub'));\n\n  test('it should inject params from resolved routes', async t => {\n    await t.click(Selector('a').withText('Root'));\n    await t.expect(Selector('p[data-test=anchored]').innerText).contains('HOME');\n    await t.expect(Selector('p[data-test=anchored]').innerText).notContains('ABOUT');\n    await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n  });\n\n  test('it should skip non-exact routes from matched ones', async t => {\n    await t.click(Selector('a').withText('About page'));\n    await t.expect(Selector('p[data-test=anchored]').innerText).contains('ABOUT');\n    await t.expect(Selector('p[data-test=anchored]').innerText).notContains('HOME');\n    await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n  });\n\n  test('it should handle non-matched routes as fallback', async t => {\n    await t.click(Selector('a').withText('Broken anchor'));\n    await t.expect(Selector('h2[data-test=fallback]').exists).notOk();\n    await t.expect(Selector('fieldset').innerText).contains(\"Unreachable '/sub#broken'\");\n    await t.expect(Selector('[data-test=counter]').innerText).contains(2);\n  });\n}\n\nfixture('yrv (nested routes)')\n  .page(url('/top'));\n\ntest('it should nothing at top-level', async t => {\n  await t.expect(Selector('p[data-test=nested]').innerText).contains('?');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('a');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('b');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('c');\n\n  await t.click(Selector('a').withText('1'));\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('?');\n  await t.expect(Selector('p[data-test=nested]').innerText).contains('a');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('b');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('c');\n\n  await t.click(Selector('a').withText('2'));\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('?');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('a');\n  await t.expect(Selector('p[data-test=nested]').innerText).contains('b');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('c');\n\n  await t.click(Selector('a').withText('3'));\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('?');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('a');\n  await t.expect(Selector('p[data-test=nested]').innerText).notContains('b');\n  await t.expect(Selector('p[data-test=nested]').innerText).contains('c');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(4);\n});\n\nfixture('yrv (hashed routes)')\n  .page(url('/gist'));\n\ntest('it should load root-handlers', async t => {\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('GIST INFO');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('SHA1: N/A');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(edit)');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(save)');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest.page(url('/gist#test'))('it should load sub-handlers', async t => {\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('GIST INFO');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('SHA1: test');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(edit)');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(save)');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest.page(url('/gist#test/edit'))('it should load nested sub-handlers (/edit)', async t => {\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('GIST INFO');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('SHA1: test');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('(edit)');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(save)');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest.page(url('/gist#test/save'))('it should load nested root-handlers (/save)', async t => {\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('GIST INFO');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('SHA1: test');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(edit)');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('(save)');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\ntest.page(url('/gist#test/not_found'))('it should fail on unreachable routes', async t => {\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('GIST INFO');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('SHA1: test');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(edit)');\n  await t.expect(Selector('[data-test=hashed]').innerText).notContains('(save)');\n  await t.expect(Selector('[data-test=hashed]').innerText).contains('Unreachable');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(1);\n});\n\nfixture('yrv (conditional routes)')\n  .page(url('/auth'));\n\ntest('it should redirect from protected pages', async t => {\n  await t.click(Selector('a').withText('Protected page'));\n  await t.expect(Selector('[data-test=logged]').innerText).contains('Log-in');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('Welcome back.');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('O.K.');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(4);\n});\n\ntest('it should skip redirections otherwise', async t => {\n  await t.click(Selector('[data-test=logged]').find('input'));\n  await t.click(Selector('a').withText('→'));\n  await t.expect(Selector('[data-test=logged]').innerText).contains('Welcome back.');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('Log-in');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('O.K.');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(3);\n});\n\ntest('it should allow routes if conditions are met', async t => {\n  await t.expect(Selector('[data-test=secret]').exists).notOk();\n  await t.click(Selector('[data-test=logged]').find('input'));\n  await t.click(Selector('a').withText('Protected page'));\n  await t.expect(Selector('[data-test=secret]').innerText).contains('Top-secret');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('Log-in');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('Welcome back.');\n  await t.expect(Selector('[data-test=logged]').innerText).contains('O.K.');\n\n  await t.click(Selector('[data-test=logged]').find('input'));\n  await t.expect(Selector('[data-test=secret]').exists).notOk();\n  await t.expect(Selector('[data-test=logged]').innerText).contains('Log-in');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('Welcome back.');\n  await t.expect(Selector('[data-test=logged]').innerText).notContains('O.K.');\n  await t.expect(Selector('[data-test=counter]').innerText).contains(4);\n});\n\nfixture('yrv (dynamic imports)')\n  .page(url('/import', true));\n\ntest('it should allow routes to be loaded through dynamic-imports', async t => {\n  await t\n    .expect(Selector('[data-test=container]').innerText).contains('Loading...')\n    .expect(Selector('[data-test=import]').exists)\n    .ok();\n});\n\nif (!process.env.HASHCHANGE) {\n  fixture('yrv (base-href)')\n    .page(url('/folder', true));\n\n  test('it should rebase all links to preserve base-href location', async t => {\n    await t.expect(Selector('a').withText('Home').getAttribute('href')).eql(href('/folder'));\n    await t.expect(Selector('a').withText('Home').hasAttribute('aria-current')).ok();\n  });\n\n  test('it should handle <base href=\"...\" /> on all routes and links', async t => {\n    await t.click(Selector('a').withText('Test page'));\n    await t.expect(Selector('h2').withText('Testing features').visible).ok();\n\n    await t.click(Selector('a').withText('Test props'));\n    await t.click(Selector('a').withText('Do not click!'));\n    await t.expect(Selector('li').withText('query: {\"truth\":\"42\"}').exists).ok();\n\n    await t.click(Selector('a').withText('Anchor page'));\n    await t.click(Selector('a').withText('Root'));\n\n    await t.expect(Selector('p[data-test=anchored]').innerText).contains('HOME');\n    await t.expect(Selector('p[data-test=anchored]').innerText).notContains('ABOUT');\n\n    await t.click(Selector('a').withText('Link'));\n    await t.expect(Selector('p[data-test=example').innerText).contains('Hello a');\n    await t.expect(Selector('[data-test=counter]').innerText).contains(7);\n  });\n}\n\n// this test seems to be working if you don't use chrom*:headless\nif (!process.argv.some(x => x.includes(':headless'))) {\n  fixture('yrv (links a new-tab)')\n    .page(url('/'));\n\n  test('should open links on new tabs', async t => {\n    const initialURL = await t.eval(() => document.documentURI);\n\n    await t.click(Selector('a').withText('Test page'), { modifiers: { meta: true } }).wait(1000);\n\n    const openedURL = await t.eval(() => document.documentURI);\n\n    await t.expect(initialURL).notEql(openedURL);\n\n    try {\n      // this crashes the browser after closing\n      await t.eval(() => window.close());\n    } catch (e) {\n      // ok\n    }\n\n    const prevURL = await t.eval(() => document.documentURI);\n\n    await t.expect(initialURL).eql(prevURL);\n  });\n}\n"
  },
  {
    "path": "e2e/cases/routers.test.js",
    "content": "import { Selector } from 'testcafe';\nimport { url } from '../helpers';\n\n/* global fixture, test */\n\nfixture('yrv (nested routers)')\n  .page(url('/routers', true));\n\ntest('should keep working as expected when isLoggedIn is unchecked', async t => {\n  await t\n    .click(Selector('input[type=checkbox]'))\n    .click(Selector('input[type=checkbox]'));\n\n  await t\n    .expect(Selector('h1').innerText).contains('This is Home')\n    .expect(Selector('a').withText('Home').hasAttribute('aria-current')).ok();\n\n  await t\n    .click(Selector('a').withText('Players'))\n    .expect(Selector('h1').innerText).contains('This is Players');\n\n  await t.expect(Selector('h2').innerText).contains('This is List');\n\n  await t\n    .expect(Selector('a').withText('Players').hasAttribute('aria-current')).ok()\n    .expect(Selector('a').withText('List').hasAttribute('aria-current')).ok();\n\n  await t\n    .click(Selector('a').withText('New Team'))\n    .expect(Selector('h2').innerText).contains('This is New Team');\n\n  await t.expect(Selector('a').withText('New Team').hasAttribute('aria-current')).ok();\n\n  await t\n    .click(Selector('a').withText('Not found'))\n    .expect(Selector('h1').innerText).contains('This is NotFound');\n\n  await t.expect(Selector('a').withText('Not found').hasAttribute('aria-current')).ok();\n});\n\ntest('should fallback to <Login /> when isLoggedIn is unchecked', async t => {\n  await t\n    .click(Selector('input[type=checkbox]'));\n\n  await t\n    .expect(Selector('a').withText('Home').exists).ok()\n    .expect(Selector('h1').innerText).contains('This is Login');\n\n  await t\n    .click(Selector('a').withText('Players'))\n    .expect(Selector('h1').innerText).contains('This is Login');\n\n  await t\n    .click(Selector('a').withText('Not found'))\n    .expect(Selector('h1').innerText).contains('This is Login');\n});\n"
  },
  {
    "path": "e2e/components/Example.svelte",
    "content": "<p data-test=\"import\">Components can be lazy-loaded through <code>`() => import('...')`</code> calls.</p>\n"
  },
  {
    "path": "e2e/components/Import.svelte",
    "content": "<script>\n  import { Router, Route } from 'yrv';\n\n  function delay(promise) {\n    return new Promise(ok => setTimeout(() => ok(promise), 500));\n  }\n</script>\n\n<div data-test=\"container\">\n  <Router pending=\"Loading...\">\n    <Route fallback component={() => delay(import('./Example.svelte'))} />\n  </Router>\n</div>\n"
  },
  {
    "path": "e2e/components/Main.svelte",
    "content": "<script>\n  import {\n    Router, Route, Link, router,\n  } from 'yrv';\n\n  import Testing from './Testing.svelte';\n\n  export let hashchange = null;\n\n  router.hashchange = hashchange;\n\n  let loggedIn;\n  let myLink = '/';\n  let count = 0;\n\n  router.subscribe(info => {\n    if (!info.initial) count += 1;\n  });\n</script>\n\n<h1 id=\"top\">\n  <span>Example page</span>\n  <small>{$router.path}</small>\n</h1>\n\n<p>This content is static, always shown.</p>\n\n<Link exact href=\"/\">Home</Link> | <Link href=\"/test\">Test page</Link>\n| <Link href=\"/sub\">Anchor page</Link> | <Link href=\"/e\">Error page</Link>\n\n<p>\n  Links can open windows, and they can set callbacks too:\n  <Link open href=\"//google.com\" on:close={() => /* eslint-disable no-alert */ alert('GREAT!')}>Open window</Link>\n</p>\n\n<Router path=\"/example\">\n  <Link exact href=\"/example/a\">Link</Link> | <Link exact href=\"/example/a/b\">Broken link</Link>\n\n  <p data-test=\"example\">\n    <Route fallback>Not found?</Route>\n    <Route exact>Hello World</Route>\n    <Route exact path=\"/:name\" let:router>Hello {router.params.name}</Route>\n  </p>\n</Router>\n\n<p>\n  Routes with exactly one segment are considered nested routes, e.g.\n\n  <Link href=\"/top/foo/a\">1</Link>\n  | <Link href=\"/top/bar/b\">2</Link>\n  | <Link href=\"/top/bar/c\">3</Link>\n  | <Link href=\"/top\">?</Link>\n</p>\n\n<p>\n  Link's `href` can be changed as well, e.g.\n  <Link data-test=\"customhref\" href={myLink}>Change me!</Link>\n  <input data-test=\"custominput\" type=\"text\" bind:value={myLink} />\n</p>\n\n<p data-test=\"nested\">\n  <Router path=\"/top\">\n    <Route exact fallback>?</Route>\n    <Route exact path=\"/foo/a\">a</Route>\n    <Route exact path=\"/bar/b\">b</Route>\n    <Route exact path=\"/bar/c\">c</Route>\n  </Router>\n</p>\n\n<Router path=\"/test\" nofallback>\n  <Route>\n    <h2>Testing features</h2>\n\n    <p>This content is always mounted when the current URL starts-with <tt>/test</tt>.</p>\n\n    <Link exact button go=\"-1\" href=\"/test\">Undo</Link> | <Link href=\"/test/props\">Test props</Link>\n\n    | <Link href=\"/test/static\">Redirect</Link>\n    | <Link href=\"/test/dynamic\">Protected</Link>\n\n    <p data-test=\"redirect\">\n      <Route path=\"/failed\">Wrong!</Route>\n      <Route path=\"/static\" redirect=\"/test\" />\n      <Route path=\"/dynamic\" redirect=\"/test/failed\" condition={() => /* eslint-disable no-alert */ window.confirm('Are you sure?')}>Yay!</Route>\n    </p>\n  </Route>\n\n  <Route path=\"/props\" component={Testing} />\n\n  <p data-test=\"routeless\">Any <tt>Route</tt>-less content is always shown!</p>\n</Router>\n\n<div data-test=\"hashed\">\n  <Router path=\"/gist\">\n    <Route exact>GIST INFO</Route>\n    <Router path=\"#:sha1\" nofallback>\n      <Route let:router>SHA1: {router.params.sha1 || 'N/A'}</Route>\n      <Route exact path=\"/edit\">(edit)</Route>\n      <Route exact path=\"/save\">(save)</Route>\n    </Router>\n  </Router>\n</div>\n\n<Link exact href=\"/gist\">gists</Link>\n| <Link href=\"/gist#x\" exact>gshow</Link>\n| <Link href=\"/gist#x/edit\">gedit</Link>\n| <Link href=\"/gist#x/save\">gsave</Link>\n\n<hr />\n\n<div data-test=\"logged\">\n  <label>\n    <input type=\"checkbox\" bind:checked={loggedIn} /> on/off\n  </label>\n\n  <Link exact href=\"/auth\">&rarr;</Link>\n  | <Link href=\"/auth/login\">Login</Link>\n  | <Link href=\"/auth/not_found\">Not found</Link>\n  | <Link href=\"/auth/protected\">Protected page</Link>\n\n  <Router path=\"/auth\">\n    <Route path=\"/protected\" condition={() => loggedIn} redirect=\"/auth/login\">O.K.</Route>\n    <Route path=\"/login\">Log-in</Route>\n\n    <Route condition={() => loggedIn} exact redirect=\"/auth/login\" />\n    <Route disabled={!loggedIn} exact>Welcome back.</Route>\n  </Router>\n</div>\n\n<Router disabled={!loggedIn}>\n  <p data-test=\"secret\">\n    <Route>Shhhh! Top-secret</Route>\n  </p>\n</Router>\n\n<Router path=\"/sub\">\n  <Route>\n    <Link exact href=\"/sub#\">Root</Link> | <Link href=\"/sub#/about\">About page</Link> | <Link href=\"/sub#broken\">Broken anchor</Link>\n  </Route>\n\n  <p data-test=\"anchored\">\n    <Route exact path=\"#\">HOME</Route>\n    <Route exact path=\"#/about\">ABOUT</Route>\n  </p>\n</Router>\n\n<Router path=\"/e\">\n  <Route exact>\n    <h2>It works!</h2>\n  </Route>\n\n  <Route fallback>\n    <h2 data-test=\"fallback\">NOT FOUND</h2>\n  </Route>\n</Router>\n\n<div>\n  <p>You can also hook into the router's state with <code>`router.subscribe(...)`, e.g.</code></p>\n  <p data-test=\"counter\">Times router-info has been changed: {count}</p>\n</div>\n\n<p data-test=\"unordered\">\n  <Router path=\"/page\">\n    <Route path=\"/:x/:y\">I</Route>\n    <Route path=\"/:x\">II</Route>\n    <Route path=\"/\">III</Route>\n  </Router>\n</p>\n\n<Link href=\"/page\">List</Link>\n<Link href=\"/page/1\">Show</Link>\n<Link href=\"/page/1/edit\">Edit</Link>\n\n<a style=\"margin-top:1000px;display:block\" href=\"#top\">&uarr;</a>\n"
  },
  {
    "path": "e2e/components/Testing.svelte",
    "content": "<script>\n  import {\n    Router, Route, Link, navigateTo,\n  } from 'yrv';\n\n  export let router = null;\n\n  let newKey = '';\n  let newValue = '';\n\n  function overrideQueryParams(key, value) {\n    if (key) {\n      navigateTo(router.path, { replace: true, queryParams: { ...router.query, [key]: value } });\n    }\n  }\n\n  function addNewValue() {\n    overrideQueryParams(newKey, newValue);\n\n    newKey = '';\n    newValue = '';\n  }\n\n  function rmValue(key) {\n    overrideQueryParams(key);\n  }\n</script>\n\n<h3>Injected parameters</h3>\n\n<fieldset data-test=\"parameters\">\n  <legend>router</legend>\n  <ul>\n    <li>key: {JSON.stringify(router.key)}</li>\n    <li>matches: {JSON.stringify(router.matches)}</li>\n    <li>params: {JSON.stringify(router.params)}</li>\n    <li>route: {JSON.stringify(router.route)}</li>\n    <li>query: {JSON.stringify(router.query)}</li>\n    <li>path: {JSON.stringify(router.path)}</li>\n  </ul>\n\n  <table>\n    <caption>QueryParams</caption>\n    <tr>\n      <th>key</th>\n      <th>value</th>\n    </tr>\n    {#each Object.entries(router.query) as [key, value]}\n      <tr>\n        <td>{key}</td>\n        <td>{value}</td>\n        <td><button on:click={() => rmValue(key)}>rm</button></td>\n      </tr>\n    {/each}\n    <tr>\n      <td><input data-test=\"key\" bind:value={newKey} /></td>\n      <td><input data-test=\"value\" bind:value={newValue} /></td>\n      <td><button data-test=\"append\" on:click={addNewValue}>add</td>\n    </tr>\n  </table>\n\n  <Link on:click={() => overrideQueryParams('truth', 42)}>Do not click!</Link>\n  | <Link href=\"/test/props/Hello%20World.\">Hello World.</Link>\n</fieldset>\n\n<Router>\n  <Route path=\"/:value\" let:router>\n    <p>Value: {router.params.value}</p>\n  </Route>\n</Router>\n"
  },
  {
    "path": "e2e/components/nested-routers/App.svelte",
    "content": "<script>\n  import { Router, Route, Link } from 'yrv';\n\n  import Home from './Home.svelte';\n  import Players from './Players.svelte';\n  import NotFound from './NotFound.svelte';\n  import Login from './Login.svelte';\n\n  let isLoggedIn = true;\n</script>\n\n<Link href=\"/\">Home</Link> |\n<Link href=\"/players\">Players</Link> |\n<Link href=\"/notfound\">Not found</Link> |\n<input type=\"checkbox\" bind:checked={isLoggedIn}> isLoggedIn\n\n<Router>\n  {#if isLoggedIn}\n    <Route key=\"home\" exact component=\"{Home}\" />\n    <Route key=\"play\" path=\"/players\" component=\"{Players}\" />\n    <Route key=\"404\" fallback component={NotFound} />\n  {:else}\n    <Route key=\"ask\" fallback component={Login} />\n  {/if}\n</Router>\n"
  },
  {
    "path": "e2e/components/nested-routers/Home.svelte",
    "content": "<h1>This is Home</h1>\n"
  },
  {
    "path": "e2e/components/nested-routers/List.svelte",
    "content": "<h2>This is List</h2>\n"
  },
  {
    "path": "e2e/components/nested-routers/Login.svelte",
    "content": "<h1>This is Login</h1>\n"
  },
  {
    "path": "e2e/components/nested-routers/NewTeam.svelte",
    "content": "<h2>This is New Team</h2>\n"
  },
  {
    "path": "e2e/components/nested-routers/NotFound.svelte",
    "content": "<h1>This is NotFound</h1>\n"
  },
  {
    "path": "e2e/components/nested-routers/Players.svelte",
    "content": "<script>\n  import { Router, Route, Link } from 'yrv';\n\n  import List from './List.svelte';\n  import NewTeam from './NewTeam.svelte';\n</script>\n\n<h1>This is Players</h1>\n\n<Link exact href=\"/players\">List</Link> |\n<Link href=\"/players/team/new\">New Team</Link>\n\n<Router>\n  <Route exact component=\"{List}\" />\n  <Route path=\"/team/new\" exact component=\"{NewTeam}\" />\n</Router>\n"
  },
  {
    "path": "e2e/helpers.js",
    "content": "const prefix = process.env.BASE_URL || 'http://localhost:8080';\n\nexport function url(x, y) {\n  if (!y && process.env.HASHCHANGE) {\n    return `${prefix}#${x}`;\n  }\n\n  return prefix + x;\n}\n\nexport function href(x) {\n  if (process.env.HASHCHANGE) {\n    return `#${x !== '/' ? x : ''}`;\n  }\n  return x;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"yrv\",\n  \"version\": \"0.0.57\",\n  \"description\": \"Your routing!\",\n  \"types\": \"types/index.d.ts\",\n  \"_main\": \"build/dist/index.js\",\n  \"_module\": \"build/src/index.js\",\n  \"svelte\": \"build/dist/index.js\",\n  \"files\": [\n    \"build/dev/**\",\n    \"build/dist/**\",\n    \"build/src/index.js\",\n    \"types/*.*\",\n    \"debug.js\"\n  ],\n  \"scripts\": {\n    \"release\": \"standard-version\",\n    \"lint\": \"eslint --ext js,svelte src e2e\",\n    \"dev\": \"npm run build:test -- -w\",\n    \"postbuild\": \"npm run copy:vendor && npm run copy:index\",\n    \"prebuild\": \"rm -rf build\",\n    \"copy:vendor\": \"cp build/src/vendor.js build/dev/ && cp build/src/vendor.js build/dist/\",\n    \"copy:index\": \"cp src/index.js build/dev/ && cp src/index.js build/dist/\",\n    \"mortero\": \"mortero -ayrv:./components USE_HASH_CHANGE=$HASHCHANGE DEBUG=true --platform browser\",\n    \"build:module\": \"npm run mortero -- src -Xtest -Dbuild/src -Nsvelte -fyindex.js --format esm\",\n    \"build:debug\": \"npm run mortero -- src/lib -Xtest -fKDbuild/dev --format esm\",\n    \"build:test\": \"npm run mortero -- src e2e -X{lib,cases,components} -Xhelpers.js -X'**/_*'\",\n    \"build:all\": \"mortero src/lib -fKXtest -Dbuild/dist --format esm --platform browser\",\n    \"build\": \"npm run build:all && npm run build:debug && npm run build:module\",\n    \"test:e2e\": \"testcafe ${BROWSER:-chrome:headless} --color -q\",\n    \"test\": \"npm run build:test -- -fyjs && npm run test:e2e -- -a 'npm run dev' e2e/cases\"\n  },\n  \"mortero\": {\n    \"bundle\": [\n      \"**/app/*.js\",\n      \"**/index.js\",\n      \"**/vendor.js\"\n    ],\n    \"rename\": [\n      \"**/test/**/!(index).html:{basedir}/{name}/index.html\",\n      \"**/{src,e2e}/**:{filepath/1}\",\n      \"**/test/**:{filepath/1}\"\n    ]\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/pateketrueke/yrv/issues\"\n  },\n  \"homepage\": \"https://github.com/pateketrueke/yrv\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pateketrueke/yrv.git\"\n  },\n  \"author\": \"Alvaro Cabrera <pateketrueke@gmail.com>\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"router\",\n    \"svelte\",\n    \"svelte3\",\n    \"svelte-router\",\n    \"svelte3-router\"\n  ],\n  \"peerDependencies\": {\n    \"svelte\": \"3.x\"\n  },\n  \"devDependencies\": {\n    \"abstract-nested-router\": \"^0.2.1\",\n    \"eslint\": \"^7.27.0\",\n    \"eslint-config-airbnb-base\": \"^14.0.0\",\n    \"eslint-plugin-import\": \"^2.18.2\",\n    \"eslint-plugin-svelte3\": \"^3.2.0\",\n    \"eslint-utils\": \">=1.4.1\",\n    \"mortero\": \"^0.0.62\",\n    \"pug\": \"^3.0.0\",\n    \"query-string\": \"^6.8.3\",\n    \"standard-version\": \"^9.0.0\",\n    \"svelte\": \"^3.48.0\",\n    \"testcafe\": \"1.18.6\"\n  }\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "export { default as Router } from './lib/Router.svelte';\nexport { default as Route } from './lib/Route.svelte';\nexport { default as Link } from './lib/Link.svelte';\n\nexport { navigateTo, router } from './lib/utils';\n"
  },
  {
    "path": "src/lib/Link.svelte",
    "content": "<script>\n  import { createEventDispatcher } from 'svelte';\n\n  import {\n    ROOT_URL, fixedLocation, navigateTo, cleanPath, isActive, getProps, router,\n  } from './utils';\n\n  let ref;\n  let active;\n  let cssClass = '';\n  let fixedHref = null;\n\n  export let go = null;\n  export let open = null;\n  export let href = '';\n  export let title = '';\n  export let button = false;\n  export let exact = false;\n  export let reload = false;\n  export let replace = false;\n  export { cssClass as class };\n\n  // replacement for `Object.keys(arguments[0].$$.props)`\n  const thisProps = ['go', 'open', 'href', 'class', 'title', 'button', 'exact', 'reload', 'replace'];\n\n  // rebase active URL\n  $: if (!/^(\\w+:)?\\/\\//.test(href)) {\n    fixedHref = cleanPath(ROOT_URL, true) + cleanPath(router.hashchange ? `#${href}` : href);\n  }\n\n  $: if (ref && $router.path) {\n    if (isActive(href, $router.path, exact)) {\n      if (!active) {\n        active = true;\n        ref.setAttribute('aria-current', 'page');\n\n        if (button) {\n          ref.setAttribute('disabled', true);\n        }\n      }\n    } else if (active) {\n      active = false;\n      ref.removeAttribute('disabled');\n      ref.removeAttribute('aria-current');\n    }\n  }\n\n  // extract additional props\n  $: fixedProps = getProps($$props, thisProps);\n\n  const dispatch = createEventDispatcher();\n\n  // this will enable `<Link on:click={...} />` calls\n  function handleOnClick(e) {\n    e.preventDefault();\n\n    if (typeof go === 'string' && window.history.length > 1) {\n      if (go === 'back') window.history.back();\n      else if (go === 'fwd') window.history.forward();\n      else window.history.go(parseInt(go, 10));\n      return;\n    }\n\n    if (!fixedHref && href !== '') {\n      if (open) {\n        let specs = typeof open === 'string' ? open : '';\n\n        const wmatch = specs.match(/width=(\\d+)/);\n        const hmatch = specs.match(/height=(\\d+)/);\n\n        if (wmatch) specs += `,left=${(window.screen.width - wmatch[1]) / 2}`;\n        if (hmatch) specs += `,top=${(window.screen.height - hmatch[1]) / 2}`;\n\n        if (wmatch && !hmatch) {\n          specs += `,height=${wmatch[1]},top=${(window.screen.height - wmatch[1]) / 2}`;\n        }\n\n        const w = window.open(href, '', specs);\n        const t = setInterval(() => {\n          if (w.closed) {\n            dispatch('close');\n            clearInterval(t);\n          }\n        }, 120);\n      } else window.location.href = href;\n      return;\n    }\n\n    fixedLocation(href, () => {\n      navigateTo(fixedHref || '/', { reload, replace });\n    }, () => dispatch('click', e));\n  }\n\n  function handleAnchorOnClick(e) {\n    // user used a keyboard shortcut to force open link in a new tab\n    if (e.metaKey || e.ctrlKey || e.button !== 0) {\n      return;\n    }\n  \n    handleOnClick(e);\n  }\n</script>\n\n{#if button}\n  <button {...fixedProps} bind:this={ref} class={cssClass} {title} on:click={handleOnClick}>\n    <slot />\n  </button>\n{:else}\n  <a {...fixedProps} href={cleanPath(fixedHref || href)} bind:this={ref} class={cssClass} {title} on:click={handleAnchorOnClick}>\n    <slot />\n  </a>\n{/if}\n"
  },
  {
    "path": "src/lib/Route.svelte",
    "content": "<script context=\"module\">\n  import { writable } from 'svelte/store';\n  import { routeInfo } from './router';\n  import {\n    CTX_ROUTER, CTX_ROUTE, router, getProps, isPromise, isSvelteComponent,\n  } from './utils';\n</script>\n\n<script>\n  import { onDestroy, getContext, setContext } from 'svelte';\n\n  export let key = null;\n  export let path = '/';\n  export let exact = null;\n  export let pending = null;\n  export let disabled = false;\n  export let fallback = null;\n  export let component = null;\n  export let condition = null;\n  export let redirect = null;\n\n  // replacement for `Object.keys(arguments[0].$$.props)`\n  const thisProps = ['key', 'path', 'exact', 'pending', 'disabled', 'fallback', 'component', 'condition', 'redirect'];\n\n  const routeContext = getContext(CTX_ROUTE);\n  const routerContext = getContext(CTX_ROUTER);\n\n  const { assignRoute, unassignRoute, pendingComponent } = routerContext || {};\n\n  const routePath = routeContext ? routeContext.routePath : writable(path);\n\n  let activeRouter = null;\n  let activeProps = {};\n  let fullpath;\n  let hasLoaded;\n\n  const fixedRoot = $routePath !== path && $routePath !== '/'\n    ? `${$routePath}${path !== '/' ? path : ''}`\n    : path;\n\n  function resolve() {\n    const fixedRoute = path !== fixedRoot && fixedRoot.substr(-1) !== '/'\n      ? `${fixedRoot}/`\n      : fixedRoot;\n\n    [key, fullpath] = assignRoute(key, fixedRoute, {\n      condition, redirect, fallback, exact,\n    });\n  }\n\n  // IF DEBUG\n  let failure;\n\n  try {\n    if (redirect !== null && !/^(?:\\w+:\\/\\/|\\/)/.test(redirect)) {\n      throw new TypeError(`Expecting valid URL to redirect, given '${redirect}'`);\n    }\n\n    if (condition !== null && typeof condition !== 'function') {\n      throw new TypeError(`Expecting condition to be a function, given '${condition}'`);\n    }\n\n    if (path.charAt() !== '#' && path.charAt() !== '/') {\n      throw new TypeError(`Expecting a leading slash or hash, given '${path}'`);\n    }\n\n    if (!assignRoute) {\n      throw new TypeError(`Missing top-level <Router>, given route: ${path}`);\n    }\n\n    resolve();\n  } catch (e) {\n    failure = e;\n  }\n  // ENDIF\n  // IF_NOT DEBUG\n  resolve();\n  // ENDIF\n\n  $: if (key) {\n    activeRouter = !disabled && $routeInfo[key];\n    activeProps = getProps($$props, thisProps);\n    activeProps.router = activeRouter;\n  }\n\n  $: if (activeRouter) {\n    for (const k in $router.params) {\n      if (typeof activeRouter.params[k] === 'undefined') {\n        activeRouter.params[k] = $router.params[k];\n      }\n    }\n\n    if (!component) { // component passed as slot\n      hasLoaded = true;\n    } else if (isSvelteComponent(component)) { // component passed as Svelte component\n      hasLoaded = true;\n    } else if (isPromise(component)) { // component passed as import()\n      component.then(module => {\n        component = module.default;\n        hasLoaded = true;\n      });\n    } else { // component passed as () => import()\n      component().then(module => {\n        component = module.default;\n        hasLoaded = true;\n      });\n    }\n  }\n\n  onDestroy(() => {\n    if (unassignRoute) {\n      unassignRoute(fullpath);\n    }\n  });\n\n  setContext(CTX_ROUTE, {\n    routePath,\n  });\n</script>\n\n<!--IF DEBUG-->\n<style>\n  [data-failure] {\n    color: red;\n  }\n</style>\n\n{#if failure}\n  <p data-failure>{failure}</p>\n{/if}\n<!--ENDIF-->\n\n{#if activeRouter}\n<!--<fieldset><legend>{key} ({exact} | {fullpath})</legend>-->\n  {#if !hasLoaded}\n    {#if pending || pendingComponent}\n      {#if isSvelteComponent(pending)}\n        <svelte:component this={pending} {...activeProps} />\n      {:else if isSvelteComponent(pendingComponent)}\n        <svelte:component this={pendingComponent} {...activeProps} />\n      {:else}\n        {pending || pendingComponent}\n      {/if}\n    {/if}\n  {:else}\n    {#if component}\n      <svelte:component this={component} {...activeProps} />\n    {:else}\n      <slot {...activeProps} />\n    {/if}\n  {/if}\n<!--</fieldset>-->\n{/if}\n"
  },
  {
    "path": "src/lib/Router.svelte",
    "content": "<script context=\"module\">\n  import { writable } from 'svelte/store';\n  import { CTX_ROUTER, router } from './utils';\n  import {\n    baseRouter, addRouter, findRoutes, doFallback,\n  } from './router';\n\n  // const __CACHED_ROUTES__ = new Map();\n</script>\n\n<script>\n  import {\n    onMount, onDestroy, getContext, setContext,\n  } from 'svelte';\n\n  let cleanup;\n  let failure;\n  let fallback;\n\n  export let key = '';\n  export let path = '/';\n  export let pending = null;\n  export let disabled = false;\n  export let condition = null;\n\n  // IF DEBUG\n  export let nofallback = false;\n  // ENDIF\n\n  const routerContext = getContext(CTX_ROUTER);\n  const basePath = routerContext ? routerContext.basePath : writable(path);\n\n  const fixedRoot = $basePath !== path && $basePath !== '/'\n    ? `${$basePath}${path !== '/' ? path : ''}`\n    : path;\n\n  // IF DEBUG\n  try {\n    if (condition !== null && typeof condition !== 'function') {\n      throw new TypeError(`Expecting condition to be a function, given '${condition}'`);\n    }\n\n    if (path.charAt() !== '#' && path.charAt() !== '/') {\n      throw new TypeError(`Expecting a leading slash or hash, given '${path}'`);\n    }\n  } catch (e) {\n    failure = e;\n  }\n  // ENDIF\n\n  function assignRoute(_key, route, detail) {\n    _key = _key || `route-${Math.random().toString(36).substr(2)}`;\n\n    const $key = [key, _key].filter(Boolean).join('.');\n    const handler = { key: $key, ...detail };\n\n    let fullpath;\n    baseRouter.mount(fixedRoot, () => {\n      fullpath = baseRouter.add(route, handler);\n      fallback = (handler.fallback && $key) || fallback;\n    });\n\n    findRoutes();\n\n    return [$key, fullpath];\n  }\n\n  function unassignRoute(route) {\n    try {\n      baseRouter.rm(route);\n    } catch (e) {\n      // 🔥 this is fine...\n    }\n    findRoutes();\n  }\n\n  function onError(err) {\n    failure = err;\n\n    if (failure && fallback) {\n      doFallback(failure, fallback);\n    }\n  }\n\n  onMount(() => {\n    cleanup = addRouter(fixedRoot, fallback, onError);\n  });\n\n  onDestroy(() => {\n    if (cleanup) cleanup();\n  });\n\n  setContext(CTX_ROUTER, {\n    basePath,\n    assignRoute,\n    unassignRoute,\n    pendingComponent: pending,\n  });\n\n  $: if (condition) {\n    disabled = !condition($router);\n  }\n</script>\n\n{#if !disabled}\n  <slot router={$router} />\n{/if}\n\n<!--IF DEBUG-->\n<style>\n  [data-failure] {\n    border: 1px dashed silver;\n  }\n</style>\n\n{#if failure && !fallback && !nofallback}\n  <fieldset data-failure>\n    <legend>Router failure: {path}</legend>\n    <pre>{failure}</pre>\n  </fieldset>\n{/if}\n<!--ENDIF-->\n"
  },
  {
    "path": "src/lib/router.js",
    "content": "import { writable } from 'svelte/store';\nimport { Router, parse } from '../vendor';\n\nimport {\n  ROOT_URL, navigateTo, cleanPath, isActive, router,\n} from './utils';\n\nexport const baseRouter = new Router();\nexport const routeInfo = writable({});\n\n// private registries\nconst onError = {};\nconst shared = {};\n\nlet errors = [];\nlet routers = 0;\nlet interval;\nlet currentURL;\n\n// take snapshot from current state...\nrouter.subscribe(value => { shared.router = value; });\nrouteInfo.subscribe(value => { shared.routeInfo = value; });\n\nexport function doFallback(failure, fallback) {\n  routeInfo.update(defaults => ({\n    ...defaults,\n    [fallback]: {\n      ...shared.router,\n      failure,\n    },\n  }));\n}\n\nexport function handleRoutes(map, params, enforce) {\n  map.some(x => {\n    if (x.key && (enforce || (x.matches && !shared.routeInfo[x.key]))) {\n      if (x.redirect && (x.condition === null || x.condition(shared.router) !== true)) {\n        if (x.exact && shared.router.path !== x.path) return false;\n        navigateTo(x.redirect);\n        return true;\n      }\n\n      if (x.exact && x.path !== currentURL) {\n        if (currentURL.replace(/[#/]$/, '') !== x.path) return false;\n      }\n\n      if (enforce && x.fallback) {\n        return false;\n      }\n\n      Object.assign(params, x.params);\n\n      // upgrade matching routes!\n      routeInfo.update(defaults => ({\n        ...defaults,\n        [x.key]: {\n          ...shared.router,\n          ...x,\n        },\n      }));\n    }\n\n    return false;\n  });\n}\n\nexport function evtHandler() {\n  let baseUri = !router.hashchange ? window.location.href.replace(window.location.origin, '') : window.location.hash || '/';\n  let failure;\n\n  // unprefix active URL\n  if (ROOT_URL !== '/') {\n    baseUri = baseUri.replace(cleanPath(ROOT_URL), '');\n  }\n\n  // skip given anchors if already exists on document, see #43\n  if (\n    /^#[\\w-]+$/.test(window.location.hash)\n    && document.querySelector(window.location.hash)\n    && currentURL === baseUri.split('#')[0]\n  ) return;\n\n  // trailing slash is required to keep route-info on nested routes!\n  // see: https://github.com/pateketrueke/abstract-nested-router/commit/0f338384bddcfbaee30f3ea2c4eb0c24cf5174cd\n  const normalizedURL = baseUri.replace('/#', '#').replace(/^#\\//, '/');\n  const [path, qs] = normalizedURL.split('?');\n  const fullpath = path.replace(/\\/?$/, '/');\n  const params = {};\n\n  if (currentURL !== normalizedURL) {\n    currentURL = normalizedURL;\n    router.set({\n      path: cleanPath(fullpath),\n      query: parse(qs),\n      params,\n    });\n  }\n\n  routeInfo.set({});\n\n  // load all matching routes...\n  baseRouter.resolve(fullpath, (err, result) => {\n    if (err) {\n      failure = err;\n      return;\n    }\n\n    handleRoutes(result, params);\n  });\n\n  if (!failure) {\n    try {\n      handleRoutes(baseRouter.find(fullpath), params, true);\n    } catch (e) {\n      // noop\n    }\n  }\n\n  // it's fine to omit failures for '/' paths\n  if (failure && failure.path !== '/') {\n    console.debug(failure);\n  } else {\n    failure = null;\n  }\n\n  // clear previously failed handlers\n  errors.forEach(cb => cb());\n  errors = [];\n\n  let fallback;\n\n  // invoke error-handlers to clear out previous state!\n  Object.keys(onError).forEach(root => {\n    if (isActive(root, fullpath, false)) {\n      const fn = onError[root].callback;\n\n      fn(failure);\n      errors.push(fn);\n    }\n\n    if (!fallback && onError[root].fallback) {\n      fallback = onError[root].fallback;\n    }\n  });\n\n  // handle unmatched fallbacks\n  if (failure && fallback) {\n    doFallback(failure, fallback);\n  }\n}\n\nexport function findRoutes() {\n  clearTimeout(interval);\n  interval = setTimeout(evtHandler);\n}\n\nexport function addRouter(root, fallback, callback) {\n  if (!routers) {\n    window.addEventListener('popstate', findRoutes, false);\n  }\n\n  // register error-handlers\n  if (!onError[root] || fallback) {\n    onError[root] = { fallback, callback };\n  }\n\n  routers += 1;\n\n  return () => {\n    routers -= 1;\n\n    if (!routers) {\n      window.removeEventListener('popstate', findRoutes, false);\n    }\n  };\n}\n"
  },
  {
    "path": "src/lib/utils.js",
    "content": "import { writable } from 'svelte/store';\nimport { Router, stringify } from '../vendor';\n\nconst cache = {};\nconst baseTag = document.getElementsByTagName('base');\nconst basePrefix = (baseTag[0] && baseTag[0].href) || '/';\n\nexport const ROOT_URL = basePrefix.replace(window.location.origin, '');\n\nexport const router = writable({\n  path: '/',\n  query: {},\n  params: {},\n  initial: true,\n});\n\nexport const CTX_ROUTER = {};\nexport const CTX_ROUTE = {};\n\n// use location.hash on embedded pages, e.g. Svelte REPL\nlet HASHCHANGE = window.location.origin === 'null';\n\nexport function hashchangeEnable(value) {\n  if (typeof value === 'boolean') {\n    HASHCHANGE = !!value;\n  }\n\n  return HASHCHANGE;\n}\n\nObject.defineProperty(router, 'hashchange', {\n  set: value => hashchangeEnable(value),\n  get: () => hashchangeEnable(),\n  configurable: false,\n  enumerable: false,\n});\n\nexport function fixedLocation(path, callback, doFinally) {\n  const baseUri = router.hashchange ? window.location.hash.replace('#', '') : window.location.pathname;\n\n  // this will rebase anchors to avoid location changes\n  if (path.charAt() !== '/') {\n    path = baseUri + path;\n  }\n\n  const currentURL = baseUri + window.location.hash + window.location.search;\n\n  // do not change location et all...\n  if (currentURL !== path) {\n    callback(path);\n  }\n\n  // invoke final guard regardless of previous result\n  if (typeof doFinally === 'function') {\n    doFinally();\n  }\n}\n\nexport function cleanPath(uri, fix) {\n  return uri !== '/' || fix ? uri.replace(/\\/$/, '') : uri;\n}\n\nexport function navigateTo(path, options) {\n  const {\n    reload, replace,\n    params, queryParams,\n  } = options || {};\n\n  // If path empty or no string, throws error\n  if (!path || typeof path !== 'string' || (path[0] !== '/' && path[0] !== '#')) {\n    throw new Error(`Expecting '/${path}' or '#${path}', given '${path}'`);\n  }\n\n  if (params) {\n    path = path.replace(/:([a-zA-Z][a-zA-Z0-9_-]*)/g, (_, key) => params[key]);\n  }\n\n  if (queryParams) {\n    const qs = stringify(queryParams);\n\n    if (qs) {\n      path += `?${qs}`;\n    }\n  }\n\n  if (router.hashchange) {\n    let fixedURL = path.replace(/^#|#$/g, '');\n\n    if (ROOT_URL !== '/') {\n      fixedURL = fixedURL.replace(cleanPath(ROOT_URL), '');\n    }\n\n    window.location.hash = fixedURL !== '/' ? fixedURL : '';\n    return;\n  }\n\n  // If no History API support, fallbacks to URL redirect\n  if (reload || !window.history.pushState || !window.dispatchEvent) {\n    window.location.href = path;\n    return;\n  }\n\n  // If has History API support, uses it\n  fixedLocation(path, nextURL => {\n    window.history[replace ? 'replaceState' : 'pushState'](null, '', nextURL);\n    window.dispatchEvent(new Event('popstate'));\n  });\n}\n\nexport function getProps(given, required) {\n  const { props: sub, ...others } = given;\n\n  // prune all declared props from this component\n  required.forEach(k => {\n    delete others[k];\n  });\n\n  return {\n    ...sub,\n    ...others,\n  };\n}\n\nexport function isActive(uri, path, exact) {\n  if (!cache[[uri, path, exact]]) {\n    if (exact !== true && path.indexOf(uri) === 0) {\n      cache[[uri, path, exact]] = /^[#/?]?$/.test(path.substr(uri.length, 1));\n    } else if (uri.includes('*') || uri.includes(':')) {\n      cache[[uri, path, exact]] = Router.matches(uri, path);\n    } else {\n      cache[[uri, path, exact]] = cleanPath(path) === uri;\n    }\n  }\n\n  return cache[[uri, path, exact]];\n}\n\nexport function isPromise(object) {\n  return object && typeof object.then === 'function';\n}\n\nexport function isSvelteComponent(object) {\n  return object && object.prototype;\n}\n"
  },
  {
    "path": "src/test/_layout.pug",
    "content": "doctype html\nhtml(lang='en')\n  head\n    meta(charset='UTF-8')\n    meta(name='viewport', content='width=device-width, initial-scale=1.0')\n    meta(http-equiv='X-UA-Compatible', content='ie=edge')\n    block head\n    style.\n      a[aria-current]{font-weight:bold}\n  body\n    script.\n      if (!!window.MSInputMethodContext && !!document.documentMode)\n      document.write('<script src=\"https://polyfill.io/v3/polyfill.min.js?features=default,Promise,Object.entries,Object.getOwnPropertyDescriptors\"><\\\\/script>');\n    block body\n"
  },
  {
    "path": "src/test/folder.pug",
    "content": "extends _layout\n\nblock head\n  base(href='/folder/')\n  title Your routing! (base-href)\n\nblock body\n  script(src='../app/testing.js')\n"
  },
  {
    "path": "src/test/import.pug",
    "content": "extends _layout\n\nblock head\n  base(href='/import/')\n  title Your routing! (dynamic imports)\n\nblock body\n  script(src='../app/import.esm.js' type='module')\n"
  },
  {
    "path": "src/test/index.pug",
    "content": "extends _layout\n\nblock head\n  title Your routing!\n\nblock body\n  script(src='/app/testing.js')\n"
  },
  {
    "path": "src/test/routers.pug",
    "content": "extends _layout\n\nblock head\n  base(href='/routers/')\n  title Your routing! (nested routers)\n\nblock body\n  script(src='../app/routers.js')\n"
  },
  {
    "path": "src/vendor.js",
    "content": "export { parse, stringify } from 'query-string';\nexport { default as Router } from 'abstract-nested-router';\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "import { SvelteComponentTyped, SvelteComponent } from \"svelte\";\nimport { Writable } from 'svelte/store';\n\ninterface RouterState {\n  path: string;\n  query: Record<string, any>;\n  params: Record<string, any>;\n  initial?: boolean;\n}\n\ninterface RouterProps {\n  /**\n   * @description any segment to derive a fullpath from. \n   * @default /\n   */\n  path?: string;\n  /**\n   * @description A Svelte-component or string. Shown while we wait for a component to load.\n   */\n  pending?: SvelteComponent | string;\n  /**\n   * @description Similar to condition, but for bound props.\n   */\n  disabled?: boolean;\n  /**\n   * @description If given, render only if this function evaluates to true.\n   */\n  condition?: () => boolean;\n}\ninterface RouterSlots {\n  router: RouterState;\n}\nexport class Router extends SvelteComponentTyped<RouterProps & {\n  /**\n   * @description if set, non-matched routes will never raise a failure.\n   */\n  nofallback?: boolean;\n}, any, RouterSlots> { }\n\ninterface RouteProps extends RouterProps {\n  /**\n   * @description the route identity, not its path; defaults to a random psuedo-hash\n   */\n  key?: string;\n  /**\n   * @description if set, the route will only render if the route _exact_ matches the current route. \n   */\n  exact?: boolean;\n  /**\n   * @description if set the route will render only if no more routes were matched.\n   */\n  fallback?: boolean;\n  /**\n   * @description accepts either a valid Svelte component, a promise that resolves to a component, or a dynamic import function.\n   * \n   * _Note:_ supplying a dynamic import function will start the network call immediately when the route is mounted. If you would like to wait until the route is matched to start loading, use `() => import()` instead.\n   */\n  component?: SvelteComponent | Promise<SvelteComponent> | Promise<typeof import('*.svelte')> | (() => Promise<SvelteComponent>) | (() => Promise<typeof import('*.svelte')>);\n  /**\n   * @description alternate redirection location, only if the `condition` is true.\n   */\n  redirect?: string;\n}\n\nexport class Route extends SvelteComponentTyped<RouteProps> { }\n\ninterface LinkProps {\n  /**\n   * @description history shortcut.\n   */\n  go?: 'back' | 'fwd' | number;\n  /**\n   * @description New location; defaults to `/`\n   */\n  href?: string;\n  /** \n   * @description Same behavior as `<a target=\"_blank\">`\n   */\n  open?: boolean;\n  /**\n   * @description HTML title-attribute value.\n   */\n  title?: string;\n  /**\n   * @description if set will use a button-tag instead of an anchor tag.\n   */\n  button?: boolean;\n  /**\n   * determine if the link should be matched exactly in order to be set as active.\n   */\n  exact?: boolean;\n  /**\n   * @description use `location.href` instead\n   */\n  reload?: boolean;\n  /**\n   * @description use `history.replaceState()` instead.\n   */\n  replace?: boolean;\n  /**\n   * @description custom class name for the mounted anchor.\n   */\n  class?: string;\n}\n\nexport class Link extends SvelteComponentTyped<LinkProps> { }\n\ninterface NavigateToOps {\n  /**\n   * @description if true will use `location.href` instead.\n   */\n  reload?: boolean;\n  /**\n   * @description if true will use `history.replaceState()` instead.\n   */\n  replace?: boolean;\n  /**\n   * @description used to replace `:placeholders` in the `path` value.\n   */\n  params?: Record<string, any>;\n  /**\n   * @description additional search-parameters for new location.\n   */\n  queryParams?: string | Record<string, any>;\n}\n/**\n * \n * @param path the path to change the URL to.\n * @param options changes behavior of function call.\n */\nexport function navigateTo(path: string, options?: NavigateToOps);\n/**\n * @description a store with shared route information; similar to `let:router`\n * \n * ```js\n * import { router } from 'yrv'\n * router.subscribe($router => {\n *  // code run on router update.\n * })\n * ```\n */\nexport const router: Writable<RouterState>\n\n"
  }
]