UNPKG

perry

Version:

Multi-dimensional query string parser and generator

122 lines (105 loc) 3.44 kB
var querystring = require('querystring'); var Perry = exports; Perry.stringify = function(obj, sep, eq, bo, bc, prefix) { sep = sep || '&'; eq = eq || '='; bo = bo || '['; bc = bc || ']'; obj = (obj === null) ? {} : obj; return Object.keys(obj).map(function(i) { var key = prefix ? prefix + bo + Perry.escape(i) + bc : Perry.escape(i); var value = obj[i] === null ? '' : obj[i]; if(value instanceof RegExp) value = value.toString() switch(typeof value) { case 'object': return Perry.stringify(value, sep, eq, bo, bc, key); case 'undefined': return false; default: return key + eq + Perry.escape(value); } }).filter(function(i) { return i; }).join(sep); } Perry.parse = function(str, sep, eq, bo, bc) { sep = sep || '&'; eq = eq || '='; bo = bo || '['; bc = bc || ']'; str = str || ''; var eql_regex = new RegExp("(^.*?)[" + eq + "](.*)"); var arr_regex = new RegExp("\\" + bo + "?(.*?)[\\" + bc + "\\" + bo + "]","g"); // thanks @mkorfmann for this solution var empty_index = {}; var obj = {}; str.split(sep).forEach(function(chunk) { var parts = chunk.match(eql_regex); if(!parts) { return; } var key = Perry.unescape(parts[1]); var val = Perry.unescape(parts[2], true); val = val === '' ? null : val; var flat_keys = []; while((match = arr_regex.exec(key)) != null) { if(match[1] == '') { empty_index[flat_keys.join('_')] = empty_index[flat_keys.join('_')] || 0; match[1] = empty_index[flat_keys.join('_')]; empty_index[flat_keys.join('_')]++; } flat_keys.push(Perry.unescape(match[1].toString(), true)); } if(flat_keys.length) { obj = Perry.mergeRecursive(obj, Perry.constructObj(flat_keys, val)); } else { obj[Perry.unescape(key, true)] = val; } }); return Perry.numericIndexedObjectToArray(obj); } Perry.escape = function(str) { return encodeURIComponent(str); } Perry.unescape = function(s, decodeSpaces) { return querystring.unescapeBuffer(s, decodeSpaces).toString(); }; Perry.numericIndexedObjectToArray = function(obj) { var array = []; if(typeof obj == 'object' && obj != null) { if(Array.isArray(obj)) { obj.forEach(function(value,key) { array[key] = Perry.numericIndexedObjectToArray(value); }); } else if(Object.keys(obj).every(function(key) { return key == parseInt(key, 10); })) { var max = Math.max.apply(Math,Object.keys(obj)) for(var key=0;key<=max;key++) { array[key] = Perry.numericIndexedObjectToArray(obj[key]); } } else { Object.keys(obj).forEach(function(key) { obj[key] = Perry.numericIndexedObjectToArray(obj[key]); }); } } return array.length ? array : obj; } Perry.constructObj = function(array, value) { var obj = {}; if(array.length) { obj[array.shift()] = Perry.constructObj(array, value); } else { return value; } return obj; } Perry.mergeRecursive = function(targetObj, sourceObj) { Object.keys(sourceObj).forEach(function(property) { targetObj[property] = (sourceObj[property] != null && sourceObj[property].constructor == Object && targetObj[property]) ? Perry.mergeRecursive(targetObj[property], sourceObj[property]) : sourceObj[property]; }); return targetObj; } function max(array) { array.reduce }