From a6d4a3f480b2810a8cce3c0118a2aacc6c6c7add Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Fri, 26 Feb 2021 18:15:35 +0700
Subject: [PATCH 01/12] Fix TypeScript type for `stringifyUrl()`
Fixes #308
---
index.d.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/index.d.ts b/index.d.ts
index b6d651b..4a115fb 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -372,7 +372,7 @@ export interface UrlObject {
/**
Overrides queries in the `url` property.
*/
- readonly query: StringifiableRecord;
+ readonly query?: StringifiableRecord;
/**
Overrides the fragment identifier in the `url` property.
From 0090a3418253eea4b2c437ba034dd445361325b2 Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Fri, 26 Feb 2021 18:16:40 +0700
Subject: [PATCH 02/12] 6.14.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 3b90b26..c75f01a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "query-string",
- "version": "6.14.0",
+ "version": "6.14.1",
"description": "Parse and stringify URL query strings",
"license": "MIT",
"repository": "sindresorhus/query-string",
From 44abc66628199bd3766ac471e265e64206f146c9 Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Sat, 13 Mar 2021 00:54:58 +0700
Subject: [PATCH 03/12] Meta tweaks
---
readme.md | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 280972e..884b0fd 100644
--- a/readme.md
+++ b/readme.md
@@ -17,7 +17,20 @@
-
+
+
+
+
+
+
+

+
+ All your environment variables, in one place
+
+ Stop struggling with scattered API keys, hacking together home-brewed tools,
+
+ and avoiding access controls. Keep your team and servers in sync with Doppler.
+
From 828f032306216f09a17d900fb765b002e1fd7691 Mon Sep 17 00:00:00 2001
From: Miguel Valenzuela
Date: Tue, 16 Mar 2021 22:56:31 -0700
Subject: [PATCH 04/12] Implement skips for stringify array format comma (#304)
Co-authored-by: Sindre Sorhus
---
index.d.ts | 5 +++++
index.js | 12 ++++++++++--
readme.md | 5 +++++
test/parse.js | 31 +++++++++++++++++++++++++++++--
test/stringify.js | 23 ++++++++++++++++++-----
5 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/index.d.ts b/index.d.ts
index 4a115fb..035ded8 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -229,6 +229,11 @@ export interface StringifyOptions {
queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'comma'});
//=> 'foo=1,2,3'
+
+ queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
+ //=> 'foo=1,,'
+ // Note that typing information for null values is lost
+ // and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
```
- `separator`: Serialize arrays by separating elements with character:
diff --git a/index.js b/index.js
index 423b9d6..07764d5 100644
--- a/index.js
+++ b/index.js
@@ -50,12 +50,20 @@ function encoderForArrayFormat(options) {
case 'comma':
case 'separator':
return key => (result, value) => {
- if (value === null || value === undefined || value.length === 0) {
+ if (
+ value === undefined ||
+ (options.skipNull && value === null) ||
+ (options.skipEmptyString && value === '')
+ ) {
return result;
}
if (result.length === 0) {
- return [[encode(key, options), '=', encode(value, options)].join('')];
+ return [[encode(key, options), '=', encode(value === null ? '' : value, options)].join('')];
+ }
+
+ if (value === null || value === '') {
+ return [[result, ''].join(options.arrayFormatSeparator)];
}
return [[result, encode(value, options)].join(options.arrayFormatSeparator)];
diff --git a/readme.md b/readme.md
index 884b0fd..f90aba6 100644
--- a/readme.md
+++ b/readme.md
@@ -241,6 +241,11 @@ const queryString = require('query-string');
queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'comma'});
//=> 'foo=1,2,3'
+
+queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
+//=> 'foo=1,,'
+// Note that typing information for null values is lost
+// and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
```
- `'none'`: Serialize arrays by using duplicate keys:
diff --git a/test/parse.js b/test/parse.js
index 9bfc034..70759f1 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -218,7 +218,7 @@ test('query strings having ordered index arrays and format option as `index`', t
}), {bat: 'buz', foo: ['zero', 'two', 'one', 'three']});
});
-test('circuit parse -> stringify', t => {
+test('circuit parse → stringify', t => {
const original = 'foo[3]=foo&foo[2]&foo[1]=one&foo[0]=&bat=buz';
const sortedOriginal = 'bat=buz&foo[0]=&foo[1]=one&foo[2]&foo[3]=foo';
const expected = {bat: 'buz', foo: ['', 'one', null, 'foo']};
@@ -231,7 +231,7 @@ test('circuit parse -> stringify', t => {
t.is(queryString.stringify(expected, options), sortedOriginal);
});
-test('circuit original -> parse - > stringify -> sorted original', t => {
+test('circuit original → parse → stringify → sorted original', t => {
const original = 'foo[21474836471]=foo&foo[21474836470]&foo[1]=one&foo[0]=&bat=buz';
const sortedOriginal = 'bat=buz&foo[0]=&foo[1]=one&foo[2]&foo[3]=foo';
const options = {
@@ -241,6 +241,33 @@ test('circuit original -> parse - > stringify -> sorted original', t => {
t.deepEqual(queryString.stringify(queryString.parse(original, options), options), sortedOriginal);
});
+test('circuit parse → stringify with array commas', t => {
+ const original = 'c=,a,,&b=&a=';
+ const sortedOriginal = 'a=&b=&c=,a,,';
+ const expected = {
+ c: ['', 'a', '', ''],
+ b: '',
+ a: ''
+ };
+ const options = {
+ arrayFormat: 'comma'
+ };
+
+ t.deepEqual(queryString.parse(original, options), expected);
+
+ t.is(queryString.stringify(expected, options), sortedOriginal);
+});
+
+test('circuit original → parse → stringify with array commas → sorted original', t => {
+ const original = 'c=,a,,&b=&a=';
+ const sortedOriginal = 'a=&b=&c=,a,,';
+ const options = {
+ arrayFormat: 'comma'
+ };
+
+ t.deepEqual(queryString.stringify(queryString.parse(original, options), options), sortedOriginal);
+});
+
test('decode keys and values', t => {
t.deepEqual(queryString.parse('st%C3%A5le=foo'), {ståle: 'foo'});
t.deepEqual(queryString.parse('foo=%7B%ab%%7C%de%%7D+%%7Bst%C3%A5le%7D%'), {foo: '{%ab%|%de%} %{ståle}%'});
diff --git a/test/stringify.js b/test/stringify.js
index 5c3487b..4b8bda5 100644
--- a/test/stringify.js
+++ b/test/stringify.js
@@ -126,13 +126,26 @@ test('array stringify representation with array commas', t => {
}), 'bar=one,two&foo');
});
-test('array stringify representation with array commas and null value', t => {
+test('array stringify representation with array commas, null & empty string', t => {
t.is(queryString.stringify({
- foo: [null, 'a', null, ''],
- bar: [null]
+ c: [null, 'a', '', null],
+ b: [null],
+ a: ['']
+ }, {
+ arrayFormat: 'comma'
+ }), 'a=&b=&c=,a,,');
+});
+
+test('array stringify representation with array commas, null & empty string (skip both)', t => {
+ t.is(queryString.stringify({
+ c: [null, 'a', '', null],
+ b: [null],
+ a: ['']
}, {
+ skipNull: true,
+ skipEmptyString: true,
arrayFormat: 'comma'
- }), 'foo=a');
+ }), 'c=a');
});
test('array stringify representation with array commas and 0 value', t => {
@@ -141,7 +154,7 @@ test('array stringify representation with array commas and 0 value', t => {
bar: [null]
}, {
arrayFormat: 'comma'
- }), 'foo=a,0');
+ }), 'bar=&foo=a,,0');
});
test('array stringify representation with a bad array format', t => {
From b10bc19699a09580c055a381541e726dfd01a001 Mon Sep 17 00:00:00 2001
From: Austin Keener
Date: Thu, 18 Mar 2021 07:52:12 -0400
Subject: [PATCH 05/12] Add support for `arrayFormat: 'bracket-separator'`
(#276)
Co-authored-by: Sindre Sorhus
---
benchmark.js | 5 +++-
index.d.ts | 57 ++++++++++++++++++++++++++++++++++++++---
index.js | 43 ++++++++++++++++++++++++++-----
readme.md | 60 +++++++++++++++++++++++++++++++++++++++++++
test/parse.js | 30 ++++++++++++++++++++++
test/stringify.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 250 insertions(+), 10 deletions(-)
diff --git a/benchmark.js b/benchmark.js
index af120ea..b152460 100644
--- a/benchmark.js
+++ b/benchmark.js
@@ -20,6 +20,7 @@ const TEST_STRING = stringify(TEST_OBJECT);
const TEST_BRACKETS_STRING = stringify(TEST_OBJECT, {arrayFormat: 'bracket'});
const TEST_INDEX_STRING = stringify(TEST_OBJECT, {arrayFormat: 'index'});
const TEST_COMMA_STRING = stringify(TEST_OBJECT, {arrayFormat: 'comma'});
+const TEST_BRACKET_SEPARATOR_STRING = stringify(TEST_OBJECT, {arrayFormat: 'bracket-separator'});
const TEST_URL = stringifyUrl({url: TEST_HOST, query: TEST_OBJECT});
// Creates a test case and adds it to the suite
@@ -41,6 +42,7 @@ defineTestCase('parse', TEST_STRING, {decode: false});
defineTestCase('parse', TEST_BRACKETS_STRING, {arrayFormat: 'bracket'});
defineTestCase('parse', TEST_INDEX_STRING, {arrayFormat: 'index'});
defineTestCase('parse', TEST_COMMA_STRING, {arrayFormat: 'comma'});
+defineTestCase('parse', TEST_BRACKET_SEPARATOR_STRING, {arrayFormat: 'bracket-separator'});
// Stringify
defineTestCase('stringify', TEST_OBJECT);
@@ -51,6 +53,7 @@ defineTestCase('stringify', TEST_OBJECT, {skipEmptyString: true});
defineTestCase('stringify', TEST_OBJECT, {arrayFormat: 'bracket'});
defineTestCase('stringify', TEST_OBJECT, {arrayFormat: 'index'});
defineTestCase('stringify', TEST_OBJECT, {arrayFormat: 'comma'});
+defineTestCase('stringify', TEST_OBJECT, {arrayFormat: 'bracket-separator'});
// Extract
defineTestCase('extract', TEST_URL);
@@ -66,7 +69,7 @@ suite.on('cycle', event => {
const {name, hz} = event.target;
const opsPerSec = Math.round(hz).toLocaleString();
- console.log(name.padEnd(36, '_') + opsPerSec.padStart(12, '_') + ' ops/s');
+ console.log(name.padEnd(46, '_') + opsPerSec.padStart(3, '_') + ' ops/s');
});
suite.run();
diff --git a/index.d.ts b/index.d.ts
index 035ded8..847336d 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -45,6 +45,30 @@ export interface ParseOptions {
//=> {foo: ['1', '2', '3']}
```
+ - `bracket-separator`: Parse arrays (that are explicitly marked with brackets) with elements separated by a custom character:
+
+ ```
+ import queryString = require('query-string');
+
+ queryString.parse('foo[]', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: []}
+
+ queryString.parse('foo[]=', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: ['']}
+
+ queryString.parse('foo[]=1', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: ['1']}
+
+ queryString.parse('foo[]=1|2|3', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: ['1', '2', '3']}
+
+ queryString.parse('foo[]=1||3|||6', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: ['1', '', 3, '', '', '6']}
+
+ queryString.parse('foo[]=1|2|3&bar=fluffy&baz[]=4', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> {foo: ['1', '2', '3'], bar: 'fluffy', baz:['4']}
+ ```
+
- `none`: Parse arrays with elements using duplicate keys:
```
@@ -54,7 +78,7 @@ export interface ParseOptions {
//=> {foo: ['1', '2', '3']}
```
*/
- readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
+ readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'bracket-separator' | 'none';
/**
The character used to separate array elements when using `{arrayFormat: 'separator'}`.
@@ -236,7 +260,7 @@ export interface StringifyOptions {
// and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
```
- - `separator`: Serialize arrays by separating elements with character:
+ - `separator`: Serialize arrays by separating elements with character:
```
import queryString = require('query-string');
@@ -245,6 +269,33 @@ export interface StringifyOptions {
//=> 'foo=1|2|3'
```
+ - `bracket-separator`: Serialize arrays by explicitly post-fixing array names with brackets and separating elements with a custom character:
+
+ ```
+ import queryString = require('query-string');
+
+ queryString.stringify({foo: []}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]'
+
+ queryString.stringify({foo: ['']}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]='
+
+ queryString.stringify({foo: [1]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]=1'
+
+ queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]=1|2|3'
+
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]=1||3|||6'
+
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|', skipNull: true});
+ //=> 'foo[]=1||3|6'
+
+ queryString.stringify({foo: [1, 2, 3], bar: 'fluffy', baz: [4]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+ //=> 'foo[]=1|2|3&bar=fluffy&baz[]=4'
+ ```
+
- `none`: Serialize arrays by using duplicate keys:
```
@@ -254,7 +305,7 @@ export interface StringifyOptions {
//=> 'foo=1&foo=2&foo=3'
```
*/
- readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
+ readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'bracket-separator' | 'none';
/**
The character used to separate array elements when using `{arrayFormat: 'separator'}`.
diff --git a/index.js b/index.js
index 07764d5..7ab5d92 100644
--- a/index.js
+++ b/index.js
@@ -49,6 +49,11 @@ function encoderForArrayFormat(options) {
case 'comma':
case 'separator':
+ case 'bracket-separator': {
+ const keyValueSep = options.arrayFormat === 'bracket-separator' ?
+ '[]=' :
+ '=';
+
return key => (result, value) => {
if (
value === undefined ||
@@ -58,16 +63,16 @@ function encoderForArrayFormat(options) {
return result;
}
- if (result.length === 0) {
- return [[encode(key, options), '=', encode(value === null ? '' : value, options)].join('')];
- }
+ // Translate null to an empty string so that it doesn't serialize as 'null'
+ value = value === null ? '' : value;
- if (value === null || value === '') {
- return [[result, ''].join(options.arrayFormatSeparator)];
+ if (result.length === 0) {
+ return [[encode(key, options), keyValueSep, encode(value, options)].join('')];
}
return [[result, encode(value, options)].join(options.arrayFormatSeparator)];
};
+ }
default:
return key => (result, value) => {
@@ -138,6 +143,28 @@ function parserForArrayFormat(options) {
accumulator[key] = newValue;
};
+ case 'bracket-separator':
+ return (key, value, accumulator) => {
+ const isArray = /(\[\])$/.test(key);
+ key = key.replace(/\[\]$/, '');
+
+ if (!isArray) {
+ accumulator[key] = value ? decode(value, options) : value;
+ return;
+ }
+
+ const arrayValue = value === null ?
+ [] :
+ value.split(options.arrayFormatSeparator).map(item => decode(item, options));
+
+ if (accumulator[key] === undefined) {
+ accumulator[key] = arrayValue;
+ return;
+ }
+
+ accumulator[key] = [].concat(accumulator[key], arrayValue);
+ };
+
default:
return (key, value, accumulator) => {
if (accumulator[key] === undefined) {
@@ -261,7 +288,7 @@ function parse(query, options) {
// Missing `=` should be `null`:
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
- value = value === undefined ? null : ['comma', 'separator'].includes(options.arrayFormat) ? value : decode(value, options);
+ value = value === undefined ? null : ['comma', 'separator', 'bracket-separator'].includes(options.arrayFormat) ? value : decode(value, options);
formatter(decode(key, options), value, ret);
}
@@ -343,6 +370,10 @@ exports.stringify = (object, options) => {
}
if (Array.isArray(value)) {
+ if (value.length === 0 && options.arrayFormat === 'bracket-separator') {
+ return encode(key, options) + '[]';
+ }
+
return value
.reduce(formatter(key), [])
.join('&');
diff --git a/readme.md b/readme.md
index f90aba6..600a971 100644
--- a/readme.md
+++ b/readme.md
@@ -138,6 +138,30 @@ queryString.parse('foo=1|2|3', {arrayFormat: 'separator', arrayFormatSeparator:
//=> {foo: ['1', '2', '3']}
```
+- `'bracket-separator'`: Parse arrays (that are explicitly marked with brackets) with elements separated by a custom character:
+
+```js
+const queryString = require('query-string');
+
+queryString.parse('foo[]', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: []}
+
+queryString.parse('foo[]=', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: ['']}
+
+queryString.parse('foo[]=1', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: ['1']}
+
+queryString.parse('foo[]=1|2|3', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: ['1', '2', '3']}
+
+queryString.parse('foo[]=1||3|||6', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: ['1', '', 3, '', '', '6']}
+
+queryString.parse('foo[]=1|2|3&bar=fluffy&baz[]=4', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> {foo: ['1', '2', '3'], bar: 'fluffy', baz:['4']}
+```
+
- `'none'`: Parse arrays with elements using duplicate keys:
```js
@@ -248,6 +272,42 @@ queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
// and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
```
+- `'separator'`: Serialize arrays by separating elements with a custom character:
+
+```js
+const queryString = require('query-string');
+
+queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'separator', arrayFormatSeparator: '|'});
+//=> 'foo=1|2|3'
+```
+
+- `'bracket-separator'`: Serialize arrays by explicitly post-fixing array names with brackets and separating elements with a custom character:
+
+```js
+const queryString = require('query-string');
+
+queryString.stringify({foo: []}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]'
+
+queryString.stringify({foo: ['']}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]='
+
+queryString.stringify({foo: [1]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]=1'
+
+queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]=1|2|3'
+
+queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]=1||3|||6'
+
+queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|', skipNull: true});
+//=> 'foo[]=1||3|6'
+
+queryString.stringify({foo: [1, 2, 3], bar: 'fluffy', baz: [4]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
+//=> 'foo[]=1|2|3&bar=fluffy&baz[]=4'
+```
+
- `'none'`: Serialize arrays by using duplicate keys:
```js
diff --git a/test/parse.js b/test/parse.js
index 70759f1..731a848 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -184,6 +184,36 @@ test('query strings having indexed arrays and format option as `index`', t => {
}), {foo: ['bar', 'baz']});
});
+test('query strings having brackets+separator arrays and format option as `bracket-separator` with 1 value', t => {
+ t.deepEqual(queryString.parse('foo[]=bar', {
+ arrayFormat: 'bracket-separator'
+ }), {foo: ['bar']});
+});
+
+test('query strings having brackets+separator arrays and format option as `bracket-separator` with multiple values', t => {
+ t.deepEqual(queryString.parse('foo[]=bar,baz,,,biz', {
+ arrayFormat: 'bracket-separator'
+ }), {foo: ['bar', 'baz', '', '', 'biz']});
+});
+
+test('query strings with multiple brackets+separator arrays and format option as `bracket-separator` using same key name', t => {
+ t.deepEqual(queryString.parse('foo[]=bar,baz&foo[]=biz,boz', {
+ arrayFormat: 'bracket-separator'
+ }), {foo: ['bar', 'baz', 'biz', 'boz']});
+});
+
+test('query strings having an empty brackets+separator array and format option as `bracket-separator`', t => {
+ t.deepEqual(queryString.parse('foo[]', {
+ arrayFormat: 'bracket-separator'
+ }), {foo: []});
+});
+
+test('query strings having a brackets+separator array and format option as `bracket-separator` with a single empty string', t => {
+ t.deepEqual(queryString.parse('foo[]=', {
+ arrayFormat: 'bracket-separator'
+ }), {foo: ['']});
+});
+
test('query strings having = within parameters (i.e. GraphQL IDs)', t => {
t.deepEqual(queryString.parse('foo=bar=&foo=ba=z='), {foo: ['bar=', 'ba=z=']});
});
diff --git a/test/stringify.js b/test/stringify.js
index 4b8bda5..c8751eb 100644
--- a/test/stringify.js
+++ b/test/stringify.js
@@ -172,6 +172,71 @@ test('array stringify representation with array indexes and sparse array', t =>
t.is(queryString.stringify({bar: fixture}, {arrayFormat: 'index'}), 'bar[0]=one&bar[1]=two&bar[2]=three');
});
+test('array stringify representation with brackets and separators with empty array', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: []
+ }, {
+ arrayFormat: 'bracket-separator'
+ }), 'bar[]&foo');
+});
+
+test('array stringify representation with brackets and separators with single value', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['one']
+ }, {
+ arrayFormat: 'bracket-separator'
+ }), 'bar[]=one&foo');
+});
+
+test('array stringify representation with brackets and separators with multiple values', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['one', 'two', 'three']
+ }, {
+ arrayFormat: 'bracket-separator'
+ }), 'bar[]=one,two,three&foo');
+});
+
+test('array stringify representation with brackets and separators with a single empty string', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['']
+ }, {
+ arrayFormat: 'bracket-separator'
+ }), 'bar[]=&foo');
+});
+
+test('array stringify representation with brackets and separators with a multiple empty string', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['', 'two', '']
+ }, {
+ arrayFormat: 'bracket-separator'
+ }), 'bar[]=,two,&foo');
+});
+
+test('array stringify representation with brackets and separators with dropped empty strings', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['', 'two', '']
+ }, {
+ arrayFormat: 'bracket-separator',
+ skipEmptyString: true
+ }), 'bar[]=two&foo');
+});
+
+test('array stringify representation with brackets and separators with dropped null values', t => {
+ t.is(queryString.stringify({
+ foo: null,
+ bar: ['one', null, 'three', null, '', 'six']
+ }, {
+ arrayFormat: 'bracket-separator',
+ skipNull: true
+ }), 'bar[]=one,three,,six');
+});
+
test('should sort keys in given order', t => {
const fixture = ['c', 'a', 'b'];
const sort = (key1, key2) => fixture.indexOf(key1) - fixture.indexOf(key2);
From 20992772758fc74188db64e789535469adaf241f Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Thu, 18 Mar 2021 18:53:55 +0700
Subject: [PATCH 06/12] 7.0.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index c75f01a..2680bc1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "query-string",
- "version": "6.14.1",
+ "version": "7.0.0",
"description": "Parse and stringify URL query strings",
"license": "MIT",
"repository": "sindresorhus/query-string",
From bc6b4785b123aa97d5bb44876356b9a1069798f6 Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Fri, 21 May 2021 19:05:11 +0700
Subject: [PATCH 07/12] Meta tweaks
---
readme.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/readme.md b/readme.md
index 600a971..68a8b6a 100644
--- a/readme.md
+++ b/readme.md
@@ -21,6 +21,7 @@
+

@@ -32,6 +33,16 @@
and avoiding access controls. Keep your team and servers in sync with Doppler.
+
+
+
+

+
+ Strapi is the leading open-source headless CMS.
+
+ It’s 100% JavaScript, fully customizable, and developer-first.
+
+
From 9e2482d458a5fc4a997fa9f1558d8a0daeeaa512 Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Wed, 26 May 2021 00:04:51 +0700
Subject: [PATCH 08/12] Update readme.md
---
readme.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 68a8b6a..67bd4bc 100644
--- a/readme.md
+++ b/readme.md
@@ -56,7 +56,9 @@
$ npm install query-string
```
-This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari. If you want support for older browsers, or, if your project is using create-react-app v1, use version 5: `npm install query-string@5`.
+**Not `npm install querystring`!!!!!**
+
+This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari.
## Usage
From 4279ef880c0d4fbbed60c3149bed73298800daa2 Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Wed, 9 Jun 2021 01:11:53 +0700
Subject: [PATCH 09/12] Meta tweaks
---
readme.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/readme.md b/readme.md
index 67bd4bc..24310d7 100644
--- a/readme.md
+++ b/readme.md
@@ -43,6 +43,15 @@
It’s 100% JavaScript, fully customizable, and developer-first.
+
+
+
+

+
+
+ Founded in 2018, OSS Capital is the first and only venture capital platform focused
exclusively on supporting early-stage COSS (commercial open source) startup founders.
+
+
From 8887f78ddc5a5755916ff53b7c4f9a2c845fa3df Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Sun, 20 Jun 2021 20:55:12 +0700
Subject: [PATCH 10/12] Add FAQ to the readme
Closes #305
---
readme.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/readme.md b/readme.md
index 24310d7..3af49af 100644
--- a/readme.md
+++ b/readme.md
@@ -620,6 +620,12 @@ queryString.stringify({foo: undefined});
//=> ''
```
+## FAQ
+
+### Why is it parsing `+` as a space?
+
+See [this answer](https://github.com/sindresorhus/query-string/issues/305).
+
## query-string for enterprise
Available as part of the Tidelift Subscription.
From fd3e7792e0ec0fb72925627869a4d583ed832e54 Mon Sep 17 00:00:00 2001
From: Richie Bendall
Date: Tue, 22 Jun 2021 05:30:44 +1200
Subject: [PATCH 11/12] Don't encode the fragment identifier in `.pick` and
`.exclude` (#320)
---
index.js | 10 +++++++---
test/exclude.js | 4 ++++
test/pick.js | 4 ++++
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/index.js b/index.js
index 7ab5d92..cc57637 100644
--- a/index.js
+++ b/index.js
@@ -6,6 +6,8 @@ const filterObject = require('filter-obj');
const isNullOrUndefined = value => value === null || value === undefined;
+const encodeFragmentIdentifier = Symbol('encodeFragmentIdentifier');
+
function encoderForArrayFormat(options) {
switch (options.arrayFormat) {
case 'index':
@@ -402,7 +404,8 @@ exports.parseUrl = (url, options) => {
exports.stringifyUrl = (object, options) => {
options = Object.assign({
encode: true,
- strict: true
+ strict: true,
+ [encodeFragmentIdentifier]: true
}, options);
const url = removeHash(object.url).split('?')[0] || '';
@@ -417,7 +420,7 @@ exports.stringifyUrl = (object, options) => {
let hash = getHash(object.url);
if (object.fragmentIdentifier) {
- hash = `#${encode(object.fragmentIdentifier, options)}`;
+ hash = `#${options[encodeFragmentIdentifier] ? encode(object.fragmentIdentifier, options) : object.fragmentIdentifier}`;
}
return `${url}${queryString}${hash}`;
@@ -425,7 +428,8 @@ exports.stringifyUrl = (object, options) => {
exports.pick = (input, filter, options) => {
options = Object.assign({
- parseFragmentIdentifier: true
+ parseFragmentIdentifier: true,
+ [encodeFragmentIdentifier]: false
}, options);
const {url, query, fragmentIdentifier} = exports.parseUrl(input, options);
diff --git a/test/exclude.js b/test/exclude.js
index 91e0d4f..646db88 100644
--- a/test/exclude.js
+++ b/test/exclude.js
@@ -15,3 +15,7 @@ test('excludes elements in a URL with a filter predicate', t => {
parseNumbers: true
}), 'http://example.com/?b=2&c=3#a');
});
+
+test('excludes elements in a URL without encoding fragment identifiers', t => {
+ t.is(queryString.exclude('https://example.com?a=b#/home', ['a']), 'https://example.com#/home');
+});
diff --git a/test/pick.js b/test/pick.js
index e5e4381..0bfaf72 100644
--- a/test/pick.js
+++ b/test/pick.js
@@ -15,3 +15,7 @@ test('picks elements in a URL with a filter predicate', t => {
parseNumbers: true
}), 'http://example.com/?a=1#a');
});
+
+test('picks elements in a URL without encoding fragment identifiers', t => {
+ t.is(queryString.pick('https://example.com?a=b#/home', []), 'https://example.com#/home');
+});
From b03e2e709664834e6cdcf50cd84b0056cdb5b7ff Mon Sep 17 00:00:00 2001
From: Sindre Sorhus
Date: Tue, 22 Jun 2021 00:33:16 +0700
Subject: [PATCH 12/12] 7.0.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 2680bc1..c1a4a75 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "query-string",
- "version": "7.0.0",
+ "version": "7.0.1",
"description": "Parse and stringify URL query strings",
"license": "MIT",
"repository": "sindresorhus/query-string",