{"id":23635331,"url":"https://github.com/filefoxper/type-qs","last_synced_at":"2025-08-31T11:30:57.002Z","repository":{"id":57383235,"uuid":"267555864","full_name":"filefoxper/type-qs","owner":"filefoxper","description":"parse a location.search with type descriptions, and get a more useful query data","archived":false,"fork":false,"pushed_at":"2021-08-13T08:49:13.000Z","size":118,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-11T23:11:39.704Z","etag":null,"topics":["browser","location-search","parsers","qs-api","query-parser","querystring","template","type","url-parser"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/filefoxper.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-28T10:05:27.000Z","updated_at":"2021-08-13T08:49:16.000Z","dependencies_parsed_at":"2022-09-13T23:50:30.804Z","dependency_job_id":null,"html_url":"https://github.com/filefoxper/type-qs","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filefoxper%2Ftype-qs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filefoxper%2Ftype-qs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filefoxper%2Ftype-qs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filefoxper%2Ftype-qs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/filefoxper","download_url":"https://codeload.github.com/filefoxper/type-qs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231590314,"owners_count":18396922,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","location-search","parsers","qs-api","query-parser","querystring","template","type","url-parser"],"created_at":"2024-12-28T05:33:59.631Z","updated_at":"2024-12-28T05:34:00.455Z","avatar_url":"https://github.com/filefoxper.png","language":"TypeScript","readme":"[![npm][npm-image]][npm-url]\n[![standard][standard-image]][standard-url]\n\n[npm-image]: https://img.shields.io/npm/v/type-qs.svg?style=flat-square\n[npm-url]: https://www.npmjs.com/package/type-qs\n[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square\n[standard-url]: http://npm.im/standard\n\n# type-qs [-\u003e中文文档](https://github.com/filefoxper/type-qs/blob/master/readme_zh-cn.md)\n\n# problem\nWhen we parse a search from location, we often get an object like ```{[key: string]: string|string[]|undefined}```, \nbut we really want an object like ```{[key:string]:number|boolean|Date|string|string[]...} ``` which can describe more \ntypes about the values. Also we want to validate these values, if they are invalid we can replace them from an default.\n\n# resolve\nHere is a tool ```type-qs``` which can do something like transforming value type and replacing value which is invalid.\n It use [qs](https://www.npmjs.com/package/qs) to parse your `search` to `query` first, \n then parse query with your template.\n# dependencies\n1. [qs](https://www.npmjs.com/package/qs)\n2. [type-query-parser](https://www.npmjs.com/package/type-query-parser)\n# differs with qs\nthe only differs with [qs](https://www.npmjs.com/package/qs) is the parse function.\n\nparse(search: string, opt?: IParseOptions \u0026 { defaults?: any, template?: Template })\n\nwe add the \u003cstrong\u003etemplate and defaults\u003c/strong\u003e into options. So you can work with template to recompute your query and use defaults to replace the invalid query params.\n \n\u003cstrong\u003eif you set nothing about template, it works what qs.parse works.\u003c/strong\u003e\n# example (more in [test](https://github.com/filefoxper/type-qs/blob/master/test/index.test.ts))\ncheck and transform\n```js\nimport {parse} from 'type-qs';\nimport {Parsers} from 'type-qs/libs';\n\n...\nconst template={\n    id:Parsers.natural(),           //get a natural number 0,1,2,3, ......\n    name:Parsers.string(true),      //get a string data with trim option: boolean, if true then the name will be trimmed\n    active:Parsers.boolean(),       //get a boolean data\n    role:Parsers.enum(['GUEST','USER','MASTER','ADMIN']),\n                                    //get a data which only can be one of 'GUEST'|'USER'|'MASTER'|'ADMIN'\n    page:Parsers.natural()          //get a natural number, check out the source page is not a natural number, but 'abc', then get an undefined\n};\nconst query=parse('id=123456\u0026name= jimmy \u0026active=true\u0026role=MASTER\u0026page=abc',{template});\n...\nconsole.log(query);\n\n/*** result ***/\n{\n    id:123456,\n    name:'jimmy',\n    active:true,\n    role:'MASTER',\n    page:undefined\n}\n```\ncheck and transform with default values\n```js\nimport {parse} from 'type-qs';\nimport {Parsers} from 'type-qs/libs';\n\n...\nconst template={\n    id:Parsers.natural(),           //get a natural number 0,1,2,3, ......\n    name:Parsers.string(true),      //get a string data with trim option: boolean, if true then the name will be trimmed\n    active:Parsers.boolean(),       //get a boolean data\n    role:Parsers.enum(['GUEST','USER','MASTER','ADMIN']),\n                                    //get a data which only can be one of 'GUEST'|'USER'|'MASTER'|'ADMIN'\n    page:Parsers.natural()          //get a natural number, check out the source page is not a natural number, then get an undefined\n};\nconst defaults={\n    role:'GUEST',                   //notice now we change role=MASTERR in search, and it should be undefined, \n                                    //but we give an defaults which contains a 'role' key\n    page:1\n};\nconst query=parse('id=123456\u0026name= jimmy \u0026active=true\u0026role=MASTERR\u0026page=abc',{template,defaults});\n...\nconsole.log(query);\n\n/*** result ***/\n{\n    id:123456,\n    name:'jimmy',\n    active:true,\n    role:'GUEST',\n    page:1\n}\n```\nomit entries which we do not care\n```js\nimport {parse} from 'type-qs';\nimport {Parsers} from 'type-qs/libs';\n\n...\nconst template={\n    ids:Parsers.array(),\n}\n\nconst query=parse('ids=1%2C2%2C3\u0026useless=123',{template,defaults:{useless:'123'}}); //the url like ids=1,2,3\u0026useless=123\n...\nconsole.log(query);\n\n/*** result ***/\n{\n    ids:['1','2','3']\n}                                   //the 'useless' in url is omited, because the template has no key 'useless'\n```\nmake array data type by numbers\n```js\nimport {parse} from 'type-qs';\nimport {Parsers} from 'type-qs/libs';\n\n...\nconst template={\n    ids:Parsers.array(Parsers.natural()), //the param to Parses.array can be another Parser which use map array data to you want\n}\n\nconst query=parse('ids=1%2C2%2C3',{template}); //the url like ids=1,2,3\n...\nconsole.log(query);\n\n/*** result ***/\n{\n    ids:[1,2,3]\n}                 \n```\nmake a custom Parser function\n```js\nimport {parse} from 'type-qs';\n\n\nconst numberToBoolean=(value:string='')=\u003e{\n    if(value.trim()==='1'){\n        return true;\n    }\n    if(value.trim()==='0'){\n        return false\n    }\n}\n\nconst template={\n    active:numberToBoolean\n}\n\nconst query=parse('active=1',{template});\n...\nconsole.log(query);\n\n/*** result ***/\n{\n    active:true\n}\n```\nuse qs abilities\n```js\nimport {parse,stringify} from 'type-qs';\nimport {Parsers} from 'type-qs/libs';\n\nconst source={\n    id:1,\n    more:{\n        active:true,\n        name:'Jimmy',\n        size:'ab'\n    }\n};\n\nconst template={\n    id:Parsers.natural(),\n    more:{\n        active:Parsers.boolean(),\n        name:Parsers.string(),\n        size:Parsers.natural()\n    }\n};\n\nconst defaults={\n    more:{\n        size:10\n    }\n};\n\nconst search = stringify(source);                 //id=1\u0026more%5Bactive%5D=true\u0026more%5Bname%5D=Jimmy\u0026more%5Bsize%5D=ab\nconst result = parse(search,{template,defaults});\n...\nconsole.log(result);\n\n/*** result ***/\n{\n    id:1,\n    more:{\n        active:true,\n        name:'Jimmy',\n        size:10                                 //from defaults\n    }\n}                   \n```\n# api\n\u003cstrong\u003eparse\u003c/strong\u003e `search` to an object you want by `template` and `defaults` in `opt`.\n\ntypes:\n\ntype Parser = (value?: string|string[]) =\u003e any|void;\n`any function matches Parser is used to transform value to you want`\n\ntype Template = {\n    [key: string]: Template | Parser\n} | Parser[];\n`any object matches Template is used to structure result you want`\n\ntype IParseOption is from qs, you can learn it with [qs api](https://www.npmjs.com/package/qs)\n\ntype {defaults?:any} \n`the default value you provide, when the value is undefined, the value in defaults with same key will replace the undefined one.`\n```\nfunction parse(search:string,opt?: IParseOptions \u0026 { defaults?: any,template?:Template })\n```\n\u003cstrong\u003estringify\u003c/strong\u003e is from qs, you can earn it with [qs api](https://www.npmjs.com/package/qs)\n\n```\nfunction stringify(obj: any, opt?: IStringifyOptions): string\n```\n\u003cstrong\u003eParsers\u003c/strong\u003e provide some `Parser`, which is helpful, also you can write yourself Parsers.\n\n\u003cstrong\u003eParsers.number:\u003c/strong\u003e\n```\nfunction Parsers.number() return a Parser\n \nParser:(value?:string)=\u003enumber|undefined\n\nif the value isNaN (can not be a number), it will return an undefined value, \nelse it will provide a number value (typeof returnValue==='number').\n```\n\n\u003cstrong\u003eParsers.natural:\u003c/strong\u003e\n```\nfunction Parsers.natural() return a Parser\n \nParser:(value?:string)=\u003enumber|undefined\n\nif the value can not be a natural number, it will return an undefined value, \nelse it will provide a natural number value (typeof returnValue==='number').\n```\n\n\u003cstrong\u003eParsers.integer:\u003c/strong\u003e\n```\nfunction Parsers.natural() return a Parser\n \nParser:(value?:string)=\u003enumber|undefined\n\nif the value can not be a integer, it will return an undefined value, \nelse it will provide a integer value (typeof returnValue==='number').\n```\n\n\u003cstrong\u003eParsers.string:\u003c/strong\u003e\n```\nfunction Parsers.string(trim:boolean) return a Parser\n \nParser:(value?:string)=\u003estring\n\nthe value will be a string, if you set trim:true the string value will be trimmed.\n```\n\n\u003cstrong\u003eParsers.boolean:\u003c/strong\u003e\n```\nfunction Parsers.boolean() return a Parser\n \nParser:(value?:string)=\u003eboolean|undefined\n\nif the value trimmed is not 'true' or 'false', it will return an undefined value, \nelse it will provide a boolean value (typeof returnValue==='boolean').\n```\n\n\u003cstrong\u003eParsers.enum:\u003c/strong\u003e\n```\nfunction Parsers.enum(array:Array\u003cany\u003e) return a Parser\n \nParser:(value?:string)=\u003eany|undefined\n\nif the value trimmed is not included in array, it will return an undefined value, \nelse it will return the one in array which matches value by '==' not '==='.\n```\n\n\u003cstrong\u003eParsers.array:\u003c/strong\u003e\n```\nfunction Parsers.array(mapper?: (data: string) =\u003e any) return a Parser\n \nParser: (value?: string | Array\u003cstring\u003e)=\u003eArray\u003cany\u003e|Array\u003cstring\u003e\n\nif the value is string, it will transform to array by string.split, then the array will map with mapper, \nat last the mapped array will filter out the datas to a new array which data is not undefined.\n```\n\n\u003cstrong\u003eParsers.regExp:\u003c/strong\u003e\n```\nfunction Parsers.regExp(regExp: RegExp) return a Parser\n \nParser:(value?:string)=\u003estring|undefined\n\nif the value 'regExp.test(value)' is passed, it will return value, else it will undefined.\n```\n\n\u003cstrong\u003eParsers.date:\u003c/strong\u003e\n```\nfunction Parsers.date(...dateLikeReduces: Array\u003cDateLikeReduce\u003e) return a Parser\n \nParser:(value?:string)=\u003eDateLike|undefined\n\ntype DateLike = string | number | Date;\n\ntype DateLikeReduce = (dateLike: DateLike) =\u003e DateLike\n\nif the value trimmed can be a Date value, it will return a DateLike value, \nwhich might be produced by dateLikeReduces, else it will return undefined.\n\nhere is some dateLikeReduces provided, they can help you use it more quickly:\n\nstartOfDay(dateLike: DateLike)=\u003eDate                // DateLike[2020-05-23 12:11:34] =\u003e new Date(2020-05-23 00:00:00:000)\nendOfDay(dateLike: DateLike)=\u003eDate                  // DateLike[2020-05-23 12:11:34] =\u003e new Date(2020-05-23 23:59:59:999)\ntoDateString(date: DateLike)=\u003estring                // DateLike[2020-05-23 12:11:34] =\u003e '2020-05-23'\ntoDatetimeString(date: DateLike)=\u003estring            // DateLike[2020-05-23 12:11:34] =\u003e '2020-05-23 12:11:34'\npattern(pat: string)=\u003eformatDateLike(dateLike: DateLike)=\u003estring\n                                                    // pattern('YYYY-MM-DD HH:mm')=\u003eformatter\n                                                    // formatter(DateLike[2020-05-23 12:11:34])\n                                                    // =\u003e'2020-05-23 12:11'\n                                                    \nwe can use like this:\nimport {parse,Parsers} from 'type-qs';\nimport {startOfDay,pattern,endOfDay,toDatetimeString} from 'type-qs/libs';\n\nconst template={\n    start:Parsers.date(startOfDay,pattern('YYYY-MM-DD HH:mm:ss')),\n    end:Parsers.date(endOfDay,toDatetimeString)\n};\n\nconst data=parse('start=2020-01-01%2011%3A11%3A11\u0026end=2020-12-13%2010%3A01%3A18',{template});\n\n/*** result ***/\n{\n    start:'2020-01-01 00:00:00',\n    end:'2020-12-13 23:59:59'\n}\n```\n\n\u003cstrong\u003eParsers.datePattern:\u003c/strong\u003e\n```\nfunction Parsers.datePattern(...dateLikeReduces: Array\u003cDateLikeReduce\u003e) return a Parser\n \nParser:(value?:string)=\u003estring|undefined\n\nit is just a wrap on Parsers.date, and returns a 'YYYY-MM-DD' formatted string value or undefined.\n```\n\n\u003cstrong\u003eParsers.datetimePattern:\u003c/strong\u003e\n```\nfunction Parsers.datetimePattern(...dateLikeReduces: Array\u003cDateLikeReduce\u003e) return a Parser\n \nParser:(value?:string)=\u003estring|undefined\n\nit is just a wrap on Parsers.date, and returns a 'YYYY-MM-DD HH:mm:ss' formatted string value or undefined.\n```\n\n# summary\nif you like this tool, give me a little start, thank you.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilefoxper%2Ftype-qs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffilefoxper%2Ftype-qs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilefoxper%2Ftype-qs/lists"}