[Pkg-javascript-commits] [node-qs] 07/09: Imported Upstream version 0.6.5

Jérémy Lal kapouer-guest at alioth.debian.org
Wed Aug 14 09:32:09 UTC 2013


This is an automated email from the git hooks/post-receive script.

kapouer-guest pushed a commit to branch master
in repository node-qs.

commit ac3fb6de461f5b249b8138312424ca08e0a05892
Author: Jérémy Lal <kapouer at melix.org>
Date:   Wed Aug 14 11:27:40 2013 +0200

    Imported Upstream version 0.6.5
---
 .npmignore => .gitignore |    0
 .npmignore               |    8 +-
 .travis.yml              |    7 +-
 History.md               |   37 ++++++++++
 component.json           |    2 +-
 examples.js              |    6 +-
 index.js                 |  185 ++++++++++++++++++++++++++++++++++++++--------
 package.json             |    8 +-
 test/browser/qs.js       |  139 ++++++++++++++++++++++++----------
 test/parse.js            |   32 +++++++-
 test/stringify.js        |    3 +-
 11 files changed, 345 insertions(+), 82 deletions(-)

diff --git a/.npmignore b/.gitignore
similarity index 100%
copy from .npmignore
copy to .gitignore
diff --git a/.npmignore b/.npmignore
index 3c3629e..e85ce2a 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1 +1,7 @@
-node_modules
+test
+.travis.yml
+benchmark.js
+component.json
+examples.js
+History.md
+Makefile
diff --git a/.travis.yml b/.travis.yml
index 2c0a8f6..d999054 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,7 @@
 language: node_js
 node_js:
-  - 0.6
-  - 0.4
\ No newline at end of file
+  - "0.11"
+  - "0.10"
+  - "0.9"
+  - "0.8"
+  - "0.6"
diff --git a/History.md b/History.md
index e3721f8..992ba6b 100644
--- a/History.md
+++ b/History.md
@@ -1,4 +1,41 @@
 
+0.6.5 / 2013-05-13 
+==================
+
+  * Use hasOwnProperty when iterating over Array
+
+0.6.4 / 2013-05-07 
+==================
+
+  * Don't throw when native prototype has enumerable properties
+  * check hasOwnProperty before restoring proto
+
+0.6.3 / 2013-05-03 
+==================
+
+  * add proto restoration. Closes #61
+
+0.6.2 / 2013-05-02 
+==================
+
+  * fix possibility to create huge sparse arrays.
+
+0.6.1 / 2013-04-26 
+==================
+
+  * use nullary objects
+
+0.6.0 / 2013-04-23 
+==================
+
+  * add shims for browser compat
+  * fix empty string key in .stringify()
+
+0.5.6 / 2013-04-09 
+==================
+
+  * fix empty key productions in parser
+
 0.5.5 / 2013-03-20 
 ==================
 
diff --git a/component.json b/component.json
index 3020745..e1e8c6b 100644
--- a/component.json
+++ b/component.json
@@ -2,7 +2,7 @@
   "name": "querystring",
   "repo": "visionmedia/node-querystring",
   "description": "query-string parser / stringifier with nesting support",
-  "version": "0.5.5",
+  "version": "0.6.5",
   "keywords": ["querystring", "query", "parser"],
   "scripts": ["index.js"],
   "license": "MIT"
diff --git a/examples.js b/examples.js
index 27617b7..581d81f 100644
--- a/examples.js
+++ b/examples.js
@@ -48,4 +48,8 @@ var obj = qs.parse('user[0]=tj&user[foo]=TJ');
 console.log(obj)
 
 var str = qs.stringify({ user: { name: 'Tobi', email: 'tobi at learnboost.com' }});
-console.log(str);
\ No newline at end of file
+console.log(str);
+
+console.log(qs.parse('constructor[prototype][hasOwnProperty]=foo'));
+
+console.log(qs.parse('foo[10]=1&foo[5]=2'));
diff --git a/index.js b/index.js
index 35cc861..590491e 100644
--- a/index.js
+++ b/index.js
@@ -1,4 +1,3 @@
-
 /**
  * Object#toString() ref for stringify().
  */
@@ -6,15 +5,87 @@
 var toString = Object.prototype.toString;
 
 /**
+ * Object#hasOwnProperty ref
+ */
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Array#indexOf shim.
+ */
+
+var indexOf = typeof Array.prototype.indexOf === 'function'
+  ? function(arr, el) { return arr.indexOf(el); }
+  : function(arr, el) {
+      for (var i = 0; i < arr.length; i++) {
+        if (arr[i] === el) return i;
+      }
+      return -1;
+    };
+
+/**
+ * Array.isArray shim.
+ */
+
+var isArray = Array.isArray || function(arr) {
+  return toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Object.keys shim.
+ */
+
+var objectKeys = Object.keys || function(obj) {
+  var ret = [];
+  for (var key in obj) ret.push(key);
+  return ret;
+};
+
+/**
+ * Array#forEach shim.
+ */
+
+var forEach = typeof Array.prototype.forEach === 'function'
+  ? function(arr, fn) { return arr.forEach(fn); }
+  : function(arr, fn) {
+      for (var i = 0; i < arr.length; i++) fn(arr[i]);
+    };
+
+/**
+ * Array#reduce shim.
+ */
+
+var reduce = function(arr, fn, initial) {
+  if (typeof arr.reduce === 'function') return arr.reduce(fn, initial);
+  var res = initial;
+  for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]);
+  return res;
+};
+
+/**
+ * Create a nullary object if possible
+ */
+
+function createObject() {
+  return Object.create
+    ? Object.create(null)
+    : {};
+}
+
+/**
  * Cache non-integer test regexp.
  */
 
 var isint = /^[0-9]+$/;
 
 function promote(parent, key) {
-  if (parent[key].length == 0) return parent[key] = {};
-  var t = {};
-  for (var i in parent[key]) t[i] = parent[key][i];
+  if (parent[key].length == 0) return parent[key] = createObject();
+  var t = createObject();
+  for (var i in parent[key]) {
+    if (hasOwnProperty.call(parent[key], i)) {
+      t[i] = parent[key][i];
+    }
+  }
   parent[key] = t;
   return t;
 }
@@ -23,7 +94,7 @@ function parse(parts, parent, key, val) {
   var part = parts.shift();
   // end
   if (!part) {
-    if (Array.isArray(parent[key])) {
+    if (isArray(parent[key])) {
       parent[key].push(val);
     } else if ('object' == typeof parent[key]) {
       parent[key] = val;
@@ -36,21 +107,21 @@ function parse(parts, parent, key, val) {
   } else {
     var obj = parent[key] = parent[key] || [];
     if (']' == part) {
-      if (Array.isArray(obj)) {
+      if (isArray(obj)) {
         if ('' != val) obj.push(val);
       } else if ('object' == typeof obj) {
-        obj[Object.keys(obj).length] = val;
+        obj[objectKeys(obj).length] = val;
       } else {
         obj = parent[key] = [parent[key], val];
       }
       // prop
-    } else if (~part.indexOf(']')) {
+    } else if (~indexOf(part, ']')) {
       part = part.substr(0, part.length - 1);
-      if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
+      if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
       parse(parts, obj, part, val);
       // key
     } else {
-      if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
+      if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
       parse(parts, obj, part, val);
     }
   }
@@ -61,15 +132,15 @@ function parse(parts, parent, key, val) {
  */
 
 function merge(parent, key, val){
-  if (~key.indexOf(']')) {
+  if (~indexOf(key, ']')) {
     var parts = key.split('[')
       , len = parts.length
       , last = len - 1;
     parse(parts, parent, 'base', val);
     // optimize
   } else {
-    if (!isint.test(key) && Array.isArray(parent.base)) {
-      var t = {};
+    if (!isint.test(key) && isArray(parent.base)) {
+      var t = createObject();
       for (var k in parent.base) t[k] = parent.base[k];
       parent.base = t;
     }
@@ -80,15 +151,63 @@ function merge(parent, key, val){
 }
 
 /**
+ * Compact sparse arrays.
+ */
+
+function compact(obj) {
+  if ('object' != typeof obj) return obj;
+
+  if (isArray(obj)) {
+    var ret = [];
+
+    for (var i in obj) {
+      if (hasOwnProperty.call(obj, i)) {
+        ret.push(obj[i]);
+      }
+    }
+
+    return ret;
+  }
+
+  for (var key in obj) {
+    obj[key] = compact(obj[key]);
+  }
+
+  return obj;
+}
+
+/**
+ * Restore Object.prototype.
+ * see pull-request #58
+ */
+
+function restoreProto(obj) {
+  if (!Object.create) return obj;
+  if (isArray(obj)) return obj;
+  if (obj && 'object' != typeof obj) return obj;
+
+  for (var key in obj) {
+    if (hasOwnProperty.call(obj, key)) {
+      obj[key] = restoreProto(obj[key]);
+    }
+  }
+
+  obj.__proto__ = Object.prototype;
+  return obj;
+}
+
+/**
  * Parse the given obj.
  */
 
 function parseObject(obj){
   var ret = { base: {} };
-  Object.keys(obj).forEach(function(name){
+
+  forEach(objectKeys(obj), function(name){
     merge(ret, name, obj[name]);
   });
-  return ret.base;
+
+  return compact(ret.base);
 }
 
 /**
@@ -96,20 +215,21 @@ function parseObject(obj){
  */
 
 function parseString(str){
-  return String(str)
-    .split('&')
-    .reduce(function(ret, pair){
-      var eql = pair.indexOf('=')
-        , brace = lastBraceInKey(pair)
-        , key = pair.substr(0, brace || eql)
-        , val = pair.substr(brace || eql, pair.length)
-        , val = val.substr(val.indexOf('=') + 1, val.length);
-
-      // ?foo
-      if ('' == key) key = pair, val = '';
-
-      return merge(ret, decode(key), decode(val));
-    }, { base: {} }).base;
+  var ret = reduce(String(str).split('&'), function(ret, pair){
+    var eql = indexOf(pair, '=')
+      , brace = lastBraceInKey(pair)
+      , key = pair.substr(0, brace || eql)
+      , val = pair.substr(brace || eql, pair.length)
+      , val = val.substr(indexOf(val, '=') + 1, val.length);
+
+    // ?foo
+    if ('' == key) key = pair, val = '';
+    if ('' == key) return ret;
+
+    return merge(ret, decode(key), decode(val));
+  }, { base: createObject() }).base;
+
+  return restoreProto(compact(ret));
 }
 
 /**
@@ -136,7 +256,7 @@ exports.parse = function(str){
  */
 
 var stringify = exports.stringify = function(obj, prefix) {
-  if (Array.isArray(obj)) {
+  if (isArray(obj)) {
     return stringifyArray(obj, prefix);
   } else if ('[object Object]' == toString.call(obj)) {
     return stringifyObject(obj, prefix);
@@ -190,11 +310,12 @@ function stringifyArray(arr, prefix) {
 
 function stringifyObject(obj, prefix) {
   var ret = []
-    , keys = Object.keys(obj)
+    , keys = objectKeys(obj)
     , key;
 
   for (var i = 0, len = keys.length; i < len; ++i) {
     key = keys[i];
+    if ('' == key) continue;
     if (null == obj[key]) {
       ret.push(encodeURIComponent(key) + '=');
     } else {
@@ -222,7 +343,7 @@ function set(obj, key, val) {
   var v = obj[key];
   if (undefined === v) {
     obj[key] = val;
-  } else if (Array.isArray(v)) {
+  } else if (isArray(v)) {
     v.push(val);
   } else {
     obj[key] = [v, val];
diff --git a/package.json b/package.json
index c73cd21..887d67a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "qs",
   "description": "querystring parser",
-  "version": "0.5.5",
+  "version": "0.6.5",
   "keywords": ["query string", "parser", "component"],
   "repository": {
     "type" : "git",
@@ -11,10 +11,8 @@
       "mocha": "*"
     , "expect.js": "*"
   },
-  "component": {
-    "scripts": {
-      "querystring": "querystring.js"
-    }
+  "scripts": {
+    "test": "make test"
   },
   "author": "TJ Holowaychuk <tj at vision-media.ca> (http://tjholowaychuk.com)",
   "main": "index",
diff --git a/test/browser/qs.js b/test/browser/qs.js
index 452d197..ccd9a9c 100644
--- a/test/browser/qs.js
+++ b/test/browser/qs.js
@@ -103,6 +103,58 @@ require.register("querystring", function(module, exports, require){
 var toString = Object.prototype.toString;
 
 /**
+ * Array#indexOf shim.
+ */
+
+var indexOf = typeof Array.prototype.indexOf === 'function'
+  ? function(arr, el) { return arr.indexOf(el); }
+  : function(arr, el) {
+      for (var i = 0; i < arr.length; i++) {
+        if (arr[i] === el) return i;
+      }
+      return -1;
+    };
+
+/**
+ * Array.isArray shim.
+ */
+
+var isArray = Array.isArray || function(arr) {
+  return toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Object.keys shim.
+ */
+
+var objectKeys = Object.keys || function(obj) {
+  var ret = [];
+  for (var key in obj) ret.push(key);
+  return ret;
+};
+
+/**
+ * Array#forEach shim.
+ */
+
+var forEach = typeof Array.prototype.forEach === 'function'
+  ? function(arr, fn) { return arr.forEach(fn); }
+  : function(arr, fn) {
+      for (var i = 0; i < arr.length; i++) fn(arr[i]);
+    };
+
+/**
+ * Array#reduce shim.
+ */
+
+var reduce = function(arr, fn, initial) {
+  if (typeof arr.reduce === 'function') return arr.reduce(fn, initial);
+  var res = initial;
+  for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]);
+  return res;
+};
+
+/**
  * Cache non-integer test regexp.
  */
 
@@ -120,7 +172,7 @@ function parse(parts, parent, key, val) {
   var part = parts.shift();
   // end
   if (!part) {
-    if (Array.isArray(parent[key])) {
+    if (isArray(parent[key])) {
       parent[key].push(val);
     } else if ('object' == typeof parent[key]) {
       parent[key] = val;
@@ -133,21 +185,21 @@ function parse(parts, parent, key, val) {
   } else {
     var obj = parent[key] = parent[key] || [];
     if (']' == part) {
-      if (Array.isArray(obj)) {
+      if (isArray(obj)) {
         if ('' != val) obj.push(val);
       } else if ('object' == typeof obj) {
-        obj[Object.keys(obj).length] = val;
+        obj[objectKeys(obj).length] = val;
       } else {
         obj = parent[key] = [parent[key], val];
       }
       // prop
-    } else if (~part.indexOf(']')) {
+    } else if (~indexOf(part, ']')) {
       part = part.substr(0, part.length - 1);
-      if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
+      if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
       parse(parts, obj, part, val);
       // key
     } else {
-      if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
+      if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
       parse(parts, obj, part, val);
     }
   }
@@ -158,14 +210,14 @@ function parse(parts, parent, key, val) {
  */
 
 function merge(parent, key, val){
-  if (~key.indexOf(']')) {
+  if (~indexOf(key, ']')) {
     var parts = key.split('[')
       , len = parts.length
       , last = len - 1;
     parse(parts, parent, 'base', val);
     // optimize
   } else {
-    if (!isint.test(key) && Array.isArray(parent.base)) {
+    if (!isint.test(key) && isArray(parent.base)) {
       var t = {};
       for (var k in parent.base) t[k] = parent.base[k];
       parent.base = t;
@@ -182,7 +234,7 @@ function merge(parent, key, val){
 
 function parseObject(obj){
   var ret = { base: {} };
-  Object.keys(obj).forEach(function(name){
+  forEach(objectKeys(obj), function(name){
     merge(ret, name, obj[name]);
   });
   return ret.base;
@@ -193,26 +245,19 @@ function parseObject(obj){
  */
 
 function parseString(str){
-  return String(str)
-    .split('&')
-    .reduce(function(ret, pair){
-      try{
-        pair = decodeURIComponent(pair.replace(/\+/g, ' '));
-      } catch(e) {
-        // ignore
-      }
-
-      var eql = pair.indexOf('=')
-        , brace = lastBraceInKey(pair)
-        , key = pair.substr(0, brace || eql)
-        , val = pair.substr(brace || eql, pair.length)
-        , val = val.substr(val.indexOf('=') + 1, val.length);
-
-      // ?foo
-      if ('' == key) key = pair, val = '';
-
-      return merge(ret, key, val);
-    }, { base: {} }).base;
+  return reduce(String(str).split('&'), function(ret, pair){
+    var eql = indexOf(pair, '=')
+      , brace = lastBraceInKey(pair)
+      , key = pair.substr(0, brace || eql)
+      , val = pair.substr(brace || eql, pair.length)
+      , val = val.substr(indexOf(val, '=') + 1, val.length);
+
+    // ?foo
+    if ('' == key) key = pair, val = '';
+    if ('' == key) return ret;
+
+    return merge(ret, decode(key), decode(val));
+  }, { base: {} }).base;
 }
 
 /**
@@ -239,14 +284,14 @@ exports.parse = function(str){
  */
 
 var stringify = exports.stringify = function(obj, prefix) {
-  if (Array.isArray(obj)) {
+  if (isArray(obj)) {
     return stringifyArray(obj, prefix);
   } else if ('[object Object]' == toString.call(obj)) {
     return stringifyObject(obj, prefix);
   } else if ('string' == typeof obj) {
     return stringifyString(obj, prefix);
   } else {
-    return prefix + '=' + obj;
+    return prefix + '=' + encodeURIComponent(String(obj));
   }
 };
 
@@ -277,7 +322,7 @@ function stringifyArray(arr, prefix) {
   var ret = [];
   if (!prefix) throw new TypeError('stringify expects an object');
   for (var i = 0; i < arr.length; i++) {
-    ret.push(stringify(arr[i], prefix + '['+i+']'));
+    ret.push(stringify(arr[i], prefix + '[' + i + ']'));
   }
   return ret.join('&');
 }
@@ -293,14 +338,18 @@ function stringifyArray(arr, prefix) {
 
 function stringifyObject(obj, prefix) {
   var ret = []
-    , keys = Object.keys(obj)
+    , keys = objectKeys(obj)
     , key;
 
   for (var i = 0, len = keys.length; i < len; ++i) {
     key = keys[i];
-    ret.push(stringify(obj[key], prefix
-      ? prefix + '[' + encodeURIComponent(key) + ']'
-      : encodeURIComponent(key)));
+    if (null == obj[key]) {
+      ret.push(encodeURIComponent(key) + '=');
+    } else {
+      ret.push(stringify(obj[key], prefix
+        ? prefix + '[' + encodeURIComponent(key) + ']'
+        : encodeURIComponent(key)));
+    }
   }
 
   return ret.join('&');
@@ -321,7 +370,7 @@ function set(obj, key, val) {
   var v = obj[key];
   if (undefined === v) {
     obj[key] = val;
-  } else if (Array.isArray(v)) {
+  } else if (isArray(v)) {
     v.push(val);
   } else {
     obj[key] = [v, val];
@@ -347,5 +396,21 @@ function lastBraceInKey(str) {
     if ('=' == c && !brace) return i;
   }
 }
+
+/**
+ * Decode `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function decode(str) {
+  try {
+    return decodeURIComponent(str.replace(/\+/g, ' '));
+  } catch (err) {
+    return str;
+  }
+}
 })();
 });
diff --git a/test/parse.js b/test/parse.js
index be827a8..a06dcd8 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -1,4 +1,3 @@
-
 if (require.register) {
   var qs = require('querystring');
 } else {
@@ -6,8 +5,13 @@ if (require.register) {
     , expect = require('expect.js');
 }
 
+Array.prototype.dummy = function () {}; // is should not be affected by Array.prototype
+
 describe('qs.parse()', function(){
   it('should support the basics', function(){
+    qs.parse('foo=bar').hasOwnProperty('foo');
+    qs.parse('foo[bar]=baz').foo.hasOwnProperty('foo');
+
     expect(qs.parse('0=foo')).to.eql({ '0': 'foo' });
 
     expect(qs.parse('foo=c++'))
@@ -144,4 +148,28 @@ describe('qs.parse()', function(){
     expect(qs.parse({ 'user[name]': 'tobi', 'user[email][main]': 'tobi at lb.com' }))
       .to.eql({ user: { name: 'tobi', email: { main: 'tobi at lb.com' } }});
   })
-})
\ No newline at end of file
+
+  it('should not produce empty keys', function(){
+    expect(qs.parse('_r=1&'))
+      .to.eql({ _r: '1' })
+  })
+
+  it('should not create big arrays of null objects', function(){
+    var q = qs.parse('a[999999999]=1&a[2]=2');
+    expect(q['a'].length).to.eql(2);
+    expect(q).to.eql({ a: ['2', '1'] });
+  })
+
+  if ('undefined' == typeof window) {
+    it('should not be possible to access Object prototype', function() {
+      qs.parse('constructor[prototype][bad]=bad');
+      qs.parse('bad[constructor][prototype][bad]=bad');
+      expect(Object.prototype.bad).to.be(undefined);
+    });
+    
+    it('should not throw when a native prototype has an enumerable property', function() {
+      Object.prototype.crash = '';
+      expect(qs.parse.bind(null, 'test')).to.not.throwException();
+    })
+  }
+})
diff --git a/test/stringify.js b/test/stringify.js
index 3dc694e..0d52250 100644
--- a/test/stringify.js
+++ b/test/stringify.js
@@ -17,7 +17,8 @@ var str_identities = {
     { str: 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F', obj: {'my weird field': "q1!2\"'w$5&7/z8)?"}},
     { str: 'foo%3Dbaz=bar', obj: {'foo=baz': 'bar'}},
     { str: 'foo=bar&bar=baz', obj: {foo: 'bar', bar: 'baz'}},
-    { str: 'foo=bar&baz=&raz=', obj: { foo: 'bar', baz: null, raz: undefined }}
+    { str: 'foo=bar&baz=&raz=', obj: { foo: 'bar', baz: null, raz: undefined }},
+    { str: 'foo=bar', obj: { foo: 'bar', '':'' }}
   ],
   'escaping': [
     { str: 'foo=foo%20bar', obj: {foo: 'foo bar'}},

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/node-qs.git



More information about the Pkg-javascript-commits mailing list