Socket
Socket
Sign inDemoInstall

qs-kit

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

qs-kit - npm Package Compare versions

Comparing version 0.5.1 to 0.6.0

315

lib/qs.js

@@ -27,17 +27,24 @@ /*

"use strict" ;
/*
Most of this code is directly borrowed from the core Node.js 'querystring' module.
If option 'autoNumber' is on, valid numbers are cast to number
If option 'keyPath' is on, this modification allow object dot notation and left-hand-side array notation:
a.b=1&a.c=2 -> { a: { b: '1' , c: '2' } }
a[0]=one&a[1]=two -> { a: [ 'one' , 'two' ] }
a.b=1&a.c=2 -> { a: { b: '1' , c: '2' } }
a[0]=one&a[1]=two -> { a: [ 'one' , 'two' ] }
If option 'brackets' is on:
a=[b,c,d] -> { a: [ 'b' , 'c' , 'd' ] }
a=[b,c,d] -> { a: [ 'b' , 'c' , 'd' ] }
If option 'autoPush' is on:
a=b&a=c&a=d -> { a: [ 'b' , 'c' , 'd' ] }
a=b&a=c&a=d -> { a: [ 'b' , 'c' , 'd' ] }
If option 'restQueryFilter' is on:
.path.to.prop.$lt=10 -> { "path.to.prop": { $lt: 10 } }
Still, not everything is possible.

@@ -48,13 +55,13 @@ */

'use strict' ;
const tree = require( 'tree-kit' ) ;
// Load modules
var tree = require( 'tree-kit' ) ;
const QueryString = {} ;
module.exports = QueryString ;
var QueryString = {} ;
module.exports = QueryString ;
const partRe = /\+/g ;
const numberRe = /^-?[0-9]+(?:\.[0-9]+)?$/ ;

@@ -68,16 +75,15 @@

*/
QueryString.parse = QueryString.decode = function( str , options ) {
if ( ! options ) { options = {} ; }
QueryString.parse = QueryString.decode = function( str , options = {} ) {
var i , iMax , j , jMax , count = 0 ,
strParts , current ,
key , value , operator ,
indexOfEq , indexOfDotDollar ,
object = {} ;
//console.log( "QS-kit: " , str , options ) ;
var i , iMax , j , jMax , x , idx , k , v , count = 0 , obj = {} ;
var sep = options.separator || '&' ;
var eq = options.equal || '=' ;
if ( typeof str !== 'string' || str.length === 0 ) { return obj ; }
if ( typeof str !== 'string' || str.length === 0 ) { return object ; }
var regexp = /\+/g ;
str = str.split( sep ) ;
strParts = str.split( sep ) ;

@@ -87,35 +93,49 @@ var maxItems = 1000 ;

iMax = str.length ;
iMax = strParts.length ;
var decode = QueryString.unescape ;
for ( i = 0 ; i < iMax && count < maxItems ; i ++ , count ++ ) {
current = strParts[ i ].replace( partRe , '%20' ) ;
indexOfEq = current.indexOf( eq ) ;
if ( typeof options.decodeURIComponent === 'function' ) {
decode = options.decodeURIComponent ;
}
if ( indexOfEq === -1 ) { continue ; }
for ( i = 0 ; i < iMax && count < maxItems ; i ++ , count ++ ) {
x = str[ i ].replace( regexp , '%20' ) ;
idx = x.indexOf( eq ) ;
key = decodeURIComponent( current.substring( 0 , indexOfEq ) ) ;
if ( idx === -1 ) { continue ; }
if ( ! key ) { throw Error( "Empty key" ) ; }
k = decodeStr( x.substring( 0 , idx ) , decode ) ;
//console.log( "key:",key ) ;
if ( ! k ) { throw Error( "Empty key" ) ; }
value = current.substring( indexOfEq + 1 ) ;
//console.log( "k:",k ) ;
if ( options.restQueryFilter && key[ 0 ] === '.' ) {
if ( options.autoNumber && numberRe.test( value ) ) { value = parseFloat( value ) ; }
v = x.substring( idx + 1 ) ;
indexOfDotDollar = key.lastIndexOf( '.$' ) ;
if ( options.brackets && v[ 0 ] === '[' && v[ v.length - 1 ] === ']' ) {
if ( v.length === 2 ) {
if ( indexOfDotDollar >= 0 ) {
operator = key.slice( indexOfDotDollar + 1 ) ;
key = key.slice( 1 , indexOfDotDollar ) ;
object[ key ] = {} ;
object[ key ][ operator ] = value ;
}
else {
key = key.slice( 1 ) ;
object[ key ] = value ;
}
continue ;
}
if ( options.brackets && value[ 0 ] === '[' && value[ value.length - 1 ] === ']' ) {
if ( value.length === 2 ) {
// This is an empty array
v = [] ;
value = [] ;
}
else {
v = v.substring( 1 , v.length - 1 ).split( ',' ) ;
jMax = v.length ;
value = value.substring( 1 , value.length - 1 ).split( ',' ) ;
jMax = value.length ;
for ( j = 0 ; j < jMax && count < maxItems ; j ++ , count ++ ) {
v[ j ] = decodeStr( v[ j ] , decode ) ;
value[ j ] = decodeURIComponent( value[ j ] ) ;
if ( options.autoNumber && numberRe.test( value[ j ] ) ) { value[ j ] = parseFloat( value[ j ] ) ; }
}

@@ -125,16 +145,23 @@ }

else {
v = decodeStr( v , decode ) ;
value = decodeURIComponent( value ) ;
if ( options.autoNumber && numberRe.test( value ) ) { value = parseFloat( value ) ; }
}
//console.log( "tree.path.set( obj , k , v ):\nobj:" , obj , "\nk:" , k , "\nv:" , v ) ;
//console.log( "tree.path.set( object , k , value ):\nobject:" , object , "\nk:" , k , "\nvalue:" , value ) ;
if ( options.keyPath ) {
if ( options.autoPush ) { tree.path.autoPush( obj , k , v ) ; }
else { tree.path.set( obj , k , v ) ; }
if ( options.autoPush ) { tree.path.autoPush( object , key , value ) ; }
else { tree.path.set( object , key , value ) ; }
}
else if ( obj[ k ] === undefined || ! options.autoPush ) { obj[ k ] = v ; }
else if ( Array.isArray( obj[ k ] ) ) { obj[ k ].push( v ) ; }
else { obj[ k ] = [ obj[ k ] , v ] ; }
else if ( object[ key ] === undefined || ! options.autoPush ) {
object[ key ] = value ;
}
else if ( Array.isArray( object[ key ] ) ) {
object[ key ].push( value ) ;
}
else {
object[ key ] = [ object[ key ] , value ] ;
}
}
return obj ;
return object ;
} ;

@@ -146,5 +173,3 @@

QueryString.stringify = QueryString.encode = function( obj , options ) {
if ( ! options ) { options = {} ; }
QueryString.stringify = QueryString.encode = function( object , options = {} ) {
var i , iMax , j , k , v , ks , keys ,

@@ -155,10 +180,7 @@ lastField , fields = '' , vLength , vLast ;

var eq = options.equal || '=' ;
var encode = QueryString.escape ;
obj = tree.extend( EXTEND_OPTIONS , {} , obj ) ;
object = tree.extend( EXTEND_OPTIONS , {} , object ) ;
if ( typeof options.encodeURIComponent === 'function' ) { encode = options.encodeURIComponent ; }
if ( obj !== null && typeof obj === 'object' ) {
keys = Object.keys( obj ) ;
if ( object !== null && typeof object === 'object' ) {
keys = Object.keys( object ) ;
iMax = keys.length ;

@@ -169,4 +191,4 @@ lastField = iMax - 1 ;

k = keys[ i ] ;
v = obj[ k ] ;
ks = encode( stringifyPrimitive( k ) ) ;
v = object[ k ] ;
ks = encodeURIComponent( stringifyPrimitive( k ) ) ;

@@ -181,3 +203,3 @@ if ( Array.isArray( v ) ) {

for ( j = 0 ; j < vLength ; j ++ ) {
fields += encode( stringifyPrimitive( v[ j ] ) ) ;
fields += encodeURIComponent( stringifyPrimitive( v[ j ] ) ) ;
if ( j < vLast ) { fields += ',' ; }

@@ -195,3 +217,3 @@ }

for ( j = 0 ; j < vLength ; j ++ ) {
fields += ks + '[' + j + ']' + eq + encode( stringifyPrimitive( v[ j ] ) ) ;
fields += ks + '[' + j + ']' + eq + encodeURIComponent( stringifyPrimitive( v[ j ] ) ) ;
if ( j < vLast ) { fields += '&' ; }

@@ -204,3 +226,3 @@ }

else {
fields += ks + eq + encode( stringifyPrimitive( v ) ) ;
fields += ks + eq + encodeURIComponent( stringifyPrimitive( v ) ) ;
if ( i < lastField ) { fields += sep ; }

@@ -218,173 +240,8 @@ }

// Unmodified part, from Node.js v4.1.1
// Turn off eslint, since it's not my code...
/* eslint-disable */
function charCode(c) {
return c.charCodeAt(0);
function stringifyPrimitive( v ) {
if ( typeof v === 'string' ) { return v ; }
if ( typeof v === 'number' && isFinite( v ) ) { return '' + v ; }
if ( typeof v === 'boolean' ) { return v ? 'true' : 'false' ; }
return '' ;
}
// a safe fast alternative to decodeURIComponent
QueryString.unescapeBuffer = function(s, decodeSpaces) {
var out = Buffer.allocUnsafe(s.length);
var state = 'CHAR'; // states: CHAR, HEX0, HEX1
var n, m, hexchar;
for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
var c = s.charCodeAt(inIndex);
switch (state) {
case 'CHAR':
switch (c) {
case charCode('%'):
n = 0;
m = 0;
state = 'HEX0';
break;
case charCode('+'):
if (decodeSpaces) c = charCode(' ');
// falls through
default:
out[outIndex++] = c;
break;
}
break;
case 'HEX0':
state = 'HEX1';
hexchar = c;
if (charCode('0') <= c && c <= charCode('9')) {
n = c - charCode('0');
} else if (charCode('a') <= c && c <= charCode('f')) {
n = c - charCode('a') + 10;
} else if (charCode('A') <= c && c <= charCode('F')) {
n = c - charCode('A') + 10;
} else {
out[outIndex++] = charCode('%');
out[outIndex++] = c;
state = 'CHAR';
break;
}
break;
case 'HEX1':
state = 'CHAR';
if (charCode('0') <= c && c <= charCode('9')) {
m = c - charCode('0');
} else if (charCode('a') <= c && c <= charCode('f')) {
m = c - charCode('a') + 10;
} else if (charCode('A') <= c && c <= charCode('F')) {
m = c - charCode('A') + 10;
} else {
out[outIndex++] = charCode('%');
out[outIndex++] = hexchar;
out[outIndex++] = c;
break;
}
out[outIndex++] = 16 * n + m;
break;
}
}
// TODO support returning arbitrary buffers.
return out.slice(0, outIndex - 1);
};
QueryString.unescape = function(s, decodeSpaces) {
try {
return decodeURIComponent(s);
} catch (e) {
return QueryString.unescapeBuffer(s, decodeSpaces).toString();
}
};
var hexTable = new Array(256);
for (var i = 0; i < 256; ++i)
hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
QueryString.escape = function(str) {
// replaces encodeURIComponent
// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
str = '' + str;
var len = str.length;
var out = '';
var i, c;
if (len === 0)
return str;
for (i = 0; i < len; ++i) {
c = str.charCodeAt(i);
// These characters do not need escaping (in order):
// ! - . _ ~
// ' ( ) *
// digits
// alpha (uppercase)
// alpha (lowercase)
if (c === 0x21 || c === 0x2D || c === 0x2E || c === 0x5F || c === 0x7E ||
(c >= 0x27 && c <= 0x2A) ||
(c >= 0x30 && c <= 0x39) ||
(c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A)) {
out += str[i];
continue;
}
// Other ASCII characters
if (c < 0x80) {
out += hexTable[c];
continue;
}
// Multi-byte characters ...
if (c < 0x800) {
out += hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)];
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out += hexTable[0xE0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3F)] +
hexTable[0x80 | (c & 0x3F)];
continue;
}
// Surrogate pair
++i;
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
out += hexTable[0xF0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3F)] +
hexTable[0x80 | ((c >> 6) & 0x3F)] +
hexTable[0x80 | (c & 0x3F)];
}
return out;
};
var stringifyPrimitive = function(v) {
if (typeof v === 'string')
return v;
if (typeof v === 'number' && isFinite(v))
return '' + v;
if (typeof v === 'boolean')
return v ? 'true' : 'false';
return '';
};
function decodeStr(s, decoder) {
try {
return decoder(s);
} catch (e) {
return QueryString.unescape(s, true);
}
}
{
"name": "qs-kit",
"version": "0.5.1",
"version": "0.6.0",
"description": "A query string manipulation toolbox.",

@@ -5,0 +5,0 @@ "main": "lib/qs.js",

@@ -51,2 +51,9 @@ /*

it( "'autoNumber' option" , () => {
var options = { autoNumber: true } ;
expect( qs.parse( "a=10&b=20&c=string" , options ) ).to.equal( { a: 10 , b: 20 , c: "string" } ) ;
expect( qs.parse( "a=1&b=-2&c=12.345&d=-123.45" , options ) ).to.equal( { a: 1 , b: -2 , c: 12.345 , d: -123.45 } ) ;
expect( qs.parse( "a=10ab&b=2a" , options ) ).to.equal( { a: "10ab" , b: "2a" } ) ;
} ) ;
it( "String encoded" , () => {

@@ -57,3 +64,3 @@ expect( qs.parse( "key=some%20value" ) ).to.equal( { key: "some value" } ) ;

it( "Array 'autoPush' option" , () => {
options = { autoPush: true } ;
var options = { autoPush: true } ;
expect( qs.parse( "key=one&key=two&key=three" ) ).to.equal( { key: 'three' } ) ;

@@ -70,3 +77,3 @@ expect( qs.parse( "key=one&key=two&key=three" , options ) ).to.equal( { key: [ 'one' , 'two' , 'three' ] } ) ;

it( "Array 'keyPath' option" , () => {
options = { keyPath: true } ;
var options = { keyPath: true } ;
expect( qs.parse( "a[0]=val&a[1]=val2" ) ).to.equal( { "a[0]": 'val' , "a[1]": 'val2' } ) ;

@@ -77,5 +84,7 @@ expect( qs.parse( "a[0]=val&a[1]=val2" , options ) ).to.equal( { a: [ 'val' , 'val2' ] } ) ;

it( "Object 'keyPath' option" , () => {
options = { keyPath: true } ;
var options = { keyPath: true } ;
expect( qs.parse( "a.b=val" ) ).to.equal( { "a.b": 'val' } ) ;
expect( qs.parse( "a.b=val" , options ) ).to.equal( { a: { b: 'val' } } ) ;
expect( qs.parse( "a.b=val&a.c=ue" , options ) ).to.equal( { a: { b: 'val' , c: 'ue' } } ) ;
expect( qs.parse( "a.b=val&c.d=ue" , options ) ).to.equal( { a: { b: 'val' } , c: { d: 'ue' } } ) ;
} ) ;

@@ -89,2 +98,8 @@

} ) ;
it( "'restQueryFilter' option" , () => {
var options = { restQueryFilter: true , autoNumber: true } ;
expect( qs.parse( ".path.to.prop=value" , options ) ).to.equal( { "path.to.prop": "value" } ) ;
expect( qs.parse( ".path.to.prop.$lt=10" , options ) ).to.equal( { "path.to.prop": { $lt: 10 } } ) ;
} ) ;
} ) ;

@@ -115,5 +130,1 @@

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