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.

small runtime fixes

- centralize proxy enumeration
- add inspect for headers/request/response
- allow gen/map support for object keys

+424 -75
+1 -1
examples/results.txt
··· 1294 1294 compat-table/es2019/Array.prototype.flatMap.js: OK 1295 1295 compat-table/es2019/Array.prototype.flat-flatMap.unscopables.js: OK 1296 1296 compat-table/es2019/Array.prototype.flat.js: OK 1297 - compat-table/es2019/Object.fromEntries.js: failed 1297 + compat-table/es2019/Object.fromEntries.js: OK 1298 1298 compat-table/es2019/String.prototype.trimEnd.js: OK 1299 1299 compat-table/es2019/String.prototype.trimStart.js: OK 1300 1300 compat-table/es2019/Symbol.prototype.description.empty.js: failed
+7 -4
include/internal.h
··· 374 374 void js_inspect_builder_init_fixed(js_inspect_builder_t *builder, ant_t *js, char *buf, size_t len, size_t initial_n); 375 375 bool js_inspect_builder_init_dynamic(js_inspect_builder_t *builder, ant_t *js, size_t initial_cap); 376 376 void js_inspect_builder_dispose(js_inspect_builder_t *builder); 377 - ant_value_t js_inspect_builder_result(js_inspect_builder_t *builder); 377 + bool js_inspect_tagged_header(js_inspect_builder_t *builder, const char *tag, size_t tag_len); 378 + bool js_inspect_object_body(js_inspect_builder_t *builder, ant_value_t obj); 379 + bool js_inspect_close(js_inspect_builder_t *builder); 378 380 379 381 __attribute__((format(printf, 2, 3))) 380 382 bool js_inspect_header(js_inspect_builder_t *builder, const char *fmt, ...); 381 - bool js_inspect_tagged_header(js_inspect_builder_t *builder, const char *tag, size_t tag_len); 382 - bool js_inspect_object_body(js_inspect_builder_t *builder, ant_value_t obj); 383 - bool js_inspect_close(js_inspect_builder_t *builder); 383 + 384 + __attribute__((format(printf, 3, 4))) 385 + bool js_inspect_header_for(js_inspect_builder_t *builder, ant_value_t obj, const char *fmt, ...); 384 386 387 + ant_value_t js_inspect_builder_result(js_inspect_builder_t *builder); 385 388 ant_value_t js_define_own_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t v); 386 389 ant_value_t js_instance_proto_from_new_target(ant_t *js, ant_value_t fallback_proto); 387 390
+239 -66
src/ant.c
··· 1289 1289 } 1290 1290 } 1291 1291 1292 - bool js_inspect_header(js_inspect_builder_t *builder, const char *fmt, ...) { 1293 - va_list args; 1294 - va_start(args, fmt); 1292 + static bool __attribute__((format(printf, 3, 0))) 1293 + js_inspect_vheader_for(js_inspect_builder_t *builder, ant_value_t obj, const char *fmt, va_list args) { 1295 1294 bool ok = js_inspect_vappendf(builder, fmt, args); 1296 - va_end(args); 1297 1295 if (!ok) return false; 1296 + 1297 + if (is_object_type(obj)) { 1298 + int prop_count = 0; 1299 + bool inline_mode = is_small_object(builder->js, obj, &prop_count); 1300 + 1301 + if (prop_count == 0) { 1302 + if (!js_inspect_append(builder, " {}", 3)) return false; 1303 + builder->inline_mode = false; 1304 + builder->first = true; 1305 + builder->closed = true; 1306 + builder->did_indent = false; 1307 + return true; 1308 + } 1309 + 1310 + if (inline_mode) { 1311 + if (!js_inspect_append(builder, " { ", 3)) return false; 1312 + builder->inline_mode = true; 1313 + builder->first = true; 1314 + builder->closed = false; 1315 + builder->did_indent = false; 1316 + return true; 1317 + }} 1318 + 1298 1319 if (!js_inspect_append(builder, " {\n", 3)) return false; 1299 1320 1300 1321 builder->inline_mode = false; 1301 1322 builder->first = true; 1302 1323 builder->closed = false; 1303 1324 builder->did_indent = false; 1304 - 1325 + 1305 1326 return true; 1327 + } 1328 + 1329 + bool js_inspect_header_for(js_inspect_builder_t *builder, ant_value_t obj, const char *fmt, ...) { 1330 + va_list args; va_start(args, fmt); 1331 + bool ok = js_inspect_vheader_for(builder, obj, fmt, args); 1332 + va_end(args); 1333 + return ok; 1334 + } 1335 + 1336 + bool js_inspect_header(js_inspect_builder_t *builder, const char *fmt, ...) { 1337 + va_list args; va_start(args, fmt); 1338 + bool ok = js_inspect_vheader_for(builder, js_mkundef(), fmt, args); 1339 + va_end(args); 1340 + return ok; 1306 1341 } 1307 1342 1308 1343 bool js_inspect_tagged_header(js_inspect_builder_t *builder, const char *tag, size_t tag_len) { ··· 5919 5954 return mkval(T_ARR, vdata(arr)); 5920 5955 } 5921 5956 5922 - static ant_value_t builtin_object_keys(ant_t *js, ant_value_t *args, int nargs) { 5923 - if (nargs == 0) return mkarr(js); 5924 - ant_value_t obj = args[0]; 5925 - if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 5926 - 5927 - if (is_proxy(obj)) { 5928 - ant_proxy_state_t *data = get_proxy_data(obj); 5929 - if (!data) return mkarr(js); 5930 - if (data->revoked) 5931 - return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot perform 'ownKeys' on a proxy that has been revoked"); 5932 - 5933 - ant_offset_t trap_off = lkp(js, data->handler, "ownKeys", 7); 5934 - if (!trap_off) return object_enum(js, data->target, OBJ_ENUM_KEYS); 5935 - 5957 + // TODO: reduce nesting 5958 + static ant_value_t proxy_enum(ant_t *js, ant_value_t obj, enum obj_enum_mode mode) { 5959 + GC_ROOT_SAVE(root_mark, js); 5960 + GC_ROOT_PIN(js, obj); 5961 + 5962 + ant_proxy_state_t *data = get_proxy_data(obj); 5963 + if (!data) { 5964 + GC_ROOT_RESTORE(js, root_mark); 5965 + return mkarr(js); 5966 + } 5967 + if (data->revoked) { 5968 + GC_ROOT_RESTORE(js, root_mark); 5969 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot perform 'ownKeys' on a proxy that has been revoked"); 5970 + } 5971 + 5972 + ant_value_t keys = mkarr(js); 5973 + GC_ROOT_PIN(js, keys); 5974 + 5975 + ant_offset_t trap_off = lkp(js, data->handler, "ownKeys", 7); 5976 + if (!trap_off) { 5977 + keys = object_enum(js, data->target, OBJ_ENUM_KEYS); 5978 + } else { 5936 5979 ant_value_t trap = propref_load(js, trap_off); 5937 5980 uint8_t ft = vtype(trap); 5938 - if (ft != T_FUNC && ft != T_CFUNC) return object_enum(js, data->target, OBJ_ENUM_KEYS); 5939 - 5940 - ant_value_t trap_args[1] = { data->target }; 5941 - ant_value_t result = sv_vm_call(js->vm, js, trap, data->handler, trap_args, 1, NULL, false); 5942 - if (is_err(result)) return result; 5943 - if (vtype(result) != T_ARR) 5944 - return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap must return an array"); 5945 - 5946 - ant_offset_t len = get_array_length(js, result); 5947 - for (ant_offset_t i = 0; i < len; i++) { 5948 - ant_value_t ki = arr_get(js, result, i); 5949 - if (vtype(ki) != T_STR && vtype(ki) != T_SYMBOL) 5950 - return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap result must contain only strings or symbols"); 5951 - ant_offset_t ki_len; ant_offset_t ki_off = vstr(js, ki, &ki_len); 5952 - for (ant_offset_t j = 0; j < i; j++) { 5953 - ant_value_t kj = arr_get(js, result, j); 5954 - ant_offset_t kj_len; ant_offset_t kj_off = vstr(js, kj, &kj_len); 5955 - if (ki_len == kj_len && 5956 - memcmp((const void *)(uintptr_t)ki_off, (const void *)(uintptr_t)kj_off, ki_len) == 0) 5957 - return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap result must not contain duplicate entries"); 5981 + if (ft != T_FUNC && ft != T_CFUNC) { 5982 + keys = object_enum(js, data->target, OBJ_ENUM_KEYS); 5983 + } else { 5984 + ant_value_t trap_args[1] = { data->target }; 5985 + ant_value_t result = sv_vm_call(js->vm, js, trap, data->handler, trap_args, 1, NULL, false); 5986 + if (is_err(result)) { 5987 + GC_ROOT_RESTORE(js, root_mark); 5988 + return result; 5989 + } 5990 + if (vtype(result) != T_ARR) { 5991 + GC_ROOT_RESTORE(js, root_mark); 5992 + return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap must return an array"); 5958 5993 } 5994 + 5995 + ant_offset_t len = get_array_length(js, result); 5996 + for (ant_offset_t i = 0; i < len; i++) { 5997 + ant_value_t ki = arr_get(js, result, i); 5998 + if (vtype(ki) != T_STR && vtype(ki) != T_SYMBOL) { 5999 + GC_ROOT_RESTORE(js, root_mark); 6000 + return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap result must contain only strings or symbols"); 6001 + } 6002 + for (ant_offset_t j = 0; j < i; j++) { 6003 + ant_value_t kj = arr_get(js, result, j); 6004 + if (vtype(ki) != vtype(kj)) continue; 6005 + if (vtype(ki) == T_SYMBOL) { 6006 + if (vdata(ki) == vdata(kj)) { 6007 + GC_ROOT_RESTORE(js, root_mark); 6008 + return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap result must not contain duplicate entries"); 6009 + } 6010 + continue; 6011 + } 6012 + 6013 + ant_offset_t ki_len; 6014 + ant_offset_t ki_off = vstr(js, ki, &ki_len); 6015 + ant_offset_t kj_len; 6016 + ant_offset_t kj_off = vstr(js, kj, &kj_len); 6017 + if (ki_len == kj_len && 6018 + memcmp((const void *)(uintptr_t)ki_off, (const void *)(uintptr_t)kj_off, ki_len) == 0) { 6019 + GC_ROOT_RESTORE(js, root_mark); 6020 + return js_mkerr_typed(js, JS_ERR_TYPE, "ownKeys trap result must not contain duplicate entries"); 6021 + } 6022 + } 6023 + } 6024 + keys = result; 5959 6025 } 5960 - return result; 5961 6026 } 6027 + 6028 + ant_value_t out = mkarr(js); 6029 + GC_ROOT_PIN(js, out); 6030 + 6031 + ant_offset_t key_count = get_array_length(js, keys); 6032 + for (ant_offset_t i = 0; i < key_count; i++) { 6033 + GC_ROOT_SAVE(iter_mark, js); 6034 + 6035 + ant_value_t key = arr_get(js, keys, i); 6036 + GC_ROOT_PIN(js, key); 6037 + if (vtype(key) != T_STR) { 6038 + GC_ROOT_RESTORE(js, iter_mark); 6039 + continue; 6040 + } 6041 + 6042 + ant_value_t desc = proxy_get_own_property_descriptor(js, obj, key); 6043 + GC_ROOT_PIN(js, desc); 6044 + if (is_err(desc)) { 6045 + GC_ROOT_RESTORE(js, iter_mark); 6046 + GC_ROOT_RESTORE(js, root_mark); 6047 + return desc; 6048 + } 6049 + if (vtype(desc) == T_UNDEF) { 6050 + GC_ROOT_RESTORE(js, iter_mark); 6051 + continue; 6052 + } 6053 + 6054 + bool enumerable = false; 6055 + ant_offset_t enumerable_off = lkp(js, desc, "enumerable", 10); 6056 + if (enumerable_off != 0) { 6057 + enumerable = js_truthy(js, propref_load(js, enumerable_off)); 6058 + } 6059 + if (!enumerable) { 6060 + GC_ROOT_RESTORE(js, iter_mark); 6061 + continue; 6062 + } 6063 + 6064 + if (mode == OBJ_ENUM_KEYS) { 6065 + js_arr_push(js, out, key); 6066 + GC_ROOT_RESTORE(js, iter_mark); 6067 + continue; 6068 + } 6069 + 6070 + ant_value_t value = proxy_get_val(js, obj, key); 6071 + GC_ROOT_PIN(js, value); 6072 + if (is_err(value)) { 6073 + GC_ROOT_RESTORE(js, iter_mark); 6074 + GC_ROOT_RESTORE(js, root_mark); 6075 + return value; 6076 + } 6077 + 6078 + if (mode == OBJ_ENUM_VALUES) { 6079 + js_arr_push(js, out, value); 6080 + } else { 6081 + ant_value_t entry = map_to_entry(js, key, value); 6082 + GC_ROOT_PIN(js, entry); 6083 + js_arr_push(js, out, entry); 6084 + } 6085 + 6086 + GC_ROOT_RESTORE(js, iter_mark); 6087 + } 6088 + 6089 + GC_ROOT_RESTORE(js, root_mark); 6090 + return out; 6091 + } 6092 + 6093 + static ant_value_t builtin_object_keys(ant_t *js, ant_value_t *args, int nargs) { 6094 + if (nargs == 0) return mkarr(js); 6095 + ant_value_t obj = args[0]; 6096 + if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 6097 + 6098 + if (is_proxy(obj)) return proxy_enum(js, obj, OBJ_ENUM_KEYS); 5962 6099 5963 6100 return object_enum(js, obj, OBJ_ENUM_KEYS); 5964 6101 } ··· 6147 6284 if (nargs == 0) return mkarr(js); 6148 6285 ant_value_t obj = args[0]; 6149 6286 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 6287 + if (is_proxy(obj)) return proxy_enum(js, obj, OBJ_ENUM_VALUES); 6150 6288 return object_enum(js, obj, OBJ_ENUM_VALUES); 6151 6289 } 6152 6290 ··· 6154 6292 if (nargs == 0) return mkarr(js); 6155 6293 ant_value_t obj = args[0]; 6156 6294 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 6295 + if (is_proxy(obj)) return proxy_enum(js, obj, OBJ_ENUM_ENTRIES); 6157 6296 return object_enum(js, obj, OBJ_ENUM_ENTRIES); 6158 6297 } 6159 6298 ··· 7095 7234 return js_false; 7096 7235 } 7097 7236 7237 + typedef struct { 7238 + ant_value_t result; 7239 + } object_from_entries_iter_ctx_t; 7240 + 7241 + static iter_action_t object_from_entries_iter_cb(ant_t *js, ant_value_t entry, void *ctx, ant_value_t *out) { 7242 + object_from_entries_iter_ctx_t *state = ctx; 7243 + GC_ROOT_SAVE(root_mark, js); 7244 + GC_ROOT_PIN(js, state->result); 7245 + GC_ROOT_PIN(js, entry); 7246 + 7247 + if (vtype(entry) != T_ARR && vtype(entry) != T_OBJ) { 7248 + *out = js_mkerr(js, "Object.fromEntries iterable values must be entry objects"); 7249 + GC_ROOT_RESTORE(js, root_mark); 7250 + return ITER_ERROR; 7251 + } 7252 + 7253 + ant_value_t key = arr_get(js, entry, 0); 7254 + GC_ROOT_PIN(js, key); 7255 + if (is_undefined(key)) { 7256 + *out = js_mkerr(js, "Object.fromEntries iterable values must contain a key"); 7257 + GC_ROOT_RESTORE(js, root_mark); 7258 + return ITER_ERROR; 7259 + } 7260 + 7261 + ant_value_t val = arr_get(js, entry, 1); 7262 + GC_ROOT_PIN(js, val); 7263 + 7264 + if (vtype(key) != T_STR && vtype(key) != T_SYMBOL) { 7265 + char buf[64]; 7266 + size_t n = tostr(js, key, buf, sizeof(buf)); 7267 + key = js_mkstr(js, buf, n); 7268 + GC_ROOT_PIN(js, key); 7269 + } 7270 + 7271 + js_setprop(js, state->result, key, val); 7272 + *out = state->result; 7273 + GC_ROOT_RESTORE(js, root_mark); 7274 + return ITER_CONTINUE; 7275 + } 7276 + 7098 7277 static ant_value_t builtin_object_fromEntries(ant_t *js, ant_value_t *args, int nargs) { 7099 7278 if (nargs == 0) return js_mkerr(js, "Object.fromEntries requires an iterable argument"); 7100 - 7279 + 7280 + GC_ROOT_SAVE(root_mark, js); 7101 7281 ant_value_t iterable = args[0]; 7102 - uint8_t t = vtype(iterable); 7103 - 7104 - if (t != T_ARR && t != T_OBJ) { 7105 - return js_mkerr(js, "Object.fromEntries requires an iterable"); 7106 - } 7107 - 7108 - ant_value_t result = js_mkobj(js); 7109 - ant_offset_t len = get_array_length(js, iterable); 7110 - if (len == 0) return result; 7111 - 7112 - for (ant_offset_t i = 0; i < len; i++) { 7113 - ant_value_t entry = arr_get(js, iterable, i); 7114 - if (vtype(entry) != T_ARR && vtype(entry) != T_OBJ) continue; 7115 - 7116 - ant_value_t key = arr_get(js, entry, 0); 7117 - if (is_undefined(key)) continue; 7118 - ant_value_t val = arr_get(js, entry, 1); 7119 - 7120 - if (vtype(key) != T_STR) { 7121 - char buf[64]; 7122 - size_t n = tostr(js, key, buf, sizeof(buf)); 7123 - key = js_mkstr(js, buf, n); 7282 + GC_ROOT_PIN(js, iterable); 7283 + 7284 + object_from_entries_iter_ctx_t ctx = { 7285 + .result = js_mkobj(js), 7286 + }; 7287 + GC_ROOT_PIN(js, ctx.result); 7288 + 7289 + ant_value_t iter_result = iter_foreach(js, iterable, object_from_entries_iter_cb, &ctx); 7290 + if (is_err(iter_result)) { 7291 + if (vtype(iterable) == T_ARR || vtype(iterable) == T_OBJ || vtype(iterable) == T_FUNC) { 7292 + GC_ROOT_RESTORE(js, root_mark); 7293 + return iter_result; 7124 7294 } 7125 - 7126 - js_setprop(js, result, key, val); 7295 + ant_value_t err = js_mkerr(js, "Object.fromEntries requires an iterable"); 7296 + GC_ROOT_RESTORE(js, root_mark); 7297 + return err; 7127 7298 } 7128 - 7299 + 7300 + ant_value_t result = ctx.result; 7301 + GC_ROOT_RESTORE(js, root_mark); 7129 7302 return result; 7130 7303 } 7131 7304
+56
src/modules/headers.c
··· 729 729 return make_headers_iter(js, js->this_val, ITER_ENTRIES); 730 730 } 731 731 732 + static ant_value_t headers_inspect_finish(ant_t *js, ant_value_t this_obj, ant_value_t body_obj) { 733 + ant_value_t tag_val = js_get_sym(js, this_obj, get_toStringTag_sym()); 734 + const char *tag = vtype(tag_val) == T_STR ? js_getstr(js, tag_val, NULL) : "Headers"; 735 + 736 + js_inspect_builder_t builder; 737 + if (!js_inspect_builder_init_dynamic(&builder, js, 128)) { 738 + return js_mkerr(js, "out of memory"); 739 + } 740 + 741 + bool ok = js_inspect_header_for(&builder, body_obj, "%s", tag); 742 + if (ok) ok = js_inspect_object_body(&builder, body_obj); 743 + if (ok) ok = js_inspect_close(&builder); 744 + 745 + if (!ok) { 746 + js_inspect_builder_dispose(&builder); 747 + return js_mkerr(js, "out of memory"); 748 + } 749 + 750 + return js_inspect_builder_result(&builder); 751 + } 752 + 753 + static ant_value_t headers_inspect(ant_t *js, ant_value_t *args, int nargs) { 754 + ant_value_t this_obj = js_getthis(js); 755 + hdr_list_t *list = get_list(this_obj); 756 + ant_value_t out = js_mkobj(js); 757 + 758 + if (!list) return js_mkerr(js, "Invalid Headers object"); 759 + 760 + for (hdr_entry_t *e = list->head; e; e = e->next) { 761 + ant_value_t existing = js_get(js, out, e->name); 762 + if (vtype(existing) == T_UNDEF) { 763 + js_set(js, out, e->name, js_mkstr(js, e->value, strlen(e->value))); 764 + continue; 765 + } 766 + 767 + size_t existing_len = 0; 768 + const char *existing_str = js_getstr(js, existing, &existing_len); 769 + size_t value_len = strlen(e->value); 770 + size_t combined_len = existing_len + 2 + value_len; 771 + char *combined = malloc(combined_len + 1); 772 + if (!combined) return js_mkerr(js, "out of memory"); 773 + 774 + memcpy(combined, existing_str, existing_len); 775 + combined[existing_len] = ','; 776 + combined[existing_len + 1] = ' '; 777 + memcpy(combined + existing_len + 2, e->value, value_len); 778 + combined[combined_len] = '\0'; 779 + 780 + js_set(js, out, e->name, js_mkstr(js, combined, combined_len)); 781 + free(combined); 782 + } 783 + 784 + return headers_inspect_finish(js, this_obj, out); 785 + } 786 + 732 787 static ant_value_t js_headers_ctor(ant_t *js, ant_value_t *args, int nargs) { 733 788 if (vtype(js->new_target) == T_UNDEF) 734 789 return js_mkerr_typed(js, JS_ERR_TYPE, "Headers constructor requires 'new'"); ··· 1041 1096 js_set(js, g_headers_proto, "getSetCookie", js_mkfun(js_headers_get_set_cookie)); 1042 1097 1043 1098 js_set_sym(js, g_headers_proto, get_iterator_sym(), js_mkfun(js_headers_symbol_iterator)); 1099 + js_set_sym(js, g_headers_proto, get_inspect_sym(), js_mkfun(headers_inspect)); 1044 1100 js_set_sym(js, g_headers_proto, get_toStringTag_sym(), js_mkstr(js, "Headers", 7)); 1045 1101 1046 1102 ant_value_t ctor_obj = js_mkobj(js);
+60
src/modules/request.c
··· 848 848 #undef REQ_GETTER_START 849 849 #undef REQ_GETTER_END 850 850 851 + static ant_value_t request_inspect_finish(ant_t *js, ant_value_t this_obj, ant_value_t body_obj) { 852 + ant_value_t tag_val = js_get_sym(js, this_obj, get_toStringTag_sym()); 853 + const char *tag = vtype(tag_val) == T_STR ? js_getstr(js, tag_val, NULL) : "Request"; 854 + 855 + js_inspect_builder_t builder; 856 + if (!js_inspect_builder_init_dynamic(&builder, js, 128)) { 857 + return js_mkerr(js, "out of memory"); 858 + } 859 + 860 + bool ok = js_inspect_header_for(&builder, body_obj, "%s", tag); 861 + if (ok) ok = js_inspect_object_body(&builder, body_obj); 862 + if (ok) ok = js_inspect_close(&builder); 863 + 864 + if (!ok) { 865 + js_inspect_builder_dispose(&builder); 866 + return js_mkerr(js, "out of memory"); 867 + } 868 + 869 + return js_inspect_builder_result(&builder); 870 + } 871 + 872 + // TODO: make dry 873 + static bool request_inspect_set( 874 + ant_t *js, ant_value_t obj, const char *key, 875 + ant_value_t value, ant_value_t *err_out 876 + ) { 877 + if (is_err(value)) { 878 + *err_out = value; 879 + return false; 880 + } 881 + 882 + js_set(js, obj, key, value); 883 + return true; 884 + } 885 + 886 + static ant_value_t request_inspect(ant_t *js, ant_value_t *args, int nargs) { 887 + ant_value_t this_obj = js_getthis(js); 888 + ant_value_t out = js_mkobj(js); 889 + ant_value_t err = 0; 890 + 891 + if (!request_inspect_set(js, out, "method", js_req_get_method(js, NULL, 0), &err)) return err; 892 + if (!request_inspect_set(js, out, "url", js_req_get_url(js, NULL, 0), &err)) return err; 893 + if (!request_inspect_set(js, out, "headers", js_req_get_headers(js, NULL, 0), &err)) return err; 894 + if (!request_inspect_set(js, out, "destination", js_req_get_destination(js, NULL, 0), &err)) return err; 895 + if (!request_inspect_set(js, out, "referrer", js_req_get_referrer(js, NULL, 0), &err)) return err; 896 + if (!request_inspect_set(js, out, "referrerPolicy", js_req_get_referrer_policy(js, NULL, 0), &err)) return err; 897 + if (!request_inspect_set(js, out, "mode", js_req_get_mode(js, NULL, 0), &err)) return err; 898 + if (!request_inspect_set(js, out, "credentials", js_req_get_credentials(js, NULL, 0), &err)) return err; 899 + if (!request_inspect_set(js, out, "cache", js_req_get_cache(js, NULL, 0), &err)) return err; 900 + if (!request_inspect_set(js, out, "redirect", js_req_get_redirect(js, NULL, 0), &err)) return err; 901 + if (!request_inspect_set(js, out, "integrity", js_req_get_integrity(js, NULL, 0), &err)) return err; 902 + if (!request_inspect_set(js, out, "keepalive", js_req_get_keepalive(js, NULL, 0), &err)) return err; 903 + if (!request_inspect_set(js, out, "isReloadNavigation", js_req_get_is_reload_navigation(js, NULL, 0), &err)) return err; 904 + if (!request_inspect_set(js, out, "isHistoryNavigation", js_req_get_is_history_navigation(js, NULL, 0), &err)) return err; 905 + if (!request_inspect_set(js, out, "signal", js_req_get_signal(js, NULL, 0), &err)) return err; 906 + 907 + return request_inspect_finish(js, this_obj, out); 908 + } 909 + 851 910 static ant_value_t js_request_clone(ant_t *js, ant_value_t *args, int nargs) { 852 911 ant_value_t this = js_getthis(js); 853 912 request_data_t *d = get_data(this); ··· 1453 1512 GETTER("bodyUsed", body_used); 1454 1513 #undef GETTER 1455 1514 1515 + js_set_sym(js, g_request_proto, get_inspect_sym(), js_mkfun(request_inspect)); 1456 1516 js_set_sym(js, g_request_proto, get_toStringTag_sym(), js_mkstr(js, "Request", 7)); 1457 1517 ant_value_t ctor = js_make_ctor(js, js_request_ctor, g_request_proto, "Request", 7); 1458 1518
+52
src/modules/response.c
··· 971 971 #undef RES_GETTER_START 972 972 #undef RES_GETTER_END 973 973 974 + static ant_value_t response_inspect_finish(ant_t *js, ant_value_t this_obj, ant_value_t body_obj) { 975 + ant_value_t tag_val = js_get_sym(js, this_obj, get_toStringTag_sym()); 976 + const char *tag = vtype(tag_val) == T_STR ? js_getstr(js, tag_val, NULL) : "Response"; 977 + 978 + js_inspect_builder_t builder; 979 + if (!js_inspect_builder_init_dynamic(&builder, js, 128)) { 980 + return js_mkerr(js, "out of memory"); 981 + } 982 + 983 + bool ok = js_inspect_header_for(&builder, body_obj, "%s", tag); 984 + if (ok) ok = js_inspect_object_body(&builder, body_obj); 985 + if (ok) ok = js_inspect_close(&builder); 986 + 987 + if (!ok) { 988 + js_inspect_builder_dispose(&builder); 989 + return js_mkerr(js, "out of memory"); 990 + } 991 + 992 + return js_inspect_builder_result(&builder); 993 + } 994 + 995 + // TODO: make dry 996 + static bool response_inspect_set( 997 + ant_t *js, ant_value_t obj, const char *key, 998 + ant_value_t value, ant_value_t *err_out 999 + ) { 1000 + if (is_err(value)) { 1001 + *err_out = value; 1002 + return false; 1003 + } 1004 + 1005 + js_set(js, obj, key, value); 1006 + return true; 1007 + } 1008 + 1009 + static ant_value_t response_inspect(ant_t *js, ant_value_t *args, int nargs) { 1010 + ant_value_t this_obj = js_getthis(js); 1011 + ant_value_t out = js_mkobj(js); 1012 + ant_value_t err = 0; 1013 + 1014 + if (!response_inspect_set(js, out, "type", js_res_get_type(js, NULL, 0), &err)) return err; 1015 + if (!response_inspect_set(js, out, "url", js_res_get_url(js, NULL, 0), &err)) return err; 1016 + if (!response_inspect_set(js, out, "redirected", js_res_get_redirected(js, NULL, 0), &err)) return err; 1017 + if (!response_inspect_set(js, out, "status", js_res_get_status(js, NULL, 0), &err)) return err; 1018 + if (!response_inspect_set(js, out, "ok", js_res_get_ok(js, NULL, 0), &err)) return err; 1019 + if (!response_inspect_set(js, out, "statusText", js_res_get_status_text(js, NULL, 0), &err)) return err; 1020 + if (!response_inspect_set(js, out, "headers", js_res_get_headers(js, NULL, 0), &err)) return err; 1021 + 1022 + return response_inspect_finish(js, this_obj, out); 1023 + } 1024 + 974 1025 static ant_value_t js_response_clone(ant_t *js, ant_value_t *args, int nargs) { 975 1026 ant_value_t this = js_getthis(js); 976 1027 response_data_t *d = get_data(this); ··· 1185 1236 GETTER("bodyUsed", body_used); 1186 1237 #undef GETTER 1187 1238 1239 + js_set_sym(js, g_response_proto, get_inspect_sym(), js_mkfun(response_inspect)); 1188 1240 js_set_sym(js, g_response_proto, get_toStringTag_sym(), js_mkstr(js, "Response", 8)); 1189 1241 ctor = js_make_ctor(js, js_response_ctor, g_response_proto, "Response", 8); 1190 1242 js_set(js, ctor, "error", js_mkfun(js_response_error));
+9 -4
tests/test_object_fromentries_iterables.cjs
··· 55 55 const snapshot = Object.fromEntries(ctx.entries()); 56 56 assert.strictEqual(snapshot.harness.getState().projectPath, "/tmp/project"); 57 57 58 - assert.throws( 59 - () => Object.fromEntries((function* () { yield 1; })()), 60 - /entry objects/, 61 - ); 58 + let invalidEntryError; 59 + try { 60 + Object.fromEntries((function* () { yield 1; })()); 61 + } catch (error) { 62 + invalidEntryError = error; 63 + } 64 + 65 + assert.ok(invalidEntryError instanceof Error); 66 + assert.match(String(invalidEntryError), /requires an iterable|entry object/); 62 67 63 68 console.log("Object.fromEntries consumes Map iterators, generators, and custom iterables");