@arc-js/fodat 0.0.1
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/README.md +312 -0
- package/fodat.all.js +102 -0
- package/fodat.all.min.js +1 -0
- package/index.d.ts +15 -0
- package/index.js +94 -0
- package/index.min.d.ts +15 -0
- package/index.min.js +1 -0
- package/package.json +18 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# @arc-js/fodat
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
**@arc-js/fodat** est une bibliothèque JavaScript/TypeScript légère et puissante pour la transformation bidirectionnelle entre FormData et objets JSON. Conçue pour simplifier la manipulation des données de formulaires complexes avec support natif des fichiers et structures imbriquées.
|
|
9
|
+
|
|
10
|
+
## ✨ Fonctionnalités Principales
|
|
11
|
+
|
|
12
|
+
- 🔄 **Transformation bidirectionnelle** : FormData → JSON et JSON → FormData
|
|
13
|
+
- 🏗️ **Support des structures complexes** : objets imbriqués, tableaux multidimensionnels
|
|
14
|
+
- 📁 **Gestion native des fichiers** : préservation des objets File sans conversion
|
|
15
|
+
- 🎯 **Typage TypeScript complet** : auto-complétion et sécurité des types
|
|
16
|
+
- ⚡ **Léger et performant** : aucune dépendance, optimisé pour les performances
|
|
17
|
+
- 🌐 **Multi-plateforme** : navigateur, Node.js, Deno, Bun
|
|
18
|
+
- 🔧 **Parsing intelligent** : conversion automatique des types (booléens, nombres)
|
|
19
|
+
|
|
20
|
+
## 📦 Installation
|
|
21
|
+
|
|
22
|
+
### Via npm/yarn/pnpm
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @arc-js/fodat
|
|
26
|
+
# ou
|
|
27
|
+
yarn add @arc-js/fodat
|
|
28
|
+
# ou
|
|
29
|
+
pnpm add @arc-js/fodat
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Importation directe (CDN)
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<script src="@arc-js/fodat/fodat.all.js"></script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 🚀 Démarrage Rapide
|
|
39
|
+
|
|
40
|
+
### TypeScript/ES Modules
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import Fodat from '@arc-js/fodat';
|
|
44
|
+
// ou
|
|
45
|
+
import { Fodat } from '@arc-js/fodat';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### CommonJS
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const { Fodat } = require('@arc-js/fodat');
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Navigateur (global)
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<script src="@arc-js/fodat/fodat.all.js"></script>
|
|
58
|
+
<script>
|
|
59
|
+
// Disponible globalement comme window.Fodat
|
|
60
|
+
const formData = new FormData();
|
|
61
|
+
formData.append('user.name', 'John');
|
|
62
|
+
const json = Fodat.transform(formData);
|
|
63
|
+
console.log(json.user.name); // "John"
|
|
64
|
+
</script>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 📚 Documentation API
|
|
68
|
+
|
|
69
|
+
### Méthodes Statiques
|
|
70
|
+
|
|
71
|
+
#### `Fodat.transform(formData: FormData): any`
|
|
72
|
+
|
|
73
|
+
Transforme un objet FormData en structure JavaScript/JSON.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const formData = new FormData();
|
|
77
|
+
formData.append('user.firstName', 'Jean');
|
|
78
|
+
formData.append('user.lastName', 'Dupont');
|
|
79
|
+
formData.append('user.age', '30');
|
|
80
|
+
formData.append('addresses[0].city', 'Paris');
|
|
81
|
+
|
|
82
|
+
const result = Fodat.transform(formData);
|
|
83
|
+
/*
|
|
84
|
+
Résultat:
|
|
85
|
+
{
|
|
86
|
+
user: {
|
|
87
|
+
firstName: "Jean",
|
|
88
|
+
lastName: "Dupont",
|
|
89
|
+
age: 30 // Converti automatiquement en nombre
|
|
90
|
+
},
|
|
91
|
+
addresses: [{
|
|
92
|
+
city: "Paris"
|
|
93
|
+
}]
|
|
94
|
+
}
|
|
95
|
+
*/
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### `Fodat.toFormData(json: any, formData?: FormData, parentKey?: string): FormData`
|
|
99
|
+
|
|
100
|
+
Transforme un objet JavaScript/JSON en FormData.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const data = {
|
|
104
|
+
user: {
|
|
105
|
+
name: "Marie",
|
|
106
|
+
active: true,
|
|
107
|
+
profile: new File(['content'], 'profile.jpg')
|
|
108
|
+
},
|
|
109
|
+
tags: ["js", "typescript"]
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const formData = Fodat.toFormData(data);
|
|
113
|
+
// Peut être envoyé via fetch ou XMLHttpRequest
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Fonctionnalités Avancées
|
|
117
|
+
|
|
118
|
+
#### Conversion Automatique des Types
|
|
119
|
+
|
|
120
|
+
Fodat convertit intelligemment les valeurs string en types appropriés :
|
|
121
|
+
|
|
122
|
+
- `"true"` → `true` (booléen)
|
|
123
|
+
- `"false"` → `false` (booléen)
|
|
124
|
+
- `"42"` → `42` (nombre)
|
|
125
|
+
- `"3.14"` → `3.14` (nombre)
|
|
126
|
+
- Fichiers → préservés comme objets File natifs
|
|
127
|
+
|
|
128
|
+
#### Syntaxe des Clés
|
|
129
|
+
|
|
130
|
+
| Type | Syntaxe | Exemple |
|
|
131
|
+
|------|---------|---------|
|
|
132
|
+
| Propriété simple | `key` | `name` |
|
|
133
|
+
| Propriété imbriquée | `key.subkey` | `user.name` |
|
|
134
|
+
| Tableau | `key[index]` | `tags[0]` |
|
|
135
|
+
| Tableau d'objets | `key[index].prop` | `users[0].email` |
|
|
136
|
+
| Mixte | `key.subkey[index].prop` | `data.items[0].value` |
|
|
137
|
+
|
|
138
|
+
#### Gestion des Fichiers
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// Ajout de fichiers
|
|
142
|
+
const formData = new FormData();
|
|
143
|
+
formData.append('avatar', new File([''], 'photo.jpg'));
|
|
144
|
+
formData.append('documents[0]', new File([''], 'doc.pdf'));
|
|
145
|
+
|
|
146
|
+
// Transformation
|
|
147
|
+
const json = Fodat.transform(formData);
|
|
148
|
+
console.log(json.avatar instanceof File); // true
|
|
149
|
+
console.log(json.documents[0] instanceof File); // true
|
|
150
|
+
|
|
151
|
+
// Transformation inverse
|
|
152
|
+
const newFormData = Fodat.toFormData(json);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 🎯 Exemples Complets
|
|
156
|
+
|
|
157
|
+
### Exemple 1 : Formulaire d'Utilisateur Complexe
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Création d'un FormData complexe
|
|
161
|
+
const formData = new FormData();
|
|
162
|
+
formData.append('personal.firstName', 'Jean');
|
|
163
|
+
formData.append('personal.lastName', 'Dupont');
|
|
164
|
+
formData.append('personal.email', 'jean@example.com');
|
|
165
|
+
formData.append('personal.age', '35');
|
|
166
|
+
formData.append('personal.active', 'true');
|
|
167
|
+
|
|
168
|
+
formData.append('addresses[0].street', '123 Rue Exemple');
|
|
169
|
+
formData.append('addresses[0].city', 'Paris');
|
|
170
|
+
formData.append('addresses[1].street', '456 Autre Rue');
|
|
171
|
+
formData.append('addresses[1].city', 'Lyon');
|
|
172
|
+
|
|
173
|
+
formData.append('skills[0]', 'JavaScript');
|
|
174
|
+
formData.append('skills[1]', 'TypeScript');
|
|
175
|
+
formData.append('skills[2]', 'React');
|
|
176
|
+
|
|
177
|
+
// Transformation en JSON
|
|
178
|
+
const userData = Fodat.transform(formData);
|
|
179
|
+
console.log(userData.personal.age); // 35 (nombre)
|
|
180
|
+
console.log(userData.personal.active); // true (booléen)
|
|
181
|
+
console.log(userData.addresses.length); // 2
|
|
182
|
+
console.log(userData.skills); // ["JavaScript", "TypeScript", "React"]
|
|
183
|
+
|
|
184
|
+
// Envoi au serveur après modification
|
|
185
|
+
userData.personal.age = 36;
|
|
186
|
+
const updatedFormData = Fodat.toFormData(userData);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Exemple 2 : Upload avec Métadonnées
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Préparation des données avec fichiers
|
|
193
|
+
const uploadData = {
|
|
194
|
+
metadata: {
|
|
195
|
+
title: "Document Important",
|
|
196
|
+
category: "legal",
|
|
197
|
+
tags: ["contract", "signed"],
|
|
198
|
+
priority: "high"
|
|
199
|
+
},
|
|
200
|
+
files: [
|
|
201
|
+
new File(['contenu'], 'contrat.pdf'),
|
|
202
|
+
new File(['annexe'], 'annexe.jpg')
|
|
203
|
+
],
|
|
204
|
+
options: {
|
|
205
|
+
encrypt: true,
|
|
206
|
+
notify: false
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Conversion en FormData pour upload
|
|
211
|
+
const formData = Fodat.toFormData(uploadData);
|
|
212
|
+
|
|
213
|
+
// Simulation d'envoi
|
|
214
|
+
fetch('/api/upload', {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
body: formData
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Exemple 3 : Traitement de Réponse Serveur
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Supposons que vous recevez un FormData d'une API
|
|
224
|
+
async function handleFormDataResponse(response: Response) {
|
|
225
|
+
const formData = await response.formData();
|
|
226
|
+
|
|
227
|
+
// Transformation en objet utilisable
|
|
228
|
+
const data = Fodat.transform(formData);
|
|
229
|
+
|
|
230
|
+
// Traitement typé
|
|
231
|
+
if (data.user && typeof data.user.age === 'number') {
|
|
232
|
+
console.log(`Âge: \${data.user.age}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Modification et renvoi
|
|
236
|
+
data.timestamp = new Date().toISOString();
|
|
237
|
+
return Fodat.toFormData(data);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 🔧 Build et Développement
|
|
242
|
+
|
|
243
|
+
### Structure du Projet
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
@arc-js/fodat/
|
|
247
|
+
├── fodat.all.js
|
|
248
|
+
├── fodat.all.min.js
|
|
249
|
+
├── index.d.ts
|
|
250
|
+
├── index.js
|
|
251
|
+
├── index.min.d.ts
|
|
252
|
+
├── index.min.js
|
|
253
|
+
├── package.json
|
|
254
|
+
├── tsconfig.json
|
|
255
|
+
└── README.md
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 📋 Compatibilité
|
|
259
|
+
|
|
260
|
+
### Navigateurs Supportés
|
|
261
|
+
|
|
262
|
+
- Chrome 60+
|
|
263
|
+
- Firefox 55+
|
|
264
|
+
- Safari 12+
|
|
265
|
+
- Edge 79+
|
|
266
|
+
- Opera 47+
|
|
267
|
+
- Tous les navigateurs supportant FormData
|
|
268
|
+
|
|
269
|
+
### Environnements
|
|
270
|
+
|
|
271
|
+
- Node.js 18+ (avec polyfill FormData)
|
|
272
|
+
- Deno 1.30+
|
|
273
|
+
- Bun 1.0+
|
|
274
|
+
- Tous les environnements ES5+
|
|
275
|
+
|
|
276
|
+
## 🚨 Notes Importantes
|
|
277
|
+
|
|
278
|
+
### Performances
|
|
279
|
+
|
|
280
|
+
Fodat est optimisé pour la performance mais gardez à l'esprit que :
|
|
281
|
+
- La transformation de FormData très larges peut avoir un impact
|
|
282
|
+
- Préférez transformer uniquement les données nécessaires
|
|
283
|
+
- Les fichiers volumineux sont référencés, non copiés
|
|
284
|
+
|
|
285
|
+
### Limitations
|
|
286
|
+
|
|
287
|
+
- Les valeurs `null` et `undefined` dans FormData sont traitées comme chaînes vides
|
|
288
|
+
- Les objets cycliques ne sont pas supportés
|
|
289
|
+
- La profondeur maximale d'imbrication est limitée par la pile d'appels
|
|
290
|
+
|
|
291
|
+
### Sécurité
|
|
292
|
+
|
|
293
|
+
- Validez toujours les données d'entrée
|
|
294
|
+
- Les fichiers sont préservés tels quels, assurez-vous de valider leur type et taille
|
|
295
|
+
- Évitez d'exposer Fodat à des données non fiables sans validation
|
|
296
|
+
|
|
297
|
+
## 📄 Licence
|
|
298
|
+
|
|
299
|
+
MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
|
300
|
+
|
|
301
|
+
## 🐛 Signaler un Bug
|
|
302
|
+
|
|
303
|
+
Envoyez nous un mail à l'adresse `contact.inicode@gmail.com` pour :
|
|
304
|
+
- Signaler un bug
|
|
305
|
+
- Proposer une amélioration
|
|
306
|
+
- Poser une question
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
**@arc-js/fodat** - La passerelle intelligente entre FormData et JSON. 🔄
|
|
311
|
+
|
|
312
|
+
*Développé par l'équipe INICODE*
|
package/fodat.all.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
class Fodat {
|
|
2
|
+
static transform(formData) {
|
|
3
|
+
if (formData instanceof FormData) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const [key, value] of formData.entries()) {
|
|
6
|
+
const path = this.parseKeyPath(key);
|
|
7
|
+
this.setDeepValue(result, path, this.wrapValue(value));
|
|
8
|
+
}
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
else if (typeof formData === 'object' &&
|
|
12
|
+
!Array.isArray(formData)) {
|
|
13
|
+
return formData;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
static toFormData(json, form = new FormData(), parentKey) {
|
|
18
|
+
if (json === null || json === undefined)
|
|
19
|
+
return form;
|
|
20
|
+
if (json?.__file === true && json.file instanceof File) {
|
|
21
|
+
form.append(parentKey, json.file);
|
|
22
|
+
return form;
|
|
23
|
+
}
|
|
24
|
+
if (typeof json !== "object" || json instanceof File) {
|
|
25
|
+
if (parentKey)
|
|
26
|
+
form.append(parentKey, json);
|
|
27
|
+
return form;
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(json)) {
|
|
30
|
+
json.forEach((item, index) => {
|
|
31
|
+
const key = parentKey ? `${parentKey}[${index}]` : `${index}`;
|
|
32
|
+
this.toFormData(item, form, key);
|
|
33
|
+
});
|
|
34
|
+
return form;
|
|
35
|
+
}
|
|
36
|
+
Object.keys(json).forEach((key) => {
|
|
37
|
+
const newKey = parentKey ? `${parentKey}.${key}` : key;
|
|
38
|
+
this.toFormData(json[key], form, newKey);
|
|
39
|
+
});
|
|
40
|
+
return form;
|
|
41
|
+
}
|
|
42
|
+
static wrapValue(value) {
|
|
43
|
+
if (value instanceof File) {
|
|
44
|
+
// return {
|
|
45
|
+
// __file: true,
|
|
46
|
+
// name: value.name,
|
|
47
|
+
// type: value.type,
|
|
48
|
+
// size: value.size,
|
|
49
|
+
// lastModified: value.lastModified,
|
|
50
|
+
// file: value,
|
|
51
|
+
// };
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const strValue = value.toString();
|
|
56
|
+
if (strValue === "true")
|
|
57
|
+
return true;
|
|
58
|
+
if (strValue === "false")
|
|
59
|
+
return false;
|
|
60
|
+
if (!isNaN(Number(strValue)))
|
|
61
|
+
return Number(strValue);
|
|
62
|
+
return strValue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
static setDeepValue(obj, path, value) {
|
|
66
|
+
let current = obj;
|
|
67
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
68
|
+
const key = path[i];
|
|
69
|
+
const nextKey = path[i + 1];
|
|
70
|
+
if (current[key] === undefined) {
|
|
71
|
+
current[key] = typeof nextKey === "number" ? [] : {};
|
|
72
|
+
}
|
|
73
|
+
current = current[key];
|
|
74
|
+
}
|
|
75
|
+
const finalKey = path[path.length - 1];
|
|
76
|
+
current[finalKey] = value;
|
|
77
|
+
}
|
|
78
|
+
static parseKeyPath(key) {
|
|
79
|
+
const path = [];
|
|
80
|
+
const parts = key.split(/\.|(\[\d+\])/).filter(Boolean);
|
|
81
|
+
for (const p of parts) {
|
|
82
|
+
const match = p.match(/\[(\d+)\]/);
|
|
83
|
+
if (match) {
|
|
84
|
+
path.push(Number(match[1]));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
path.push(p);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return path;
|
|
91
|
+
}
|
|
92
|
+
static exposeToGlobal() {
|
|
93
|
+
if (typeof window !== "undefined") {
|
|
94
|
+
window.Fodat = Fodat;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (typeof window !== "undefined") {
|
|
99
|
+
window.Fodat = Fodat;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
package/fodat.all.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class Fodat{static transform(t){if(t instanceof FormData){var e,a,r={};for([e,a]of t.entries()){var o=this.parseKeyPath(e);this.setDeepValue(r,o,this.wrapValue(a))}return r}if("object"==typeof t&&!Array.isArray(t))return t}static toFormData(e,a=new FormData,r){return null!=e&&(!0===e?.__file&&e.file instanceof File?a.append(r,e.file):"object"!=typeof e||e instanceof File?r&&a.append(r,e):Array.isArray(e)?e.forEach((t,e)=>{this.toFormData(t,a,r?r+`[${e}]`:""+e)}):Object.keys(e).forEach(t=>{this.toFormData(e[t],a,r?r+"."+t:t)})),a}static wrapValue(t){return t instanceof File?t:"true"===(t=t.toString())||"false"!==t&&(isNaN(Number(t))?t:Number(t))}static setDeepValue(t,e,a){let r=t;for(let t=0;t<e.length-1;t++){var o=e[t],i=e[t+1];void 0===r[o]&&(r[o]="number"==typeof i?[]:{}),r=r[o]}t=e[e.length-1];r[t]=a}static parseKeyPath(t){var e,a=[];for(e of t.split(/\.|(\[\d+\])/).filter(Boolean)){var r=e.match(/\[(\d+)\]/);a.push(r?Number(r[1]):e)}return a}static exposeToGlobal(){"undefined"!=typeof window&&(window.Fodat=Fodat)}}"undefined"!=typeof window&&(window.Fodat=Fodat);
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
Fodat: typeof Fodat;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
declare class Fodat {
|
|
7
|
+
static transform(formData: any): any;
|
|
8
|
+
static toFormData(json: any, form?: FormData, parentKey?: string): FormData;
|
|
9
|
+
private static wrapValue;
|
|
10
|
+
private static setDeepValue;
|
|
11
|
+
private static parseKeyPath;
|
|
12
|
+
static exposeToGlobal(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { Fodat, Fodat as default };
|
package/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
class Fodat {
|
|
2
|
+
static transform(formData) {
|
|
3
|
+
if (formData instanceof FormData) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const [key, value] of formData.entries()) {
|
|
6
|
+
const path = this.parseKeyPath(key);
|
|
7
|
+
this.setDeepValue(result, path, this.wrapValue(value));
|
|
8
|
+
}
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
else if (typeof formData === 'object' &&
|
|
12
|
+
!Array.isArray(formData)) {
|
|
13
|
+
return formData;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
static toFormData(json, form = new FormData(), parentKey) {
|
|
18
|
+
if (json === null || json === undefined)
|
|
19
|
+
return form;
|
|
20
|
+
if (json?.__file === true && json.file instanceof File) {
|
|
21
|
+
form.append(parentKey, json.file);
|
|
22
|
+
return form;
|
|
23
|
+
}
|
|
24
|
+
if (typeof json !== "object" || json instanceof File) {
|
|
25
|
+
if (parentKey)
|
|
26
|
+
form.append(parentKey, json);
|
|
27
|
+
return form;
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(json)) {
|
|
30
|
+
json.forEach((item, index) => {
|
|
31
|
+
const key = parentKey ? `${parentKey}[${index}]` : `${index}`;
|
|
32
|
+
this.toFormData(item, form, key);
|
|
33
|
+
});
|
|
34
|
+
return form;
|
|
35
|
+
}
|
|
36
|
+
Object.keys(json).forEach((key) => {
|
|
37
|
+
const newKey = parentKey ? `${parentKey}.${key}` : key;
|
|
38
|
+
this.toFormData(json[key], form, newKey);
|
|
39
|
+
});
|
|
40
|
+
return form;
|
|
41
|
+
}
|
|
42
|
+
static wrapValue(value) {
|
|
43
|
+
if (value instanceof File) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const strValue = value.toString();
|
|
48
|
+
if (strValue === "true")
|
|
49
|
+
return true;
|
|
50
|
+
if (strValue === "false")
|
|
51
|
+
return false;
|
|
52
|
+
if (!isNaN(Number(strValue)))
|
|
53
|
+
return Number(strValue);
|
|
54
|
+
return strValue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
static setDeepValue(obj, path, value) {
|
|
58
|
+
let current = obj;
|
|
59
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
60
|
+
const key = path[i];
|
|
61
|
+
const nextKey = path[i + 1];
|
|
62
|
+
if (current[key] === undefined) {
|
|
63
|
+
current[key] = typeof nextKey === "number" ? [] : {};
|
|
64
|
+
}
|
|
65
|
+
current = current[key];
|
|
66
|
+
}
|
|
67
|
+
const finalKey = path[path.length - 1];
|
|
68
|
+
current[finalKey] = value;
|
|
69
|
+
}
|
|
70
|
+
static parseKeyPath(key) {
|
|
71
|
+
const path = [];
|
|
72
|
+
const parts = key.split(/\.|(\[\d+\])/).filter(Boolean);
|
|
73
|
+
for (const p of parts) {
|
|
74
|
+
const match = p.match(/\[(\d+)\]/);
|
|
75
|
+
if (match) {
|
|
76
|
+
path.push(Number(match[1]));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
path.push(p);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
static exposeToGlobal() {
|
|
85
|
+
if (typeof window !== "undefined") {
|
|
86
|
+
window.Fodat = Fodat;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (typeof window !== "undefined") {
|
|
91
|
+
window.Fodat = Fodat;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { Fodat, Fodat as default };
|
package/index.min.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
Fodat: typeof Fodat;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
declare class Fodat {
|
|
7
|
+
static transform(formData: any): any;
|
|
8
|
+
static toFormData(json: any, form?: FormData, parentKey?: string): FormData;
|
|
9
|
+
private static wrapValue;
|
|
10
|
+
private static setDeepValue;
|
|
11
|
+
private static parseKeyPath;
|
|
12
|
+
static exposeToGlobal(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { Fodat, Fodat as default };
|
package/index.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class Fodat{static transform(t){if(t instanceof FormData){var e,a,r={};for([e,a]of t.entries()){var o=this.parseKeyPath(e);this.setDeepValue(r,o,this.wrapValue(a))}return r}if("object"==typeof t&&!Array.isArray(t))return t}static toFormData(e,a=new FormData,r){return null!=e&&(!0===e?.__file&&e.file instanceof File?a.append(r,e.file):"object"!=typeof e||e instanceof File?r&&a.append(r,e):Array.isArray(e)?e.forEach((t,e)=>{this.toFormData(t,a,r?r+`[${e}]`:""+e)}):Object.keys(e).forEach(t=>{this.toFormData(e[t],a,r?r+"."+t:t)})),a}static wrapValue(t){return t instanceof File?t:"true"===(t=t.toString())||"false"!==t&&(isNaN(Number(t))?t:Number(t))}static setDeepValue(t,e,a){let r=t;for(let t=0;t<e.length-1;t++){var o=e[t],i=e[t+1];void 0===r[o]&&(r[o]="number"==typeof i?[]:{}),r=r[o]}t=e[e.length-1];r[t]=a}static parseKeyPath(t){var e,a=[];for(e of t.split(/\.|(\[\d+\])/).filter(Boolean)){var r=e.match(/\[(\d+)\]/);a.push(r?Number(r[1]):e)}return a}static exposeToGlobal(){"undefined"!=typeof window&&(window.Fodat=Fodat)}}"undefined"!=typeof window&&(window.Fodat=Fodat);export{Fodat,Fodat as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arc-js/fodat",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.0.1",
|
|
7
|
+
"description": "Fodat est une bibliothèque JavaScript/TypeScript légère et puissante pour la transformation bidirectionnelle entre FormData et objets JSON. Conçue pour simplifier la manipulation des données de formulaires complexes avec support natif des fichiers et structures imbriquées",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "INICODE <contact@inicode@gmail.com>",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"init": "npm init --scope=@arc-js/fodat",
|
|
14
|
+
"login": "npm login"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {},
|
|
17
|
+
"dependencies": {}
|
|
18
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext"],
|
|
6
|
+
"strict": false,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": false,
|
|
10
|
+
"sourceMap": false,
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"noEmit": false
|
|
13
|
+
},
|
|
14
|
+
"include": [],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"node_modules",
|
|
17
|
+
"**/*.d.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|