Skip to content

Commit

Permalink
Add parseNumbers option to .parse() (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
yaodingyd authored and sindresorhus committed Jun 8, 2019
1 parent 5295243 commit f7be831
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 10 deletions.
21 changes: 16 additions & 5 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ export interface ParseOptions {
*
*
* queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'});
* //=> foo: [1, 2, 3]
* //=> foo: ['1', '2', '3']
*
* - `index`: Parse arrays with index representation:
*
*
* queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'});
* //=> foo: [1, 2, 3]
* //=> foo: ['1', '2', '3']
*
* - `comma`: Parse arrays with elements separated by comma:
*
*
* queryString.parse('foo=1,2,3', {arrayFormat: 'comma'});
* //=> foo: [1, 2, 3]
* //=> foo: ['1', '2', '3']
*
* - `none`: Parse arrays with elements using duplicate keys:
*
*
* queryString.parse('foo=1&foo=2&foo=3');
* //=> foo: [1, 2, 3]
* //=> foo: ['1', '2', '3']
*/
readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none';

Expand All @@ -55,10 +55,21 @@ export interface ParseOptions {
*/
readonly sort?: ((itemLeft: string, itemRight: string) => number) | false;

/**
* Parse the value as a number type instead of string type if it's a number.
*
* @default false
*
* @example
*
* queryString.parse('foo[]=1&foo[]=2&foo[]=3', {parseNumbers: true});
* //=> foo: [1, 2, 3]
*/
readonly parseNumbers?: boolean;
}

export interface ParsedQuery {
readonly [key: string]: string | string[] | null | undefined;
readonly [key: string]: string | number | Array<string | number> | null | undefined;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ function parse(input, options) {
options = Object.assign({
decode: true,
sort: true,
arrayFormat: 'none'
arrayFormat: 'none',
parseNumbers: false
}, options);

const formatter = parserForArrayFormat(options);
Expand All @@ -200,6 +201,10 @@ function parse(input, options) {
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
value = value === undefined ? null : decode(value, options);

if (options.parseNumbers && !Number.isNaN(Number(value))) {
value = Number(value);
}

formatter(decode(key, options), value, ret);
}

Expand Down
6 changes: 6 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ expectType<queryString.ParsedQuery>(
expectType<queryString.ParsedQuery>(
queryString.parse('?foo=bar', {arrayFormat: 'comma'})
);
expectType<queryString.ParsedQuery>(
queryString.parse('?foo=1', {parseNumbers: true})
);

// Parse URL
expectType<queryString.ParsedUrl>(queryString.parseUrl('?foo=bar'));
Expand All @@ -70,6 +73,9 @@ expectType<queryString.ParsedUrl>(
expectType<queryString.ParsedUrl>(
queryString.parseUrl('?foo=bar', {arrayFormat: 'comma'})
);
expectType<queryString.ParsedQuery>(
queryString.parse('?foo=1', {parseNumbers: true})
);

// Extract
expectType<string>(queryString.extract('http://foo.bar/?abc=def&hij=klm'));
20 changes: 16 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,28 @@ Default: `'none'`

```js
queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'});
//=> foo: [1, 2, 3]
//=> foo: ['1', '2', '3']
```

- `'index'`: Parse arrays with index representation:

```js
queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'});
//=> foo: [1, 2, 3]
//=> foo: ['1', '2', '3']
```

- `'comma'`: Parse arrays with elements separated by comma:

```js
queryString.parse('foo=1,2,3', {arrayFormat: 'comma'});
//=> foo: [1, 2, 3]
//=> foo: ['1', '2', '3']
```

- `'none'`: Parse arrays with elements using duplicate keys:

```js
queryString.parse('foo=1&foo=2&foo=3');
//=> foo: [1, 2, 3]
//=> foo: ['1', '2', '3']
```

##### sort
Expand All @@ -103,6 +103,18 @@ Default: `true`

Supports both `Function` as a custom sorting function or `false` to disable sorting.

##### parseNumbers

Type: `boolean`<br>
Default: `false`

```js
queryString.parse('foo[]=1&foo[]=2&foo[]=3', {parseNumbers: true});
//=> foo: [1, 2, 3]
```

Parse the value as a number type instead of string type if it's a number.

### .stringify(object, [options])

Stringify an object into a query string and sorting the keys.
Expand Down
16 changes: 16 additions & 0 deletions test/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,19 @@ test('decode keys and values', t => {
test('disable decoding of keys and values', t => {
t.deepEqual(queryString.parse('tags=postal%20office,burger%2C%20fries%20and%20coke', {decode: false}), {tags: 'postal%20office,burger%2C%20fries%20and%20coke'});
});

test('number value returns as string by default', t => {
t.deepEqual(queryString.parse('foo=1'), {foo: '1'});
});

test('number value returns as number if option is set', t => {
t.deepEqual(queryString.parse('foo=1', {parseNumbers: true}), {foo: 1});
t.deepEqual(queryString.parse('foo=12.3&bar=123e-1', {parseNumbers: true}), {foo: 12.3, bar: 12.3});
t.deepEqual(queryString.parse('foo=0x11&bar=12.00', {parseNumbers: true}), {foo: 17, bar: 12});
});

test('NaN value returns as string if option is set', t => {
t.deepEqual(queryString.parse('foo=null', {parseNumbers: true}), {foo: 'null'});
t.deepEqual(queryString.parse('foo=undefined', {parseNumbers: true}), {foo: 'undefined'});
t.deepEqual(queryString.parse('foo=100a&bar=100', {parseNumbers: true}), {foo: '100a', bar: 100});
});

0 comments on commit f7be831

Please sign in to comment.