{"_id":"@carforyou/search-parameters","_rev":"35-6f3a506c0283a83b3ed6837b44627f0b","name":"@carforyou/search-parameters","dist-tags":{"parameters-encoding":"1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1","parameter-classification":"1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1","search-context":"1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1","release-v1":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14","fix-remove-empty-elements-from-arrays":"1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1","force-filter-label":"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4","remove-derived-filters":"2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1","callback-mode-for-client-side-search":"2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1","rollup-pkg":"2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1","latest":"2.0.2"},"versions":{"1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1":{"name":"@carforyou/search-parameters","version":"1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"4d507a14758dc238979484de5916fed59470d1de","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1.tgz","fileCount":17,"integrity":"sha512-9ybhw1RlxY4RHwTIfkC8VDoWPB/8XieERnHOWBQxhm8HHIcVUletRG+rYrhE/xF7IMG1aL99p1n6reouwgeEhQ==","signatures":[{"sig":"MEUCIEQqTfV6Y3JFO4qnCitn7diJhfxT1xpDXksjysu0+6UCAiEA/THJux2TTVSgBsuwwfPy462gzQH/O1S5F71MpPlVnTk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40730,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdct0CRA9TVsSAnZWagAAx7EP/RWpQkPkqXOMEnfKjd0N\nBI1Apnvvg21KpuRZ9++xFGSPmPhFd31X1yYEFDvNw/Oc80qVNC3Wj4vi1zgj\nSGpCxYqXQ22I7f2MzhT9OYWmGyVgKa9ZXgMBT95Hj/E8nM7WidEhdsY2DiXD\nsR7UJgpLLx0zpdVRXn21zWEFkLJWSULzADBGUNE/EAj91CVSE56Fp1gtRRWk\n3tiw/ZSsD2Mp3HFdj9mKEev7U903aHTca4f0ELg25jRdNMMWu6SwasggzrQV\nJAT0X5GwxFNF+X/arwWeyluh9/DQ8PXQE6WTVwEhadogXueqlK8U9lBPHG/w\n89/3/4ZaN/dys0s2i5gkk7wZvVTR9v0yh79VWpMtCO2hzffZkOhht5QGwxr+\nc8H/l7mGtGn1oOCrPOTP0TJtG6iPUA359Z6D0Jh6DTp7jQOrQzQ+F5fS+2ml\nqZeLyA+cP805ZLNZUL++awlvVRZlfISMeNjMQCojtQag16I6YsJJ9um1blWl\nDI7CBL6Xn95zYwGfsqUMS/TyNy381oP4YrvZDac6/RUx9we9Fp2k0Wr7vzhB\ng/8D+Gz7HM038ZwqJQ69U8kLHWnjjwecvJSRZVruQjDxJieY0klgV+cGF0LS\noks2sNcAS9uBrdAFN838nrHTohJR14jHHSWFHLMbKZb8l3iSSIlYuv6G6Yp6\nNmAn\r\n=nvel\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","ts-jest":"^26.3.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","semantic-release":"^17.0.3","@pika/plugin-build-web":"^0.9.0","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1_1618332532101_0.6729977805168765","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1":{"name":"@carforyou/search-parameters","version":"1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"10c2ce9cd6d72b9aea5707b1f037d3818e612b4e","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1.tgz","fileCount":17,"integrity":"sha512-1peZEQM5oSBbZ8HVXnbcsWvZm3SDBIIVI9NpuuvFArDJ33ZVDw4ixf4IY6btVAdVyYPSXKJLGcj6dWnfg8KOZw==","signatures":[{"sig":"MEYCIQCcn5ktr3IISuxMy9XXdkIH8Q3AwrwKxVeBIZvrSLDqmwIhAIhwsfVslRPx/TVZ4OM0sxnV+FA/2C8QwiBYSt2HtFcy","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41690,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdqC3CRA9TVsSAnZWagAAKycP/0ECiJbcn02rq6ed87kK\n5OMd74jASjFqPKHWCc+D/BPN5sYrvKBAkpbRxAcVr+IdAXf2QxT9f+34g7Bu\n5PrgZ/EdSNKQibYziSu+fDKiLiguqwDT55IjagzqgHqVrWM3J7arzIUQ5GFo\nleON6Rp+rZeapm7kZc/QoduiO4QzJCnQe0zbJNxrZuh05L+RMS5Zs8nH30uL\nULzGjIrMyWTXoe99gEhUuRgA1WLHeA5qJMAkUpFuaiTx13MDvtgDjIFkUfhK\nYhh/rik4Pt6eBaYw9DHNe6auIz0lzAYlIm62zbikCw/2MveSBgwhosiynUnj\n/Cyh85DM4gFjxuhBZCk+GmmuTducegYy4bxjEVf8FlxlU3dZKvCVaDq/SA3e\npTsoWTDUlFRbpsOr57TdECSBHQmmkausaZ0HSCBfrcxexX1Pk7wDAMR8kUHp\nAvfrifNv2P6vU/4Ffo5TFcUKukkipSNjsxUsDrabXlBcVZylVSQ0VQk+OUvE\nUO6EypPazbczHB080c5xxbp06O2z9ywnYuo4aO/lxvq3T1GLRzR5Cs1acn4Q\ntjdsyI4rLJ45gzmsk0mjUIpHJSqi4hNxq3TdQfAInBcpZpSbI6Dfx3UOqxu9\nWU9Y5P4Bb0/44t1GAVh7uUtbG4/nf4Fa4YH2g43+QXKiqrsfgfUU0m+UBygI\nymin\r\n=hdP+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","ts-jest":"^26.3.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","semantic-release":"^17.0.3","@pika/plugin-build-web":"^0.9.0","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1_1618387127318_0.10860947750938332","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"fd6f93d36890eef68e648135eee64fb079cc09c1","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1.tgz","fileCount":17,"integrity":"sha512-P1fzczNm1/vjldsW5WFZv2zYmgfk0q9lB+Mn6OaJLHII4M7ByATMg041oEz77uEOmPJrOMBxU38jDuODDy6C6Q==","signatures":[{"sig":"MEYCIQCUVMOUEUzBqadOpnFZFcaw6sgbCWaBH09hz8sZzSJfawIhANpuCmtLIZLrTSRzg8Z/8TBoLEdbjOtnJG3JgF+zH9HK","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41673,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdqFKCRA9TVsSAnZWagAAY6MP+gO5ZKm8OP/7hbPj2NMz\nj7RucwjbBUXKIK6YAJRYSKVAN4TYHVOAQfmI6uXJDSi/e4IWQYAALfMEEbzp\nEl9LtjNDziRoqWlG5xVx2iFrLzmNd4rSWmZ4nf08EXQLNY32VRiZ2jvjq7wK\nJ2jPoek8KJ4YF6NzjSfTbtSfxG2iirWCOHOeGXNr9xlWsAb8VgH8g3mB8O75\nM1L/zBuQGF78/pi4Q1B/jSR5+P/bwTu2EggpAj4Sq8f9pL7UBOPXoPJbO8es\nViF/bUKWn0UI4lzMgAudbBiPJyxJxNTDa0tVoecdFZKeHbS3UP6Z92Oc2Kro\ndL87AlZDTwNKhxagV+Kc/xeTCjYonG3Sqp7Sz2uNgrYKCYtKpAou47ilAG2m\nHQVWwwdna57k4tLlJiTM96jmzAYgJBID/af/5zuHToA7hKo2yeP5ceyvSi5W\nWV/eHfJH5yWzNJkSuQb4OQHX6qkf9WoJfpcO8CsxDpk+PQW4fPYNebfBSLmq\n/cUQrLd5e/QTGewgmdZSzt3YpHfWf8nRzkxR6OvKJP3IArLO0o/X4H+2UM4/\n49O+lG+npjDSOQgbIZw0F4G5IDXxlKk2OR5cKvuG/7so+XdBGkoEoLryvuf5\nRkAcvvWk6aDQ1idMMzPXJeiDqKXQwrwcLGYPS7Y8CK2oaa4wSy/tq8bioNrj\nGn4j\r\n=b4Wf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","ts-jest":"^26.3.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","semantic-release":"^17.0.3","@pika/plugin-build-web":"^0.9.0","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1_1618387274379_0.27826287955840034","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1":{"name":"@carforyou/search-parameters","version":"1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"ab43a1b0a209087e7708f5e41ceef984951cfe3c","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1.tgz","fileCount":25,"integrity":"sha512-X5HHojEElhVJKgM0ijzwPvslRrv7SkeVk68RGf8pbJ48bIL9D8F+3JQPNXAJpMxeRQpBKngsmDbwKPKWti0yTQ==","signatures":[{"sig":"MEUCIQDiGv3ZQ3uIKOBW+QhSkXSfumDoeiohoiXZYzBMoPVXgwIgKXhXVVLcGLR7BbcCPI7lk3aHcND8FkJO8euj2RjfIZ8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":64969,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgdvIxCRA9TVsSAnZWagAAvl8P/378F2DwKGkBdPp9YphA\nilN3Gpz7UdsMIcW/a46l5Bd/DL/EVNXSSoWEc/TqFZg/w0EfmZIa5QzDodDZ\nLWITnYCLfE9G/lkkwwEMc41Yrp08h1dqCT9s5b7B7ZGyB2Kmi6g4nsNAiZqA\nmEh+pE73NJWAb5fES98/hvGSIcybHIAB7E2xJ3q2ZzbTdqiPe4a8KCs432Ra\ngRIXW3nQc3Lyefo3iI3Yi7skWySCsHEUeYL5OiVLl0CbHJOJ/6QOf4qsjqi5\nguzbxLcSCaPUMrfyIEL8eg465baNueRPBPwrfUAV9X6qnQ8HsqzNOp0lh8Rv\nwIGZC6QGj3sygglxnx4bGBWlZvbZwkUL+srZsZk3iPiuZ0FxPfRmyxTCt8RR\nfBER0R2Kh7Y/h2T7+2YNoATphoOsLGQqi0Ig2IU6zqxTm8biRRDUIrUwN9ew\nQJkL30fyAv3LDb2xCmzXqQzNMN68up2gUh5GzzbMgxBuSX3oZoObcGjV5THf\nSwwRLqTmuHM4j/98jBvmLzOL54gRf9fRz+56f8SDF18QmbbP4rjYcxQ0KO5z\n2lnaWOA7RKatskz3A/Pq5+MoZ7TYuP7vrlQZtKQ1jr1iLAEPURa7nirSPyBl\nvxISQMdkPzLAZm1rnzf/AOPuTlmjdXsTCkJy0aigD810GMB/2nrl3t0q9Ogp\nkP4L\r\n=66zm\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing all applied filters and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: (filters) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: (filters) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","ts-jest":"^26.3.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","semantic-release":"^17.0.3","@pika/plugin-build-web":"^0.9.0","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1_1618407984985_0.12924257285288898","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"f395783fca67c89142b41e7bb48aa4e5401be755","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1.tgz","fileCount":25,"integrity":"sha512-gqV2WnYsEuHXfF1r5bX3nDSqFzjHbIbXSAQIyJJIr5aSFgwuTOz6MVaMdd4tVKxvWbU++i9vR9AUsZSeE8r7AQ==","signatures":[{"sig":"MEUCIQDcDHTv9Nq9q6lZePwyAAHfa4x2kpm1jZpWP+Cjz8G38gIgYVNpq9o2B+hJRgvOCWZSaEMZE8+3JDRu5DYxOEpGuDs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":64947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgd+uyCRA9TVsSAnZWagAArOYP/RZXy9eLRKdFzvkqG+TC\nvAZlP2LBXIvNsSbv2prw4t2/coVp2bKsN48SBa4puTl19lFLQtij7wEGStfu\nGlqMCBvOnLVK/RDe9miD6s5bSwG0VoRHcGHtKz5Di5RF3ZZDaIROSu0S5ioU\nZpvzmgrzjnFZL9dHC74kb4ond8NnHlNOdq9iDMguewZeKV2l0YTL9xrkFiwa\n1pyAR1+QYio/yGj89fWCX0ILukP7LAlvTxulGu2IojgmGzE86epkJOxsJA5y\n9EsyS9toTQGxf0OvSunjBwuLq8sf+Q9z05Oe+Wie87/M/Qe07hqLLC0fJbPa\nzaFSr5UkLvsMmsMv8hsybi4+9zoTX3n4PvwcYti1vKGIqunaJqZol3iUlWQV\n7UBYnRwnufxzxEprbEA7Pus6y4uZK359NXf2mgnp9/rRIOIewAEIzSRoV0ah\n5uNyeDbWhtY2j7gClHkCqXPkqTK4DK3vttOJhObVm0Hul2AwhEkscRTSyJU6\nHnnI5F68Mp1ZIJ3Wi2c2MvQ6s3VBRFfO6UB8FSbUqaiPfuqztWK9etbywrow\ndjWysDFj4skdE2NmSRcU+E/RDvM4ohqMnzQIaEHVpXtWZ9Q3my4FCUZR1ygd\nW3mf8YXbUeqdHDCDXX3BzjlIUnEqWVXrk+4AVMaFo2Y6PQnTAN6F/3bnPczO\nuYIX\r\n=R+R1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing all applied filters and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: (filters) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: (filters) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","ts-jest":"^26.3.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","semantic-release":"^17.0.3","@pika/plugin-build-web":"^0.9.0","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1_1618471857973_0.5458536149693556","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1":{"name":"@carforyou/search-parameters","version":"1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"daa74bf8c72b7a92621fde489d85882322c0bffd","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1.tgz","fileCount":31,"integrity":"sha512-Ur7Q+uRIqdB6dKQY+jAqZzFhoYUK1hRVpE/J0ePl1g1hZSTrfj8yUtFNwb/DPQE4zkHedbCWXcgMVkeAD0DWaA==","signatures":[{"sig":"MEYCIQDhbAUMTVyApZBhdBw1KNzFfpKIaZgUtOwUaOKdaarg1QIhANhfgvspPkrm6Bc9b25F3iHcDn4IfyXxRPoVgEUk11SN","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81699,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeYL1CRA9TVsSAnZWagAA1GgP/ikggI0e/TKswMDfIPUa\nLmO3nvhIwupzk0HnbZyHdK8SaHK0OFkZHvqw5ECJWfXczDv3++K12GC5H52f\nnJR4FkHKWgUyyHLzV7Y+X9AcWS5ni5wO5zMESz4t9fF1YO+3AA7aG0NiHUfr\nM2nCd3H/4xBJ5+tu5JRSgMInPGCpSKE8eqn20lumu+WefrIhwk7TJKngDvq7\nFC/fd+Aut0y8VCMTDuclMi7i94vAFQVtavnCS1xcJFDLn57Ci34HhPWE99OG\n2Vi3036ENRcN0KKSzkyA4kjcA8m+EKGpHPZuMrVDUXK5tfbEaFDri+PoaFF0\nVxI/nU09nn3J3a0ZcTk86lb7Cb1EifEjz7w4JHSU9DEDHNvHcIRp8Myr7juK\ncqimQ0l5OuRMUEKnWOCiSyB5DNOHDrErRVUzqkR14/Ty54VtJV2RWOoFcIrn\ns1eFawJYF+KyyPkjubA7PTfZ/wrUOd3tLqLmAO6N7UT+SXAULA5vshyD9QPw\nKjdUjyFR5RlN9Rv1QGtEY6oHZ/rxm582D3f5ROAT7vzcCZuXo88QwGLQ3zlo\nODUqyoqOScPBfzGG5ZmE2hzdNpzDokrP1sgukF/LBpH2INBFf+YY/uCh5xKt\n5QinoJYAFP7tFcunDE9eviuYXwGNiLQkiouWlHksshLkmVEUoGvlA/zrbBP/\ndSXu\r\n=lWbk\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing all applied filters and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: (filters) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: (filters) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1_1618576117045_0.47292751072949013","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"c7d727f8d2c7749982638af00f86832b6d7e4e96","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2.tgz","fileCount":31,"integrity":"sha512-bDCladxqVHknq71uunGEJTKCKnFYsUoUv7M01NL6tcDZdUURNnToTferrWSOnHjgfsPhIzD/u465K60tdC2kKQ==","signatures":[{"sig":"MEQCIB/bE6Oh13R+yyBX2/4n9IIMbWDZ8Bf+kXECInd94pcgAiBxppJASmWVL08lmCt3tfUstYAaE0y35WSsVqtCLC/vhQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":81687,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgm4aBCRA9TVsSAnZWagAAAhkQAI7tP140bh0FGUhY7T6L\nT+DjSmZISgrVEUVSHehDPXIz7Dhso9CZ5xIEpAoWUKtrE4U21Z3sPtOLcDip\nC9QxVuLCcK0nSe1I1JMGFc2Z/UeqzEF4dKQ/Wnl9b7GL90Y8ZYa/ev4u7x35\nRwbDiUFMNLHcyVFJDuVrvAqKbDaRR75VlmHHJDGhXgkIr+4Ysl2L7TaZBLGF\niKQJWbof2CtmB3H21xo3L24iFkf9GVp6qBIyrkhmBdT9tiMtlWM3xZ+fRN2H\nmhpdffNa7mrMPykPNYLrR8sHh6OOfmr3TavG72Y+Zu+U1IEerFArRjg8jYFq\n92/enzpASDgKeEH0eG9K7r9tP5h38P/ZdkI+sF9cPKLgNt29z8mjj/Dcr1Yw\nwqYmu33Oq6/b3eNV8Z2itpj5Ect52roFGYkahGSj1ADxWRkrs0NOnzyFPuAm\nJIo3CvDdsiN3gk4t0myAg6vlApomsyUeHi2zoFuAaXRl6wNliVLi7U8+TOES\nMhehV/hecAQuzrEgk4/q8kaYDfD3kH07doCBywELHGRr8R6oYgCWI7MtPAlO\n0zHUBoI9yXUWFcjVZkH2APenbuJhTCUtDNvSNK9Kn4AcB3exVmPM6Gcxa0wA\nnD8/CwTQn8/wMiEZtisQIkVhRb0lz0F4SUzGho4p0eb479g8ITVQ8TXUzHSo\n1f3T\r\n=/5YL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing all applied filters and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: (filters) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: (filters) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.16.1","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2_1620805249037_0.5328914875719541","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"cc0b1b03dcb759233ea2489473e431707bceda63","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3.tgz","fileCount":31,"integrity":"sha512-4zQ+yphCWWXblVJ3kAE4eS95BlRxSvxDB1n1Gq9bUrKmEhOzpWkC4UcMqX71jcu2leUtKHOw4201CeKLdfSvWA==","signatures":[{"sig":"MEUCIAeAPJbjbx1T4mJhui7Ofj+LIRANc3YXAb0SmNwUyM6JAiEA9nYmmXLeXtVMiTWq+lglBHajTp9vW8e6kumt59nzJuQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":86492,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgp4xZCRA9TVsSAnZWagAAHaAQAJRCfptV2pFfOvoTnWAF\nYp0VIHkxjEsK8VV2EQeYjYT+uD4sFhaGAFLdhRWRLVY2hSIkGUQlVNHu53uG\na+3ylRoEto1mWdDsSHGaMBS69GKxGro/IYX+e9sUpk6j7FjZEA7qTrUO8ia5\nrHUwXFBG13pfmdQ908xWHJF51jqFi7PEH9BEXrACUKnS1D9VSkPF+dWABRQq\nj9WaHGu+z8L5LLImBpV2R5jsYG+GspKHax0dYAg1HNzaulWuszQRvMUXnb4q\nV5lknUUrCLJ7gXZS1CeEBFFSSBIR2ft9UU1yfnRaf5Wqf17iG6wQOfU3JmYW\nQSJ/QuzExMQXmkuDRTKdDL7Bb7aXTeuJtwO2g1xy2AGRuUrC+cJG8Mi0NBgh\nkBPGM3k6CmMLabuPSp1/xUjBxYJBhzgVm+Ou4aKyz10xI4HSPP3GZxD8mUNL\nLuXo8iJjrZw6RW88OFDq/PQ+1Nx6ZFJpIYjWi5dcivvtzRtZmKJCLzdDHtys\nsm+ZxrW9YxAaB4W1Q/7BGcv2djYq1o5OnHOW/W+fzqPovFGGQ0sgAyk9kjrG\nBYGR1szHLJoUKbr7IwhsIBO1rExjJ8IxoU4n0OfKJFzo5FkzEujCCZjek05C\nfGxjqoEtce5ih7OvIq2ccyPXdIHdXkpIkVUMreshNy2gl8s8tf8H1B9IEKSr\n392E\r\n=jy+d\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing all applied filters and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: (filters) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: (filters) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3_1621593177231_0.9454407692127953","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"d3bdfb3b079cd8ea3cd5b1feb741cb64f5e463f5","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4.tgz","fileCount":31,"integrity":"sha512-0fEP8OPOvXwbFft1xmKJdm8bsjxkGBlgoFQIWX3FwXzuZisv6+NwfuNInAJWQ4Dd1+u4oW5XhsTRd1KS9lOGvw==","signatures":[{"sig":"MEUCIQCqoliS+slLOiqWTeMYg/SnD2DicgupxlYnsuJh5Up+nwIgCfvlkRz6Op7iCz1+es/Bqh2Lci1riEXnoBTVPTwJWFM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85219,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgp5NzCRA9TVsSAnZWagAAjCMP/RyG71vZJDGLBuxwxt5b\nYkTx5yfDB/0wD8LfULFn7UMnuYOJwJgEsQeHEsCllrQYeZFKvMQ67pPCj/xC\nqWDFbuGmA1NzbeAR8HKrnTHJSrF3w0m4CIqcFviXaMfTpQUgi07NclDPSnu3\n18w7lwlDjtpbUoOjmKZrfz0zimubKkldyX+ecsc+9QfatbEL3OGnRhYMxSj6\nHkaVDbK6IaYNxd3INbOtb6FRRCfKv4KIGtzItAKqXT4vyABb0mbE8MTCDAE7\nzcyjT+alk13mMvdC6/30UeEMOyHyRcL/FZQtxwrySKjcbDUwi2akTx4pWT9D\nTQ9TJywyHlbNiz9NZyPcDk+750witkT6zcINV2ftaYu4iz2RqjvSQMS9l66d\n0O7L2m/vdwdPnxQ1W28jHDuvZcs9Y6N5l5PMv5GrlBljttdoBVj/9vJcK/5F\nv93JIq7OecV29hFNbUC7xV8SP5XRLP4J17M1ADW6YcbQ7cLYI5w3Zu4yLwnG\nKTJQ9XaaBiN0+EZmF5K93NDsxzkZcmIk/R+IawWb0jccTRMGgVUDkJGcH9sC\nniClWUjcGyg6LWvlNZwkUFsmRHJphzfxQS0f2cHZGynDCPOJ9hHpQ42Ee9o/\njr0yM3B7LZhEjvpaSR3bBdQZvRn8pxl1haW2QnZs8HJ6NrWkbb1mymxTsJXm\nA0vL\r\n=RRKb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4_1621594995247_0.37657005714835945","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"d864e6ad2efd1e59946660c503af011950c9a46a","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5.tgz","fileCount":31,"integrity":"sha512-ZrJ342D+VUe4PdiIeCXGSSvtZYQ1U7GdpPj7sUnQI5sK5+nrR2AFOrP9R1gEdfmSlroyWMK+K1NXr5wN0WOu7g==","signatures":[{"sig":"MEUCIQCsf/YLYtXoDjg47b8tTN06/I2AuP0vUNG8+8G9LcnYIwIgKkzW6TBQ7i69VwDvRUPM5l6dWop49oWLjse8G389MHw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85228,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgp5i8CRA9TVsSAnZWagAAVPQQAJBn4H9sVixVSXmzz6Vo\ndvmngFsaJV4s2V4I7w9ap0z7k7LlgErulNIukCKBqLneuV8CvhvC/pOaRaTN\n5RYBugsIOHauPUlXukv5bLF7z2uv6v2x3SOoV+wY9hMPpFmbozBKY3S8M3XJ\nPOApaMN+00koZEwn+C3WAQJrw64ygCU4RFuRyX89HIMfmRNtaY2FRWSQrpLt\nEWWx+pQn712AgLyH8C6/SwF6PLpJEeyrb+WGqBBNaGoY4xkuN4NVKDbndEZf\nHqzpsutiUMhyN6kgVg8i1alW41EwIdPliss10HbI0Zmo4+NuMPfHB/foAd85\nmp1027fkUldlKvceeXvUAa9uWVeo/MdnhVcBlBSWmeJT5qxYVzHzXexuXdd1\ncHxDV6cDpmHKe2mVRQWUXeq53e9IS05E0T0eSCLPuIk/8aNuFWBej83h8R75\nm5sLoTlqp4uEBo2vpOjxmjim57zg+qtz/4PsPIYUMU03TFmzeKA8rlsJAV4K\nIAMO7jX+fBM6CPXZRvlIMAHmwNBc8RjNb7HWZM3EPaXxOmoGL3DHtDdkB5Q0\nd99OYwyEvHvv0ktVHQybZMnv2pVzPA2on5qBGg4ghOLurBhGxlCRxuzG/6NI\nBdPTiQX967oI69OlD5vtTDvYRWpiLpY7aLTwoN9I0EtSn01TSPa7m8vRL1uq\ns8uM\r\n=Hcw2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5_1621596348322_0.6433719453731914","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"e2bd78678d79712d970c20c6d308284ca274bbfa","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6.tgz","fileCount":31,"integrity":"sha512-+rCInBhMwM8viiFfRVqu0RDVWZn4KXBOh5rsV1c2UBUz9L/5RUVoOQwVaAYIGL2BQwINvCAqyKGo7CcG9ivNYg==","signatures":[{"sig":"MEQCIFsJ4JO3s2wHw3CbG1yVpal4mFIInQInaRdgNkrkaR6BAiBjI+yYbvwP2y5BrsObkmcafH2W1QXdXRtYBzw7ISb8/A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85297,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrOmBCRA9TVsSAnZWagAA3HoP+wUuoGmIavELuzkati63\n1LTjRot/g5CBuYMIAFsdpiBdj3fsFnZLfXXlOL7Dqo4+dirkzwioMTGMu/4B\nZlTwoVMOhXaQtKb1NkxMyia8UeSzmC6+mSaFcDPqnwEFdRRYatyXGcBVtIgN\nrgOhgWfMnxSsFEex5ODXUB72D54U6et8hji2PvNWKeRFK+80ZFU6GXGn9Dqj\nqx38olmptSgzAyVc6KiquOk3OqtDVD1Glh9EBYem33p9sdufPoL6B16mjLoQ\noxOwuF/Hf3QvRoBRvuXq8nc+V7CWnuGqcEIQ9vK+mL3aga7u4Y53y0KdIAeP\npeQ1CAf9+bRvoGu1qkKzuyI7KdAKhbn26feWaLSEdDfEaFturl8FdSVS5j6V\nNpC/qu9Kcq4rf+sqeDGeo5gjlLtTF8eyI2uAZkzmBvakUn8hDHVITHnEi9K0\nSF1kTyNWRdZFeNs3Qys2fri9cU51VBlwn2gNDIX2E7UgcUae86tGdQlL8P4S\n/46X2Q79/TlmL+H7S4DzTEu8n9ecz0SaWIRKz9M2VeP1L0UTCZc6DsMiiBha\nfk4DegESoZ/RajnNEx8wHa95DYiergPGxzPVXTiJonfn5AmHsBLx2ANEw0FH\n9CCl5RaroAizx/kY/E5FeVRLvytvJ9S9/QbZaDfP4f0UKMJW20dD912o67bg\npWhG\r\n=96JI\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6_1621944704807_0.9621810332451586","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"ae45a30f8e34ba22625a5bb1036661b9dad160e4","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7.tgz","fileCount":31,"integrity":"sha512-inzJOTWX+x0S6/zmC13dIVxJsnDFzl/q6mN1wRyk1rVBe8kk+30wMS1zNIWcRcCXjD7y8ExC3glGKyr5WNYBXA==","signatures":[{"sig":"MEUCIQCRgmsFAOFScehxX3txk8EgSf0MMiRu7QW9vB2HoX43MwIgGBhGhoaxYbLtYEYPXBmMbaP6gXfkQrzhgpYtogi/LyY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85627,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrQ5BCRA9TVsSAnZWagAAeQ8P/2sTsee35lRO4O7qVprf\no+1i/OVLUyWE/Z1y0VL3xlL200chpIPMKPN7n5BtvMuPoHr8lxr1Qe7QBCEh\n8c7RoQCG7w8DjhHFv4TVusPk1BmjZlVmg3HpTzdLFZcx5er1b6I6AtyvtzRT\nFKtrAg/R6U/Zx+7vjTSt1Yqt05wNRzr3IRnkR50oRTW4btUjeDF5cFNMgli0\nxcI3YVhpxfYWen5Gmjt/+92wWEGQdxGuMIUht7zac/5OudBLQbY54u1dTrMb\n+64iHMVfdLgV4zG7ob2iX9aDJbWRSoBLGHBQtRSM1a1LP1KM5ulS4EzUq9vo\notPEGWVy9nwCQCow5+5hAYZKkKkrqrN3KCFlJYlwreO92x0LN+AnMK+qvLVA\nbKDpQVuGXMAdfzpHWABfons3gj2ugtJXRDsTlEk85/COaGHqTmUmK2Q2y20q\nuyCUCtZ9vo4gVuZ/2w0uXSGB2tjw1PHsajHk/HeUj/mn4YbOUCead3YS1wbv\nKAGQWOVFcwqhGtqOSyJyxEjHCDEo/O0tc+3tjR64PyMJOKU+nDTnbS2DHWV7\nyxBaITJvnFslF7oEwZM4dqX1JZPhc3ilaXS2IdHlF5eZvM3oFD0Y4c3+us+0\nBTQYmgbOjB/ApzSbivTbBzwfXvn3k4vDOiOVv8OpvDshAHPxktinRfPFxyfW\nu1mo\r\n=C9Jl\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7_1621954112390_0.25522040365727205","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"4bf86cc95bdae2a15bca55216b643b394b06cc70","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8.tgz","fileCount":31,"integrity":"sha512-2R0GdS8+aMIxNhILPCsSRO3PmpKHf+YiHb3Daa2J3mPGEKCHt+/3kilBsft3ibMggNG/1eOupRJjgX6N5g3iLA==","signatures":[{"sig":"MEUCIQCU+vz9a/h1Zd9atT17uLzcDd53mziVYfCFOVtQNLQs8wIgFHIo2i+V1JOhgmaAlK97tXuhsWXMHDeSjx9Q8ihnX1o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85637,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrktpCRA9TVsSAnZWagAANdAQAIP7HfGqNwyHAEaFxnQm\nHm0TFSp4opdgFNfZw+ahAXZJcyRkTZKTgNAeDOfldr22gcDS9taUoTpy60/H\nWVaX3c0r55ltkah1iqjHHf1qscXawmF7dhWJi3t92Bu0Kpm0/HBHodviyuhb\nEQ2oE3nMNgH07LcSFE7C7odp3wLfZKctynRXNNHaG3vBNQdgovTQphOW+03/\nR7gbTlgy4eTXrbpaHKc8Nl0gbCeD33LRdcingWRXTBm7Wsyxuu67JV/umeZz\nq1Fu/NlkUln4y9ZgP9f+2mTcZ4o7d0flYyk8aZ+g1Q+zdwavwcpLom5BjE46\nTcVAFQP3/D5S47wD+cbQdbEuddvSeSb8QPQVJKaGH+Ox135sXCx5uQnwFSz8\ng497WdKY+M0hlQtCHPEDhJwJFqZfAzBgTCXPHsVI/ajp6+aRPJsp7fAsDCiJ\nYRUihDkadqrn/Il67Jw3B7nNx52AbbNmH1Kzo8I4RDZSsZX3wpSggV4RQtmu\nqFinzXI+QeRLZvUbzhYMkHQOi46fKtJzKpEArc9Q5fVhXy8fpJ5nQZQFcY3L\nYKFl6SQO78H8JaL1QNuiI6Xst2w0WXmv30urxOEEywhvRzKU9BrVYBJez5PG\nt6ZC8wfy+xgDFk1usEZy1tumYEWU/ZUUDh2AG58Ml9AxcFRee6EGRiUkFF+1\nuSyB\r\n=0+k9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8_1622035305301_0.3473438832493658","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"3746d0671b4c34297c68e585276104b97fc8df37","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9.tgz","fileCount":31,"integrity":"sha512-6z5nlAbO7nFA1TxVaZEiCXI+0ybohZ/0a4ka7D79XBbhVlEkKyKgTgHobvJVhmqi5QlpvBtkIihTqvd17w60BA==","signatures":[{"sig":"MEUCICXuJyxEbo9dBBvedNqUR+ODIO6DhxfYS29bWtE5wCEbAiEA+bZMLQdYC5aCiSzh1UFBaJFvE4SGgTBsf6bUMhU/Z9c=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":85564,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrlLiCRA9TVsSAnZWagAAwqMP/3PkrzEePQ93NLelvA71\n8063AHGG4ChxHRafJ0qWBpNgeYaX3d0OAeQGL6ah6JDkc7BkyNC4v3ztzWZv\nFfecKbf31Oj2L7G4IeLEIyygg8Ycynh7OnMCFj8nKf8bwVqHrNaF2q8Jrk+R\nH7vtFUpbnML0Wm0VA4Xk/M4WRx98UEoDnYkmu7XLD+/BaPscbzNw+skjIGKr\nZZMlA+IzgTQXnNY9GZ1uwjB2Ozd88pMgLXUAMH6RR/ONxosFEcCONQOMN0If\noV1/g/pqX34Ea/treKaykSRH0smT+omIbP9S2jDAnnK44mESnN+KoX7b6Zrk\n3Hc9luXfcMlRuNcgcGbZHfCjrkZdKJqUWXKBuUmhFyNrzELxwSoAEljQdNRT\nj3/VBOF6KI0hBQyfdZ67VkKxxdLG7W4muazYEmq/oNdXUN4sJUxu1Msm7eZ/\n9v9kC9Btq+ToiUe/V2K1u25vkX7W1KDGS/15Uk/FA/5SonP/7flnhkszVoM3\n7hZ29x/w4sS47TrSqx5WesgjF9FjN5AyuRoi9Ld03kMp+nQGdC+7AaAMiUEY\nFDebE0BZjx4ATTrMBAEzdQFIJ/nzPzVc0ctknJkX7/EHPoCWcSQqZjcJ2bsO\npxippiCO5nztbjI17PFgk9VmwjEvXPjIT9HkPlLPl5so7SjLLY+KsrhXD55L\nconk\r\n=tQzC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9_1622037218133_0.7886153730611343","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"fb7f822b37d50ab3a64ccc38b5cbc93a24764e3d","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10.tgz","fileCount":31,"integrity":"sha512-FWHpqSWP+TOp6IhyMpCOTjOSnOTDZA372lzF488X/UxRL0SbxOCgP+y0a2hPb2gKN1tcM6jQK7u8oceEhnYvlg==","signatures":[{"sig":"MEUCIQDd+1K0axtU2LvriHAvoZ67UP0w4TRCLZgd90DN1yFQgQIgYx/qwNn+NTCL5MFUSeQIZmqx5P9Ru93H56W091QB7co=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":88868,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrlxwCRA9TVsSAnZWagAAXvQP/2Yxl+O43qwLUL3f35zY\nFmu4RrVuivja66Dd8DAbo44Lk9sre5qEXWdiAy2xeF9gw4loaMadOvgPQEZh\n90INxPjEnP5OcwgEae09b0+10HgoDX3XuNIqcB8ToD+5ijAhDq+43grC+D8w\niv7/7mZ59zuGqAF+2b/j342Ss12g6VUwlyKogI66uf7CV0tgqMxc5xnvNyWb\nbF8Z4l5cimI+OFMZ7zJjYEyMveQbfYZG4hrqbSFTZLn9GvUFP0+/Vw2IaW44\nx4d90Tzu4nUZUqBIKfrot4ub2TPuU1k2+7pt/8Ir0Rg1+u0/kWL7Jdpy+A7y\n0uOCbfyUR/lyYAw0NKnnD7dvukmQZeWTbCqbzr4UR2pDQDdyA3pnbWxbcYqK\nZ+vw35ipVM7BHNCLY3XG2WBTz7pQ2+TMHMlkdJu9Ed4vVo+W3R0RWvUyzD+O\n77E1zyaICEmyOAymLCIygLIxu8u7/YOVnYY7OWm78EIsf3m7mayTwWY7Fudl\nOPLX8QLn1NlTDoVzwED1AqzqxG0hIeygemZOKP2aMOD44rMo0xzKsVtQDmhj\nDB/lAmbqi3kLGMs8AHH/ffwmM5q3kjn0GjXXd0uERw+pNq7pSSs0oLrQZM8O\nBnwrv4YKjoLHij+fwIqamlgqrQZKVbrZaC/N+4HDtfIy9CnE+kKL20viS+SK\ngdKn\r\n=55P5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `primitiveFilters` \\\n  use this group if you want to treat parameter as filter (e.g. clean it when filters are cleaned) but it's not a filter per se (it can be used to derive a filter or is a filter only if combined with another parameter)\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10_1622039664049_0.6797466114863708","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"567ab96ea98211dd3e3bcd1b8968915dae923f73","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11.tgz","fileCount":31,"integrity":"sha512-nwUAbirnK487cMKd0pP6mVn4igwQZCfkV/grbLYkzZ4vQFaHbk8WIzOAQTKJRQOUOmTRO5c70EKSD2yGKSX+7Q==","signatures":[{"sig":"MEUCIQCgPcLI1eXMtwd+l8rLtpng6CSx6TIPPbk54fGqDTzstgIgFqmyY0nYAOAx8bp7cOkYGTPz8v7f5BPAjd5PK4wb3rY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":86199,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgth81CRA9TVsSAnZWagAAQfEP+gN3LvyHOkBveb4U/9gU\n/9WZ2HXQS07dVNn/WwB1nmvzp5JGD3w70aMmfgituWxEiTRD4w0eocgtpC9p\n1HFjftQXxXlUXiScFdFTKKe5SpfMmozun+xGQTuNmxktA4w1FBS1Kzj29Ewz\nr5yNugWPf1lOb7FA/SZsyt9j0jssswHWrcgjYB3kizWRd3xrBSvLAHKn29Lg\neHHaHSpo4HsZ2USAASVVJ0qn50awNYzQOdHt6UvqMliMfakEXjVj1nsLiVeg\ngJoriNxWy7/XovVpmSixaAd5Ix48exVTrfwQCa3KRF5oHuIGnymImFhZDMUs\naHC2J8iox+C5nKxn7SrJz4UL2B8j0qcGKIrwTcI8cbcHaty79oR5ZDtjqNJ7\nio+X0adl0GyJSyW7bI6xd/RnQA52qbcY4MYwFJ1qNaVnMIcgCC5OJr5HJ7yq\nOn9LU7gvSBEyOtYe24wpqCul0NxhKzGzvvHtaqb5LZaU74bBP7uyd8oQD4el\niz3l998PJsaJKR6XjPJX0nm7nYk/mgssTTWTUi4d08qeqbb20vUeC5D83LNh\nwDUpLxc3fn2geFmTzDroP/PW0PeoZkT4ivBwpHN4h2SajumCGz3ISn+evETu\nKc4q6hFBPhRk97A9+TYEKx3FQf3XzAB28V2QeP18HZ54n6thOCCeQ9vBK5h+\nbqlH\r\n=q4ZL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11_1622548277165_0.27452423150496763","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"f71eacd895a97047809f1563d455b67bda1e9fda","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12.tgz","fileCount":31,"integrity":"sha512-X3Ua7OtWbzpMFPa10O2GKXDmeyF+Qy54INfiXVIPKSZ87kjVg9yxWS1iNb5aFNDx0DbJNHpFf4V0+qR4uIXIkw==","signatures":[{"sig":"MEQCIHGQ5LLbQ64lmIpW7/xkJo3wR+Q6/sS4ccNH/0rRwdVvAiBABFlk2SnqluaSvr14RT1LoHDFjgrxx65YkPVYx8QxSQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":86272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtiCuCRA9TVsSAnZWagAAcD4P/jlVWt3VxKYxgjGWWKCh\ns+5AhAnUgoSi/K9/wnygU48ifscP1svGDafYqbN58qK64uStCExRcKOlkzq4\njGQpvjJ6aqNhKCg/c8SBlG/c2tgD2PT1ZQdoBbH14wus4Q0ZyHIpamtJK54q\nPiPVSQc7qYOWAbFZQHsCnG/4mXJRyxywaT5XUqg/1VjXec8cRjc4ADdYEb3f\nZiM6RGq4q9oYU19l5n/cps2QkiVTt9/X9HGJ51K8h7NLcib0g91Q7J17ZP71\nbEEygURkoiNFddmF0qWy/5nAqZVpSMd3ny5J/ZTABTgQ38+g+KxLB4oM/mV1\nVOGEf3eZ9Haux9CMPaH5qGhVlJtX5AAl+WP8/rMg4BrixmFRcQQ1tsSSP5M0\n/GpiQA4vxSKHlzcrTSi56g+35UhHywnpEcqrrCOyxlMmuaO4dOiDPC83rtvE\nrlvCaQWPqdMPnzNiFcGNIeR2RNtru9DMK0YErRH1wt2lLH1+hV6dki/9Fqpa\nKruPfNNLy3U+rVzKVp9ZH31oktgbxoFkYziJKYwAySMDsCQo0I2IEcdQJrrG\n2JzJ3h0dSpsVbfMXjglZlUToLV4E/HRMakSagAw9Kxui6m5I0HUR/d7XwbPC\nYgerUr3axGueWK0laxOkjFijU8eJAeCVVCvGa6NrBy13eADXBzVoGT665sFE\nDSfl\r\n=/XoM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12_1622548654030_0.6585198342227245","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"02460a8ec5c4a16696ffeaa2864985c1dbca18a6","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13.tgz","fileCount":31,"integrity":"sha512-03K0fRrXvrWpoujcVmaD0sCsBRe/5BryPs7yEFak6j3dwGFPAOTCx1qcUy2xV+AEKOkk8qvEbWk2CbhNjDNnPg==","signatures":[{"sig":"MEQCIGr4RGTaD53MSl+VRiE/M1bHyRLu3YZzouHaXm7tdDb4AiAdz3Xs/MqpesQJD5EAWg8jexD2dU/DFMMPmrOL3G5iyg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":86544,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwIKPCRA9TVsSAnZWagAAd5oP/2u+fOM3Z6ym8hZJDZRR\nw++fmQ+OFO3rbjzKRncCRMCcFtjXgIx1mKh7LSQTFOPySTKv7YYvxAMn26YU\nNemawlydfWR9Wlx1Dtfu6krg1z3p7ds0Svi7TMbWjagVveQT+U3xLc8kzkwV\nWPoQoQWDDpGaqDzJRP8YZL7SESs2w6m137Anl5Z8UPAJ6Rd4OjUvnj34l589\nC4ls8TSSPXxhVUrfLxu438SszYKsPE4PEw7rLL+ltrOV/4YTydsBopnnqj7L\nv4aBw7NSU9/SQe1ySHsGYqWhp/dZsGzatKiDu1caXm/uFam2oF8urqkq8hHn\nH8Kx9hSj+xlCvs6i9hnhR31IGj9QJ0Lh9r9wDubSfkFaB1zMZKkKT8wwHXzB\nCyZxv95sSnRl6TRC9gxgQRnX2Ra8CZWn7EYO9lUEf3JsMU5f5Z7juxWvBC0o\nKZteWMK35vHdbPDFyPEAUXo7hxkiFigCAvtBkXFCv2fObUZP6GkoUszeRHRp\nVGFjUPaCHKZryiODnqvFC/X0ycXcRC7+5TsvVC0LPjEHjdoczvZoJ1k1Fq/5\nIuJgeqLu0yWkkKi+/xz5iKsQdae3iYznvU2kmAMDIAsvApkAUSnrywD5u5uo\nj3GUK/iopTbU6QAJNpaYQxa7hXKUfWFeEg7+6Cm9WebvDpgQPw39Vj4KmWzz\nWA8o\r\n=zg/x\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^17.0.3","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13_1623229071435_0.018832390953126055","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14":{"name":"@carforyou/search-parameters","version":"1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14","license":"MIT","_id":"@carforyou/search-parameters@1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"56c9d0656217c7505606693c982d6cd64444bc22","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14.tgz","fileCount":33,"integrity":"sha512-28rVHwqesQkqazoeQGahg9M59sL0XshqKXdNl/MYGHNAcGIIpN0RyRWhJYt28xJE7RGiA+P2aUBQb2ap7dxI0A==","signatures":[{"sig":"MEYCIQDCnCbIoLWWg+bn4p/OQSlmT02nhSVHE3zquqbSAc7pLwIhAIZ3xBgbWYUqY2rhWw53hunakwOPrTGWqmQEbROT+aBu","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":97906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwK7NCRA9TVsSAnZWagAAADoP/16BNYr6QPU8RboYynqM\nVt48UHYSSzI5jyOnzfFAGMNq1SS7dcHOt00pflZ9KB167a1MHC9d1wIyQ/3I\ndJD1h/HYhAJ5wLqo9oT2JQ9I3h97tdQyCiVwY7heaTT979evMoubYyhzvLwh\nYy1kAEATIKhCPmAiqEQoKjCBnnATv5c93t2QB2HU1OTT3wCTm//wn7lctrvP\nmuWSb5rF93yPeTJqrEv4b4QSKfwv2UThErMbUnzayeDTtLb1OFNT/b8N9peX\nkz9zaRU3k5cjcaoRb6pFw6O64JUkZuKZp9R+3hu/JRHPb2FZNqVrqKGmYkzC\nKKwjudtWMXMcjr+TLvvvtykybCqcR33YDGoRxsUq2tezUPV2BBSSyuM3HL4K\nKhhp8chf0otqI2GXnvU/TXEz8V25xRjqpMRc+MtvNp3GsFj6DtXnzDy67ogm\n6FuaRdrirbIhce8oPgCYBJH/73x6G3s8a7JkF/7kPjVImtIteiwY0P/Miwk6\n7iGx5apVehsWx+FG25Cx/4Ww0nNb01msPAM03Qdja2EsmZ7GQZDyVKNUY7kZ\nP6HRYCpRAEHtl+FONsG2bPwpUGpx3I3tn4AKASk2v962LeWnHSS+JFCEGHQH\nCRBUv6spblZgd+XXUKpJ/El6GEc0Tvclo83Et1NmQyqX1OaCSjLv9Wf0E/gK\ndbXh\r\n=uJic\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n### Shared definitions\nSince listing search is common in most of our projects this package exports basic filters and parameter encoding definitions. You can import `listingParametersEncodingDefinition` and `  listingSearchParametersClassification`.\n\nThey contain encoding and classification for the following filters:\n- `makeModelType`\n- `conditionType`\n- `gbdScore`\n- `bodyType`\n- `transmissionType`\n- `driveType`\n- `fuelType`\n\nas well as a classification for `sort` (`sortOrder` and  `sortType`) and `pagination` (`page` and `size`) parameters.\n\nYou can directly extend them in the project to add more filters and encoded parameters.\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14_1623240397086_0.876652316600941","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.0":{"name":"@carforyou/search-parameters","version":"1.0.0","license":"MIT","_id":"@carforyou/search-parameters@1.0.0","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"8705adbb1f5826361992a4905811e8fee8fd70f2","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.0.tgz","fileCount":33,"integrity":"sha512-+h+J9TMJEab34Zqge+1at6+GbG3BmCsGPVPVxUDLH3knr14U3lCBNWyq58/RbrUYj0Af+OlppVkutUEHwZHGIg==","signatures":[{"sig":"MEUCIDpAF6jPUv0xvH3P23BNTX48sjpepg1GS9oigN1sXbPUAiEAvtSlVabYnst0RxjOtAqMjKtjTokSf8KytFaSX4txxFs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":97859,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwcBZCRA9TVsSAnZWagAARc8P/0H+IXWgDPD0bXZR9yaR\nPhs9jNj20vY2JnVdNe56C+motz3ghoDXYwz09aXpDFIjK94gYHfoHA+aYo0B\nspuAKrc+uwsLEQGLgHrTKIJidVbkj6zX4waU2TcKKjgOFIrVio8/Jng41MPB\nstmZlq132+OvmGlgTMW6etXiRZeffl/crpaikbpXAfjJPSpSd747GbxdsADx\n2vtIae7CGOIvMQiGikcchvZM+MfoFvrCqn/lR/PkboVhTKXYNU7CgJXCI/Ja\n8BE9gbR47n2kFoZXW6WJjboEg1RacHOwRjFzpHuoGx64TauZ3u/i9re8WCwU\nEl1KNRGxF4k/7x6BCqRJj29sB+1x1DoVgmEE9rEggv6CVGljKQHI/KU59BJe\n8LPMzXOhtgEIy5aBah0ZaiWglUGeg/fHip1JocdS/kLX/rvkb6w0HcE7t6oV\nD3z5muGe7jV7XDTUm+R1yG7MPrjLM/Sz6jrlXbzVHKWeT3v4L0QAXDOfKGW6\n9EsJAWfPYvRn5/YfshnOEaBSYFwPJEfMZHRnJbUq4NzPYbZA1z0926uOmuSc\nSn2l52iE5/r1uuoXwnu1U8z/a5CzzqnbUQw76qu3DBYVzaaqBVe6P18yGsjF\nk+gP2Oa5OY7yVn0UFEsJxPcx6jCsJ+FjfxVfSbmcOOsod0ro5y8mwQm+WjE7\nCGBr\r\n=r1Us\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.0_1623310425469_0.7964080769878672","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1":{"name":"@carforyou/search-parameters","version":"1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"5190f11f462ea2866b2df618e357518f46184cd4","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1.tgz","fileCount":33,"integrity":"sha512-prQcBH7A23Av/cLdHnTGEyKNDYglCzO0PR9n3UE30nwQZrH0nNAHlP5V7gJ4jU8ohTCpDlnfQsyHRCfJZ3vwFQ==","signatures":[{"sig":"MEQCIAtd4xn9UyPJN5OGmb9c7qP2PcK8TUGq+YBKVXr9roqgAiBlefn6z4Sls5j9yY6DzI7rbiXuQh+UsCNhFFkZjq0jHg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":98677,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyIkRCRA9TVsSAnZWagAA6zAP/i5mz50h4GRU9+3lTzSg\ng/T+4k+hvNrB4CHTjpgHfwS0rbieg62+2Y5t6eEvpC5ggtjTPM4Vd2o5J/0P\nppdWgW4FGJ7H6fkP2A8zMyVuNm1OniiQ/ESysCk279MH90hruzOaUxLtq1t5\nElkRvYsYgvr8rKVVbQfUUgSIxzPrwUXDOckmjxAlB6nmG9vJGr7PT0VM71O4\nCq8Rtol4LdAt76tBR5Xv2J3rBMHbQ6+KZoqI8ZKNFYdcCbfxmFuFywTSzjjx\n4PG9z/8niuxITFr80GQ7ZcqBD3s58psfmtsiT5x4kBLEXyb7OlUGZwp70atS\ndpP3EcvizN4t9jOVDMp/1pTxxFodEbm8Xatqar2JDAtuhILJnK9MFJePWQxW\nCY5hpVc4noM/dTR6c+t07hlpBZ1W1+CKliMYb9/5p2dMIQfPTAqoWDZ9Ot0p\nnguQHwPyFQ1v0axxAneE2Mbfr58dAfhBA7zOEswMzyHf/P+Fks7onfZR4EEk\n0EvlvqTk4DuhsxdqWLxYjgvD1gk4UM9/nleVXU0d88WsVqiY9syxGbsU/+8x\nvGsVqw0abIIx3C9qAXdDJwDoy9+srLS4iELv6nhwmF04u3/W0SWLq1YmEo50\n8H0rc5MSGcmuK+kpXj9C/FmR4dy05g14dgj7sU8Wu3UNlNfE4GhhQXBxF+oS\nX0/N\r\n=QtIh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you pla to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `power`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: \"filters\",\n  hasImages: \"filters\",\n  listingType: \"filters\",\n  power: \"filters\",\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n### Shared definitions\nSince listing search is common in most of our projects this package exports basic filters and parameter encoding definitions. You can import `listingParametersEncodingDefinition` and `  listingSearchParametersClassification`.\n\nThey contain encoding and classification for the following filters:\n- `makeModelType`\n- `conditionType`\n- `gbdScore`\n- `bodyType`\n- `transmissionType`\n- `driveType`\n- `fuelType`\n\nas well as a classification for `sort` (`sortOrder` and  `sortType`) and `pagination` (`page` and `size`) parameters.\n\nYou can directly extend them in the project to add more filters and encoded parameters.\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1_1623755025020_0.23234825480775312","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.1":{"name":"@carforyou/search-parameters","version":"1.0.1","license":"MIT","_id":"@carforyou/search-parameters@1.0.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"c75d1397fb344e814d92daca4282bd5c395b5261","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.1.tgz","fileCount":33,"integrity":"sha512-BUx15nsbPiL5mOPRv+lpvtvxO7oVs9VfV7RaES+WNsdwObR6hQGJOf9joU8ZC633zrjBz6syLAKfULJamfBsHw==","signatures":[{"sig":"MEYCIQCOnUGgzJmNGHB+BcvoqG/as6XU2NaXBXqZ9A0gE9TRoAIhALldpG26/IkM2KiPYJAW/EfLVzuVhHTkZxWh7afm9A9I","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":99710,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyJL0CRA9TVsSAnZWagAAe48P/im/6AMdMzU6r18rmI6f\n1gbU439jsNGXVuPkYiry0elNhs4HPH1zi/+Bsl10DBD/eXHPaQHG1xFjGXxX\n0TXDCJgN4c6dykgs47GehZxR3iXScVuMKJ/iv1NKJpyUXeq3JP+G2J23yc59\nT66jIseXcpBnLPI0cPKDYcjclIRgAbQLNd2U6KljYv1uDbmIrGYNzx4Hzh1y\nkpb6qnBUbkTym2rWfrx8Mn8Y53m0mJIGBkOnpQDvpTCBGWMKkP2pTRun6DZn\nc8Yl8pkK6iZ3IZDepcxg3QJ7H+VyJGT1AXAASuCg8921AmV/VIU1TlXzjtQ2\ncIGYNaV617cXwcdXZ2ryijrQ/MeMN2r7rafZoLP12lpjXpuIVPymlj7mIsJv\nBunGi18LNXGnXpfLdG1LsyC35//mw3z5ecWSjyeLGIE7erHvh44JkTBOJdvw\nzoMHEuQxvVy2GM0ocpcdpPdXew0p6uUZzFrFBP2VaM+M9vuDdj+oIAFMuU2M\nI2ItRcCJ/7gdcn2DTTHPDZJhCpUp4eXAQUqK/0P80vF/X5XHQnwVeVH5atqY\n6isaJK/9m8i8v6/MUGl7Moi/YGjOlUl7gq5uHX4hdwHxdIt7iGa+kOpnW82N\nG4GmDsNanvdEp9jCMh48iV2FxXA6Qr473gQXsxSOKSNSscdUU1gpDo/we4gg\nwAaZ\r\n=BN5+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{"es-abstract":"^1.18.0-next.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.1_1623757556421_0.405346636747135","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"1.0.2":{"name":"@carforyou/search-parameters","version":"1.0.2","license":"MIT","_id":"@carforyou/search-parameters@1.0.2","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"11b406d87016fbd6cf42d970dc76bf0ffe5e3145","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-1.0.2.tgz","fileCount":33,"integrity":"sha512-Eh5prsjR9vppisIzdDoce97r78/oeniiHqYjqmT7ltSeSgvkaz0ryi1GlPbYanLknL/XeElKqwRKFrzAxrAw1g==","signatures":[{"sig":"MEQCIDNuNZacW8g3DqplBl06nbDTGONzyG0GjxW7WUD58ztBAiAc892Rq0MgW5o/jZzLau9Kp7btlSg4y8Veues33VlSww==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":99671,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg0cYvCRA9TVsSAnZWagAALK0P/AxZ36ljrB7VaesANu53\nw51pGTiWa0ZZen38hRP/mywa/wb9c4mwbAhxpnh8T1HUwHswRCoc3WHHlp3E\nAnh1rGehRTudXVQiGq9spf/lR11pLKBHqf58IkstIULTKCJXLfB0AT4cF26z\nsBo1iHV6J3NTo5Odo1c8sDP9wRT+kBfnq0is3z02lqjCESy0+N1/gqF3NTeF\n5rUqdBuCQ3taQjN1POH6+y1RxLhO8oJVHX5qZFGrj4nVZyHBOtuMRz1hEAed\nxOUk1jDn52NWxFL5HS0CFlqVkej0wgAm3tm6WntapwC8+Ed5x6xHBVSo5yb8\nsiMCEFw+eqtkFg5XkZ/E3GNEcwxxxqY93gfC3XCQGDQNZqJun5m4DEptJyn+\n4KbR9XKXPrNi8JVLLIvyG3YYhFPpnhAEHfQ5C/cey7F7IONKzogyU/zHNgFs\nmOdgVTHIq/2EfidmQui+PZDcBd/qSYArZv88Ld8ojDSww3r2a56qCfpXFLWw\nhQXfG4tu4u7TGFdygH6LESiqf+Aia/FbuE6JX2rGiz49oBX8lns9ypz046YO\nJ6VzWywiVR5XWpX2JHkaJi5ikavORHH5mohWm0Kh6cxJGf2vGEv/kanhgAc0\nstRBiEvs5NEpARJXBaqHcOUDruVMmTU49a6iR1rARyn9oz1durGNCeUOhlw5\naHij\r\n=9Esc\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_1.0.2_1624360494629_0.7270230014299468","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1":{"name":"@carforyou/search-parameters","version":"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1","license":"MIT","_id":"@carforyou/search-parameters@2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"5f6fce7709daebbc48c06ba10f19517f2a1ecee7","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1.tgz","fileCount":31,"integrity":"sha512-O190jwNYS+rMliDMbuYtZ5Kugp4qfF3/hwlFlw50v4M5nQLc1z6DXojy3TkirMrjGFNMmoQncwV2dxR+tssA8w==","signatures":[{"sig":"MEUCIQDMWLi98JT2ocZKOXwXmY80NwDJ7fZQocMUXicUtRBUPQIgEGsw3USPdlgpRtFcttXlYPO/AlKs4J18XDZgdoDkmF0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93365,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg1FapCRA9TVsSAnZWagAAXgcP/jtcHHWGRCaIRY6HbUa9\nW/1CDmfH91URGg4NFtZ9iJrMN3oay3dbVPN08LgIOuPQQfP/HB60PVHI7aPW\nyIByWWRwtDN2x6JlHIq0jVdFuCJ093O7XvRUDpTe2TSghuRSvEUtU2oZ4f/0\nT5V8oWlqQ4W570zjPrCb56Nwp8Rl4KE5prT04vXSvbs/BAaRV+ozUzmTx3k+\nDjSJThNGxutWZe6vMTzPh0L8XbwSvA7kx2m0mBcW3ePNb0pPhF0B1hZ+IUyt\nnegR6cLqeay9YEho6IsDfh7of7TpeVszs03hGQepUWUU37JrKPkzDaEY8YEX\nS6rfB2YyPpdNdsDcDdSik7QeG32i0eZpgr0dgqtFem9NiLgQk5qalmONXrhI\n8bgVtF8/D6kW2/P2x85rlh/OWRcVaYODt/4AwMOG8zaDM0QUOZOm4YIiWvTa\noUl8sdWP8rZJCcEpXmSs6cDZYOY0W5/dYgigCeI1PaaPiRqtnMUQ1Zvokyx8\nS6yRZ/YdRiDqWg8kM7ISwiHghlMefkBSk2FYAdu3jhO9fQ+OQVxMcWx5klyi\nvrcfUOR/+XRRvuWMrZbmG2D26qxQIfcEAYqkYiXrzTNr9L6FyeyYAqAmLQFi\niXcIOkYf28z/pvrV/z4AkJWIG7ixn3C84PAqHEf5nsd6TrPKVf3z3gjglOM8\nWPv7\r\n=Pj/6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are function. The argument the function is an object containing classified query and the result is the value of the derived filter.\n\n```typescript\nconst definition = {\n  isManual: ({ filters }) => {\n    switch (filters?.listingType) {\n      case ListingType.Manual:\n        return true\n      case ListingType.Imported:\n        return false\n    }\n  },\n  isPremium: ({ filters }) => filters?.listingType === ListingType.Premium\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1_1624528553368_0.0426630334357736","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2":{"name":"@carforyou/search-parameters","version":"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2","license":"MIT","_id":"@carforyou/search-parameters@2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"57c24a67cac3f098030a6ae254275bfcd35fb211","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2.tgz","fileCount":31,"integrity":"sha512-Nfj7Rgi2+NmbBW1sWuOM8eMP5w8+6iF/UZHSoSkhzveHKnfUyt+ljMXaVqdqOFpwkYXb8z/p1h031ng6PmqcJg==","signatures":[{"sig":"MEUCIQCznQjEXbHaj51DQTps+pha0igjrXamSGLzGzGLfjkoxQIgE9afBWpNMjCEhQmd5RbjNeK2KqirMfZKrPGY7BwBrW0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93703,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg2zNkCRA9TVsSAnZWagAApUYP/jCWLFYVMbfAqXNY10+C\naOsGgFXeX27vvmHunFUZA6OUwLE4J/etG/7LLL+fnhrILuvrEl+PZDA18eud\ntVfWpo/pAMWKXxkYPQp5IU+gahY/mRLEXjpfABocNrjx030usyQdaF/2NWh2\nCwpxn1xYB9UC9yviAgkWh9iXBbbeXifLjLWtpm664l3T5wykaVSLoEkaPDpH\nBejxvfyzMk+n7ffAgKoa5LQTzYTKxHo0txjDz+Pwx/DOPe8LhTtrV85RQkWU\nKY67+4xVRVPn9kbOidAPqn540BmTkX66wzeTZOzaE36zdDygDuMFq1o1Nq9w\nfQTnevsWfjUMekFbZW70+Eg3seZLW6hwtxoC7Kz16BqXIVh2+NYpZsKtnvRC\nyAHn1t726vAc0WMrRN47VSt2zKFsRLOFzvvdJWKMqMj4IQZcAA2uVmpZZ5De\n7qnMamsqI3dKMEMY3L3MVxSAFOfS96rBVwtZwyyR/tcAJH02GLBnwVzxbwJV\n+/RN+Qij4dpkqXn0f+FZRE3f+zWE2JFVOkT/Y5a6M1xP5DurhVPfcz7k/jiY\nZrbrWChDSD8Seiza8/O3W+H6TM52O3ZReLvwGJlrTgPMRhkDxk9rF0DdWwdz\npDOXaArALEVnAHQvKZSvnBtebhDqQhQg9tJ8x00gwynAzyoR3d7uvWjdQgFO\nKc0u\r\n=oOgS\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `power` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows to find listing with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `derive` - a function that derives the filter\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    derive: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2_1624978275855_0.15744433427072524","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3":{"name":"@carforyou/search-parameters","version":"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3","license":"MIT","_id":"@carforyou/search-parameters@2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"dc3f8c5d8014f16cb4565ac9740d4bf774438433","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3.tgz","fileCount":31,"integrity":"sha512-8zQ6C9RS85vM7p5EUWma1dernwPWtgksRgB9GDg18T4AHaMQhxc3NlP1/WJjk7y+8cW6f8KBuyBV8buIZxJwSA==","signatures":[{"sig":"MEUCICSI1FgWTWtcbMoZnvTCs0+0/G269pwNNVp/UHxJLX2xAiEA0ElwQ5J1hQcbX6dCr2FWNgMdW/bISy7efhwOQhncKSo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93929,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3sX8CRA9TVsSAnZWagAAaPEQAJw6kJ9lq+jZqkHNwY8I\nfwnQL0/XkZpDaYveXbNgn3Wy3ckUxRtB65VDEegnTGzgGY6rW5r8Rf3GV3Da\nGnvq7IMB/VaYcIIlXPfhYNZOg0YM9iMqLX/il8SYlUBSxHWrYf5mXKJM8QON\n4nwDX13Ft5Pl/C4NDeQ015ZHwc7AYeh/ZVH0K0/RzdkKCzjXH211NccKUmFh\n2OMX3gf6iotf5Lk/dCVPOlohfKXg3ODgIvpAI/1FfX5dYtrIj+h3C8v5YYb3\npb8TuSYiK07me0EW1H7oXaRffhSln5alfkiTqCENeGGDpLeN/5m1GfNcuMLJ\nMhqOpDRkolvom2dXS75LdnNscQiiEycYkyKpVXkTZbfGkaAXQHFH3IPJwVXY\nRYc2fLZ9jLqGxhgVdxmis5HlSo3SGbaYJsgBOCzSCCaU5JZUwuutfU9BpUlk\nqMdSiJuwtz+RthK6wiZ2TmR1khqnaIFVWPcU5i4sZi+CN2FX9cz375JiCHBj\nqNJ/wr+dw+YbypQzTVnQQLO9rlm3dbQd6xXYdLTFB8EWkix+eMGV5lbKV+ax\nI6t44yo2mDtuPoD+4Zet6t8gcGjdXqPWViJMdVaBvwgVj5FHLte5aZNYIZwA\n9dQeyUHrOIje80k+J61HZbjD2LygUlbQziu7BwDH3KMUu6VqhIulrW8UuSJB\nrK/8\r\n=duUG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3_1625212412487_0.9672150462223372","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4":{"name":"@carforyou/search-parameters","version":"2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4","license":"MIT","_id":"@carforyou/search-parameters@2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"2440a185ebb255cbd31918f1ab74dd28fd47a678","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4.tgz","fileCount":31,"integrity":"sha512-hiALkFp+8UImIKEpeyiTdozl092lag8nEMEPA0XDA6ywiDtq1bOwAjFgWiSyv5tAKUf9jcIL9DCKNLguul8/Fg==","signatures":[{"sig":"MEQCIGDVzuKCWv8BKbgxHGoaUShpJ/xhFnuC/i80nCxTApPgAiA9NunPH9u1AvKktobqHaO1As8spFcci4Bg4jrmAoityA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93929,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3sm4CRA9TVsSAnZWagAAO+EP/iTMSf8FI0E2OADr+KU2\nIHLJPl/HqezH4i+lEao86GYSztWFEV/Hc+YK+QioTfQvf6X856rnF889px1F\nquoaWPRbqg356KfKlULbNgad+kBlW3JTIEj+7CSbSSZ++wiehP+VuLUSVRUd\ncrXvcxyGk+mMZFKdGKzYCI9icwDDsFythalZGPjbKQRl27N69b7c2dmDrAHM\n9lMd1gEXr3ijQuQ+4zRW5uzzl7xw0Iar/OwUn2dU2Fmq+u7cQxiWl8N+JOVu\nPzl66wy7exWbOc5eNnsp0t+/AisecfPjMU+Fqbgtdjdz6gs7rN6kKUZgz7zV\ntboe0uqfTm8elzWdKOrnVbgUXh13u3DRC5UyHyzkcTYT+S/FLRYbjFUDOgZv\nTLy44/tYBfrRT9Jl0HgIhn4DZN9CdXrKl10hRjDGIoqORN6a/mY/SjFcjWUX\n+7ODbhSNBWNG14tnm/A/cfLPr9pRJZy+8Tq6pj2LWKcuY4/8hibeSzSVWIKz\n8QjL4ia0jlIz9OczsYQnQ1VxIQyLXO3m6b5jghdAmwkRSfCajMgfj0k9AzPh\n3BzzsvKLakcjOhuQ6yCK3siHqdHniNZxJpK/csn6cnUVJ7TpyQncnctHc4st\n3thGSb0VEMVxcY7mNY+z7wXIvG0YvBGv+iyjfEUQTjLUe6B7dlJ681wbaMeN\n7673\r\n=29P5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4_1625213368163_0.21575445078430544","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.0":{"name":"@carforyou/search-parameters","version":"2.0.0","license":"MIT","_id":"@carforyou/search-parameters@2.0.0","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"148bb5f12dc6778eaf4c654be39d1110bfbaa360","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.0.tgz","fileCount":31,"integrity":"sha512-w6J9gGDoxOcjsxik49xCYBDOYUrK9VtgxnR4kxJy4dZ5bUV2009TA3ALwqsUHfNH0aQrRY/PpnZihW86gJHuzg==","signatures":[{"sig":"MEUCIGtuW6c7BD/FGxZvuVNYkqL632mDtiZm+NaOkjAJjWwSAiEAza7phd4sKg5ct1+RQkfGYLi4nLUMGv0ss5VS8RPEKNw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":93867,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg5XIxCRA9TVsSAnZWagAAEBEP/16j8d+bWt2vzS/suAKE\nv5Xt75wzMDuntyaRaulaLE2qP0AH+ZKw/zAg6LPBGomvSUEL0+SIfllD1I8D\nGY08IHx7Ql0yLedLEcwuKXQh4arduZuOAc7s7fwVq3wfB2yPut6vHcWp0799\nQAXQP9BvbQC9b/hkCAAEv4IO1/3UAspanUjRm1Dq2bFYgLKDCB3WYxgF3Fud\nADrkSGedXue2rgYm+4N1n/ockS6XxpehBSjA68ZslRImJR+5EjlnkxBAK5LB\nXy8fXC9aop9kdaFcI/r2000oUHQ5vFz1GTYgpuqt/UNR2tpkv/mIKHSrMvXT\nFjSVVVYLpnaUacXyOz4NH7vFGH904/LUsbn/s8mQCvxxrkdbKjdXoafSaYC7\ncyEpLh9pR2GrKFG3QqGUuHlGQYqCoG+8heXDqBmGGwZiVRw2dsJbHwabL6Wm\n1UWRenp9KIbaOi76qT5klajHN8vVG8rxSpGtbYqWC3z/mDUHjE+SNzM+O5it\nf+IL5NUBPdrpDqduS6p34en/s8Gaa7fkFAZXDaaIE5Boe58WfbiGOGTeWF1q\nyYsnZXFbc3rY0pwa1S2eCeWsWb9JblVyS40YtQcN30OgEUR25OsXeFlLDvTz\nYIznHwo4N5E3SYuIbdcEY7Fc36BD31AoLk5TNJy2u4Jq5KsUW8nvfYip0cuE\n2X5l\r\n=yC1d\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.0_1625649713094_0.485962928254275","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1":{"name":"@carforyou/search-parameters","version":"2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1","license":"MIT","_id":"@carforyou/search-parameters@2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"929247384dbde579f4f4ee81f978cc138a212481","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1.tgz","fileCount":31,"integrity":"sha512-5XrogxX/bDgz+pHuhVhoDgHZwnkb6f2RpORUg7GNFe7wN2bV82+6LFZBbgXENpGUt2IfyxjxV59eExkoHz5/Aw==","signatures":[{"sig":"MEUCIEdHtzqQZXRaRoN3Z7WhgLJD85n+SfnnwC8nadWOy4QCAiEA+rzPipeC2rYSRPTSTRU/eBIQkdsFQc9JM0A78Mdj23Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":96775},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1_1632477202677_0.3187803940635483","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.1":{"name":"@carforyou/search-parameters","version":"2.0.1","license":"MIT","_id":"@carforyou/search-parameters@2.0.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"fd19f5621e00857514811dc449536e9a36931c12","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.1.tgz","fileCount":31,"integrity":"sha512-EfN/aPuSW1eLKJFjM+wRzZJff8Fdw5XEt4PJ0xG2vEXYcVieJW6AwLb6HO3zLcG+ORsUbvqvFhvKya8uYJlfOw==","signatures":[{"sig":"MEUCIQCPWnQw9YiEacFmfFMMblT48y/eXi5OQ96ANTieSauccgIgUxdDMOjQ/HMbmEN86KjEApaEb5V8GF7dIOe4QUGCUL4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":96709,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhzbYRCRA9TVsSAnZWagAAiGQP+gN9FFeuIkAsYd92GdfW\nkf15TIq51QNNBjorbOpMpTmKiHQSRSx/028LrLW8OwvqbZh6Cq2unj2hJ7V4\nM8Im96OK1F6MiYVS4qhzOW70V4XCriIG/R2ofHejMQpLRcwvbJxi2y0ecuhk\njyyHWyp5LER2XWZkvM9ownFjAEMsjzMBuFbKqjSr1d1glnnmrHTwrlzZ4xru\nvlol8aXbtL25ECsUl/cD7oEmhRyIPAsApeU6L3dNhgsf6hjjA6gb3ViFrR7k\n6zADncxhochuaJWShA7cW1MRUwcu9Fn4oqxEd/Mf1RsD7JLDX7P1fzOPAplb\nhyrZMH4QJ/b82zZdKvcI0sI6pkTEaO34W8B2XYj5mnBI10CPnTUIogAP0GIc\nz/QJQFDCfZOiROdRtTYzbSHmTMNUmNVdTTqPHUQahfiklyQUM2IaRw+Af4qj\nKsBsYu6uZVYyx13VD7Q/Po93ahg0hVtjFSfmCMCiKmiUV9d+AtUahn3PqNxO\npHwLpOfiw7dNeVGpQjXWOPwr5Sc88D3GxTFKz+xLg3rKyUmYZ1jPL4pVy4qJ\nT47bEeiTq9uDq8EDiOoHVPdSI2jK3Ndy1geSbkGhYc2ORDAFzm8ARgWN2ATS\n4TUBukwgrv9nbogvtxtkOlIwHdOyziH9VDbCfyejMGQycfEaT5FbMmry8o7F\nn1xo\r\n=YFHv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"14.17.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^26.4.2","next":"^10.1.3","react":"^16.14.0","ts-jest":"^26.3.0","react-dom":"^16.14.0","@pika/pack":"^0.5.0","typescript":"^4.0.0","@types/jest":"^26.0.10","@types/react":"^16.14.5","@types/react-dom":"^16.9.13","semantic-release":"^17.0.3","react-test-renderer":"^16.14.0","@pika/plugin-build-web":"^0.9.0","@testing-library/react":"^11.2.6","@pika/plugin-build-node":"^0.9.0","@carforyou/eslint-config":"3.1.2","@pika/plugin-ts-standard-pkg":"^0.9.0"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.1_1632816911980_0.37644173764652233","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1":{"name":"@carforyou/search-parameters","version":"2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1","license":"MIT","_id":"@carforyou/search-parameters@2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"3d55ab7c272108d35177d34b24b5ea687fc72b14","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1.tgz","fileCount":31,"integrity":"sha512-aKwD1wtAVfB2KEVy7LlC8NojGK9sPkpBrwoLw5Ja53mlw5/1V/v//EKn/HZLc6Xa4Vh/ni+M3Vs/KeN0r4UKqw==","signatures":[{"sig":"MEQCIBklpUr7AIKanWbKoL+bwH9wRs3dFyIhlEw0O30ArUFEAiAg7I5MjsFbzFBbf1jKsbDnk/yJ/x2xKRr0oTLZiPw3XQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":101416,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh3/hDCRA9TVsSAnZWagAATmYP/jXXm4qXMfJgtsJuSDcO\nfKQhFEeAuIS4EPp3I5oyOS9lcbWnfMVjXfNOMgijWBzKaMRLEkf53Wprxv52\nHPuTtyZRf1t9Qpyptdn8F9WT/Ra2VS3SaG4hvIxpLOjhECDwtzogLW5RXby6\n9bhy7OCFT8VVEQBpPP1/UYZkB+y3PuRErJ84kHp/knBUDH+wGvAaOEO3otkD\nX/B73nIu9WGXthpwkmwsgfhgR/u6xb2szpEVxsHsZP7dzfadVN28t5MS6r2z\ntGAuyt/IxmcNONIjJXHBf2HXYTQF4aTbbElOm3xNUXpZBuqfcXwjzPDTjr5i\ndgZwv+bNSbf1Httwj54tDWUqFl8ONfQVadEPWDsV/GE2tRG0X20oBfnSZDS9\n5gYfK5Q8zrANHwWts8YNJrV2AZ0Ez1rdNT6eYccuqBfhBR1kH2mq2JIPKn6y\nmqG7C8u5hvRQp/xo7n8bz6xAQNXNUeuiwyBwU224JJneXbrzbpZeomwGIti5\nY8HjWXMlH5zlcFyEuBZKesHpGvMuYFj3/J6Q95TjGcFAVjoSwCb7m0rO7XXC\nJMzIfVV8PcprsyKixfePEAX/dONwd8R83tyO5Dhjr1HePacwNtFNKLCrCc0i\nL16zS4naExKBZE502+jYgbK+i4x3uHJs11t/vcs2dbIVGbe/Mvr1K5Nolp1a\nJUM4\r\n=+hJ9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist-node/index.js","pika":true,"types":"dist-types/index.d.ts","module":"dist-web/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg/pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","source":"dist-src/index.js","_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"16.13.1","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"26.6.3","next":"^10.1.3","react":"16.14.0","ts-jest":"26.5.6","react-dom":"16.14.0","@pika/pack":"0.5.0","typescript":"4.5.4","@types/jest":"26.0.24","@types/react":"16.14.21","@types/react-dom":"16.9.14","semantic-release":"17.4.7","react-test-renderer":"16.14.0","@pika/plugin-build-web":"0.9.2","@testing-library/react":"12.1.2","@pika/plugin-build-node":"0.9.2","@carforyou/eslint-config":"3.1.23","@pika/plugin-ts-standard-pkg":"0.9.2"},"peerDependencies":{"next":">= 10.0.0","react":">= 16.14.0","react-dom":">=16.14.0"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1_1642068034814_0.07306831227121524","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1":{"name":"@carforyou/search-parameters","version":"2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1","author":{"name":"CAR FOR YOU"},"license":"MIT","_id":"@carforyou/search-parameters@2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"38abfef02a9961fa65f68bf8cca835a3aa5fff40","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1.tgz","fileCount":45,"integrity":"sha512-d8uysIX7+arlCRnIi3zlkLGZOQJu0cFXn9fh9xQAvxW5yDjESpZoWdoGiIvsjoV41SilBhPE0s8DCLbeLMIGFw==","signatures":[{"sig":"MEUCIH/0JagLJq0XxBXRlGKIfb8Oq5UB0Rk7yGO7EdCbvv1lAiEA5SR5O1QSpJllw0czmZ3/kCMUt19pEvb7JcRmCFg0/lo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":64558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh6Y5yCRA9TVsSAnZWagAAe0kQAIUEs5eI43+n2h8z6iNR\nKQ7KciAu6o0ZU8igk8ICPPBxoyyJ2Qqzg1ZJdpqqwykpjGpMamA7JXlVSm8v\nEQ8VDKJc9Ks+z8iuRe5m4nnTK/Zlu/GdulXovHq07VIUV1ofGX9W7Qr+UTB1\nKcqLnJm+wGf7m/+5oKJfFmS1fWmmkDK/CkMh2pe+UEtOvfGVb56UqluLRBT8\nUoBj5MVFIGMqYfCzsHM4hbMXbtWtbysZZknxq6zro9RAg9PI1QxGcjnLkX6/\nfrJSZlUFCw91hV76P/qvRLRc3EV08Iq0drJvuOZmktyWINoISv0DVnk3QtQf\nIHls81tHTnvIhLkpA1vQhd64MKqSpqLjA0SCqCeqhVqGxBH9+pMP3vELzYBk\n5tvvz3CBPXBRCqe+w1EPo+l11+k9ckxNnj08idy/I83fmEsxspSrBV78WwOg\n0Sysh/HshZs5vdSaibm9fUcibv73o1O0Z3qivasGBC6lYyNjzogvhcHK/7jQ\ngz5/3eZsCYp6SakTqF+6GQQ9sCknQhm/4C8/xjK/gParag/YsB3zNgMyZ4Dd\nyoYkGBm4aITOnBy7gr10VAviavpgjAUhnT24o3nhNEesUWskRcyJ39sdopzz\nc7ZFeFG+PnMmEhiciW4fRQBjTBSuI2EzqyiF5FmKeoWY/4cpYXPv9DndY/sI\nwyXr\r\n=dE+w\r\n-----END PGP SIGNATURE-----\r\n"},"main":"pkg/cjs/index.js","types":"pkg/types/index.d.ts","module":"pkg/esm/index.js","readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","gitHead":"10457f2e4819d2f1cb44fbc2779ae557b76491a0","scripts":{"lint":"eslint --ext ts,js,tsx,jsx,json .","test":"jest","build":"rimraf pkg && rollup -c && tsc --outDir pkg/types --emitDeclarationOnly --declaration","format":"npm run lint -- --fix","version":"npm run build","typecheck":"tsc --noEmit","test:debug":"node --inspect-brk --inspect=127.0.0.1:9229 ./node_modules/jest/bin/jest.js --runInBand"},"_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"16.13.2","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"26.6.3","next":"12.0.7","react":"17.0.2","rimraf":"3.0.2","ts-jest":"26.5.6","react-dom":"17.0.2","typescript":"4.5.4","@types/jest":"26.0.24","@types/react":"16.14.21","@types/react-dom":"16.9.14","semantic-release":"17.4.7","@testing-library/react":"12.1.2","@rollup/plugin-commonjs":"21.0.1","@carforyou/eslint-config":"4.0.7","@rollup/plugin-typescript":"8.3.0","@rollup/plugin-node-resolve":"13.0.6"},"peerDependencies":{"next":">=10.0.0","react":">=17","react-dom":">=17"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1_1642696305934_0.6153025556446388","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"},"2.0.2":{"name":"@carforyou/search-parameters","version":"2.0.2","author":{"name":"CAR FOR YOU"},"license":"MIT","_id":"@carforyou/search-parameters@2.0.2","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"dist":{"shasum":"c7af162ad2c2085a34457fafbfab967625f8477a","tarball":"https://registry.npmjs.org/@carforyou/search-parameters/-/search-parameters-2.0.2.tgz","fileCount":45,"integrity":"sha512-BaFgEEod6TS/5tgCJzjzu/RXcCy57Jnyc7QiV6V/6/WZws1WNEYBW8rTQml7iSX2ucjU0VXQEl5uS+Zk5xFP0Q==","signatures":[{"sig":"MEYCIQCveC19khBNkFWDuaaNFUy/2UunmovupWJchVlv0ty/NgIhAIiUcNZauKRmZAERuPMi8iAHpYvRSJOXH+hKlB/5yTIG","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":64504,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh6niECRA9TVsSAnZWagAAx4kP+QEwh0OBRFm581GHI4hi\nTWjATz5U09sARsTvFX6osBOaQG1Q4SWWd1x4UKSW2x0fQbw2enCy5Qncblye\n6dq1vPOnEU2O3Mtd6jBcD7lefoTCfoq7YUgcPti3nohqwR/4iOxqxhOkax67\nJjG0Ndkh6rlRsRTev79nsCs4fThYvsWLoScYaweJybXyNr4CLoM5HTEIgxdC\ng98Ov85ANkDVODrwqRag1P9it2pDUp4KTdDA3a2wlZuzyzWmUclqXeOLbOlm\nfqnxNHZUXibgcOxvTuCmjmW9wAVnN0gLlAUOEyDD9HiEmty840RNGoTAPHuZ\nljI5oXRtR+UVgrqg4ZeFSapJr+HqiloPByGfIrqpwdS0oHcslf0yyrW6W0co\nBJ695pMMaeFDqbCltyCIlEId2dpDqBPSTB+WwaxmlWkOMEcAQwqiJQcjRhB9\nwCh7cMwDaMnQ21YqJ9Sx6jmdTVyYlWXlEaGITsjf3XGLqqVpPAjeG6TgHmBM\nWztlThK0j1AtpsvibNbl60236+bzY1co+oiOg2+V4/G7TZnCVEmRlCax4PW/\ncdQnrIxlpBpVfrynwOKIAhhx30OPb6cK1YM8GfkkjlR2a0FqJNVNQVufNid5\nfNqw6TxS//3wt1bwYYcDqmlO0fcRKPS6a5lbl0b1NN5ulLLciDRd7jPTU9A3\ncDoq\r\n=WBj1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"pkg/cjs/index.js","types":"pkg/types/index.d.ts","module":"pkg/esm/index.js","gitHead":"7136db11b2d03678094b33718b642031928d87ec","scripts":{"lint":"eslint --ext ts,js,tsx,jsx,json .","test":"jest","build":"rimraf pkg && rollup -c && tsc --outDir pkg/types --emitDeclarationOnly --declaration","format":"npm run lint -- --fix","version":"npm run build","typecheck":"tsc --noEmit","test:debug":"node --inspect-brk --inspect=127.0.0.1:9229 ./node_modules/jest/bin/jest.js --runInBand"},"_npmUser":{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},"repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"_npmVersion":"7.8.0","description":"A package that helps with search parameters handling","directories":{},"sideEffects":false,"_nodeVersion":"16.13.2","_hasShrinkwrap":false,"devDependencies":{"jest":"26.6.3","next":"12.0.7","react":"17.0.2","rimraf":"3.0.2","ts-jest":"26.5.6","react-dom":"17.0.2","typescript":"4.5.4","@types/jest":"26.0.24","@types/react":"16.14.21","@types/react-dom":"16.9.14","semantic-release":"17.4.7","@testing-library/react":"12.1.2","@rollup/plugin-commonjs":"21.0.1","@carforyou/eslint-config":"4.0.7","@rollup/plugin-typescript":"8.3.0","@rollup/plugin-node-resolve":"13.0.6"},"peerDependencies":{"next":">=10.0.0","react":">=17","react-dom":">=17"},"_npmOperationalInternal":{"tmp":"tmp/search-parameters_2.0.2_1642756228034_0.14008142861437078","host":"s3://npm-registry-packages"},"deprecated":"Platform was closed down and no longer maintained"}},"time":{"created":"2021-04-13T16:48:51.928Z","modified":"2024-11-18T10:39:42.072Z","1.0.0-parameters-encoding-eb9fe871dbffd2c5124e6c2ffed3b10d5d4915d3.1":"2021-04-13T16:48:52.267Z","1.0.0-parameters-encoding-ecb0c48a48a1202bb673f325b707d9daca76f821.1":"2021-04-14T07:58:47.443Z","1.0.0-v1-ddc6fd62ec5981f0f51f9f6ae6eabef289221955.1":"2021-04-14T08:01:14.547Z","1.0.0-parameter-classification-08f4e468cf7322b10dd25e8d5b53b8ab6c459083.1":"2021-04-14T13:46:25.227Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.1":"2021-04-15T07:30:58.107Z","1.0.0-search-context-348421e74688878682929e7f13b812f9eb10530c.1":"2021-04-16T12:28:37.213Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.2":"2021-05-12T07:40:49.175Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.3":"2021-05-21T10:32:57.399Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.4":"2021-05-21T11:03:15.368Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.5":"2021-05-21T11:25:48.471Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.6":"2021-05-25T12:11:44.923Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.7":"2021-05-25T14:48:32.630Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.8":"2021-05-26T13:21:45.471Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.9":"2021-05-26T13:53:38.330Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.10":"2021-05-26T14:34:24.188Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.11":"2021-06-01T11:51:17.323Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.12":"2021-06-01T11:57:34.150Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.13":"2021-06-09T08:57:51.554Z","1.0.0-v1-f604833233e2fbb124ced73f4deaefc1af66dedc.14":"2021-06-09T12:06:37.322Z","1.0.0":"2021-06-10T07:33:45.628Z","1.0.1-fix-remove-empty-elements-from-arrays-1598cc8de4160d4068dde78d8bd9838295096faf.1":"2021-06-15T11:03:45.213Z","1.0.1":"2021-06-15T11:45:56.581Z","1.0.2":"2021-06-22T11:14:54.746Z","2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.1":"2021-06-24T09:55:53.532Z","2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.2":"2021-06-29T14:51:16.007Z","2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.3":"2021-07-02T07:53:32.620Z","2.0.0-force-filter-label-b02b2dfcf9ac93cd42aa707418f871be2e318be1.4":"2021-07-02T08:09:28.288Z","2.0.0":"2021-07-07T09:21:53.218Z","2.0.1-remove-derived-filters-c344b2b0bfcd99f60c14d09e2fc0fb256521e3c4.1":"2021-09-24T09:53:22.832Z","2.0.1":"2021-09-28T08:15:12.192Z","2.1.0-callback-mode-for-client-side-search-c8d49ed8d578bfa134e4d8994d38083dc9213a23.1":"2022-01-13T10:00:35.091Z","2.0.2-rollup-pkg-10457f2e4819d2f1cb44fbc2779ae557b76491a0.1":"2022-01-20T16:31:46.108Z","2.0.2":"2022-01-21T09:10:28.152Z"},"bugs":{"url":"https://github.com/carforyou/carforyou-search-parameters-pkg/issues"},"author":{"name":"CAR FOR YOU"},"license":"MIT","homepage":"https://github.com/carforyou/carforyou-search-parameters-pkg#readme","repository":{"url":"git+https://github.com/carforyou/carforyou-search-parameters-pkg.git","type":"git"},"description":"A package that helps with search parameters handling","maintainers":[{"name":"carforyou-engineering","email":"engineering@carforyou.ch"},{"name":"lkappeler","email":"me@lnk.codes"}],"readme":"# CAR FOR YOU Search Parameters Handling\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n\nThis package deals with concerns regarding search query and search parameters for different things that you can search in the CAR FOR YOU universe.\n\n## Overview\n### Parameters processing\n\n<p align=\"center\">\n  <img alt=\"parameters processing\" src=\"docs/parameters-processing.png\" />\n</p>\n\n1. **Query Decoding**\\\n  In this step, the parameters that were encoded are converted back to their rich forms.\\\n  Currently, the following encodings are supported:\n\n    - array parameters (encoded as comma-separated strings)\n    - mapping strings to enums (`\"manual\"` to `ListingType.Manual`)\n    - joining multi-field values (e.g. make, model & type filter, values with a unit, dates, etc.)\n\n    After this step, the parameters are in the format expected by other parts of the application\n\n2. **Parameters Classification**\\\n  In this step parameters are assigned to groups related to their functions:\n\n    - `pagination`\n    - `sort`\n    - `filters`\n    - `others`\n\n    After this step, the parameters are in the format expected by the application and the API client.\n\n### Search context\n\nThe `SearchContext` has two functions:\n\n  - sharing classified parameters down the component tree\\\n    This reduces the need for props drilling and makes it easier to render all the components that depend on the search query\n\n  - handling changes to search-related parameters\\\n    The context provides methods to handle modification of the search query (e.g. applying a new filter). This way, they are all kept in one place and are easier to handle.\n\n## Usage\n\n### Query decoding/encoding\n\nThis package provides a way to decode/encode the basic query parameters. The following cases are supported:\n\n  - booleans\n  ```typescript\n  {\n    kind: \"boolean\"\n  }\n  ```\n  - enums\n  ```typescript\n  {\n    kind: \"enum\",\n    mapping: {\n      V1: MyEnum.Value1,\n      V2: MyEnum.Value2,\n    }\n  }\n  ```\n  - combined parameters \\\n  A combined parameter is a multi-field parameter that is passed as a single URL parameter (e.g. a value with a unit). The fields are separated by the pipe (`|`).\n  ```typescript\n  {\n    kind: \"combined\",\n    definition: {\n      fields: [\n        {\n          name: \"value\",\n          // an optional conversion function, default is identity\n          convert: Number\n        },\n        {\n          name: \"unit\"\n        }\n      ],\n      // function that ensures that the decoded object is valid\n      // if invalid parameter is passed it will be filtered out\n      isValid: ({ value, unit }) => value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n  ```\n  - dates \\\n  Dates are a special type of combined parameters - they have `year` and `month` `Number` fields that are separated by a dash (`-`).\n  ```typescript\n  {\n    kind: \"date\",\n  }\n  ```\n  - array parameters \\\n  The elements of the array are comma (`,`) separated.\n  ```typescript\n  {\n    kind: \"array\",\n    // an optional encoding of array elements\n    // it can define either `enum` or `combined` encoding\n    elementEncoding: { ... }\n  }\n  ```\n\n  This package provides a `decodeParams` function that decodes the parameters and a dual `encodeParams` function that reverses the process. Both functions are higher-order and require encoding definition to be passed to them. This is useful if you plan to reuse your encoding/decoding function across the project.\n\n#### How to use it in practice?\n\n##### Definition description\nLet's say that you have the following parameters you want to handle:\n- `hasImages` - is a boolean\n- `bodyType` - is an array of strings\n- `listingType` - is an enum in the application. Values are `imported` and `manual`\n- `powerTo` - is a number value with a unit. The `unit` can be either `kW` or `HP`\n\n##### Step 1. Creating the definition\nAn encoding definition is an object whose keys are parameter names, and values are descriptions of encoding of said parameters. Any which don't have encoding defined will just be passed through as they appear (i.e. they won't be encoded).\n\n```typescript\nenum ListingType {\n  Imported = \"imported\",\n  Manual = \"manual\",\n}\n\nconst definition = {\n  hasImages: {\n    kind: \"boolean\"\n  },\n  bodyType: {\n    kind: \"array\"\n    // no element encoding here since we want strings\n  },\n  listingType: {\n    kind: \"enum\",\n    // describes how to map strings to enum values\n    mapping: {\n      manual: ListingType.Manual,\n      imported: ListingType.Imported,\n    }\n  },\n  powerTo: {\n    kind: \"combined\",\n    definition: {\n      // this will separate fields in the string form\n      separator: \"|\",\n      fields: [\n        {\n          fieldName: \"value\",\n          // we want to have numbers\n          convert: Number\n        },\n        {\n          fieldName: \"unit\"\n        }\n      ],\n      // zero or negative power doesn't make sense\n      // we also only support two units\n      isValid: ({ value, unit }) =>\n        value > 0 && [\"kW\", \"HP\"].includes(unit),\n    }\n  }\n}\n```\n\n\n##### Step 2. Decoding the parameters\n\nLet's say those are our URL parameters:\n\n```typescript\nconst parameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\nTo decode them we would:\n\n```typescript\nimport { decodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the decoding function\nconst decodingFunction = decodeParams(definition)\n\nconst decodedParameters = decodingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n}\n```\n\n##### Step 3. Encoding the parameters\nIf you would need to generate a link with some parameters, you can convert them back:\n\n```typescript\nimport { encodeParams } from \"@carforyou/search-parameters\"\n\n// optional if you want to reuse the encoding function\nconst encodingFunction = encodeParams(definition)\n\nconst encodedParameters = decodingFunction(decodedParameters)\n```\n\nThis will yield:\n\n```typescript\nconst encodedParameters = {\n  hasImages: \"true\",\n  bodyType: \"coupe,cabriolet\",\n  listingType: \"manual\",\n  powerTo: \"150|kW\"\n}\n```\n\n### Parameters classification\n\nThis package provides a way to group related search parameters (classify them). The following cases are support\n\n  - `pagination`\n  - `filters`\n  - `sort`\n  - `other` \\\n  this group captures all the parameters which weren't classified\n  - `skip` \\\n  this removes a parameter from classification. This can be useful when you're dealing with parameters that you want the framework to handle (e.g. `language` that is handled by `i18n` framework)\n\nSince it's desirable to know how to render filter value as a tag either to visualize applied filters better or to enable clearing single filters more easily when you want to classify a parameter as a filter, you need to provide `getLabel` method as well. It takes the current filter value as an argument and returns a string or an array of strings (think about multiple selection filters). You can also pass an optional argument containing:\n- `t` - translation function\n- `mappings` - a collection of function maps keys to specific values (think `makeKey` - `make.name` mapping)\n\nThis package provides `classifyParams` that classifies the parameters and a dual `toDecodedParam` function that reverses (flattens) the classification. `classifyParams` is a higher-order function that requires classification to be passed to it. This is useful if you plan to reuse the classification function within the project. Values considered as empty (`null`, `undefined`, `\"\"` and `[]`) will be removed during classification.\n\n#### How to use it in practice\n\n##### Classification description\n\nLet's say that we have following parameters:\n- `page` - current page of the paginated request\n- `size` - page size\n- `sortOrder` - ascending or descending sorting\n- `sortType` - way the data is sorted\n- `language` - that you want to leave to `i18n` to handle\n- a few filters:\n  - `bodyType`\n  - `hasImages`\n  - `listingType`\n  - `powerTo`\n  - `cityId`\n\n##### Step 1. Creating the classification\nA parameter classification is an object whose keys are parameter names and values are classification groups. Any parameter for which classification is not defined will belong to `other` group by default.\n\n```typescript\nconst classification = {\n  page: \"pagination\",\n  size: \"pagination\",\n  sortOrder: \"sort\",\n  sortType: \"sort\",\n  language: \"skip\",\n  bodyType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value.map((bodyType) => t(`bodyTypes.${bodyType}`)),\n  },\n  hasImages: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>\n      value ? t(\"hasImages\") : t(\"noImages\"),\n  },\n  listingType: {\n    kind: \"filters\",\n    getLabel: (value, { t }) =>  t(`listingTypes.${value}`),\n  },\n  powerTo: {\n    kind: \"filters\",\n    // powerTo is a combined parameter as defined above\n    getLabel: ({ value, unit }) => `max: ${value} ${unit}`,\n  },\n  cityId: {\n    kind: \"filters\",\n    getLabel: (value, mappings: { getCityName }) => getCityName({ cityId: value })\n  }\n}\n```\n##### Step 2. Classifying the parameters\n\nLet's say those are our parameters:\n\n```typescript\n{\n  language: \"de\",\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\nTo classify them we would:\n\n```typescript\nimport { classifyParams } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the classification function\nconst classificationFunction = classifyParams(classification)\nconst classifiedParameters = classificationFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  pagination: {\n    page: 1,\n    size: 5,\n  },\n  sort: {\n    sortOrder: \"ASC\",\n    sortType: \"RELEVANCE\",\n  },\n  filters: {\n    hasImages: true,\n    bodyType: [\"coupe\", \"cabriolet\"],\n    listingType: ListingType.manual,\n    powerTo: { value: 150, unit: \"kW\" },\n  },\n  other: {\n    utm_campaign: \"i am utm campaign\",\n  }\n}\n```\n\n##### Step 3. Flattening the query\n\nIf you need to generate a link with some parameters you can reverse the classification:\n\n```typescript\nimport { toDecodedParams } from \"@carforyou/search-parameters\"\n\nconst flattenedQuery = toDecodedParams(classifiedParameters)\n```\n\nThis will yield:\n\n```typescript\n{\n  page: 1,\n  size: 5,\n  sortOrder: \"ASC\",\n  sortType: \"RELEVANCE\",\n  hasImages: true,\n  bodyType: [\"coupe\", \"cabriolet\"],\n  listingType: ListingType.manual,\n  powerTo: { value: 150, unit: \"kW\" },\n  utm_campaign: \"i am utm campaign\",\n}\n```\n\n### Deriving filters\n\nSometimes the URL parameters do not map 1-1 to the filters that you use. For example, one parameter needs be translated to multiple filters or mapped to another field.\nTo this end `deriveFilters` method provided by the package can be used. It is a higher-order function that requires a definition. This is useful if you plan to reuse it across the project.\n\n##### Example description\n\nWe want to allow user filtering by `ListingType` while `manual` and `imported` correspond directly to a `manual` filter there is also an additional `premium` type that allows finding listings with promotional features enabled.\n\n##### Step 1. Defining how to derive filters\nA derived filters definition is an object whose keys are parameters names and values are an object containing:\n  `getValue` - a function that derives the filter value\n    The argument the function is an object containing classified query and the result is the value of the derived filter.\n  `getLabel` - a function that generates the label for the filter\n    Similar to the one used in parameter classification\n\n\n\n```typescript\nconst definition = {\n  isManual: {\n    getValue: ({ filters }) => {\n      switch (filters?.listingType) {\n        case ListingType.Manual:\n          return true\n        case ListingType.Imported:\n          return false\n      }\n    },\n    getLabel: (value) => (value ? \"Manual\" : \"Imported\"),\n  },\n  isPremium: {\n    derive: ({ filters }) => filters?.listingType === ListingType.Premium,\n    getLabel: (value) => (value ? \"Premium\" : \"Non-premium\"),\n  },\n}\n```\n\n#### Step 2. Deriving the filters\nLet's say we have query (**note** that this is post-classification):\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\nTo derive the filters:\n\n```typescript\nimport { deriveFilters } from \"@carforyou/search-parameters\"\n// optional if you want to reuse the deriving function\nconst derivingFunction = deriveFilters(definition)\n\nconst queryWithDerivedFilters = derivingFunction(parameters)\n```\n\nThis will yield:\n\n```typescript\nconst classifiedQuery = {\n  filters: {\n    listingType: ListingType.Imported,\n  },\n  derivedFilters: {\n    isManual: true,\n    isPremium: false,\n  }\n  pagination: {},\n  sort: {},\n  others: {},\n}\n```\n\n### Sharing and modifying the search query\n\nTo share and allow modifying the search query `SearchQueryContext` can be used.\nYou would render the provider. The provider accepts two props:\n  - `searchQuery` - is a classified search query\n  - `buildSearchPath` - is a function that returns a search path based on a decoded query\\\n  When the query is modified (e.g. by applying new filter) this is the page the user will navigate to.\n\n```typescript\nimport {\n  SearchQueryProvider,\n  decodeParams,\n  encodeParams,\n  classifyParams,\n  deriveFilters\n} from \"@carforyou/search-parameters\"\n\nconst SearchPage = ({ searchQuery, searchResult }) => {\n  return (\n    <SearchQueryProvider\n      searchQuery={searchQuery}\n      buildSearchPath={(newQuery) =>\n        `/search?${toQueryString(encodeParams(encodingDefinition)(newQuery))}`\n      }\n    >\n      // rest of the search page\n    </SearchQueryProvider>\n  )\n}\n\nexport const getServerSideProps = async ({ query }) => {\n  const searchQuery = deriveFilters(derivingDefinition)(\n    classifyParams(classification)(\n      decodeParams(encodingDefinition)(query)\n    )\n  )\n\n  const searchResult = //...\n\n  return {\n    searchQuery,\n    searchResult,\n  }\n}\n\nexport default SearchPage\n```\n\nThe context provides following properties:\n- `searchQuery` - the query that had been passed as a prop\n- `addFilters`\n- `resetFilters` - a function that removes the filters except the ones whose names are passed to it\n- `updatePagination`\n- `updateSort`\n- `buildSearchPath` - a function that can be used to render search related links (e.g. page links in the pagination component)\n\n## Development\n```\nnpm run build\n```\n\nYou can link your local npm package to integrate it with any local project:\n```\ncd carforyou-search-parameters-pkg\nnpm run build\n\ncd carforyou-listings-web\nnpm link ../carforyou-search-parameters-pkg\n```\n\n## Release a new version\n\nNew versions are released on the ci using semantic-release as soon as you merge into master. Please\nmake sure your merge commit message adheres to the corresponding conventions.\n\n\n## Circle CI\n\nYou will need to enable the repository in circle CI UI to be able to build it.\n\nFor slack notifications to work, you will need to provide the token in circle settings.\n","readmeFilename":"README.md"}