source: frontend/node_modules/axios/lib/helpers/toFormData.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

  • Property mode set to 100644
File size: 6.6 KB
RevLine 
[9af201e]1'use strict';
2
3import utils from '../utils.js';
4import AxiosError from '../core/AxiosError.js';
5// temporary hotfix to avoid circular references until AxiosURLSearchParams is refactored
6import PlatformFormData from '../platform/node/classes/FormData.js';
7
8/**
9 * Determines if the given thing is a array or js object.
10 *
11 * @param {string} thing - The object or array to be visited.
12 *
13 * @returns {boolean}
14 */
15function isVisitable(thing) {
16 return utils.isPlainObject(thing) || utils.isArray(thing);
17}
18
19/**
20 * It removes the brackets from the end of a string
21 *
22 * @param {string} key - The key of the parameter.
23 *
24 * @returns {string} the key without the brackets.
25 */
26function removeBrackets(key) {
27 return utils.endsWith(key, '[]') ? key.slice(0, -2) : key;
28}
29
30/**
31 * It takes a path, a key, and a boolean, and returns a string
32 *
33 * @param {string} path - The path to the current key.
34 * @param {string} key - The key of the current object being iterated over.
35 * @param {string} dots - If true, the key will be rendered with dots instead of brackets.
36 *
37 * @returns {string} The path to the current key.
38 */
39function renderKey(path, key, dots) {
40 if (!path) return key;
41 return path
42 .concat(key)
43 .map(function each(token, i) {
44 // eslint-disable-next-line no-param-reassign
45 token = removeBrackets(token);
46 return !dots && i ? '[' + token + ']' : token;
47 })
48 .join(dots ? '.' : '');
49}
50
51/**
52 * If the array is an array and none of its elements are visitable, then it's a flat array.
53 *
54 * @param {Array<any>} arr - The array to check
55 *
56 * @returns {boolean}
57 */
58function isFlatArray(arr) {
59 return utils.isArray(arr) && !arr.some(isVisitable);
60}
61
62const predicates = utils.toFlatObject(utils, {}, null, function filter(prop) {
63 return /^is[A-Z]/.test(prop);
64});
65
66/**
67 * Convert a data object to FormData
68 *
69 * @param {Object} obj
70 * @param {?Object} [formData]
71 * @param {?Object} [options]
72 * @param {Function} [options.visitor]
73 * @param {Boolean} [options.metaTokens = true]
74 * @param {Boolean} [options.dots = false]
75 * @param {?Boolean} [options.indexes = false]
76 *
77 * @returns {Object}
78 **/
79
80/**
81 * It converts an object into a FormData object
82 *
83 * @param {Object<any, any>} obj - The object to convert to form data.
84 * @param {string} formData - The FormData object to append to.
85 * @param {Object<string, any>} options
86 *
87 * @returns
88 */
89function toFormData(obj, formData, options) {
90 if (!utils.isObject(obj)) {
91 throw new TypeError('target must be an object');
92 }
93
94 // eslint-disable-next-line no-param-reassign
95 formData = formData || new (PlatformFormData || FormData)();
96
97 // eslint-disable-next-line no-param-reassign
98 options = utils.toFlatObject(
99 options,
100 {
101 metaTokens: true,
102 dots: false,
103 indexes: false,
104 },
105 false,
106 function defined(option, source) {
107 // eslint-disable-next-line no-eq-null,eqeqeq
108 return !utils.isUndefined(source[option]);
109 }
110 );
111
112 const metaTokens = options.metaTokens;
113 // eslint-disable-next-line no-use-before-define
114 const visitor = options.visitor || defaultVisitor;
115 const dots = options.dots;
116 const indexes = options.indexes;
117 const _Blob = options.Blob || (typeof Blob !== 'undefined' && Blob);
118 const maxDepth = options.maxDepth === undefined ? 100 : options.maxDepth;
119 const useBlob = _Blob && utils.isSpecCompliantForm(formData);
120
121 if (!utils.isFunction(visitor)) {
122 throw new TypeError('visitor must be a function');
123 }
124
125 function convertValue(value) {
126 if (value === null) return '';
127
128 if (utils.isDate(value)) {
129 return value.toISOString();
130 }
131
132 if (utils.isBoolean(value)) {
133 return value.toString();
134 }
135
136 if (!useBlob && utils.isBlob(value)) {
137 throw new AxiosError('Blob is not supported. Use a Buffer instead.');
138 }
139
140 if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
141 return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
142 }
143
144 return value;
145 }
146
147 /**
148 * Default visitor.
149 *
150 * @param {*} value
151 * @param {String|Number} key
152 * @param {Array<String|Number>} path
153 * @this {FormData}
154 *
155 * @returns {boolean} return true to visit the each prop of the value recursively
156 */
157 function defaultVisitor(value, key, path) {
158 let arr = value;
159
160 if (utils.isReactNative(formData) && utils.isReactNativeBlob(value)) {
161 formData.append(renderKey(path, key, dots), convertValue(value));
162 return false;
163 }
164
165 if (value && !path && typeof value === 'object') {
166 if (utils.endsWith(key, '{}')) {
167 // eslint-disable-next-line no-param-reassign
168 key = metaTokens ? key : key.slice(0, -2);
169 // eslint-disable-next-line no-param-reassign
170 value = JSON.stringify(value);
171 } else if (
172 (utils.isArray(value) && isFlatArray(value)) ||
173 ((utils.isFileList(value) || utils.endsWith(key, '[]')) && (arr = utils.toArray(value)))
174 ) {
175 // eslint-disable-next-line no-param-reassign
176 key = removeBrackets(key);
177
178 arr.forEach(function each(el, index) {
179 !(utils.isUndefined(el) || el === null) &&
180 formData.append(
181 // eslint-disable-next-line no-nested-ternary
182 indexes === true
183 ? renderKey([key], index, dots)
184 : indexes === null
185 ? key
186 : key + '[]',
187 convertValue(el)
188 );
189 });
190 return false;
191 }
192 }
193
194 if (isVisitable(value)) {
195 return true;
196 }
197
198 formData.append(renderKey(path, key, dots), convertValue(value));
199
200 return false;
201 }
202
203 const stack = [];
204
205 const exposedHelpers = Object.assign(predicates, {
206 defaultVisitor,
207 convertValue,
208 isVisitable,
209 });
210
211 function build(value, path, depth = 0) {
212 if (utils.isUndefined(value)) return;
213
214 if (depth > maxDepth) {
215 throw new AxiosError(
216 'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth,
217 AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
218 );
219 }
220
221 if (stack.indexOf(value) !== -1) {
222 throw Error('Circular reference detected in ' + path.join('.'));
223 }
224
225 stack.push(value);
226
227 utils.forEach(value, function each(el, key) {
228 const result =
229 !(utils.isUndefined(el) || el === null) &&
230 visitor.call(formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers);
231
232 if (result === true) {
233 build(el, path ? path.concat(key) : [key], depth + 1);
234 }
235 });
236
237 stack.pop();
238 }
239
240 if (!utils.isObject(obj)) {
241 throw new TypeError('data must be an object');
242 }
243
244 build(obj);
245
246 return formData;
247}
248
249export default toFormData;
Note: See TracBrowser for help on using the repository browser.