Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

http-querystring-stringify

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

http-querystring-stringify - npm Package Compare versions

Comparing version 1.0.0 to 2.0.0

161

index.js

@@ -1,122 +0,105 @@

'use strict';
'use strict'
toQuerystring.serialize = serialize;
toQuerystring.shake = shake;
toQuerystring.normalize = normalize;
stringify.serialize = serialize
stringify.shake = shake
stringify.normalize = normalize
module.exports = toQuerystring;
module.exports = stringify
function toQuerystring( i ){
var shaken = shake(normalize(i));
function stringify(i) {
if (i === null || typeof i !== 'object' || Array.isArray(i)) {
throw new Error('Only objects can be stringified')
}
if (shaken === undefined)
return '';
const shaken = shake(normalize(i))
return serialize(shaken);
if (shaken === undefined) return ''
return serialize(shaken)
}
function serialize( i, prefix ){
function serialize(i, prefix) {
if (Array.isArray(i)) {
var hasComplex = i.some(isComplex);
const hasComplex = i.some(isComplex)
return i.map(function( i, idx ){
return serialize(i, prefix+(hasComplex
? '['+idx+']'
: '[]'));
}).join('&');
return i
.map((i, idx) => {
return serialize(
i,
prefix + (hasComplex ? '[' + idx + ']' : '[]')
)
})
.join('&')
}
if (typeof i === 'object')
return Object.keys(i).map(function( key ){
return serialize(i[key], prefix === undefined
? encodeURIComponent(key)
: prefix+'['+encodeURIComponent(key)+']');
}).join('&');
return prefix+'='+encodeURIComponent(i);
if (typeof i === 'object') {
return Object.keys(i)
.map(key => {
return serialize(
i[key],
prefix === undefined
? encodeURIComponent(key)
: prefix + '[' + encodeURIComponent(key) + ']'
)
})
.join('&')
}
return prefix + '=' + encodeURIComponent(i)
}
function shake( i ){
if (i === undefined)
return;
function shake(i) {
if (i === undefined) return
if (Array.isArray(i)) {
var shaken = i.map(shake).filter(isDefined);
const shaken = i.map(shake).filter(isDefined)
if (shaken.length === 0)
return;
return shaken;
if (shaken.length === 0) return
return shaken
}
if (typeof i === 'object') {
var empty = true;
let empty = true
const shaken = Object.keys(i).reduce((o, key) => {
const shaken = shake(i[key])
var shaken = Object.keys(i).reduce(function( o, key ){
var shaken = shake(i[key]);
if (shaken !== undefined) {
empty = false;
o[key] = shaken;
empty = false
o[key] = shaken
}
return o;
}, {});
return o
}, {})
if (empty)
return;
return shaken;
if (empty) return
return shaken
}
return i;
return i
}
function normalize( i ){
if (i === undefined)
return undefined;
function normalize(i) {
if (i === undefined) return undefined
if (i === null) return ''
if (i === true) return 'y'
if (i === false) return 'n'
if (typeof i.toJSON === 'function') return normalize(i.toJSON())
if (i === null)
return '';
const type = typeof i
if (i === true)
return 'y';
if (type === 'string') return i
if (Array.isArray(i)) return i.map(normalize)
if (type === 'object') {
return Object.keys(i).reduce((o, key) => {
o[key] = normalize(i[key])
if (i === false)
return 'n';
return o
}, {})
}
if (typeof i.toJSON === 'function')
return normalize(i.toJSON());
var type = typeof i;
if (type === 'string')
return i;
if (Array.isArray(i))
return i.map(normalize);
if (type === 'object')
return Object.keys(i).reduce(function( o, key ){
o[key] = normalize(i[key]);
return o;
}, {});
return i+'';
return i + ''
}
function isDefined( i ){
return i !== undefined;
function isDefined(i) {
return i !== undefined
}
function isComplex( i ){
if (Array.isArray(i))
return true;
if (typeof i === 'object')
return true;
return false;
function isComplex(i) {
if (Array.isArray(i)) return true
if (typeof i === 'object') return true
return false
}
{
"name": "http-querystring-stringify",
"description": "Create querystrings",
"version": "1.0.0",
"version": "2.0.0",
"repository": "srcagency/http-querystring-stringify",
"scripts": {
"test": "node test"
"test": "node test",
"format": "prettier --write ./*"
},
"devDependencies": {
"tape": "^4.6.3"
"prettier": "^1.14.3",
"tape": "^4.9.1"
},
"prettier": {
"semi": false,
"singleQuote": true,
"useTabs": true,
"bracketSpacing": false,
"trailingComma": "es5",
"tabWidth": 4,
"overrides": [
{
"files": "*.md",
"options": {
"tabWidth": 2
}
}
]
},
"license": "MIT"
}

@@ -13,8 +13,8 @@ # http-querystring-stringify

This package was written because serialization seems to happen most often on
the client as a single operation and similar performance-focused libraries had
This package was written because serialization seems to happen most often on the
client as a single operation and similar performance-focused libraries had
trade-offs and bugs while others carried huge dependencies.
```js
var stringify = require('http-querystring-stringify');
var stringify = require('http-querystring-stringify')

@@ -24,15 +24,13 @@ stringify({

last: 'Wayne',
});
})
// -> first=John&last=Wayne
stringify({
brands: [ 'KitKat', 'Snickers', 'Bounty' ],
});
brands: ['KitKat', 'Snickers', 'Bounty'],
})
// -> brands[]=KitKat&brands[]=Snickers&brands[]=Bounty
stringify({
sites: [
{ name: 'facebook', 'color': 'blue' },
],
});
sites: [{name: 'facebook', color: 'blue'}],
})
// -> sites[0][name]=facebook&sites[0][color]=blue

@@ -44,3 +42,59 @@ ```

- `null` is represented by an empty string
- `undefined` values will be skipped completely
- `undefined` values will be skipped completely (like `JSON.stringify` does)
- arrays will be numbered only if they contain arrays or objects themselves
## Compatibility with parsers
Generally there are two types of parsers: those supporting extended nesting and
those that just support repeated keys.
### Perfect support (extended nesting):
- [querystringparser](https://github.com/petkaantonov/querystringparser) (read
open issues)
- [qs](https://github.com/ljharb/qs)
```js
var input = {
a: '',
b: 's',
c: [ '1', '2', '3' ],
d: '&=[]',
e: [ '1', '2', [ '3', '4' ] ],
f: [ '1', { a: '1' } ],
}
deepEqual(parse(stringify(input)), input);
-> true;
```
### Will flatten:
- [Node.js built-in](https://nodejs.org/api/url.html)
- [URI.js](https://github.com/medialize/URI.js)
```js
parse(stringify({
a: '',
b: 's',
c: [ '1', '2', '3' ],
d: '&=[]',
e: [ '1', '2', [ '3', '4' ] ],
f: [ '1', { a: '1' } ],
}));
-> {
a: '',
b: 's',
d: '&=[]',
// expect arrays to be collapsed like this
'c[]': [ '1', '2', '3' ],
// expect objects and multi-level arrays to be flattened like this
'e[0]': '1',
'e[1]': '2',
'e[2][]': [ '3', '4' ],
'f[0]': '1',
'f[1][a]': '1',
};
```

@@ -1,124 +0,149 @@

'use strict';
'use strict'
var test = require('tape');
var stringify = require('./');
const test = require('tape')
const stringify = require('./')
test('normalize', function( t ){
t.deepEqual(stringify.normalize([
undefined,
null,
true,
false,
1,
'a',
'',
'&=[]',
// parsers
const nodejs = require('url').parse
const querystringparser = require('querystringparser').parse
const qs = require('qs').parse
const urijs = require('urijs').parseQuery
{
a: undefined,
b: null,
c: true,
d: false,
e: 'a',
f: '',
g: '&=[]',
},
]), [
undefined,
'',
'y',
'n',
'1',
'a',
'',
'&=[]',
test('normalize', t => {
t.deepEqual(
stringify.normalize([
undefined,
null,
true,
false,
1,
'a',
'',
'&=[]',
{
a: undefined,
b: '',
c: 'y',
d: 'n',
e: 'a',
f: '',
g: '&=[]',
},
]);
{
a: undefined,
b: null,
c: true,
d: false,
e: 'a',
f: '',
g: '&=[]',
},
]),
[
undefined,
'',
'y',
'n',
'1',
'a',
'',
'&=[]',
t.deepEqual(stringify.normalize({}), {});
{
a: undefined,
b: '',
c: 'y',
d: 'n',
e: 'a',
f: '',
g: '&=[]',
},
]
)
t.end();
});
t.deepEqual(stringify.normalize({}), {})
test('shake', function( t ){
t.deepEqual(stringify.shake([
undefined,
'a',
undefined,
'',
{},
{ a: undefined },
{
a: undefined,
b: '',
},
[],
[ undefined ],
[ undefined, '' ],
]), [
'a',
'',
{ b: '' },
[ '' ]
]);
t.end()
})
t.equal(stringify.shake({}), undefined);
test('shake', t => {
t.deepEqual(
stringify.shake([
undefined,
'a',
undefined,
'',
{},
{a: undefined},
{
a: undefined,
b: '',
},
[],
[undefined],
[undefined, ''],
]),
['a', '', {b: ''}, ['']]
)
t.end();
});
t.equal(stringify.shake({}), undefined)
test('serialize', function( t ){
t.equal(stringify.serialize({
a: '',
b: 's',
c: [ '1', '2', '3' ],
d: '&=[]',
e: [ '1', '2', [ '3', '4' ] ],
f: [ '1', { a: 1 } ],
}), 'a=&b=s&c[]=1&c[]=2&c[]=3&d=%26%3D%5B%5D&e[0]=1&e[1]=2&e[2][]=3&e[2][]=4&f[0]=1&f[1][a]=1');
t.end()
})
t.deepEqual(stringify.serialize({}), '');
test('serialize', t => {
t.equal(
stringify.serialize({
a: '',
b: 's',
c: ['1', '2', '3'],
d: '&=[]',
e: ['1', '2', ['3', '4']],
f: ['1', {a: 1}],
}),
'a=&b=s&c[]=1&c[]=2&c[]=3&d=%26%3D%5B%5D&e[0]=1&e[1]=2&e[2][]=3&e[2][]=4&f[0]=1&f[1][a]=1'
)
t.end();
});
t.deepEqual(stringify.serialize({}), '')
test('stringify', function( t ){
t.equal(stringify({
// normalizes
a: true,
t.end()
})
// shakes
b: undefined,
test('stringify', t => {
t.throws(() => stringify(), /Only objects can be stringified/)
t.throws(() => stringify(null), /Only objects can be stringified/)
t.throws(() => stringify(''), /Only objects can be stringified/)
t.throws(() => stringify(1), /Only objects can be stringified/)
t.throws(() => stringify([]), /Only objects can be stringified/)
// serializes
c: '&=[]',
}), 'a=y&c=%26%3D%5B%5D');
t.equal(
stringify({
// normalizes
a: true,
t.equal(stringify({
at: new Date(0),
}), 'at=1970-01-01T00%3A00%3A00.000Z');
// shakes
b: undefined,
// serializes
c: '&=[]',
}),
'a=y&c=%26%3D%5B%5D'
)
t.equal(
stringify({
at: new Date(0),
}),
'at=1970-01-01T00%3A00%3A00.000Z'
)
// https://github.com/petkaantonov/querystringparser/issues/3
t.equal(stringify({
a: { b: { c: true } },
d: true,
}), 'a[b][c]=y&d=y');
t.equal(
stringify({
a: {b: {c: true}},
d: true,
}),
'a[b][c]=y&d=y'
)
t.equal(stringify({}), '');
t.equal(stringify({}), '')
t.equal(stringify({ code: 204 }), 'code=204');
t.equal(stringify({code: 204}), 'code=204')
t.end();
});
t.end()
})
test('serialize (from petkaantonov/querystringparser)', function( t ){
test('serialize (from petkaantonov/querystringparser)', t => {
/*

@@ -135,243 +160,295 @@

t.equal(stringify({
'foo': 'bar'
}), 'foo=bar');
t.equal(
stringify({
foo: 'bar',
}),
'foo=bar'
)
t.equal(stringify({
'foo': 'bar',
'bar': 'baz'
}), 'foo=bar&bar=baz');
t.equal(
stringify({
foo: 'bar',
bar: 'baz',
}),
'foo=bar&bar=baz'
)
t.equal(stringify({
'foo': '\"bar\"'
}), 'foo=%22bar%22');
t.equal(
stringify({
foo: '"bar"',
}),
'foo=%22bar%22'
)
t.equal(stringify({
foo: ''
}), 'foo=');
t.equal(
stringify({
foo: '',
}),
'foo='
)
t.equal(stringify({
'foo': '1',
'bar': '2'
}), 'foo=1&bar=2');
t.equal(
stringify({
foo: '1',
bar: '2',
}),
'foo=1&bar=2'
)
t.equal(stringify({
'my weird field': "q1!2\"'w$5&7/z8)?"
}), 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F');
t.equal(
stringify({
'my weird field': 'q1!2"\'w$5&7/z8)?',
}),
"my%20weird%20field=q1!2%22'w%245%267%2Fz8)%3F"
)
t.equal(stringify({
'foo=baz': 'bar'
}), 'foo%3Dbaz=bar');
t.equal(
stringify({
'foo=baz': 'bar',
}),
'foo%3Dbaz=bar'
)
t.equal(stringify({
foo: 'bar',
bar: 'baz'
}), 'foo=bar&bar=baz');
t.equal(
stringify({
foo: 'bar',
bar: 'baz',
}),
'foo=bar&bar=baz'
)
t.equal(stringify({
foo: 'bar',
baz: '',
raz: ''
}), 'foo=bar&baz=&raz=');
t.equal(
stringify({
foo: 'bar',
baz: '',
raz: '',
}),
'foo=bar&baz=&raz='
)
// escaping
t.equal(stringify({
foo: 'foo bar'
}), 'foo=foo%20bar');
t.equal(
stringify({
foo: 'foo bar',
}),
'foo=foo%20bar'
)
t.equal(stringify({
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World'
}), 'cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld');
t.equal(
stringify({
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World',
}),
'cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld'
)
// nested (some modified)
// nested (some modified)
var str, obj;
let str, obj
str = 'foo[]=bar';
str = 'foo[]=bar'
obj = {
'foo': ['bar']
};
t.equal(stringify(obj), str);
foo: ['bar'],
}
t.equal(stringify(obj), str)
str = 'foo[]=bar&foo[]=quux';
str = 'foo[]=bar&foo[]=quux'
obj = {
'foo': ['bar', 'quux']
};
t.equal(stringify(obj), str);
foo: ['bar', 'quux'],
}
t.equal(stringify(obj), str)
str = 'foo[]=0&foo[]=1';
str = 'foo[]=0&foo[]=1'
obj = {
'foo': ['0', '1']
};
t.equal(stringify(obj), str);
foo: ['0', '1'],
}
t.equal(stringify(obj), str)
str = 'foo=bar&baz[]=1&baz[]=2&baz[]=3';
str = 'foo=bar&baz[]=1&baz[]=2&baz[]=3'
obj = {
'foo': 'bar',
'baz': ['1', '2', '3']
};
t.equal(stringify(obj), str);
foo: 'bar',
baz: ['1', '2', '3'],
}
t.equal(stringify(obj), str)
str = 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3';
str = 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
obj = {
'foo': ['bar'],
'baz': ['1', '2', '3']
};
t.equal(stringify(obj), str);
foo: ['bar'],
baz: ['1', '2', '3'],
}
t.equal(stringify(obj), str)
str = 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3';
str = 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
obj = {
'foo': ['bar'],
'baz': ['1', '2', '3']
};
t.equal(stringify(obj), str);
foo: ['bar'],
baz: ['1', '2', '3'],
}
t.equal(stringify(obj), str)
str = 'x[y][z][]=1';
str = 'x[y][z][]=1'
obj = {
'x': {
'y': {
'z': ['1']
}
}
};
t.equal(stringify(obj), str);
x: {
y: {
z: ['1'],
},
},
}
t.equal(stringify(obj), str)
str = 'x[y][z]=1';
str = 'x[y][z]=1'
obj = {
'x': {
'y': {
'z': '1'
}
}
};
t.equal(stringify(obj), str);
x: {
y: {
z: '1',
},
},
}
t.equal(stringify(obj), str)
str = 'x[y][z]=2';
str = 'x[y][z]=2'
obj = {
'x': {
'y': {
'z': '2'
}
}
};
t.equal(stringify(obj), str);
x: {
y: {
z: '2',
},
},
}
t.equal(stringify(obj), str)
str = 'x[y][z][]=1&x[y][z][]=2';
str = 'x[y][z][]=1&x[y][z][]=2'
obj = {
'x': {
'y': {
'z': ['1', '2']
}
}
};
t.equal(stringify(obj), str);
x: {
y: {
z: ['1', '2'],
},
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z]=1';
str = 'x[y][0][z]=1'
obj = {
'x': {
'y': [{
'z': '1'
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: '1',
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z][]=1';
str = 'x[y][0][z][]=1'
obj = {
'x': {
'y': [{
'z': ['1']
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: ['1'],
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z][]=1';
str = 'x[y][0][z][]=1'
obj = {
'x': {
'y': [{
'z': ['1']
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: ['1'],
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z][]=1';
str = 'x[y][0][z][]=1'
obj = {
'x': {
'y': [{
'z': ['1']
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: ['1'],
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z]=1&x[y][0][w]=2';
str = 'x[y][0][z]=1&x[y][0][w]=2'
obj = {
'x': {
'y': [{
'z': '1',
'w': '2'
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: '1',
w: '2',
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][v][w]=1';
str = 'x[y][0][v][w]=1'
obj = {
'x': {
'y': [{
'v': {
'w': '1'
}
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
v: {
w: '1',
},
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z]=1&x[y][0][v][w]=2';
str = 'x[y][0][z]=1&x[y][0][v][w]=2'
obj = {
'x': {
'y': [{
'z': '1',
'v': {
'w': '2'
}
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: '1',
v: {
w: '2',
},
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z]=1&x[y][1][z]=2';
str = 'x[y][0][z]=1&x[y][1][z]=2'
obj = {
'x': {
'y': [{
'z': '1'
}, {
'z': '2'
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: '1',
},
{
z: '2',
},
],
},
}
t.equal(stringify(obj), str)
str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3';
str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3'
obj = {
'x': {
'y': [{
'z': '1',
'w': 'a'
}, {
'z': '2',
'w': '3'
}]
}
};
t.equal(stringify(obj), str);
x: {
y: [
{
z: '1',
w: 'a',
},
{
z: '2',
w: '3',
},
],
},
}
t.equal(stringify(obj), str)
str = 'user[name][first]=tj&user[name][last]=holowaychuk';
str = 'user[name][first]=tj&user[name][last]=holowaychuk'
obj = {

@@ -381,10 +458,60 @@ user: {

first: 'tj',
last: 'holowaychuk'
}
}
};
t.equal(stringify(obj), str);
last: 'holowaychuk',
},
},
}
t.equal(stringify(obj), str)
t.end()
})
t.end();
});
test('compatibility with parsers', t => {
const subject = {
a: '',
b: 's',
c: ['1', '2', '3'],
d: '&=[]',
e: ['1', '2', ['3', '4']],
f: ['1', {a: '1'}],
}
const flattened = {
a: '',
b: 's',
d: '&=[]',
// expect arrays to be collapsed like this
'c[]': ['1', '2', '3'],
// expect objects and multi-level arrays to be flattened like this
'e[0]': '1',
'e[1]': '2',
'e[2][]': ['3', '4'],
'f[0]': '1',
'f[1][a]': '1',
}
t.test('Node.js built-in (flat)', t => {
t.plan(1)
t.deepEqual(nodejs('?' + stringify(subject), true).query, flattened)
})
t.test('querystringparser', t => {
t.plan(1)
t.deepEqual(querystringparser(stringify(subject)), subject)
})
t.test('qs', t => {
t.plan(1)
t.deepEqual(qs(stringify(subject)), subject)
})
t.test('urijs (flat)', t => {
t.plan(1)
t.deepEqual(urijs(stringify(subject)), flattened)
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc