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 replacer support to JSON.stringify

+83 -6
+1 -1
meson.build
··· 75 75 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 76 76 77 77 version_conf = configuration_data() 78 - version_conf.set('ANT_VERSION', '0.1.3.9') 78 + version_conf.set('ANT_VERSION', '0.1.3.10') 79 79 version_conf.set('ANT_GIT_HASH', git_hash) 80 80 version_conf.set('ANT_BUILD_DATE', build_date) 81 81
+82 -5
src/modules/json.c
··· 57 57 int stack_size; 58 58 int stack_cap; 59 59 int has_cycle; 60 + struct js *js; 61 + jsval_t replacer_func; 62 + jsval_t replacer_arr; 63 + int replacer_arr_len; 64 + jsval_t holder; 60 65 } json_cycle_ctx; 61 66 62 67 static int json_cycle_check(json_cycle_ctx *ctx, jsval_t val) { ··· 121 126 free(props); 122 127 } 123 128 129 + static int is_key_in_replacer_arr(struct js *js, json_cycle_ctx *ctx, const char *key, size_t key_len) { 130 + if (js_type(ctx->replacer_arr) != JS_OBJ) return 1; 131 + 132 + for (int i = 0; i < ctx->replacer_arr_len; i++) { 133 + char idxstr[32]; 134 + snprintf(idxstr, sizeof(idxstr), "%d", i); 135 + jsval_t item = js_get(js, ctx->replacer_arr, idxstr); 136 + if (js_type(item) == JS_STR) { 137 + size_t item_len; 138 + char *item_str = js_getstr(js, item, &item_len); 139 + if (item_len == key_len && memcmp(item_str, key, key_len) == 0) return 1; 140 + } else if (js_type(item) == JS_NUM) { 141 + char numstr[32]; 142 + snprintf(numstr, sizeof(numstr), "%.0f", js_getnum(item)); 143 + if (strlen(numstr) == key_len && memcmp(numstr, key, key_len) == 0) return 1; 144 + } 145 + } 146 + return 0; 147 + } 148 + 149 + static yyjson_mut_val *jsval_to_yyjson_with_key(struct js *js, yyjson_mut_doc *doc, const char *key, jsval_t val, json_cycle_ctx *ctx, int in_array); 150 + 124 151 static yyjson_mut_val *jsval_to_yyjson_impl(struct js *js, yyjson_mut_doc *doc, jsval_t val, json_cycle_ctx *ctx, int in_array) { 125 152 int type = js_type(val); 126 153 yyjson_mut_val *result = NULL; ··· 167 194 yyjson_mut_val *arr = yyjson_mut_arr(doc); 168 195 int length = (int)js_getnum(length_val); 169 196 197 + jsval_t saved_holder = ctx->holder; 198 + ctx->holder = val; 199 + 170 200 for (int i = 0; i < length; i++) { 171 201 char idxstr[32]; 172 202 snprintf(idxstr, sizeof(idxstr), "%d", i); 173 - yyjson_mut_val *item = jsval_to_yyjson_impl(js, doc, js_get(js, val, idxstr), ctx, 1); 174 - if (ctx->has_cycle) goto done; 203 + jsval_t elem = js_get(js, val, idxstr); 204 + yyjson_mut_val *item = jsval_to_yyjson_with_key(js, doc, idxstr, elem, ctx, 1); 205 + if (ctx->has_cycle) { ctx->holder = saved_holder; goto done; } 175 206 yyjson_mut_arr_add_val(arr, item); 176 207 } 208 + ctx->holder = saved_holder; 177 209 result = arr; 178 210 goto done; 179 211 } ··· 182 214 int prop_count; 183 215 prop_entry *props = collect_props(js, val, &prop_count); 184 216 217 + jsval_t saved_holder = ctx->holder; 218 + ctx->holder = val; 219 + 185 220 for (int i = prop_count - 1; i >= 0; i--) { 221 + if (js_type(ctx->replacer_arr) == JS_OBJ) { 222 + if (!is_key_in_replacer_arr(js, ctx, props[i].key, props[i].key_len)) { 223 + free(props[i].key); 224 + continue; 225 + } 226 + } 227 + 186 228 int ptype = js_type(props[i].value); 187 229 188 230 if (ptype == JS_UNDEF || ptype == JS_FUNC) { ··· 190 232 continue; 191 233 } 192 234 193 - yyjson_mut_val *jval = jsval_to_yyjson_impl(js, doc, props[i].value, ctx, 0); 194 - if (ctx->has_cycle) { free_props(props, 0, i); goto done; } 235 + yyjson_mut_val *jval = jsval_to_yyjson_with_key(js, doc, props[i].key, props[i].value, ctx, 0); 236 + if (ctx->has_cycle) { free_props(props, 0, i); ctx->holder = saved_holder; goto done; } 195 237 196 238 if (jval == YYJSON_SKIP_VALUE) { 197 239 free(props[i].key); ··· 202 244 free(props[i].key); 203 245 } 204 246 247 + ctx->holder = saved_holder; 205 248 free(props); 206 249 result = obj; 207 250 ··· 210 253 return result; 211 254 } 212 255 256 + static yyjson_mut_val *jsval_to_yyjson_with_key(struct js *js, yyjson_mut_doc *doc, const char *key, jsval_t val, json_cycle_ctx *ctx, int in_array) { 257 + if (js_type(ctx->replacer_func) == JS_FUNC) { 258 + jsval_t key_str = js_mkstr(js, key, strlen(key)); 259 + jsval_t call_args[2] = { key_str, val }; 260 + jsval_t transformed = js_call(js, ctx->replacer_func, call_args, 2); 261 + if (js_type(transformed) == JS_ERR) { 262 + ctx->has_cycle = 1; 263 + return NULL; 264 + } 265 + val = transformed; 266 + } 267 + 268 + return jsval_to_yyjson_impl(js, doc, val, ctx, in_array); 269 + } 270 + 213 271 static yyjson_mut_val *jsval_to_yyjson(struct js *js, yyjson_mut_doc *doc, jsval_t val, json_cycle_ctx *ctx) { 214 - return jsval_to_yyjson_impl(js, doc, val, ctx, 0); 272 + return jsval_to_yyjson_with_key(js, doc, "", val, ctx, 0); 215 273 } 216 274 217 275 static jsval_t apply_reviver(struct js *js, jsval_t holder, const char *key, jsval_t reviver) { ··· 316 374 int top_type = js_type(args[0]); 317 375 if (top_type == JS_UNDEF || top_type == JS_FUNC || top_type == JS_SYMBOL) 318 376 return js_mkundef(); 377 + 378 + ctx.js = js; 379 + ctx.replacer_func = js_mkundef(); 380 + ctx.replacer_arr = js_mkundef(); 381 + ctx.replacer_arr_len = 0; 382 + ctx.holder = js_mkundef(); 383 + 384 + if (nargs >= 2) { 385 + int replacer_type = js_type(args[1]); 386 + if (replacer_type == JS_FUNC) { 387 + ctx.replacer_func = args[1]; 388 + } else if (replacer_type == JS_OBJ) { 389 + jsval_t len_val = js_get(js, args[1], "length"); 390 + if (js_type(len_val) == JS_NUM) { 391 + ctx.replacer_arr = args[1]; 392 + ctx.replacer_arr_len = (int)js_getnum(len_val); 393 + } 394 + } 395 + } 319 396 320 397 doc = yyjson_mut_doc_new(NULL); 321 398 if (!doc) return js_mkerr(js, "JSON.stringify() failed: out of memory");