| 'use strict'; |
| var strictUriEncode = require('strict-uri-encode'); |
| var objectAssign = require('object-assign'); |
| |
| function encoderForArrayFormat(opts) { |
| switch (opts.arrayFormat) { |
| case 'index': |
| return function (key, value, index) { |
| return value === null ? [ |
| encode(key, opts), |
| '[', |
| index, |
| ']' |
| ].join('') : [ |
| encode(key, opts), |
| '[', |
| encode(index, opts), |
| ']=', |
| encode(value, opts) |
| ].join(''); |
| }; |
| |
| case 'bracket': |
| return function (key, value) { |
| return value === null ? encode(key, opts) : [ |
| encode(key, opts), |
| '[]=', |
| encode(value, opts) |
| ].join(''); |
| }; |
| |
| default: |
| return function (key, value) { |
| return value === null ? encode(key, opts) : [ |
| encode(key, opts), |
| '=', |
| encode(value, opts) |
| ].join(''); |
| }; |
| } |
| } |
| |
| function parserForArrayFormat(opts) { |
| var result; |
| |
| switch (opts.arrayFormat) { |
| case 'index': |
| return function (key, value, accumulator) { |
| result = /\[(\d*)\]$/.exec(key); |
| |
| key = key.replace(/\[\d*\]$/, ''); |
| |
| if (!result) { |
| accumulator[key] = value; |
| return; |
| } |
| |
| if (accumulator[key] === undefined) { |
| accumulator[key] = {}; |
| } |
| |
| accumulator[key][result[1]] = value; |
| }; |
| |
| case 'bracket': |
| return function (key, value, accumulator) { |
| result = /(\[\])$/.exec(key); |
| key = key.replace(/\[\]$/, ''); |
| |
| if (!result) { |
| accumulator[key] = value; |
| return; |
| } else if (accumulator[key] === undefined) { |
| accumulator[key] = [value]; |
| return; |
| } |
| |
| accumulator[key] = [].concat(accumulator[key], value); |
| }; |
| |
| default: |
| return function (key, value, accumulator) { |
| if (accumulator[key] === undefined) { |
| accumulator[key] = value; |
| return; |
| } |
| |
| accumulator[key] = [].concat(accumulator[key], value); |
| }; |
| } |
| } |
| |
| function encode(value, opts) { |
| if (opts.encode) { |
| return opts.strict ? strictUriEncode(value) : encodeURIComponent(value); |
| } |
| |
| return value; |
| } |
| |
| function keysSorter(input) { |
| if (Array.isArray(input)) { |
| return input.sort(); |
| } else if (typeof input === 'object') { |
| return keysSorter(Object.keys(input)).sort(function (a, b) { |
| return Number(a) - Number(b); |
| }).map(function (key) { |
| return input[key]; |
| }); |
| } |
| |
| return input; |
| } |
| |
| exports.extract = function (str) { |
| return str.split('?')[1] || ''; |
| }; |
| |
| exports.parse = function (str, opts) { |
| opts = objectAssign({arrayFormat: 'none'}, opts); |
| |
| var formatter = parserForArrayFormat(opts); |
| |
| // Create an object with no prototype |
| // https://github.com/sindresorhus/query-string/issues/47 |
| var ret = Object.create(null); |
| |
| if (typeof str !== 'string') { |
| return ret; |
| } |
| |
| str = str.trim().replace(/^(\?|#|&)/, ''); |
| |
| if (!str) { |
| return ret; |
| } |
| |
| str.split('&').forEach(function (param) { |
| var parts = param.replace(/\+/g, ' ').split('='); |
| // Firefox (pre 40) decodes `%3D` to `=` |
| // https://github.com/sindresorhus/query-string/pull/37 |
| var key = parts.shift(); |
| var val = parts.length > 0 ? parts.join('=') : undefined; |
| |
| // missing `=` should be `null`: |
| // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters |
| val = val === undefined ? null : decodeURIComponent(val); |
| |
| formatter(decodeURIComponent(key), val, ret); |
| }); |
| |
| return Object.keys(ret).sort().reduce(function (result, key) { |
| var val = ret[key]; |
| if (Boolean(val) && typeof val === 'object' && !Array.isArray(val)) { |
| // Sort object keys, not values |
| result[key] = keysSorter(val); |
| } else { |
| result[key] = val; |
| } |
| |
| return result; |
| }, Object.create(null)); |
| }; |
| |
| exports.stringify = function (obj, opts) { |
| var defaults = { |
| encode: true, |
| strict: true, |
| arrayFormat: 'none' |
| }; |
| |
| opts = objectAssign(defaults, opts); |
| |
| var formatter = encoderForArrayFormat(opts); |
| |
| return obj ? Object.keys(obj).sort().map(function (key) { |
| var val = obj[key]; |
| |
| if (val === undefined) { |
| return ''; |
| } |
| |
| if (val === null) { |
| return encode(key, opts); |
| } |
| |
| if (Array.isArray(val)) { |
| var result = []; |
| |
| val.slice().forEach(function (val2) { |
| if (val2 === undefined) { |
| return; |
| } |
| |
| result.push(formatter(key, val2, result.length)); |
| }); |
| |
| return result.join('&'); |
| } |
| |
| return encode(key, opts) + '=' + encode(val, opts); |
| }).filter(function (x) { |
| return x.length > 0; |
| }).join('&') : ''; |
| }; |