{"_id":"@djaler/ts-routes","_rev":"2-10d54171452f6aa2c8ad81457bab3103","name":"@djaler/ts-routes","dist-tags":{"latest":"2.0.1"},"versions":{"2.0.1":{"name":"@djaler/ts-routes","version":"2.0.1","description":"Strongly typed routes management","main":"lib/index.cjs.js","module":"lib/index.esm.js","types":"lib/index.d.ts","scripts":{"test":"jest","test:types":"tsd","pretest:types":"npm run build","build":"rollup -c","lint":"eslint src/** __tests__/**"},"directories":{"lib":"lib"},"repository":{"type":"git","url":"git+https://github.com/djaler/ts-routes.git"},"keywords":["routes","typescript","path-to-regexp","react-router","strongly","typed","paths","pattern","routing"],"author":{"name":"LeanCode"},"license":"Apache-2.0","bugs":{"url":"https://github.com/djaler/ts-routes/issues"},"homepage":"https://github.com/djaler/ts-routes#readme","dependencies":{"path-to-regexp":">=6.0.0","qs":">=6.0.0"},"devDependencies":{"@types/jest":"26.0.23","@types/node":"^14.0.0","@types/qs":"6.9.6","@typescript-eslint/eslint-plugin":"4.27.0","@typescript-eslint/parser":"4.27.0","eslint":"7.28.0","eslint-config-prettier":"8.3.0","eslint-plugin-prettier":"3.4.0","jest":"27.0.4","prettier":"2.3.1","rollup":"2.52.1","rollup-plugin-clear":"2.0.7","rollup-plugin-typescript2":"0.30.0","ts-jest":"27.0.3","tsd":"0.17.0","typescript":"4.3.4"},"tsd":{"directory":"__tests__/types"},"gitHead":"a93446f4fd5a56ed4467235372fea4f92f42abd6","_id":"@djaler/ts-routes@2.0.1","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-TlKxPL70lTyYtOQVYRA2RPwfKY8VwwOU9z1tO/KDTH2CAx0ik3dqKYpoSiVqUYuiIey9DlGlrHgVXXg65GyXhg==","shasum":"50e95f9753de7df2e289596481306ea25da7e29a","tarball":"https://registry.npmjs.org/@djaler/ts-routes/-/ts-routes-2.0.1.tgz","fileCount":20,"unpackedSize":65835,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhzwwSCRA9TVsSAnZWagAAie4QAJuLZj1tMbiG2cjNwFs2\n0NFj63AIXjxv1iSCtHGVyY6BZFNrUIlo3T4a5jchwGndPmymnTVuzJCMSFi1\nSnn0o6X1AeJay9L+Oah9RvFx6WbdDIwxQFUijr0NHEsor6SpD6GslQRvHpNb\nT7X/OMRVpJvScAAFd3v4xdNVbFbXC2n92w3lv1eSfGF4bsTB65WfvVMCGWIA\nVKNl8jAQfVeCUYyttkAXaHAJzFxFm8vofoUNgCIJLoSYtlatKN5y2Z1urmOt\nwTfcRGCi898soFbTCOgQWdkfmqdv89VyU+erYGfRDhg7CLZhl5UBbdVF3iO0\nQzF+lZ3W2/bdzYwljST7DDdPDGEIyirk1vz5sXYuT+zPoxEaPmEWi4Er9tKa\nWY0iXuuwGqsp+5o/CgFEcBlCcIHG3IEe3976DQnR24Z5hQYlKVu2Mt+q7MNX\na7NkErfZ49FwDrKL13J2RWa7t9y3R5+6cmgMsdi8kW8DbkUb8JdzGOgFW45X\nuNbibdVQaxSkFbG75ackxZv/Y9uElR++TMfpXbH9NryDIZMJYS1ZyVQ9+Gl0\n55dfsqUU2lZup+WpSIZSSUuIJUMRC/11kEiih3pKZZo3J6V8/DhANPyqPDan\nko00QuL/X+D3pgXCXL/S4GBMztipNt0yUmXyVaMRs+fLv6GlRnLb69Xw/GE9\nnsh2\r\n=yjNG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDedrlEA+BlJbEmITsBVAuyWRKlpR+4e1OnOVbdoxsiNQIgWFMLD2tqMcP6Tek2ShfZlNj5YMjXnHpNl1rnrc1cQfM="}]},"_npmUser":{"name":"djaler","email":"djaler1@gmail.com"},"maintainers":[{"name":"djaler","email":"djaler1@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ts-routes_2.0.1_1635834623786_0.9630518027435857"},"_hasShrinkwrap":false}},"time":{"created":"2021-11-02T06:30:23.736Z","2.0.1":"2021-11-02T06:30:23.937Z","modified":"2022-04-05T04:49:58.214Z"},"maintainers":[{"name":"djaler","email":"djaler1@gmail.com"}],"description":"Strongly typed routes management","homepage":"https://github.com/djaler/ts-routes#readme","keywords":["routes","typescript","path-to-regexp","react-router","strongly","typed","paths","pattern","routing"],"repository":{"type":"git","url":"git+https://github.com/djaler/ts-routes.git"},"author":{"name":"LeanCode"},"bugs":{"url":"https://github.com/djaler/ts-routes/issues"},"license":"Apache-2.0","readme":"# ts-routes\n\n[![npm](https://img.shields.io/npm/v/ts-routes)](https://www.npmjs.com/package/ts-routes)\n[![Actions Status](https://github.com/leancodepl/ts-routes/workflows/build/badge.svg)](https://github.com/leancodepl/ts-routes/actions)\n\nHelper library for constructing strongly typed parameterized routing paths. It prevents you from passing hardcoded\nstrings with routes across the app.\n\nts-routes is independent on routing libraries and can be used together with e.g. React Router DOM or Vue Router.\n\n## Installation\n\n```\nnpm install ts-routes\nyarn add ts-routes\n```\n\n## Quick start\n\n```ts\nimport { createRouting, number, query, segment, uuid } from 'ts-routes';\n\nconst routes = createRouting({\n    products: segment`/products`,\n    users: segment`/users/${number('userId')}`,\n    items: {\n        ...segment`/items`,\n        query: {\n            filter: query()\n        }\n        children: {\n            item: segment`/${uuid('itemId')}`,\n        },\n    },\n});\n\nroutes.products(); // '/products'\nroutes.products.pattern // '/products'\n\nroutes.users({ userId: '10' }) // '/users/10'\nroutes.users.pattern // '/users/:userId([0-9]+)\n\nroutes.items({}, { filter: 'new' }) // '/items?filter=new'\nroutes.items.pattern // '/items'\n\nroutes.items.item({ itemId: '12d66718-e47c-4a2a-ad5b-8897def2f6a7' }) // '/items/12d66718-e47c-4a2a-ad5b-8897def2f6a7'\nroutes.items.item.pattern // `/items/:itemId(${uuidRegex})`\n```\n\n## Usage\n\n### Routing\n\nTo use strongly typed paths, you first have to create the routing object by calling `createRouting` and providing an\nobject defining segments. Segments represent single routing paths and are implemented as tagged template literals:\n\n```ts\nconst routes = createRouting({\n    users: segment`/users`\n});\n```\n\nSecond parameter to `createRouting` is `qs` configuration. You can extend/alter `ts-routes` functionality by providing configuration to `qs`. For example you can change array formatting and delimiter. For details on configuration please refer to [`qs` documentation](https://github.com/ljharb/qs).\n\n### Parameters\n\nYou can define route params (i.e. parts of the path that are variable) by interpolating the `arg` function inside a\nsegment:\n\n```ts\nsegment`/users/${arg(\"userId\")}`;\n```\n\nThis will enable you to create paths like `/users/1` or `/users/username`.\n\nBy default route parameters are treated as required. You can make them optional by providing extra configuration. It is\nalso possible to limit possible parameter values by passing a regex string. While trying to create a route which doesn't\nsatisfy the pattern, an exception will be thrown.\n\n```ts\nsegment`/users/${arg(\"userId\", {\n    optionality: \"optional\",\n    pattern: \"[0-9]\",\n})}`;\n```\n\nWhen creating a route, path parameters can be passed in the first argument:\n\n```ts\nroutes.users({ userId: \"10\" });\n```\n\nThere are some predefined convenience parameter types provided:\n\n-   `string(name: string, optionality?: \"optional\" | \"required\" = \"required\")` for plain strings\n-   `number(name: string, optionality?: \"optional\" | \"required\" = \"required\")` for number strings\n-   `uuid(name: string, optionality?: \"optional\" | \"required\" = \"required\")` for UUID strings\n\n### Query string\n\nQuery string parameters can be specified by adding `query` property to the route description. The `query` function\nexpects an object where keys are names of parameters and values specify whether those params are required in the path.\n\n```ts\n{\n    ...segment`/product`,\n    query: {\n        productId: query(\"required\"),\n        details: query(\"optional\")\n    }\n}\n```\n\nThe above segment defines a path which expects the `productId` URL param and the optional `details` URL param.\n\nWhen creating a route query strings can be passed in the second argument:\n\n```ts\nroutes.products(\n    {},\n    {\n        productId: \"10\",\n        details: \"false\",\n    },\n);\n```\n\nwhich will return `/product?details=false&productId=10`.\n\n`qs` by default supports also objects and arrays when stringifying and parsing query string.\n\n```ts\nconst parameters = routes.products.parseQuery(queryString)\n\n// this will yield given parameters with given type\n\ntype Parameters = {\n    productId: string | string[],\n    details?: string | string[],\n}\n```\n\nFor objects you need to specify your value type when defining routes:\n\n```ts\nimport { createRouting, number, query, uuid } from 'ts-routes';\n\ntype ProductDetails = { name: string, price: string };\n\nconst routes = createRouting({\n    products: {\n        ...segment`/product`,\n        query: {\n            productId: query(\"required\"),\n            details: query<ProductDetails, \"optional\">(\"optional\")\n        }\n    }\n});\n\nconst parameters = routes.products.parseQuery(queryString)\n\n// which will yield\n\ntype Parameters = {\n    productId: string | string[],\n    details?: ProductDetails | ProductDetails[],\n}\n```\n\nAdditionaly you can override `qs` stringify and parse option directly on each route:\n```ts\n    routes.products(undefined, { productId: \"10\" }, overrideStringifyOptions);\n\n    routes.products.parse(queryString, overrideParseOptions);\n```\n\n### Nested routes\n\nRoutes can be nested by providing an optional `children` property to segments:\n\n```ts\nconst routes = createRouting({\n    parent: {\n        ...segment`/parent`,\n        children: {\n            child: segment`/child`,\n        },\n    },\n} as const);\n```\n\nChild routes are attached to the parent route object so that to construct a child route you can call\n`routes.parent.child()` (which will return `/parent/child`).\n\nRoutes can be deeply nested and child routes will include all required and optional route parameters and query string\nparameters from parent routes.\n\n### Patterns\n\nWhile creating a routing, alongside path string generators, patterns for those paths compatible with\n[path-to-regexp](https://github.com/pillarjs/path-to-regexp) are generated. You can access them via the `pattern`\nproperty:\n\n```\nroutes.products.pattern\n```\n\nThose patterns are useful for integration with routing libraries which support\n[path-to-regexp](https://github.com/pillarjs/path-to-regexp)-style syntax (e.g. React Router DOM, Vue Router).\n\n### React Router DOM\n\nYou can use patterns for defining routes:\n\n```tsx\n<Route exact component={ProductsPage} path={routes.products.pattern} />\n```\n\nWith React it's also useful to add some helper types which can be used for typing routing props for components:\n\n```ts\nimport { FunctionComponent } from \"react\";\nimport { RouteComponentProps } from \"react-router-dom\";\nimport { PathParamsFor } from \"ts-routes\";\n\ntype PageProps<TPathParams extends (...args: any[]) => string> = RouteComponentProps<PathParamsFor<TPathParams>>;\n\ntype PageComponent<TPathParams extends (...args: any[]) => string> = FunctionComponent<PageProps<TPathParams>>;\n```\n\nWhich you can then use like so:\n\n```tsx\ntype ProductsPageProps = PageProps<typeof routes.products>;\n\nconst ProductPage: PageComponent<typeof routes.products> = ({\n    match: {\n        params: { productId },\n    },\n}) => <div>{productId}</div>;\n```\n\n### Vue Router\n\nYou can use patterns for defining routes:\n\n```ts\nconst router = new VueRouter({\n    routes: [\n        {\n            path: routes.products.pattern,\n            component: ProductsPage,\n        },\n    ],\n});\n```\n","readmeFilename":"README.md"}