From 176638af1e10bce280f44c818bfc77d7936d792e Mon Sep 17 00:00:00 2001 From: scottenock Date: Thu, 8 May 2025 17:28:39 +0100 Subject: [PATCH 1/7] FEAT: implement support for boolean type --- base.d.ts | 32 ++++++++++++++++++++++---------- base.js | 4 ++++ readme.md | 23 +++++++++++++++++++---- test/parse.js | 11 +++++++++++ 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/base.d.ts b/base.d.ts index 6bedc6d..5458a16 100644 --- a/base.d.ts +++ b/base.d.ts @@ -178,13 +178,13 @@ export type ParseOptions = { readonly parseFragmentIdentifier?: boolean; /** - Specify a pre-defined schema to be used when parsing values. The types specified will take precedence over options such as: `parseNumber`, `parseBooleans`, and `arrayFormat`. + Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as `parseNumbers`, `parseBooleans`, and `arrayFormat`. - Use this feature to override the type of a value. This can be useful when the type is ambiguous such as a phone number (see example 1 and 2). + Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs). - It is possible to provide a custom function as the parameter type. The parameter's value will equal the function's return value (see example 4). + You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result (see Example 4). - NOTE: Array types (`string[]` and `number[]`) will have no effect if `arrayFormat` is set to `none` (see example 5). + NOTE: Array types (`string[]`, `number[]`) are ignored if `arrayFormat` is set to `'none'`. (See Example 5.) @default {} @@ -217,7 +217,7 @@ export type ParseOptions = { ``` @example - Parse `age` as a number, even when `parseNumber` is false: + Force `age` to be parsed as a number even when `parseNumbers` is false: ``` import queryString from 'query-string'; @@ -230,7 +230,7 @@ export type ParseOptions = { ``` @example - Parse `age` using a custom value parser: + Use a custom parser function to transform the value of `age`: ``` import queryString from 'query-string'; @@ -243,7 +243,7 @@ export type ParseOptions = { ``` @example - Array types will have no effect when `arrayFormat` is set to `none` + Array types are ignored when `arrayFormat` is set to `'none'`: ``` queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', { arrayFormat: 'none', @@ -256,7 +256,7 @@ export type ParseOptions = { ``` @example - Parse a query utilizing all types: + Parse a query using multiple type definitions: ``` import queryString from 'query-string'; @@ -273,10 +273,22 @@ export type ParseOptions = { }); //=> {ids: '001,002,003', items: ['1', '2', '3'], price: '22.00', numbers: [1, 2, 3], double: 10, number: 20} ``` + + @example + Force `flagged` to be parsed as a boolean even when `parseBooleans` is false: + ```` + queryString.parse('?isAdmin=true&flagged=true', { + parseBooleans: false, + types: { + flagged: 'boolean', + }, + }); + //=> { isAdmin: 'true', flagged: true } + ```` */ readonly types?: Record< - string, - 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown) + string, + 'boolean' | 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown) >; }; diff --git a/base.js b/base.js index e67109d..115d674 100644 --- a/base.js +++ b/base.js @@ -309,6 +309,10 @@ function parseValue(value, options, type) { return type(value); } + if (type === 'boolean' && value !== null && (value.toLowerCase() === 'true' || value.toLowerCase() === 'false')) { + return value.toLowerCase() === 'true'; + } + if (type === 'string[]' && options.arrayFormat !== 'none' && typeof value === 'string') { return [value]; } diff --git a/readme.md b/readme.md index b2497d3..ce521fa 100644 --- a/readme.md +++ b/readme.md @@ -193,14 +193,29 @@ Parse the value as a boolean type instead of string type if it's a boolean. Type: `object`\ Default: `{}` -Specify a pre-defined schema to be used when parsing values. The types specified will take precedence over options such as: `parseNumbers`, `parseBooleans`, and `arrayFormat`. -Use this feature to override the type of a value. This can be useful when the type is ambiguous such as a phone number. +Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as `parseNumbers`, `parseBooleans`, and `arrayFormat`. + +Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs). + +You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result. -It is possible to provide a custom function as the parameter type. The parameter's value will equal the function's return value. Supported Types: + +- `'boolean'`: Parse `flagged` as a boolean (overriding the `parseBooleans` option): + +```js +queryString.parse('?isAdmin=true&flagged=true', { + parseBooleans: false, + types: { + flagged: 'boolean', + }, +}); +//=> { isAdmin: 'true', flagged: true } +``` + - `'string'`: Parse `phoneNumber` as a string (overriding the `parseNumbers` option): ```js @@ -268,7 +283,7 @@ queryString.parse('?age=20&id=01234&zipcode=90210', { //=> {age: 40, id: '01234', zipcode: '90210 } ``` -NOTE: Array types (`string[]` and `number[]`) will have no effect if `arrayFormat` is set to `none`. +NOTE: Array types (`string[]`, `number[]`) are ignored if `arrayFormat` is set to `'none'`. ```js queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', { diff --git a/test/parse.js b/test/parse.js index d20f540..d4c1911 100644 --- a/test/parse.js +++ b/test/parse.js @@ -568,3 +568,14 @@ test('types option: single element with `{arrayFormat: "comma"}, and type: numbe a: [1], }); }); + +test('types option: can parse boolean when parseboolean is false', t => { + t.deepEqual(queryString.parse('a=true', { + parsebooleans: false, + types: { + a: 'boolean', + }, + }), { + a: true, + }); +}); From 440bb4660b18bb2b16c9907ecdb677bd6bb7c7db Mon Sep 17 00:00:00 2001 From: scottenock Date: Thu, 8 May 2025 17:35:05 +0100 Subject: [PATCH 2/7] FEAT: fix xo errors --- base.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base.d.ts b/base.d.ts index 5458a16..9e9064e 100644 --- a/base.d.ts +++ b/base.d.ts @@ -287,8 +287,8 @@ export type ParseOptions = { ```` */ readonly types?: Record< - string, - 'boolean' | 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown) + string, + 'boolean' | 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown) >; }; From 15e3ee26d2b7cef013a17a63bd4657e61402d893 Mon Sep 17 00:00:00 2001 From: scottenock Date: Sun, 18 May 2025 17:42:36 +0100 Subject: [PATCH 3/7] FEAT: enable boolean parsing for '0' and '1' values --- base.d.ts | 10 ++++++---- base.js | 4 ++++ readme.md | 15 +++++++++------ test/parse.js | 13 +++++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/base.d.ts b/base.d.ts index 9e9064e..70f5eac 100644 --- a/base.d.ts +++ b/base.d.ts @@ -276,15 +276,17 @@ export type ParseOptions = { @example Force `flagged` to be parsed as a boolean even when `parseBooleans` is false: - ```` - queryString.parse('?isAdmin=true&flagged=true', { + ``` + queryString.parse('?isAdmin=true&flagged=true&isOkay=0', { parseBooleans: false, types: { flagged: 'boolean', + isOkay: 'boolean', }, }); - //=> { isAdmin: 'true', flagged: true } - ```` + //=> { isAdmin: 'true', flagged: true, isOkay: false } + ``` + Note: The 'boolean' type will also convert "0" and "1" string values to booleans. */ readonly types?: Record< string, diff --git a/base.js b/base.js index 115d674..7914110 100644 --- a/base.js +++ b/base.js @@ -313,6 +313,10 @@ function parseValue(value, options, type) { return value.toLowerCase() === 'true'; } + if (type === 'boolean' && value !== null && (value.toLowerCase() === '1' || value.toLowerCase() === '0')) { + return value.toLowerCase() === '1'; + } + if (type === 'string[]' && options.arrayFormat !== 'none' && typeof value === 'string') { return [value]; } diff --git a/readme.md b/readme.md index ce521fa..014cf71 100644 --- a/readme.md +++ b/readme.md @@ -207,15 +207,18 @@ Supported Types: - `'boolean'`: Parse `flagged` as a boolean (overriding the `parseBooleans` option): ```js -queryString.parse('?isAdmin=true&flagged=true', { - parseBooleans: false, - types: { - flagged: 'boolean', - }, +queryString.parse('?isAdmin=true&flagged=true&isOkay=0', { + parseBooleans: false, + types: { + flagged: 'boolean', + isOkay: 'boolean', + }, }); -//=> { isAdmin: 'true', flagged: true } +//=> { isAdmin: 'true', flagged: true, isOkay: false } ``` +Note: The 'boolean' type will also convert "0" and "1" string values to booleans. + - `'string'`: Parse `phoneNumber` as a string (overriding the `parseNumbers` option): ```js diff --git a/test/parse.js b/test/parse.js index d4c1911..4d2b7ac 100644 --- a/test/parse.js +++ b/test/parse.js @@ -579,3 +579,16 @@ test('types option: can parse boolean when parseboolean is false', t => { a: true, }); }); + +test('types option: boolean type accepts 1 and 0 as boolean values', t => { + t.deepEqual(queryString.parse('a=1&b=0', { + parsebooleans: false, + types: { + a: 'boolean', + b: 'boolean' + }, + }), { + a: true, + b: false, + }); +}); From e35d9da961287407e9800f278ca6ff3cd6ac0bff Mon Sep 17 00:00:00 2001 From: scottenock Date: Sun, 18 May 2025 17:46:16 +0100 Subject: [PATCH 4/7] FEAT: lint fixes --- test/parse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parse.js b/test/parse.js index 4d2b7ac..ad25dbe 100644 --- a/test/parse.js +++ b/test/parse.js @@ -585,7 +585,7 @@ test('types option: boolean type accepts 1 and 0 as boolean values', t => { parsebooleans: false, types: { a: 'boolean', - b: 'boolean' + b: 'boolean', }, }), { a: true, From 6b8c7642bb936895e196f79c83341272a1ab9c62 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 May 2025 17:00:30 +0300 Subject: [PATCH 5/7] Update base.d.ts --- base.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base.d.ts b/base.d.ts index f2815e1..a008640 100644 --- a/base.d.ts +++ b/base.d.ts @@ -284,9 +284,9 @@ export type ParseOptions = { isOkay: 'boolean', }, }); - //=> { isAdmin: 'true', flagged: true, isOkay: false } + //=> {isAdmin: 'true', flagged: true, isOkay: false} ``` - Note: The 'boolean' type will also convert "0" and "1" string values to booleans. + Note: The `'boolean'` type will also convert `'0'` and `'1'` string values to booleans. */ readonly types?: Record< string, From 91cc2e1b9945fefe48e6375daae8f1f8679e466d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 May 2025 17:00:57 +0300 Subject: [PATCH 6/7] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8ca237c..2bd1b4c 100644 --- a/readme.md +++ b/readme.md @@ -217,7 +217,7 @@ queryString.parse('?isAdmin=true&flagged=true&isOkay=0', { //=> { isAdmin: 'true', flagged: true, isOkay: false } ``` -Note: The 'boolean' type will also convert "0" and "1" string values to booleans. +Note: The `'boolean'` type will also convert `'0'` and `'1'` string values to booleans. - `'string'`: Parse `phoneNumber` as a string (overriding the `parseNumbers` option): From f6392440b4b646dd591f2286817dce448cf89d71 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 May 2025 17:01:25 +0300 Subject: [PATCH 7/7] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2bd1b4c..1813507 100644 --- a/readme.md +++ b/readme.md @@ -214,7 +214,7 @@ queryString.parse('?isAdmin=true&flagged=true&isOkay=0', { isOkay: 'boolean', }, }); -//=> { isAdmin: 'true', flagged: true, isOkay: false } +//=> {isAdmin: 'true', flagged: true, isOkay: false} ``` Note: The `'boolean'` type will also convert `'0'` and `'1'` string values to booleans.