用工小程序前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
12 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
  1. 'use strict';
  2. var utils = require('./utils');
  3. var has = Object.prototype.hasOwnProperty;
  4. var isArray = Array.isArray;
  5. var defaults = {
  6. allowDots: false,
  7. allowEmptyArrays: false,
  8. allowPrototypes: false,
  9. allowSparse: false,
  10. arrayLimit: 20,
  11. charset: 'utf-8',
  12. charsetSentinel: false,
  13. comma: false,
  14. decodeDotInKeys: false,
  15. decoder: utils.decode,
  16. delimiter: '&',
  17. depth: 5,
  18. duplicates: 'combine',
  19. ignoreQueryPrefix: false,
  20. interpretNumericEntities: false,
  21. parameterLimit: 1000,
  22. parseArrays: true,
  23. plainObjects: false,
  24. strictDepth: false,
  25. strictNullHandling: false,
  26. throwOnLimitExceeded: false
  27. };
  28. var interpretNumericEntities = function (str) {
  29. return str.replace(/&#(\d+);/g, function ($0, numberStr) {
  30. return String.fromCharCode(parseInt(numberStr, 10));
  31. });
  32. };
  33. var parseArrayValue = function (val, options, currentArrayLength) {
  34. if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
  35. return val.split(',');
  36. }
  37. if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
  38. throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
  39. }
  40. return val;
  41. };
  42. // This is what browsers will submit when the ✓ character occurs in an
  43. // application/x-www-form-urlencoded body and the encoding of the page containing
  44. // the form is iso-8859-1, or when the submitted form has an accept-charset
  45. // attribute of iso-8859-1. Presumably also with other charsets that do not contain
  46. // the ✓ character, such as us-ascii.
  47. var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓')
  48. // These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
  49. var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
  50. var parseValues = function parseQueryStringValues(str, options) {
  51. var obj = { __proto__: null };
  52. var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
  53. cleanStr = cleanStr.replace(/%5B/gi, '[').replace(/%5D/gi, ']');
  54. var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
  55. var parts = cleanStr.split(
  56. options.delimiter,
  57. options.throwOnLimitExceeded ? limit + 1 : limit
  58. );
  59. if (options.throwOnLimitExceeded && parts.length > limit) {
  60. throw new RangeError('Parameter limit exceeded. Only ' + limit + ' parameter' + (limit === 1 ? '' : 's') + ' allowed.');
  61. }
  62. var skipIndex = -1; // Keep track of where the utf8 sentinel was found
  63. var i;
  64. var charset = options.charset;
  65. if (options.charsetSentinel) {
  66. for (i = 0; i < parts.length; ++i) {
  67. if (parts[i].indexOf('utf8=') === 0) {
  68. if (parts[i] === charsetSentinel) {
  69. charset = 'utf-8';
  70. } else if (parts[i] === isoSentinel) {
  71. charset = 'iso-8859-1';
  72. }
  73. skipIndex = i;
  74. i = parts.length; // The eslint settings do not allow break;
  75. }
  76. }
  77. }
  78. for (i = 0; i < parts.length; ++i) {
  79. if (i === skipIndex) {
  80. continue;
  81. }
  82. var part = parts[i];
  83. var bracketEqualsPos = part.indexOf(']=');
  84. var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
  85. var key;
  86. var val;
  87. if (pos === -1) {
  88. key = options.decoder(part, defaults.decoder, charset, 'key');
  89. val = options.strictNullHandling ? null : '';
  90. } else {
  91. key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
  92. val = utils.maybeMap(
  93. parseArrayValue(
  94. part.slice(pos + 1),
  95. options,
  96. isArray(obj[key]) ? obj[key].length : 0
  97. ),
  98. function (encodedVal) {
  99. return options.decoder(encodedVal, defaults.decoder, charset, 'value');
  100. }
  101. );
  102. }
  103. if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
  104. val = interpretNumericEntities(String(val));
  105. }
  106. if (part.indexOf('[]=') > -1) {
  107. val = isArray(val) ? [val] : val;
  108. }
  109. var existing = has.call(obj, key);
  110. if (existing && options.duplicates === 'combine') {
  111. obj[key] = utils.combine(obj[key], val);
  112. } else if (!existing || options.duplicates === 'last') {
  113. obj[key] = val;
  114. }
  115. }
  116. return obj;
  117. };
  118. var parseObject = function (chain, val, options, valuesParsed) {
  119. var currentArrayLength = 0;
  120. if (chain.length > 0 && chain[chain.length - 1] === '[]') {
  121. var parentKey = chain.slice(0, -1).join('');
  122. currentArrayLength = Array.isArray(val) && val[parentKey] ? val[parentKey].length : 0;
  123. }
  124. var leaf = valuesParsed ? val : parseArrayValue(val, options, currentArrayLength);
  125. for (var i = chain.length - 1; i >= 0; --i) {
  126. var obj;
  127. var root = chain[i];
  128. if (root === '[]' && options.parseArrays) {
  129. obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
  130. ? []
  131. : utils.combine([], leaf);
  132. } else {
  133. obj = options.plainObjects ? { __proto__: null } : {};
  134. var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
  135. var decodedRoot = options.decodeDotInKeys ? cleanRoot.replace(/%2E/g, '.') : cleanRoot;
  136. var index = parseInt(decodedRoot, 10);
  137. if (!options.parseArrays && decodedRoot === '') {
  138. obj = { 0: leaf };
  139. } else if (
  140. !isNaN(index)
  141. && root !== decodedRoot
  142. && String(index) === decodedRoot
  143. && index >= 0
  144. && (options.parseArrays && index <= options.arrayLimit)
  145. ) {
  146. obj = [];
  147. obj[index] = leaf;
  148. } else if (decodedRoot !== '__proto__') {
  149. obj[decodedRoot] = leaf;
  150. }
  151. }
  152. leaf = obj;
  153. }
  154. return leaf;
  155. };
  156. var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
  157. if (!givenKey) {
  158. return;
  159. }
  160. // Transform dot notation to bracket notation
  161. var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey;
  162. // The regex chunks
  163. var brackets = /(\[[^[\]]*])/;
  164. var child = /(\[[^[\]]*])/g;
  165. // Get the parent
  166. var segment = options.depth > 0 && brackets.exec(key);
  167. var parent = segment ? key.slice(0, segment.index) : key;
  168. // Stash the parent if it exists
  169. var keys = [];
  170. if (parent) {
  171. // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
  172. if (!options.plainObjects && has.call(Object.prototype, parent)) {
  173. if (!options.allowPrototypes) {
  174. return;
  175. }
  176. }
  177. keys.push(parent);
  178. }
  179. // Loop through children appending to the array until we hit depth
  180. var i = 0;
  181. while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
  182. i += 1;
  183. if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
  184. if (!options.allowPrototypes) {
  185. return;
  186. }
  187. }
  188. keys.push(segment[1]);
  189. }
  190. // If there's a remainder, check strictDepth option for throw, else just add whatever is left
  191. if (segment) {
  192. if (options.strictDepth === true) {
  193. throw new RangeError('Input depth exceeded depth option of ' + options.depth + ' and strictDepth is true');
  194. }
  195. keys.push('[' + key.slice(segment.index) + ']');
  196. }
  197. return parseObject(keys, val, options, valuesParsed);
  198. };
  199. var normalizeParseOptions = function normalizeParseOptions(opts) {
  200. if (!opts) {
  201. return defaults;
  202. }
  203. if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
  204. throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
  205. }
  206. if (typeof opts.decodeDotInKeys !== 'undefined' && typeof opts.decodeDotInKeys !== 'boolean') {
  207. throw new TypeError('`decodeDotInKeys` option can only be `true` or `false`, when provided');
  208. }
  209. if (opts.decoder !== null && typeof opts.decoder !== 'undefined' && typeof opts.decoder !== 'function') {
  210. throw new TypeError('Decoder has to be a function.');
  211. }
  212. if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
  213. throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
  214. }
  215. if (typeof opts.throwOnLimitExceeded !== 'undefined' && typeof opts.throwOnLimitExceeded !== 'boolean') {
  216. throw new TypeError('`throwOnLimitExceeded` option must be a boolean');
  217. }
  218. var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
  219. var duplicates = typeof opts.duplicates === 'undefined' ? defaults.duplicates : opts.duplicates;
  220. if (duplicates !== 'combine' && duplicates !== 'first' && duplicates !== 'last') {
  221. throw new TypeError('The duplicates option must be either combine, first, or last');
  222. }
  223. var allowDots = typeof opts.allowDots === 'undefined' ? opts.decodeDotInKeys === true ? true : defaults.allowDots : !!opts.allowDots;
  224. return {
  225. allowDots: allowDots,
  226. allowEmptyArrays: typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
  227. allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
  228. allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse,
  229. arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
  230. charset: charset,
  231. charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
  232. comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
  233. decodeDotInKeys: typeof opts.decodeDotInKeys === 'boolean' ? opts.decodeDotInKeys : defaults.decodeDotInKeys,
  234. decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
  235. delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
  236. // eslint-disable-next-line no-implicit-coercion, no-extra-parens
  237. depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
  238. duplicates: duplicates,
  239. ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
  240. interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
  241. parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
  242. parseArrays: opts.parseArrays !== false,
  243. plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
  244. strictDepth: typeof opts.strictDepth === 'boolean' ? !!opts.strictDepth : defaults.strictDepth,
  245. strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling,
  246. throwOnLimitExceeded: typeof opts.throwOnLimitExceeded === 'boolean' ? opts.throwOnLimitExceeded : false
  247. };
  248. };
  249. module.exports = function (str, opts) {
  250. var options = normalizeParseOptions(opts);
  251. if (str === '' || str === null || typeof str === 'undefined') {
  252. return options.plainObjects ? { __proto__: null } : {};
  253. }
  254. var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
  255. var obj = options.plainObjects ? { __proto__: null } : {};
  256. // Iterate over the keys and setup the new object
  257. var keys = Object.keys(tempObj);
  258. for (var i = 0; i < keys.length; ++i) {
  259. var key = keys[i];
  260. var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
  261. obj = utils.merge(obj, newObj, options);
  262. }
  263. if (options.allowSparse === true) {
  264. return obj;
  265. }
  266. return utils.compact(obj);
  267. };