main
js 107 lines 2.62 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 /**
11 * Backing FormData is a wrapper around FormData that allows iterating over the
12 * keys while allowing to evict values from the FormData without affecting the iteration.
13 * Native FormData.keys() will skip keys if entries with Blob are deleted e.g.
14 * ```js
15 * const formData = new FormData();
16 * formData.append('a', new Blob());
17 * formData.append('b', 2);
18 * const keys = formData.keys();
19 * keys.next().value; // 'a'
20 * formData.delete('a');
21 * keys.next().value; // undefined, but we expect 'b'
22 * ```
23 */
24 export opaque type BackingFormData = {
25 data: FormData,
26 keyPointer: number,
27 // Lazily initialized array of keys. We only need this at the moment
28 // for referenced FormData.
29 keys: null | Array<string>,
30 };
31
32 export function peekBackingEntry(backingStore: BackingFormData): string | void {
33 let keys = backingStore.keys;
34 if (keys === null) {
35 keys = backingStore.keys = Array.from(backingStore.data.keys());
36 backingStore.keyPointer = 0;
37 }
38
39 return keys[backingStore.keyPointer];
40 }
41
42 export function advanceBackingEntryIterator(
43 backingStore: BackingFormData,
44 ): void {
45 backingStore.keyPointer++;
46 }
47
48 export function consumeBackingEntry(
49 backingStore: BackingFormData,
50 key: string,
51 ): void {
52 backingStore.data.delete(key);
53 backingStore.keyPointer++;
54 }
55
56 export function appendBackingEntry(
57 backingStore: BackingFormData,
58 key: string,
59 value: FormDataEntryValue,
60 ): void {
61 backingStore.data.append(key, value);
62 let keys = backingStore.keys;
63 if (keys === null) {
64 keys = backingStore.keys = Array.from(backingStore.data.keys());
65 backingStore.keyPointer = 0;
66 } else {
67 keys.push(key);
68 }
69 }
70
71 export function appendBackingFile(
72 backingStore: BackingFormData,
73 key: string,
74 value: Blob,
75 filename: string,
76 ): void {
77 backingStore.data.append(key, value, filename);
78 let keys = backingStore.keys;
79 if (keys === null) {
80 keys = backingStore.keys = Array.from(backingStore.data.keys());
81 backingStore.keyPointer = 0;
82 } else {
83 keys.push(key);
84 }
85 }
86
87 export function getBackingEntry(
88 backingStore: BackingFormData,
89 key: string,
90 ): ?FormDataEntryValue {
91 return backingStore.data.get(key);
92 }
93
94 export function getAllBackingEntries(
95 backingStore: BackingFormData,
96 key: string,
97 ): Array<FormDataEntryValue> {
98 return backingStore.data.getAll(key);
99 }
100
101 export function createBackingFormData(formData: FormData): BackingFormData {
102 return {
103 data: formData,
104 keyPointer: -1,
105 keys: null,
106 };
107 }