MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add FormData

+620 -35
+120
examples/spec/formdata.js
··· 1 + import { test, testThrows, testDeep, summary } from './helpers.js'; 2 + 3 + console.log('FormData constructor\n'); 4 + 5 + const fd0 = new FormData(); 6 + test('empty constructor', fd0.has('x'), false); 7 + 8 + testThrows('requires new', () => FormData()); 9 + testThrows('rejects form element', () => new FormData(document)); 10 + 11 + console.log('\nappend / get / has / delete / set\n'); 12 + 13 + const fd = new FormData(); 14 + 15 + fd.append('name', 'Alice'); 16 + test('append then get', fd.get('name'), 'Alice'); 17 + test('has returns true', fd.has('name'), true); 18 + test('has missing returns false', fd.has('other'), false); 19 + 20 + fd.append('name', 'Bob'); 21 + const all = fd.getAll('name'); 22 + test('getAll length after two appends', all.length, 2); 23 + test('getAll first', all[0], 'Alice'); 24 + test('getAll second', all[1], 'Bob'); 25 + 26 + fd.set('name', 'Carol'); 27 + test('set replaces all', fd.getAll('name').length, 1); 28 + test('set value', fd.get('name'), 'Carol'); 29 + 30 + fd.delete('name'); 31 + test('delete removes all', fd.has('name'), false); 32 + test('get after delete returns null', fd.get('name'), null); 33 + 34 + console.log('\nBlob values\n'); 35 + 36 + const blob = new Blob(['hello'], { type: 'text/plain' }); 37 + const fdb = new FormData(); 38 + fdb.append('file', blob); 39 + 40 + const got = fdb.get('file'); 41 + test('blob entry is File instance', got instanceof File, true); 42 + test('blob entry filename default', got.name, 'blob'); 43 + test('blob entry type', got.type, 'text/plain'); 44 + 45 + fdb.append('file2', blob, 'custom.txt'); 46 + const got2 = fdb.get('file2'); 47 + test('blob with filename', got2.name, 'custom.txt'); 48 + 49 + console.log('\nFile values\n'); 50 + 51 + const file = new File(['world'], 'test.txt', { type: 'text/html' }); 52 + const fdf = new FormData(); 53 + fdf.append('upload', file); 54 + 55 + const gotf = fdf.get('upload'); 56 + test('file entry is File instance', gotf instanceof File, true); 57 + test('file entry name from File', gotf.name, 'test.txt'); 58 + test('file entry type', gotf.type, 'text/html'); 59 + 60 + fdf.append('upload2', file, 'override.txt'); 61 + test('file entry name overridden', fdf.get('upload2').name, 'override.txt'); 62 + 63 + console.log('\ngetAll with mixed types\n'); 64 + 65 + const fdm = new FormData(); 66 + fdm.append('x', 'str'); 67 + fdm.append('x', new Blob(['data'])); 68 + const mixed = fdm.getAll('x'); 69 + test('mixed getAll length', mixed.length, 2); 70 + test('mixed first is string', mixed[0], 'str'); 71 + test('mixed second is File', mixed[1] instanceof File, true); 72 + 73 + console.log('\nforEach\n'); 74 + 75 + const fdfe = new FormData(); 76 + fdfe.append('b', '2'); 77 + fdfe.append('a', '1'); 78 + const seen = []; 79 + fdfe.forEach((val, name) => seen.push(`${name}=${val}`)); 80 + test('forEach visits all entries', seen.length, 2); 81 + test('forEach insertion order first', seen[0], 'b=2'); 82 + test('forEach insertion order second', seen[1], 'a=1'); 83 + 84 + console.log('\nentries / keys / values\n'); 85 + 86 + const fdi = new FormData(); 87 + fdi.append('x', '1'); 88 + fdi.append('y', '2'); 89 + fdi.append('x', '3'); 90 + 91 + const keys = [...fdi.keys()]; 92 + test('keys length', keys.length, 3); 93 + test('keys first', keys[0], 'x'); 94 + test('keys second', keys[1], 'y'); 95 + test('keys third', keys[2], 'x'); 96 + 97 + const vals = [...fdi.values()]; 98 + test('values first', vals[0], '1'); 99 + test('values second', vals[1], '2'); 100 + test('values third', vals[2], '3'); 101 + 102 + const entries = [...fdi.entries()]; 103 + test('entries length', entries.length, 3); 104 + test('entries first name', entries[0][0], 'x'); 105 + test('entries first value', entries[0][1], '1'); 106 + 107 + console.log('\nSymbol.iterator\n'); 108 + 109 + const fds = new FormData(); 110 + fds.append('k', 'v'); 111 + const iter_result = [...fds]; 112 + test('Symbol.iterator yields entries', iter_result.length, 1); 113 + test('Symbol.iterator entry name', iter_result[0][0], 'k'); 114 + test('Symbol.iterator entry value', iter_result[0][1], 'v'); 115 + 116 + console.log('\ntoStringTag\n'); 117 + 118 + test('toStringTag', Object.prototype.toString.call(new FormData()), '[object FormData]'); 119 + 120 + summary();
+6
include/modules/formdata.h
··· 1 + #ifndef FORMDATA_H 2 + #define FORMDATA_H 3 + 4 + void init_formdata_module(void); 5 + 6 + #endif
+3 -3
src/cli/misc.c
··· 16 16 s && l ? ", " : "", 17 17 l ? "--" : "", 18 18 l ? l : "", 19 - d && l && opt ? "[=" : 20 - d && l ? "=" : 21 - d && s ? " " : "", 19 + d && l && opt ? "[=" : 20 + d && l ? "=" : 21 + d && s ? " " : "", 22 22 d ? d : ""); 23 23 24 24 crfprintf(fp, "<space=2/><pad=32>%s</pad> %s</>\n", syn, g);
+32 -32
src/highlight/theme.toml
··· 1 - # Highlight theme โ€” token class โ†’ crprintf color/style string 2 - # Styles: hex colors (#RRGGBB), with optional prefix modifiers (bold+, italic+) 1 + # token class โ†’ crprintf color/style string 2 + # hex colors (#RRGGBB), with optional prefix modifiers (bold+, italic+) 3 3 4 4 [colors] 5 - number = "#E8CD7C" 6 - number_prefix = "#EADBAD" 7 - boolean = "#65B2FF" 8 - literal_null = "#65B2FF" 5 + number = "#E8CD7C" 6 + number_prefix = "#EADBAD" 7 + boolean = "#65B2FF" 8 + literal_null = "#65B2FF" 9 9 10 - string = "#FF8A7F" 10 + string = "#FF8A7F" 11 11 string_delimiter = "#FF7265" 12 - string_escape = "#F4AAA3" 13 - string_key = "#CCA3F4" 14 - string_template = "#FFB265" 12 + string_escape = "#F4AAA3" 13 + string_key = "#CCA3F4" 14 + string_template = "#FFB265" 15 15 16 - regex = "#FFB265" 17 - regex_escape = "#FFCC99" 18 - regex_delimiter = "#FF9932" 19 - regex_cdata = "#65B2FF" 16 + regex = "#FFB265" 17 + regex_escape = "#FFCC99" 18 + regex_delimiter = "#FF9932" 19 + regex_cdata = "#65B2FF" 20 20 21 - keyword = "#65B2FF" 22 - keyword_delete = "#F43D3D" 23 - keyword_italic = "italic+#65B2FF" 24 - keyword_extends = "italic+#59D8F1" 21 + keyword = "#65B2FF" 22 + keyword_delete = "#F43D3D" 23 + keyword_italic = "italic+#65B2FF" 24 + keyword_extends = "italic+#59D8F1" 25 25 26 - type = "#59D8F1" 27 - type_string = "#30E8AA" 28 - type_boolean = "#30E8AA" 26 + type = "#59D8F1" 27 + type_string = "#30E8AA" 28 + type_boolean = "#30E8AA" 29 29 30 - comment = "#758CA3" 30 + comment = "#758CA3" 31 31 32 - function_name = "#30E8AA" 33 - function = "#30E8AA" 34 - argument = "#CCA3F4" 35 - property = "#CCA3F4" 32 + function_name = "#30E8AA" 33 + function = "#30E8AA" 34 + argument = "#CCA3F4" 35 + property = "#CCA3F4" 36 36 37 - operator = "#8CB2D8" 38 - optional_chain = "#8CB2D8" 39 - bracket = "#8CB2D8" 40 - semicolon = "#B2CCE5" 37 + operator = "#8CB2D8" 38 + optional_chain = "#8CB2D8" 39 + bracket = "#8CB2D8" 40 + semicolon = "#B2CCE5" 41 41 42 - class_name = "bold+#F7B76D" 43 - parent_class = "bold+#59D8F1" 42 + class_name = "bold+#F7B76D" 43 + parent_class = "bold+#59D8F1"
+2
src/main.c
··· 77 77 #include "modules/worker_threads.h" 78 78 #include "modules/headers.h" 79 79 #include "modules/blob.h" 80 + #include "modules/formdata.h" 80 81 81 82 int js_result = EXIT_SUCCESS; 82 83 typedef int (*cmd_fn)(int argc, char **argv); ··· 586 587 init_abort_module(); 587 588 init_headers_module(); 588 589 init_blob_module(); 590 + init_formdata_module(); 589 591 init_math_module(); 590 592 init_bigint_module(); 591 593 init_date_module();
+457
src/modules/formdata.c
··· 1 + #include <stdlib.h> 2 + #include <string.h> 3 + #include <stdint.h> 4 + #include <time.h> 5 + 6 + #include "ant.h" 7 + #include "errors.h" 8 + #include "runtime.h" 9 + #include "internal.h" 10 + #include "descriptors.h" 11 + 12 + #include "silver/engine.h" 13 + #include "modules/formdata.h" 14 + #include "modules/blob.h" 15 + #include "modules/symbol.h" 16 + 17 + typedef struct fd_entry { 18 + char *name; 19 + bool is_file; 20 + char *str_value; 21 + size_t val_idx; 22 + struct fd_entry *next; 23 + } fd_entry_t; 24 + 25 + typedef struct { 26 + fd_entry_t *head; 27 + fd_entry_t **tail; 28 + size_t count; 29 + } fd_data_t; 30 + 31 + typedef struct { 32 + size_t index; 33 + int kind; 34 + } fd_iter_t; 35 + 36 + enum { 37 + FD_ITER_ENTRIES = 0, 38 + FD_ITER_KEYS = 1, 39 + FD_ITER_VALUES = 2 40 + }; 41 + 42 + static ant_value_t g_formdata_proto = 0; 43 + static ant_value_t g_formdata_iter_proto = 0; 44 + 45 + static fd_data_t *fd_data_new(void) { 46 + fd_data_t *d = calloc(1, sizeof(fd_data_t)); 47 + if (!d) return NULL; 48 + d->tail = &d->head; 49 + return d; 50 + } 51 + 52 + static void fd_entry_free(fd_entry_t *e) { 53 + if (!e) return; 54 + free(e->name); 55 + free(e->str_value); 56 + free(e); 57 + } 58 + 59 + static void fd_data_free(fd_data_t *d) { 60 + if (!d) return; 61 + for (fd_entry_t *e = d->head; e; ) { 62 + fd_entry_t *n = e->next; 63 + fd_entry_free(e); 64 + e = n; 65 + } 66 + free(d); 67 + } 68 + 69 + static fd_data_t *get_fd_data(ant_value_t obj) { 70 + ant_value_t slot = js_get_slot(obj, SLOT_DATA); 71 + if (vtype(slot) != T_NUM) return NULL; 72 + return (fd_data_t *)(uintptr_t)(size_t)js_getnum(slot); 73 + } 74 + 75 + static ant_value_t get_fd_values(ant_value_t obj) { 76 + return js_get_slot(obj, SLOT_ENTRIES); 77 + } 78 + 79 + static void formdata_finalize(ant_t *js, ant_object_t *obj) { 80 + if (!obj->extra_slots) return; 81 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 82 + 83 + for (uint8_t i = 0; i < obj->extra_count; i++) { 84 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 85 + fd_data_t *d = (fd_data_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 86 + fd_data_free(d); 87 + return; 88 + }} 89 + } 90 + 91 + static bool fd_append_str(fd_data_t *d, const char *name, const char *value) { 92 + fd_entry_t *e = calloc(1, sizeof(fd_entry_t)); 93 + if (!e) return false; 94 + 95 + e->name = strdup(name); 96 + e->str_value = strdup(value); 97 + 98 + if (!e->name || !e->str_value) { fd_entry_free(e); return false; } 99 + 100 + *d->tail = e; 101 + d->tail = &e->next; 102 + d->count++; 103 + return true; 104 + } 105 + 106 + static bool fd_append_file(fd_data_t *d, const char *name, size_t val_idx) { 107 + fd_entry_t *e = calloc(1, sizeof(fd_entry_t)); 108 + if (!e) return false; 109 + 110 + e->is_file = true; 111 + e->name = strdup(name); 112 + e->val_idx = val_idx; 113 + 114 + if (!e->name) { free(e); return false; } 115 + 116 + *d->tail = e; 117 + d->tail = &e->next; 118 + d->count++; 119 + return true; 120 + } 121 + 122 + static void fd_delete_name(fd_data_t *d, const char *name) { 123 + fd_entry_t **pp = &d->head; 124 + d->tail = &d->head; 125 + 126 + while (*pp) { 127 + if (strcmp((*pp)->name, name) == 0) { 128 + fd_entry_t *dead = *pp; 129 + *pp = dead->next; 130 + d->count--; 131 + fd_entry_free(dead); 132 + } else { 133 + d->tail = &(*pp)->next; 134 + pp = &(*pp)->next; 135 + }} 136 + } 137 + 138 + static ant_value_t entry_to_js_value(ant_t *js, ant_value_t values_arr, fd_entry_t *e) { 139 + if (!e->is_file) 140 + return js_mkstr(js, e->str_value ? e->str_value : "", strlen(e->str_value ? e->str_value : "")); 141 + return js_arr_get(js, values_arr, (ant_offset_t)e->val_idx); 142 + } 143 + 144 + static const char *resolve_name(ant_t *js, ant_value_t *name_v) { 145 + if (vtype(*name_v) != T_STR) { 146 + *name_v = js_tostring_val(js, *name_v); 147 + if (is_err(*name_v)) return NULL; 148 + } 149 + return js_getstr(js, *name_v, NULL); 150 + } 151 + 152 + static ant_value_t extract_file_entry( 153 + ant_t *js, fd_data_t *d, ant_value_t values_arr, 154 + const char *name, ant_value_t val, ant_value_t filename_v, bool is_set 155 + ) { 156 + blob_data_t *bd = blob_get_data(val); 157 + if (!bd) return js_mkerr_typed(js, JS_ERR_TYPE, "FormData value must be a string, Blob, or File"); 158 + 159 + const char *fname = NULL; 160 + char *fname_owned = NULL; 161 + 162 + if (vtype(filename_v) != T_UNDEF) { 163 + ant_value_t fv = filename_v; 164 + if (vtype(fv) != T_STR) { fv = js_tostring_val(js, fv); if (is_err(fv)) return fv; } 165 + fname_owned = strdup(js_getstr(js, fv, NULL)); 166 + fname = fname_owned; 167 + } 168 + 169 + else if (bd->name && bd->name[0]) fname = bd->name; 170 + else fname = "blob"; 171 + 172 + int64_t last_modified = bd->last_modified; 173 + if (!last_modified) { 174 + struct timespec ts; 175 + clock_gettime(CLOCK_REALTIME, &ts); 176 + last_modified = (int64_t)ts.tv_sec * 1000LL + (int64_t)(ts.tv_nsec / 1000000); 177 + } 178 + 179 + ant_value_t file_obj = blob_create(js, bd->data, bd->size, bd->type); 180 + if (is_err(file_obj)) { free(fname_owned); return file_obj; } 181 + 182 + blob_data_t *nbd = blob_get_data(file_obj); 183 + if (nbd) { 184 + nbd->name = strdup(fname); 185 + nbd->last_modified = last_modified; 186 + } free(fname_owned); 187 + 188 + js_set_proto_init(file_obj, g_file_proto); 189 + if (is_set) fd_delete_name(d, name); 190 + 191 + size_t idx = (size_t)js_arr_len(js, values_arr); 192 + js_arr_push(js, values_arr, file_obj); 193 + 194 + return fd_append_file(d, name, idx) ? js_mkundef() : js_mkerr(js, "out of memory"); 195 + } 196 + 197 + static ant_value_t js_formdata_append(ant_t *js, ant_value_t *args, int nargs) { 198 + if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "FormData.append requires 2 arguments"); 199 + fd_data_t *d = get_fd_data(js->this_val); 200 + if (!d) return js_mkerr(js, "Invalid FormData object"); 201 + 202 + ant_value_t name_v = args[0]; 203 + const char *name = resolve_name(js, &name_v); 204 + if (!name) return name_v; 205 + 206 + ant_value_t val = args[1]; 207 + if (is_object_type(val) && blob_get_data(val)) { 208 + ant_value_t fname = (nargs >= 3) ? args[2] : js_mkundef(); 209 + ant_value_t values_arr = get_fd_values(js->this_val); 210 + return extract_file_entry(js, d, values_arr, name, val, fname, false); 211 + } 212 + 213 + if (vtype(val) != T_STR) { val = js_tostring_val(js, val); if (is_err(val)) return val; } 214 + return fd_append_str(d, name, js_getstr(js, val, NULL)) ? js_mkundef() : js_mkerr(js, "out of memory"); 215 + } 216 + 217 + static ant_value_t js_formdata_set(ant_t *js, ant_value_t *args, int nargs) { 218 + if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "FormData.set requires 2 arguments"); 219 + fd_data_t *d = get_fd_data(js->this_val); 220 + if (!d) return js_mkerr(js, "Invalid FormData object"); 221 + 222 + ant_value_t name_v = args[0]; 223 + const char *name = resolve_name(js, &name_v); 224 + if (!name) return name_v; 225 + 226 + ant_value_t val = args[1]; 227 + if (is_object_type(val) && blob_get_data(val)) { 228 + ant_value_t fname = (nargs >= 3) ? args[2] : js_mkundef(); 229 + ant_value_t values_arr = get_fd_values(js->this_val); 230 + return extract_file_entry(js, d, values_arr, name, val, fname, true); 231 + } 232 + 233 + if (vtype(val) != T_STR) { val = js_tostring_val(js, val); if (is_err(val)) return val; } 234 + fd_delete_name(d, name); 235 + return fd_append_str(d, name, js_getstr(js, val, NULL)) ? js_mkundef() : js_mkerr(js, "out of memory"); 236 + } 237 + 238 + static ant_value_t js_formdata_get(ant_t *js, ant_value_t *args, int nargs) { 239 + if (nargs < 1) return js_mknull(); 240 + fd_data_t *d = get_fd_data(js->this_val); 241 + if (!d) return js_mknull(); 242 + 243 + ant_value_t name_v = args[0]; 244 + const char *name = resolve_name(js, &name_v); 245 + if (!name) return name_v; 246 + 247 + ant_value_t values_arr = get_fd_values(js->this_val); 248 + for (fd_entry_t *e = d->head; e; e = e->next) { 249 + if (strcmp(e->name, name) == 0) 250 + return entry_to_js_value(js, values_arr, e); 251 + } 252 + return js_mknull(); 253 + } 254 + 255 + static ant_value_t js_formdata_get_all(ant_t *js, ant_value_t *args, int nargs) { 256 + ant_value_t result = js_mkarr(js); 257 + if (nargs < 1) return result; 258 + fd_data_t *d = get_fd_data(js->this_val); 259 + if (!d) return result; 260 + 261 + ant_value_t name_v = args[0]; 262 + const char *name = resolve_name(js, &name_v); 263 + if (!name) return name_v; 264 + 265 + ant_value_t values_arr = get_fd_values(js->this_val); 266 + for (fd_entry_t *e = d->head; e; e = e->next) { 267 + if (strcmp(e->name, name) == 0) { 268 + ant_value_t v = entry_to_js_value(js, values_arr, e); 269 + if (is_err(v)) return v; 270 + js_arr_push(js, result, v); 271 + }} 272 + return result; 273 + } 274 + 275 + static ant_value_t js_formdata_has(ant_t *js, ant_value_t *args, int nargs) { 276 + if (nargs < 1) return js_false; 277 + fd_data_t *d = get_fd_data(js->this_val); 278 + if (!d) return js_false; 279 + 280 + ant_value_t name_v = args[0]; 281 + const char *name = resolve_name(js, &name_v); 282 + if (!name) return name_v; 283 + 284 + for (fd_entry_t *e = d->head; e; e = e->next) { 285 + if (strcmp(e->name, name) == 0) return js_true; 286 + } 287 + return js_false; 288 + } 289 + 290 + static ant_value_t js_formdata_delete(ant_t *js, ant_value_t *args, int nargs) { 291 + if (nargs < 1) return js_mkundef(); 292 + fd_data_t *d = get_fd_data(js->this_val); 293 + if (!d) return js_mkundef(); 294 + 295 + ant_value_t name_v = args[0]; 296 + const char *name = resolve_name(js, &name_v); 297 + if (!name) return name_v; 298 + 299 + fd_delete_name(d, name); 300 + return js_mkundef(); 301 + } 302 + 303 + static ant_value_t js_formdata_foreach(ant_t *js, ant_value_t *args, int nargs) { 304 + if (nargs < 1 || !is_callable(args[0])) 305 + return js_mkerr_typed(js, JS_ERR_TYPE, "FormData.forEach requires a function"); 306 + fd_data_t *d = get_fd_data(js->this_val); 307 + if (!d) return js_mkundef(); 308 + 309 + ant_value_t fn = args[0]; 310 + ant_value_t this_arg = (nargs >= 2) ? args[1] : js_mkundef(); 311 + ant_value_t self = js->this_val; 312 + ant_value_t values_arr = get_fd_values(self); 313 + 314 + for (fd_entry_t *e = d->head; e; e = e->next) { 315 + ant_value_t val = entry_to_js_value(js, values_arr, e); 316 + if (is_err(val)) return val; 317 + ant_value_t name = js_mkstr(js, e->name, strlen(e->name)); 318 + ant_value_t cb_args[3] = { val, name, self }; 319 + ant_value_t r = sv_vm_call(js->vm, js, fn, this_arg, cb_args, 3, NULL, false); 320 + if (is_err(r)) return r; 321 + } 322 + return js_mkundef(); 323 + } 324 + 325 + static ant_value_t formdata_iter_next(ant_t *js, ant_value_t *args, int nargs) { 326 + ant_value_t state_v = js_get_slot(js->this_val, SLOT_ITER_STATE); 327 + if (vtype(state_v) != T_NUM) return js_iter_result(js, false, js_mkundef()); 328 + 329 + fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(state_v); 330 + ant_value_t fd_obj = js_get_slot(js->this_val, SLOT_DATA); 331 + fd_data_t *d = get_fd_data(fd_obj); 332 + if (!d) return js_iter_result(js, false, js_mkundef()); 333 + 334 + ant_value_t values_arr = get_fd_values(fd_obj); 335 + 336 + size_t idx = 0; 337 + for (fd_entry_t *e = d->head; e; e = e->next, idx++) { 338 + if (idx == st->index) { 339 + st->index++; 340 + ant_value_t out; 341 + switch (st->kind) { 342 + case FD_ITER_KEYS: 343 + out = js_mkstr(js, e->name, strlen(e->name)); 344 + break; 345 + case FD_ITER_VALUES: 346 + out = entry_to_js_value(js, values_arr, e); 347 + break; 348 + default: { 349 + ant_value_t v = entry_to_js_value(js, values_arr, e); 350 + if (is_err(v)) return v; 351 + out = js_mkarr(js); 352 + js_arr_push(js, out, js_mkstr(js, e->name, strlen(e->name))); 353 + js_arr_push(js, out, v); 354 + break; 355 + }} 356 + if (is_err(out)) return out; 357 + return js_iter_result(js, true, out); 358 + }} 359 + 360 + return js_iter_result(js, false, js_mkundef()); 361 + } 362 + 363 + static void formdata_iter_finalize(ant_t *js, ant_object_t *obj) { 364 + if (!obj->extra_slots) return; 365 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 366 + 367 + for (uint8_t i = 0; i < obj->extra_count; i++) { 368 + if (entries[i].slot == SLOT_ITER_STATE && vtype(entries[i].value) == T_NUM) { 369 + fd_iter_t *st = (fd_iter_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 370 + free(st); 371 + return; 372 + }} 373 + } 374 + 375 + static ant_value_t make_formdata_iter(ant_t *js, ant_value_t fd_obj, int kind) { 376 + fd_iter_t *st = calloc(1, sizeof(fd_iter_t)); 377 + if (!st) return js_mkerr(js, "out of memory"); 378 + st->kind = kind; 379 + 380 + ant_value_t iter = js_mkobj(js); 381 + js_set_proto_init(iter, g_formdata_iter_proto); 382 + js_set_slot(iter, SLOT_ITER_STATE, ANT_PTR(st)); 383 + js_set_slot_wb(js, iter, SLOT_DATA, fd_obj); 384 + js_set_finalizer(iter, formdata_iter_finalize); 385 + return iter; 386 + } 387 + 388 + static ant_value_t js_formdata_entries(ant_t *js, ant_value_t *args, int nargs) { 389 + return make_formdata_iter(js, js->this_val, FD_ITER_ENTRIES); 390 + } 391 + 392 + static ant_value_t js_formdata_keys(ant_t *js, ant_value_t *args, int nargs) { 393 + return make_formdata_iter(js, js->this_val, FD_ITER_KEYS); 394 + } 395 + 396 + static ant_value_t js_formdata_values(ant_t *js, ant_value_t *args, int nargs) { 397 + return make_formdata_iter(js, js->this_val, FD_ITER_VALUES); 398 + } 399 + 400 + static ant_value_t js_formdata_ctor(ant_t *js, ant_value_t *args, int nargs) { 401 + if (vtype(js->new_target) == T_UNDEF) 402 + return js_mkerr_typed(js, JS_ERR_TYPE, "FormData constructor requires 'new'"); 403 + if (nargs >= 1 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) 404 + return js_mkerr_typed(js, JS_ERR_TYPE, "FormData does not support a form element argument"); 405 + 406 + fd_data_t *d = fd_data_new(); 407 + if (!d) return js_mkerr(js, "out of memory"); 408 + 409 + ant_value_t obj = js_mkobj(js); 410 + ant_value_t proto = js_instance_proto_from_new_target(js, g_formdata_proto); 411 + if (is_object_type(proto)) js_set_proto_init(obj, proto); 412 + 413 + js_set_slot(obj, SLOT_DATA, ANT_PTR(d)); 414 + ant_value_t vals = js_mkarr(js); 415 + js_set_slot_wb(js, obj, SLOT_ENTRIES, vals); 416 + js_set_finalizer(obj, formdata_finalize); 417 + return obj; 418 + } 419 + 420 + void init_formdata_module(void) { 421 + ant_t *js = rt->js; 422 + ant_value_t g = js_glob(js); 423 + g_formdata_proto = js_mkobj(js); 424 + 425 + js_set(js, g_formdata_proto, "append", js_mkfun(js_formdata_append)); 426 + js_set(js, g_formdata_proto, "set", js_mkfun(js_formdata_set)); 427 + js_set(js, g_formdata_proto, "get", js_mkfun(js_formdata_get)); 428 + js_set(js, g_formdata_proto, "getAll", js_mkfun(js_formdata_get_all)); 429 + js_set(js, g_formdata_proto, "has", js_mkfun(js_formdata_has)); 430 + js_set(js, g_formdata_proto, "delete", js_mkfun(js_formdata_delete)); 431 + js_set(js, g_formdata_proto, "forEach", js_mkfun(js_formdata_foreach)); 432 + js_set(js, g_formdata_proto, "entries", js_mkfun(js_formdata_entries)); 433 + js_set(js, g_formdata_proto, "keys", js_mkfun(js_formdata_keys)); 434 + js_set(js, g_formdata_proto, "values", js_mkfun(js_formdata_values)); 435 + 436 + js_set_sym(js, g_formdata_proto, get_iterator_sym(), js_mkfun(js_formdata_entries)); 437 + js_set_sym(js, g_formdata_proto, get_toStringTag_sym(), js_mkstr(js, "FormData", 8)); 438 + 439 + ant_value_t ctor_obj = js_mkobj(js); 440 + js_set_slot(ctor_obj, SLOT_CFUNC, js_mkfun(js_formdata_ctor)); 441 + js_mkprop_fast(js, ctor_obj, "prototype", 9, g_formdata_proto); 442 + js_mkprop_fast(js, ctor_obj, "name", 4, js_mkstr(js, "FormData", 8)); 443 + js_set_descriptor(js, ctor_obj, "name", 4, 0); 444 + 445 + ant_value_t ctor = js_obj_to_func(ctor_obj); 446 + js_set(js, g_formdata_proto, "constructor", ctor); 447 + js_set_descriptor(js, g_formdata_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 448 + 449 + js_set(js, g, "FormData", ctor); 450 + js_set_descriptor(js, g, "FormData", 8, JS_DESC_W | JS_DESC_C); 451 + 452 + g_formdata_iter_proto = js_mkobj(js); 453 + js_set_proto_init(g_formdata_iter_proto, js->sym.iterator_proto); 454 + js_set(js, g_formdata_iter_proto, "next", js_mkfun(formdata_iter_next)); 455 + js_set_descriptor(js, g_formdata_iter_proto, "next", 4, JS_DESC_W | JS_DESC_E | JS_DESC_C); 456 + js_set_sym(js, g_formdata_iter_proto, get_iterator_sym(), js_mkfun(sym_this_cb)); 457 + }