[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