parse-nested-form-data 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
2
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
3
+ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
4
+
5
+ - [CHANGELOG](#changelog)
6
+
7
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
8
+
9
+ # CHANGELOG
10
+
11
+ The changelog is automatically updated using
12
+ [semantic-release](https://github.com/semantic-release/semantic-release). You
13
+ can see it on the [releases page](../../releases).
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Christian Schurr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,363 @@
1
+ <div align="center">
2
+ <h1>parse-nested-form-data</h1>
3
+
4
+ <p>A tiny node module for parsing FormData by name into objects and arrays</p>
5
+ </div>
6
+
7
+ ---
8
+
9
+ <!-- prettier-ignore-start -->
10
+ [![Build Status][build-badge]][build]
11
+ [![Code Coverage][coverage-badge]][coverage]
12
+ [![version][version-badge]][package]
13
+ [![downloads][downloads-badge]][npmtrends]
14
+ [![MIT License][license-badge]][license]
15
+ [![All Contributors][all-contributors-badge]](#contributors-)
16
+ [![PRs Welcome][prs-badge]][prs]
17
+ [![Code of Conduct][coc-badge]][coc]
18
+ <!-- prettier-ignore-end -->
19
+
20
+ ## The problem
21
+
22
+ 1. You use Forms to upload data to your server (e.g. with remix-run)
23
+ 2. You want a way to upload objects and arrays with booleans and numbers
24
+ 3. You do not want to transfer the data per hand
25
+
26
+ ## This solution
27
+
28
+ A parse functions that uses the name prop to tells the parser how to create an
29
+ object out of the values. You can tell the parser to do not parse empty values.
30
+
31
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
32
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
33
+
34
+ - [Installation](#installation)
35
+ - [Name](#name)
36
+ - [Boolean](#boolean)
37
+ - [Number](#number)
38
+ - [Null](#null)
39
+ - [Array](#array)
40
+ - [Object](#object)
41
+ - [Basic Usage](#basic-usage)
42
+ - [Transform values](#transform-values)
43
+ - [Advanced usage](#advanced-usage)
44
+ - [Options](#options)
45
+ - [removeEmptyString: `[boolean]`](#removeemptystring-boolean)
46
+ - [transformEntry: `(entry: [path: string, value: string | File], defaultTransform: DefaultTransform) => [string, string | JsonLeafValue]`](#transformentry-entry-path-string-value-string--file-defaulttransform-defaulttransform--string-string--jsonleafvalue)
47
+ - [Issues](#issues)
48
+ - [🐛 Bugs](#-bugs)
49
+ - [💡 Feature Requests](#-feature-requests)
50
+ - [Contributors ✨](#contributors-)
51
+ - [LICENSE](#license)
52
+ - [Special Thanks](#special-thanks)
53
+
54
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
55
+
56
+ ## Installation
57
+
58
+ This module is distributed via [npm][npm] which is bundled with [node][node] and
59
+ should be installed as one of your project's `dependencies`:
60
+
61
+ ```sh
62
+ npm install parse-nested-form-data
63
+ ```
64
+
65
+ ## Name
66
+
67
+ The name prop is used to tell the parser how to create an object out of the
68
+ values. The name prop is a string that can contain the following characters:
69
+
70
+ - `.`: to create a nested object
71
+ - `[]`: to create an array (pushes value)
72
+ - `[$order]`: to create an array (sets value at index and squashes array)
73
+ - `&`: to transform the value to a boolean
74
+ - `-`: to transform the value to null
75
+ - `+`: to transform the value to a number
76
+
77
+ ### Boolean
78
+
79
+ If the name prop starts with a `&` the value will be transformed to a boolean.
80
+
81
+ True if the value has the following values:
82
+
83
+ - `true`
84
+ - `1`
85
+ - `on`
86
+
87
+ ```ts
88
+ const formData = new FormData()
89
+ formData.append('&isTrue', 'true')
90
+ formData.append('&isFalse', 'false')
91
+ formData.append('&isTrue1', '1')
92
+ formData.append('&isFalse1', '0')
93
+ formData.append('&isTrue2', 'on')
94
+ formData.append('&isFalse2', 'off')
95
+ parseFormData(formData)
96
+ // {
97
+ // isTrue: true,
98
+ // isFalse: false,
99
+ // isTrue1: true,
100
+ // isFalse1: false,
101
+ // isTrue2: true,
102
+ // isFalse2: false,
103
+ // }
104
+ ```
105
+
106
+ ### Number
107
+
108
+ If the name prop starts with a `+` the value will be transformed to a number.
109
+
110
+ ```ts
111
+ const formData = new FormData()
112
+ formData.append('+number', '1')
113
+ formData.append('+number2', '1.1')
114
+ formData.append('+number3', 'a')
115
+ parseFormData(formData)
116
+ // {
117
+ // number: 1,
118
+ // number2: 1.1,
119
+ // number3: NaN,
120
+ // }
121
+ ```
122
+
123
+ ### Null
124
+
125
+ If the name prop starts with a `-` the value will be transformed to null.
126
+
127
+ ```ts
128
+ const formData = new FormData()
129
+ formData.append('-null', 'null')
130
+ formData.append('-ignored', 'ignored')
131
+ parseFormData(formData)
132
+ // {
133
+ // null: null,
134
+ // ignored: null,
135
+ // }
136
+ ```
137
+
138
+ ### Array
139
+
140
+ If a path of the name prop ends with `[]` the value will be pushed to an array.
141
+ If the path of the name prop ends with `[$order]` the value will be set at the
142
+ index of the order. Cannot be mixed with `[]`.
143
+
144
+ ```ts
145
+ const formData = new FormData()
146
+ formData.append('array[0]', '1')
147
+ formData.append('array[1]', '2')
148
+ formData.append('array[2]', '3')
149
+ formData.append('array[3]', '4')
150
+ parseFormData(formData)
151
+ // {
152
+ // array: ['1', '2', '3', '4'],
153
+ // }
154
+ ```
155
+
156
+ ```ts
157
+ const formData = new FormData()
158
+ formData.append('array[]', '1')
159
+ formData.append('array[]', '2')
160
+ formData.append('array[]', '3')
161
+ parseFormData(formData)
162
+ // {
163
+ // array: ['1', '2', '3'],
164
+ // }
165
+ ```
166
+
167
+ Also works with nested objects:
168
+
169
+ ```ts
170
+ const formData = new FormData()
171
+ formData.append('array[0].a', '1')
172
+ formData.append('array[1].a', '2')
173
+ formData.append('array[2].a', '3')
174
+ parseFormData(formData)
175
+ // {
176
+ // array: [{a: '1'}, {a: '2'}, {a: '3'}],
177
+ // }
178
+ ```
179
+
180
+ Also works with nested arrays:
181
+
182
+ ```ts
183
+ const formData = new FormData()
184
+ formData.append('array[0][]', '1')
185
+ formData.append('array[0][]', '2')
186
+ formData.append('array[1][]', '3')
187
+ formData.append('array[1][]', '4')
188
+ parseFormData(formData)
189
+ // {
190
+ // array: [['1', '2'], ['3', '4']],
191
+ // }
192
+ ```
193
+
194
+ ### Object
195
+
196
+ If the name prop contains a `.` the value will be nested in an object.
197
+
198
+ ```ts
199
+ const formData = new FormData()
200
+ formData.append('object.a', '1')
201
+ formData.append('object.b', '2')
202
+ parseFormData(formData)
203
+ // {
204
+ // object: {
205
+ // a: '1',
206
+ // b: '2',
207
+ // },
208
+ // }
209
+ ```
210
+
211
+ ## Basic Usage
212
+
213
+ ### Transform values
214
+
215
+ ```ts
216
+ const formData = new FormData()
217
+ formData.append('+a', '1')
218
+ formData.append('&b', 'true')
219
+ formData.append('-c', 'null')
220
+ formData.append('d', 'foo')
221
+ parseFormData(formData, defaultTransform)
222
+ // => {a: 1, b: true, c: null, d: 'foo'}
223
+ ```
224
+
225
+ ## Advanced usage
226
+
227
+ Complex examples:
228
+
229
+ ```ts
230
+ const formData = new FormData()
231
+ formData.append('a[].b.c', '1')
232
+ formData.append('a[].b.d', '2')
233
+ formData.append('a[]', '3')
234
+ formData.append('b[0]', '4')
235
+ formData.append('+b[100]', '5')
236
+ parseFormData(formData)
237
+ // {
238
+ // a: [
239
+ // {
240
+ // b: {
241
+ // c: '1',
242
+ // d: '2',
243
+ // },
244
+ // },
245
+ // '3',
246
+ // ],
247
+ // b: ['4', 5],
248
+ // }
249
+ ```
250
+
251
+ ### Options
252
+
253
+ The second argument is an option object with following properties:
254
+
255
+ ### removeEmptyString: `[boolean]`
256
+
257
+ _Default: `false`_
258
+
259
+ If `true` empty strings will be removed from the result.
260
+
261
+ ```ts
262
+ const formData = new FormData()
263
+ formData.append('foo[1].foo', '')
264
+ formData.append('foo[1].bar', 'test2')
265
+ formData.append('foo[0].foo', 'test3')
266
+ formData.append('foo[0].baz', '4')
267
+
268
+ parseFormData(formData, {removeEmptyString: true})
269
+ // {foo: [{foo: 'test3', baz: '4'}, {bar: 'test2'}]}
270
+ ```
271
+
272
+ ### transformEntry: `(entry: [path: string, value: string | File], defaultTransform: DefaultTransform) => [string, string | JsonLeafValue]`
273
+
274
+ ```ts
275
+ const formData = new FormData()
276
+ formData.append('a', 'a')
277
+ formData.append('b', 'b')
278
+ parseFormData(formData, {
279
+ transformEntry: ([path, value], defaultTransform) => {
280
+ return {
281
+ path,
282
+ value:
283
+ typeof value === 'string'
284
+ ? value.toUpperCase()
285
+ : defaultTransform(value),
286
+ }
287
+ },
288
+ })
289
+ // => {a: 'A', b: 'B'}
290
+ ```
291
+
292
+ ## Issues
293
+
294
+ _Looking to contribute? Look for the [Good First Issue][good-first-issue]
295
+ label._
296
+
297
+ ### 🐛 Bugs
298
+
299
+ Please file an issue for bugs, missing documentation, or unexpected behavior.
300
+
301
+ [**See Bugs**][bugs]
302
+
303
+ ### 💡 Feature Requests
304
+
305
+ Please file an issue to suggest new features. Vote on feature requests by adding
306
+ a 👍. This helps maintainers prioritize what to work on.
307
+
308
+ [**See Feature Requests**][requests]
309
+
310
+ ## Contributors ✨
311
+
312
+ Thanks goes to these people ([emoji key][emojis]):
313
+
314
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
315
+ <!-- prettier-ignore-start -->
316
+ <!-- markdownlint-disable -->
317
+ <table>
318
+ <tr>
319
+ </tr>
320
+ </table>
321
+
322
+ <!-- markdownlint-restore -->
323
+ <!-- prettier-ignore-end -->
324
+
325
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
326
+
327
+ This project follows the [all-contributors][all-contributors] specification.
328
+ Contributions of any kind welcome!
329
+
330
+ ## LICENSE
331
+
332
+ MIT
333
+
334
+ ## Special Thanks
335
+
336
+ Special thanks to Kent C. Dodds and his [match-sorter][match-sorter] package
337
+ where most of the setup is from.
338
+
339
+ <!-- prettier-ignore-start -->
340
+ [npm]: https://www.npmjs.com
341
+ [node]: https://nodejs.org
342
+ [build-badge]: https://img.shields.io/github/workflow/status/milamer/parse-nested-form-data/validate?logo=github&style=flat-square
343
+ [build]: https://github.com/milamer/parse-nested-form-data/actions?query=workflow%3Avalidate
344
+ [coverage-badge]: https://img.shields.io/codecov/c/github/milamer/parse-nested-form-data.svg?style=flat-square
345
+ [coverage]: https://codecov.io/github/milamer/parse-nested-form-data
346
+ [version-badge]: https://img.shields.io/npm/v/parse-nested-form-data.svg?style=flat-square
347
+ [package]: https://www.npmjs.com/package/parse-nested-form-data
348
+ [downloads-badge]: https://img.shields.io/npm/dm/parse-nested-form-data.svg?style=flat-square
349
+ [npmtrends]: https://www.npmtrends.com/parse-nested-form-data
350
+ [license-badge]: https://img.shields.io/npm/l/parse-nested-form-data.svg?style=flat-square
351
+ [license]: https://github.com/milamer/parse-nested-form-data/blob/master/LICENSE
352
+ [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
353
+ [prs]: http://makeapullrequest.com
354
+ [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
355
+ [coc]: https://github.com/milamer/parse-nested-form-data/blob/master/CODE_OF_CONDUCT.md
356
+ [emojis]: https://github.com/all-contributors/all-contributors#emoji-key
357
+ [all-contributors]: https://github.com/all-contributors/all-contributors
358
+ [all-contributors-badge]: https://img.shields.io/github/all-contributors/milamer/parse-nested-form-data?color=orange&style=flat-square
359
+ [bugs]: https://github.com/milamer/parse-nested-form-data/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Acreated-desc+label%3Abug
360
+ [requests]: https://github.com/milamer/parse-nested-form-data/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement
361
+ [good-first-issue]: https://github.com/milamer/parse-nested-form-data/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement+label%3A%22good+first+issue%22
362
+ [match-sorter]: https://github.com/kentcdodds/match-sorter/blob/main/README.md
363
+ <!-- prettier-ignore-end -->
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,255 @@
1
+ /**
2
+ * @name parse-nested-form-data
3
+ * @license MIT license.
4
+ * @copyright (c) 2022 Christian Schurr
5
+ * @author Christian Schurr <chris@schurr.dev>
6
+ */
7
+ /**
8
+ * Thrown when a path is used multiple times or has missmatching path parts.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const formData = new FormData()
13
+ * formData.append('a[0]', 'b')
14
+ * formData.append('a[0]', 'c')
15
+ * parseFormData(formData)
16
+ * // throws DuplicateKeyError('a[0]')
17
+ * ```
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const formData = new FormData()
22
+ * formData.append('a', 'b')
23
+ * formData.append('a', 'c')
24
+ * parseFormData(formData)
25
+ * // throws DuplicateKeyError('a')
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const formData = new FormData()
30
+ * formData.append('a', 'b')
31
+ * formData.append('a[]', 'c')
32
+ * parseFormData(formData)
33
+ * // throws DuplicateKeyError('a[]')
34
+ * ```
35
+ *
36
+ */
37
+ export declare class DuplicateKeyError extends Error {
38
+ key: string;
39
+ constructor(key: string);
40
+ }
41
+ /**
42
+ * Thrown when an array is used at the same path with an order parameter and
43
+ * without an order parameter.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const formData = new FormData()
48
+ * formData.append('a[0]', 'a')
49
+ * formData.append('a[]', 'b')
50
+ * parseFormData(formData)
51
+ * // => throws `MixedArrayError(a[])`
52
+ * ```
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const formData = new FormData()
57
+ * formData.append('a[]', 'a')
58
+ * formData.append('a[0]', 'b')
59
+ * parseFormData(formData)
60
+ * // => throws `MixedArrayError(a[0])`
61
+ * ```
62
+ */
63
+ export declare class MixedArrayError extends Error {
64
+ key: string;
65
+ constructor(key: string);
66
+ }
67
+ type JsonObject = {
68
+ [Key in string]?: JsonValue;
69
+ };
70
+ type JsonArray = Array<JsonValue>;
71
+ type JsonValue = string | number | JsonObject | JsonArray | boolean | null | File;
72
+ type JsonLeafValue = Exclude<JsonValue, JsonArray | JsonObject>;
73
+ /**
74
+ * Default Transformer for `parseFormData`.
75
+ *
76
+ * Transforms a FormData Entry into a path and a `JsonLeafValue`.
77
+ *
78
+ * - `path` starts with `+` -> transform value to `number`
79
+ * - `path` starts with `&` -> transform value to `boolean`
80
+ * - `path` starts with `-` -> transform value to `null`
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * const entry = ['a[0]', 'b']
85
+ * const result = defaultTransform(entry)
86
+ * // => {path: 'a[0]', value: 'b'}
87
+ * ```
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * const entry = ['+a[0]', '1']
92
+ * const result = defaultTransform(entry)
93
+ * // => {path: 'a[0]', value: 1}
94
+ * ```
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const entry = ['&a[0]', 'true']
99
+ * const result = defaultTransform(entry)
100
+ * // => {path: 'a[0]', value: true}
101
+ * ```
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const entry = ['-a[0]', 'null']
106
+ * const result = defaultTransform(entry)
107
+ * // => {path: 'a[0]', value: null}
108
+ * ```
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * const entry = ['a[0]', new File([''], 'file.txt')]
113
+ * const result = defaultTransform(entry)
114
+ * // => {path: 'a[0]', value: File}
115
+ * ```
116
+ *
117
+ *
118
+ * @param entry [path, value]: the FormData entry
119
+ * @returns the path and the transformed value
120
+ */
121
+ declare function defaultTransform(entry: [path: string, value: string | File]): {
122
+ path: string;
123
+ value: JsonLeafValue;
124
+ };
125
+ type DefaultTransform = typeof defaultTransform;
126
+ /**
127
+ * Options to change the behavior of `parseFormData`.
128
+ * @param transformEntry - a function to transform the FormData entry into a path and a value
129
+ * (default: `defaultTransform`)
130
+ * @param removeEmptyString - skip empty values '' (default: `false`)
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * const formData = new FormData()
135
+ * formData.append('a', '')
136
+ * formData.append('b', 'b')
137
+ * const result = parseFormData(formData, {removeEmptyString: true})
138
+ * // => {b: 'b'}
139
+ * ```
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const formData = new FormData()
144
+ * formData.append('a', 'a')
145
+ * formData.append('b', 'b')
146
+ * parseFormData(formData, {
147
+ * transformEntry: ([path, value], defaultTransform) => {
148
+ * return {
149
+ * path,
150
+ * value:
151
+ * typeof value === 'string'
152
+ * ? value.toUpperCase()
153
+ * : defaultTransform(value),
154
+ * }
155
+ * },
156
+ * })
157
+ * // => {a: 'A', b: 'B'}
158
+ * ```
159
+ */
160
+ export type ParseFormDataOptions = {
161
+ removeEmptyString?: boolean;
162
+ transformEntry?: (entry: [path: string, value: string | File], defaultTransform: DefaultTransform) => {
163
+ path: string;
164
+ value: JsonLeafValue;
165
+ };
166
+ };
167
+ /**
168
+ *
169
+ * Parses a FormData object to a JSON object. This is done by parsing the `name`
170
+ * attribute of each `FormDataEntryValue` and then inserting the value at the
171
+ * path. Also by default the start of the path is used to transform the value.
172
+ *
173
+ *
174
+ * In front of the whole `key`:
175
+ * - `+` => parse to `Number`
176
+ * - `-` => set value to `null`
177
+ * - `&` => parse to `Boolean`
178
+ *
179
+ * - `.` between path parts => nest into `objects`
180
+ * - `[\d*]` after path part => push to array in order `\d` or push to end if `[]`
181
+ *
182
+
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const formData = new FormData()
187
+ * formData.append('+a', '1')
188
+ * formData.append('&b', 'true')
189
+ * formData.append('-c', 'null')
190
+ * formData.append('d', 'foo')
191
+ * parseFormData(formData, defaultTransform)
192
+ * // => {a: 1, b: true, c: null, d: 'foo'}
193
+ * ```
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * const formData = new FormData()
198
+ * formData.append('a.b', 'foo')
199
+ * parseFormData(formData)
200
+ * // => {a: {b: 'foo'}}
201
+ * ```
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * const formData = new FormData()
206
+ * formData.append('a[0]', 'foo')
207
+ * formData.append('a[1]', 'bar')
208
+ * parseFormData(formData)
209
+ * // => {a: ['foo', 'bar']}
210
+ * ```
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * const formData = new FormData()
215
+ * formData.append('a[]', 'foo')
216
+ * formData.append('a[]', 'bar')
217
+ * parseFormData(formData)
218
+ * // => {a: ['foo', 'bar']}
219
+ * ```
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * const formData = new FormData()
224
+ * formData.append('a[0]', 'foo')
225
+ * parseFormData(formData, {transformEntry: (path, value) => {path, value: value + 'bar'}})
226
+ * // => {a: ['foobar']}
227
+ * ```
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * const formData = new FormData()
232
+ * formData.append('a[0]', 'foo')
233
+ * formData.append('a[1]', '')
234
+ * parseFormData(formData, {removeEmptyString: true})
235
+ * // => {a: ['foo']}
236
+ * ```
237
+ *
238
+ * @param {Iterable<[string, string | File]>} formData - an iterator of an [`path`, `value`] tuple
239
+ * - `path` := `^(\+|\-|\&)?([^\.]+?(\[\d*\])*)(\.[^\.]+?(\[\d*\])*)*$` (e.g. `+a[][1].b`)
240
+ * - `value` := `string` or `File`
241
+ * @param {ParseFormDataOptions} options - options for parsing the form data
242
+ * - `transformEntry` - a function to transform the path and the value before
243
+ * inserting the value at the path in the resulting object (default: `defaultTransform`)
244
+ * - `removeEmptyString` - if `true` removes all entries where the value is an empty string
245
+ * @returns {JsonObject} the parsed JSON object
246
+ * @throws `DuplicateKeyError` if
247
+ * - a path part is an object and the path part is already defined as an object
248
+ * - a path part is an array and the path part is already defined as an array
249
+ * @throws `MixedArrayError` if at a specific path part an unordered array is
250
+ * defined and at a later path part an ordered array is defined or vice versa
251
+ * - e.g. `a[0]` and `a[]`
252
+ * - e.g. `a[]` and `a[0]`
253
+ */
254
+ export declare function parseFormData(formData: Iterable<[string, string | File]>, { removeEmptyString, transformEntry, }?: ParseFormDataOptions): JsonObject;
255
+ export {};