stringify.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. 'use strict';
  2. var utils = require('./utils');
  3. var formats = require('./formats');
  4. var arrayPrefixGenerators = {
  5. brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
  6. return prefix + '[]';
  7. },
  8. indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
  9. return prefix + '[' + key + ']';
  10. },
  11. repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
  12. return prefix;
  13. }
  14. };
  15. var toISO = Date.prototype.toISOString;
  16. var defaults = {
  17. delimiter: '&',
  18. encode: true,
  19. encoder: utils.encode,
  20. serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
  21. return toISO.call(date);
  22. },
  23. skipNulls: false,
  24. strictNullHandling: false
  25. };
  26. var stringify = function stringify( // eslint-disable-line func-name-matching
  27. object,
  28. prefix,
  29. generateArrayPrefix,
  30. strictNullHandling,
  31. skipNulls,
  32. encoder,
  33. filter,
  34. sort,
  35. allowDots,
  36. serializeDate,
  37. formatter
  38. ) {
  39. var obj = object;
  40. if (typeof filter === 'function') {
  41. obj = filter(prefix, obj);
  42. } else if (obj instanceof Date) {
  43. obj = serializeDate(obj);
  44. } else if (obj === null) {
  45. if (strictNullHandling) {
  46. return encoder ? encoder(prefix) : prefix;
  47. }
  48. obj = '';
  49. }
  50. if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
  51. if (encoder) {
  52. return [formatter(encoder(prefix)) + '=' + formatter(encoder(obj))];
  53. }
  54. return [formatter(prefix) + '=' + formatter(String(obj))];
  55. }
  56. var values = [];
  57. if (typeof obj === 'undefined') {
  58. return values;
  59. }
  60. var objKeys;
  61. if (Array.isArray(filter)) {
  62. objKeys = filter;
  63. } else {
  64. var keys = Object.keys(obj);
  65. objKeys = sort ? keys.sort(sort) : keys;
  66. }
  67. for (var i = 0; i < objKeys.length; ++i) {
  68. var key = objKeys[i];
  69. if (skipNulls && obj[key] === null) {
  70. continue;
  71. }
  72. if (Array.isArray(obj)) {
  73. values = values.concat(stringify(
  74. obj[key],
  75. generateArrayPrefix(prefix, key),
  76. generateArrayPrefix,
  77. strictNullHandling,
  78. skipNulls,
  79. encoder,
  80. filter,
  81. sort,
  82. allowDots,
  83. serializeDate,
  84. formatter
  85. ));
  86. } else {
  87. values = values.concat(stringify(
  88. obj[key],
  89. prefix + (allowDots ? '.' + key : '[' + key + ']'),
  90. generateArrayPrefix,
  91. strictNullHandling,
  92. skipNulls,
  93. encoder,
  94. filter,
  95. sort,
  96. allowDots,
  97. serializeDate,
  98. formatter
  99. ));
  100. }
  101. }
  102. return values;
  103. };
  104. module.exports = function (object, opts) {
  105. var obj = object;
  106. var options = opts || {};
  107. if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
  108. throw new TypeError('Encoder has to be a function.');
  109. }
  110. var delimiter = typeof options.delimiter === 'undefined' ? defaults.delimiter : options.delimiter;
  111. var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
  112. var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
  113. var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
  114. var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
  115. var sort = typeof options.sort === 'function' ? options.sort : null;
  116. var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
  117. var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
  118. if (typeof options.format === 'undefined') {
  119. options.format = formats.default;
  120. } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
  121. throw new TypeError('Unknown format option provided.');
  122. }
  123. var formatter = formats.formatters[options.format];
  124. var objKeys;
  125. var filter;
  126. if (typeof options.filter === 'function') {
  127. filter = options.filter;
  128. obj = filter('', obj);
  129. } else if (Array.isArray(options.filter)) {
  130. filter = options.filter;
  131. objKeys = filter;
  132. }
  133. var keys = [];
  134. if (typeof obj !== 'object' || obj === null) {
  135. return '';
  136. }
  137. var arrayFormat;
  138. if (options.arrayFormat in arrayPrefixGenerators) {
  139. arrayFormat = options.arrayFormat;
  140. } else if ('indices' in options) {
  141. arrayFormat = options.indices ? 'indices' : 'repeat';
  142. } else {
  143. arrayFormat = 'indices';
  144. }
  145. var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
  146. if (!objKeys) {
  147. objKeys = Object.keys(obj);
  148. }
  149. if (sort) {
  150. objKeys.sort(sort);
  151. }
  152. for (var i = 0; i < objKeys.length; ++i) {
  153. var key = objKeys[i];
  154. if (skipNulls && obj[key] === null) {
  155. continue;
  156. }
  157. keys = keys.concat(stringify(
  158. obj[key],
  159. key,
  160. generateArrayPrefix,
  161. strictNullHandling,
  162. skipNulls,
  163. encoder,
  164. filter,
  165. sort,
  166. allowDots,
  167. serializeDate,
  168. formatter
  169. ));
  170. }
  171. return keys.join(delimiter);
  172. };