| 'use strict'; |
| |
| var has = Object.prototype.hasOwnProperty |
| , undef; |
| |
| /** |
| * Decode a URI encoded string. |
| * |
| * @param {String} input The URI encoded string. |
| * @returns {String|Null} The decoded string. |
| * @api private |
| */ |
| function decode(input) { |
| try { |
| return decodeURIComponent(input.replace(/\+/g, ' ')); |
| } catch (e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Attempts to encode a given input. |
| * |
| * @param {String} input The string that needs to be encoded. |
| * @returns {String|Null} The encoded string. |
| * @api private |
| */ |
| function encode(input) { |
| try { |
| return encodeURIComponent(input); |
| } catch (e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Simple query string parser. |
| * |
| * @param {String} query The query string that needs to be parsed. |
| * @returns {Object} |
| * @api public |
| */ |
| function querystring(query) { |
| var parser = /([^=?&]+)=?([^&]*)/g |
| , result = {} |
| , part; |
| |
| while (part = parser.exec(query)) { |
| var key = decode(part[1]) |
| , value = decode(part[2]); |
| |
| // |
| // Prevent overriding of existing properties. This ensures that build-in |
| // methods like `toString` or __proto__ are not overriden by malicious |
| // querystrings. |
| // |
| // In the case if failed decoding, we want to omit the key/value pairs |
| // from the result. |
| // |
| if (key === null || value === null || key in result) continue; |
| result[key] = value; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Transform a query string to an object. |
| * |
| * @param {Object} obj Object that should be transformed. |
| * @param {String} prefix Optional prefix. |
| * @returns {String} |
| * @api public |
| */ |
| function querystringify(obj, prefix) { |
| prefix = prefix || ''; |
| |
| var pairs = [] |
| , value |
| , key; |
| |
| // |
| // Optionally prefix with a '?' if needed |
| // |
| if ('string' !== typeof prefix) prefix = '?'; |
| |
| for (key in obj) { |
| if (has.call(obj, key)) { |
| value = obj[key]; |
| |
| // |
| // Edge cases where we actually want to encode the value to an empty |
| // string instead of the stringified value. |
| // |
| if (!value && (value === null || value === undef || isNaN(value))) { |
| value = ''; |
| } |
| |
| key = encodeURIComponent(key); |
| value = encodeURIComponent(value); |
| |
| // |
| // If we failed to encode the strings, we should bail out as we don't |
| // want to add invalid strings to the query. |
| // |
| if (key === null || value === null) continue; |
| pairs.push(key +'='+ value); |
| } |
| } |
| |
| return pairs.length ? prefix + pairs.join('&') : ''; |
| } |
| |
| // |
| // Expose the module. |
| // |
| exports.stringify = querystringify; |
| exports.parse = querystring; |