@@ -21,6 +21,12 @@ export const generateFormData = (
2121 formData : FormData | URLSearchParams ,
2222 preserveStringified = false ,
2323) => {
24+ // First pass: Count occurrences of each key to handle single variable name for arrays.
25+ const keyCount : Record < string , number > = { } ;
26+ for ( const [ key ] of formData . entries ( ) ) {
27+ keyCount [ key ] = ( keyCount [ key ] || 0 ) + 1 ;
28+ }
29+ // Second pass: Build the output object
2430 // Initialize an empty output object.
2531 // biome-ignore lint/suspicious/noExplicitAny: <explanation>
2632 const outputObject : Record < any , any > = { } ;
@@ -29,51 +35,62 @@ export const generateFormData = (
2935 for ( const [ key , value ] of formData . entries ( ) ) {
3036 // Try to convert data to the original type, otherwise return the original value
3137 const data = preserveStringified ? value : tryParseJSON ( value ) ;
32- // Split the key into an array of parts.
33- const keyParts = key . split ( "." ) ;
34- // Initialize a variable to point to the current object in the output object.
35- let currentObject = outputObject ;
36-
37- // Iterate through each key part except for the last one.
38- for ( let i = 0 ; i < keyParts . length - 1 ; i ++ ) {
39- // Get the current key part.
40- const keyPart = keyParts [ i ] ;
41- // If the current object doesn't have a property with the current key part,
42- // initialize it as an object or array depending on whether the next key part is a valid integer index or not.
43- if ( ! currentObject [ keyPart ] ) {
44- currentObject [ keyPart ] = / ^ \d + $ / . test ( keyParts [ i + 1 ] ) ? [ ] : { } ;
38+ // Simple way to iterate form keys and append to either value or array.
39+ if ( key . split ( "." ) . length === 1 ) {
40+ const isArray = keyCount [ key ] > 1 ;
41+ if ( isArray ) {
42+ if ( ! outputObject [ key ] ) {
43+ outputObject [ key ] = [ ] ;
44+ }
45+ outputObject [ key ] . push ( data ) ;
46+ } else {
47+ outputObject [ key ] = data ;
4548 }
46- // Move the current object pointer to the next level of the output object.
47- currentObject = currentObject [ keyPart ] ;
48- }
49-
50- // Get the last key part.
51- const lastKeyPart = keyParts [ keyParts . length - 1 ] ;
52- const lastKeyPartIsArray = / \[ \d * \] $ | \[ \] $ / . test ( lastKeyPart ) ;
53-
54- // Handles array[] or array[0] cases
55- if ( lastKeyPartIsArray ) {
56- const key = lastKeyPart . replace ( / \[ \d * \] $ | \[ \] $ / , "" ) ;
57- if ( ! currentObject [ key ] ) {
58- currentObject [ key ] = [ ] ;
49+ } else {
50+ // Split the key into an array of parts.
51+ const keyParts = key . split ( "." ) ;
52+ // Initialize a variable to point to the current object in the output object.
53+ let currentObject = outputObject ;
54+ // Iterate through each key part except for the last one.
55+ for ( let i = 0 ; i < keyParts . length - 1 ; i ++ ) {
56+ // Get the current key part.
57+ const keyPart = keyParts [ i ] ;
58+ // If the current object doesn't have a property with the current key part,
59+ // initialize it as an object or array depending on whether the next key part is a valid integer index or not.
60+ if ( ! currentObject [ keyPart ] ) {
61+ currentObject [ keyPart ] = / ^ \d + $ / . test ( keyParts [ i + 1 ] ) ? [ ] : { } ;
62+ }
63+ // Move the current object pointer to the next level of the output object.
64+ currentObject = currentObject [ keyPart ] ;
5965 }
6066
61- currentObject [ key ] . push ( data ) ;
62- }
67+ // Get the last key part.
68+ const lastKeyPart = keyParts [ keyParts . length - 1 ] ;
69+ const lastKeyPartIsArray = / \[ \d * \] $ | \[ \] $ / . test ( lastKeyPart ) ;
70+
71+ // Handles array[] or array[0] cases
72+ if ( lastKeyPartIsArray ) {
73+ const key = lastKeyPart . replace ( / \[ \d * \] $ | \[ \] $ / , "" ) ;
74+ if ( ! currentObject [ key ] ) {
75+ currentObject [ key ] = [ ] ;
76+ }
6377
64- // Handles array.foo.0 cases
65- if ( ! lastKeyPartIsArray ) {
66- // If the last key part is a valid integer index, push the value to the current array.
67- if ( / ^ \d + $ / . test ( lastKeyPart ) ) {
68- currentObject . push ( data ) ;
78+ currentObject [ key ] . push ( data ) ;
6979 }
70- // Otherwise, set a property on the current object with the last key part and the corresponding value.
71- else {
72- currentObject [ lastKeyPart ] = data ;
80+
81+ // Handles array.foo.0 cases
82+ if ( ! lastKeyPartIsArray ) {
83+ // If the last key part is a valid integer index, push the value to the current array.
84+ if ( / ^ \d + $ / . test ( lastKeyPart ) ) {
85+ currentObject . push ( data ) ;
86+ }
87+ // Otherwise, set a property on the current object with the last key part and the corresponding value.
88+ else {
89+ currentObject [ lastKeyPart ] = data ;
90+ }
7391 }
7492 }
7593 }
76-
7794 // Return the output object.
7895 return outputObject ;
7996} ;
0 commit comments