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.

JSON.(module)

+494 -5
+13 -3
include/ant.h
··· 8 8 typedef uint64_t jsval_t; 9 9 10 10 enum { 11 - JS_UNDEF, JS_NULL, JS_TRUE, JS_FALSE, 12 - JS_STR, JS_NUM, JS_ERR, JS_PRIV 11 + JS_UNDEF, JS_NULL, JS_TRUE, JS_FALSE, 12 + JS_STR, JS_NUM, JS_ERR, JS_PRIV 13 13 }; 14 14 15 15 struct js *js_create(void *buf, size_t len); ··· 51 51 int js_getbool(jsval_t val); 52 52 53 53 double js_getnum(jsval_t val); 54 - char *js_getstr(struct js *js, jsval_t val, size_t *len); 54 + char *js_getstr(struct js *js, jsval_t val, size_t *len); 55 + 56 + typedef struct { 57 + jsval_t obj; 58 + void *current; 59 + void *js_internal; 60 + } js_prop_iter_t; 61 + 62 + js_prop_iter_t js_prop_iter_begin(struct js *js, jsval_t obj); 63 + bool js_prop_iter_next(js_prop_iter_t *iter, const char **key, size_t *key_len, jsval_t *value); 64 + void js_prop_iter_end(js_prop_iter_t *iter);
+6
include/modules/json.h
··· 1 + #ifndef JSON_H 2 + #define JSON_H 3 + 4 + void init_json_module(); 5 + 6 + #endif
+4 -2
meson.build
··· 19 19 # system dependencies 20 20 libsodium_dep = dependency('libsodium', required: true) 21 21 22 - # subprojects 22 + # dependencies 23 23 curl_dep = subproject('curl').get_variable('curl_dep') 24 + yyjson_dep = subproject('yyjson').get_variable('yyjson_dep') 24 25 uuidv7_dep = subproject('uuidv7').get_variable('uuidv7_dep') 25 26 mongoose_dep = subproject('mongoose').get_variable('mongoose_dep') 26 27 argtable3_dep = subproject('argtable3').get_variable('argtable3_dep') ··· 40 41 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 41 42 42 43 version_conf = configuration_data() 43 - version_conf.set('ANT_VERSION', '0.0.5.36') 44 + version_conf.set('ANT_VERSION', '0.0.5.37') 44 45 version_conf.set('ANT_GIT_HASH', git_hash) 45 46 version_conf.set('ANT_BUILD_DATE', build_date) 46 47 ··· 59 60 include_directories: [include, build_include], 60 61 dependencies: [ 61 62 curl_dep, 63 + yyjson_dep, 62 64 uuidv7_dep, 63 65 mongoose_dep, 64 66 argtable3_dep,
+44
src/ant.c
··· 5083 5083 return js_mkerr(js, "not a function"); 5084 5084 } 5085 5085 5086 + js_prop_iter_t js_prop_iter_begin(struct js *js, jsval_t obj) { 5087 + js_prop_iter_t iter = {0}; 5088 + iter.obj = obj; 5089 + iter.js_internal = (void *)js; 5090 + 5091 + if (vtype(obj) == T_OBJ || vtype(obj) == T_ARR || vtype(obj) == T_FUNC) { 5092 + jsval_t check_obj = (vtype(obj) == T_FUNC) ? mkval(T_OBJ, vdata(obj)) : obj; 5093 + jsoff_t next = loadoff(js, (jsoff_t) vdata(check_obj)) & ~(3U | CONSTMASK); 5094 + iter.current = (void *)(uintptr_t)next; 5095 + } 5096 + 5097 + return iter; 5098 + } 5099 + 5100 + bool js_prop_iter_next(js_prop_iter_t *iter, const char **key, size_t *key_len, jsval_t *value) { 5101 + if (!iter || !iter->js_internal) return false; 5102 + 5103 + struct js *js = (struct js *)iter->js_internal; 5104 + jsoff_t next = (jsoff_t)(uintptr_t)iter->current; 5105 + 5106 + if (next >= js->brk || next == 0) return false; 5107 + 5108 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 5109 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 5110 + 5111 + if (key) { 5112 + jsoff_t klen = offtolen(loadoff(js, koff)); 5113 + *key = (const char *) &js->mem[koff + sizeof(koff)]; 5114 + if (key_len) *key_len = klen; 5115 + } 5116 + 5117 + if (value) *value = val; 5118 + 5119 + iter->current = (void *)(uintptr_t)(loadoff(js, next) & ~(3U | CONSTMASK)); 5120 + return true; 5121 + } 5122 + 5123 + void js_prop_iter_end(js_prop_iter_t *iter) { 5124 + if (iter) { 5125 + iter->current = NULL; 5126 + iter->js_internal = NULL; 5127 + } 5128 + } 5129 + 5086 5130 #ifdef JS_DUMP 5087 5131 void js_dump(struct js *js) { 5088 5132 jsoff_t off = 0, v;
+3
src/main.c
··· 15 15 #include "modules/crypto.h" 16 16 #include "modules/server.h" 17 17 #include "modules/timer.h" 18 + #include "modules/json.h" 18 19 19 20 static struct { 20 21 char *path; ··· 240 241 struct ant_runtime *rt = ant_runtime_init(js); 241 242 242 243 init_console_module(); 244 + init_json_module(); 245 + 243 246 init_crypto_module(js, rt->ant_obj); 244 247 init_timer_module(js, rt->ant_obj); 245 248
+208
src/modules/json.c
··· 1 + #include <stdlib.h> 2 + #include <string.h> 3 + #include <yyjson.h> 4 + 5 + #include "ant.h" 6 + #include "runtime.h" 7 + #include "modules/json.h" 8 + 9 + static jsval_t yyjson_to_jsval(struct js *js, yyjson_val *val) { 10 + if (!val) return js_mkundef(); 11 + 12 + yyjson_type type = yyjson_get_type(val); 13 + 14 + switch (type) { 15 + case YYJSON_TYPE_NULL: 16 + return js_mknull(); 17 + 18 + case YYJSON_TYPE_BOOL: 19 + return yyjson_get_bool(val) ? js_mktrue() : js_mkfalse(); 20 + 21 + case YYJSON_TYPE_NUM: { 22 + if (yyjson_is_int(val)) { 23 + return js_mknum((double)yyjson_get_int(val)); 24 + } else if (yyjson_is_uint(val)) { 25 + return js_mknum((double)yyjson_get_uint(val)); 26 + } else { 27 + return js_mknum(yyjson_get_real(val)); 28 + } 29 + } 30 + 31 + case YYJSON_TYPE_STR: { 32 + const char *str = yyjson_get_str(val); 33 + size_t len = yyjson_get_len(val); 34 + return js_mkstr(js, str, len); 35 + } 36 + 37 + case YYJSON_TYPE_ARR: { 38 + jsval_t arr = js_mkobj(js); 39 + size_t idx, max; 40 + yyjson_val *item; 41 + 42 + yyjson_arr_foreach(val, idx, max, item) { 43 + char idxstr[32]; 44 + snprintf(idxstr, sizeof(idxstr), "%zu", idx); 45 + jsval_t value = yyjson_to_jsval(js, item); 46 + js_set(js, arr, idxstr, value); 47 + } 48 + 49 + js_set(js, arr, "length", js_mknum((double)yyjson_arr_size(val))); 50 + return arr; 51 + } 52 + 53 + case YYJSON_TYPE_OBJ: { 54 + jsval_t obj = js_mkobj(js); 55 + size_t idx, max; 56 + yyjson_val *key, *item; 57 + 58 + yyjson_obj_foreach(val, idx, max, key, item) { 59 + const char *key_str = yyjson_get_str(key); 60 + jsval_t value = yyjson_to_jsval(js, item); 61 + js_set(js, obj, key_str, value); 62 + } 63 + 64 + return obj; 65 + } 66 + 67 + default: 68 + return js_mkundef(); 69 + } 70 + } 71 + 72 + static yyjson_mut_val *jsval_to_yyjson(struct js *js, yyjson_mut_doc *doc, jsval_t val) { 73 + int type = js_type(val); 74 + 75 + switch (type) { 76 + case JS_UNDEF: 77 + return yyjson_mut_null(doc); 78 + 79 + case JS_NULL: 80 + return yyjson_mut_null(doc); 81 + 82 + case JS_TRUE: 83 + return yyjson_mut_bool(doc, true); 84 + 85 + case JS_FALSE: 86 + return yyjson_mut_bool(doc, false); 87 + 88 + case JS_NUM: { 89 + double num = js_getnum(val); 90 + return yyjson_mut_real(doc, num); 91 + } 92 + 93 + case JS_STR: { 94 + size_t len; 95 + char *str = js_getstr(js, val, &len); 96 + return yyjson_mut_strncpy(doc, str, len); 97 + } 98 + 99 + case JS_PRIV: { 100 + jsval_t length_val = js_get(js, val, "length"); 101 + 102 + if (js_type(length_val) == JS_NUM) { 103 + yyjson_mut_val *arr = yyjson_mut_arr(doc); 104 + int length = (int)js_getnum(length_val); 105 + 106 + for (int i = 0; i < length; i++) { 107 + char idxstr[32]; 108 + snprintf(idxstr, sizeof(idxstr), "%d", i); 109 + jsval_t item = js_get(js, val, idxstr); 110 + yyjson_mut_val *json_item = jsval_to_yyjson(js, doc, item); 111 + yyjson_mut_arr_add_val(arr, json_item); 112 + } 113 + 114 + return arr; 115 + } else { 116 + yyjson_mut_val *obj = yyjson_mut_obj(doc); 117 + 118 + js_prop_iter_t iter = js_prop_iter_begin(js, val); 119 + const char *key; 120 + size_t key_len; 121 + jsval_t prop_value; 122 + 123 + while (js_prop_iter_next(&iter, &key, &key_len, &prop_value)) { 124 + if (key_len > 2 && key[0] == '_' && key[1] == '_') continue; 125 + if (js_type(prop_value) == JS_PRIV) { 126 + jsval_t code = js_get(js, prop_value, "__code"); 127 + if (js_type(code) == JS_STR) continue; 128 + } 129 + 130 + yyjson_mut_val *json_key = yyjson_mut_strncpy(doc, key, key_len); 131 + yyjson_mut_val *json_value = jsval_to_yyjson(js, doc, prop_value); 132 + yyjson_mut_obj_add(obj, json_key, json_value); 133 + } 134 + 135 + js_prop_iter_end(&iter); 136 + return obj; 137 + } 138 + } 139 + 140 + default: 141 + return yyjson_mut_null(doc); 142 + } 143 + } 144 + 145 + static jsval_t js_json_parse(struct js *js, jsval_t *args, int nargs) { 146 + if (nargs < 1) { 147 + return js_mkerr(js, "JSON.parse() requires at least 1 argument"); 148 + } 149 + 150 + if (js_type(args[0]) != JS_STR) { 151 + return js_mkerr(js, "JSON.parse() argument must be a string"); 152 + } 153 + 154 + size_t len; 155 + char *json_str = js_getstr(js, args[0], &len); 156 + 157 + yyjson_doc *doc = yyjson_read(json_str, len, 0); 158 + if (!doc) { 159 + return js_mkerr(js, "JSON.parse() failed: invalid JSON"); 160 + } 161 + 162 + yyjson_val *root = yyjson_doc_get_root(doc); 163 + jsval_t result = yyjson_to_jsval(js, root); 164 + 165 + yyjson_doc_free(doc); 166 + 167 + return result; 168 + } 169 + 170 + static jsval_t js_json_stringify(struct js *js, jsval_t *args, int nargs) { 171 + if (nargs < 1) { 172 + return js_mkerr(js, "JSON.stringify() requires at least 1 argument"); 173 + } 174 + 175 + yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); 176 + if (!doc) { 177 + return js_mkerr(js, "JSON.stringify() failed: out of memory"); 178 + } 179 + 180 + yyjson_mut_val *root = jsval_to_yyjson(js, doc, args[0]); 181 + yyjson_mut_doc_set_root(doc, root); 182 + 183 + size_t len; 184 + yyjson_write_flag flg = YYJSON_WRITE_PRETTY; 185 + if (nargs >= 3 && js_type(args[2]) == JS_UNDEF) flg = 0; 186 + 187 + char *json_str = yyjson_mut_write(doc, flg, &len); 188 + if (!json_str) { 189 + yyjson_mut_doc_free(doc); 190 + return js_mkerr(js, "JSON.stringify() failed: write error"); 191 + } 192 + 193 + jsval_t result = js_mkstr(js, json_str, len); 194 + 195 + free(json_str); 196 + yyjson_mut_doc_free(doc); 197 + 198 + return result; 199 + } 200 + 201 + void init_json_module() { 202 + struct js *js = rt->js; 203 + jsval_t json_obj = js_mkobj(js); 204 + 205 + js_set(js, js_glob(js), "JSON", json_obj); 206 + js_set(js, json_obj, "parse", js_mkfun(js_json_parse)); 207 + js_set(js, json_obj, "stringify", js_mkfun(js_json_stringify)); 208 + }
+1
src/modules/server.c
··· 6 6 #include "mongoose.h" 7 7 #include "modules/server.h" 8 8 #include "modules/timer.h" 9 + #include "ant.h" 9 10 10 11 typedef struct { 11 12 int status;
+13
subprojects/yyjson.wrap
··· 1 + [wrap-file] 2 + directory = yyjson-0.12.0 3 + source_url = https://github.com/ibireme/yyjson/archive/refs/tags/0.12.0.tar.gz 4 + source_filename = yyjson-0.12.0.tar.gz 5 + source_hash = b16246f617b2a136c78d73e5e2647c6f1de1313e46678062985bdcf1f40bb75d 6 + patch_filename = yyjson_0.12.0-1_patch.zip 7 + patch_url = https://wrapdb.mesonbuild.com/v2/yyjson_0.12.0-1/get_patch 8 + patch_hash = 014582b328e13671dea64fcb49a795e70142360216a505212b8045134781b3b5 9 + source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/yyjson_0.12.0-1/yyjson-0.12.0.tar.gz 10 + wrapdb_version = 0.12.0-1 11 + 12 + [provide] 13 + dependency_names = yyjson
+202
tests/test_json.cjs
··· 1 + // Test JSON.parse and JSON.stringify functionality 2 + 3 + console.log("=== JSON Tests ===\n"); 4 + 5 + // Test 1: Parse simple object 6 + console.log("Test 1: Parse simple object"); 7 + let jsonStr1 = '{"name":"John","age":30}'; 8 + console.log(" Input:", jsonStr1); 9 + let obj1 = JSON.parse(jsonStr1); 10 + console.log(" Parsed:", obj1); 11 + console.log(" Name:", obj1.name); 12 + console.log(" Age:", obj1.age); 13 + 14 + // Test 2: Parse array 15 + console.log("\nTest 2: Parse array"); 16 + let jsonStr2 = '[1,2,3,4,5]'; 17 + console.log(" Input:", jsonStr2); 18 + let arr2 = JSON.parse(jsonStr2); 19 + console.log(" Parsed:", arr2); 20 + console.log(" Length:", arr2.length); 21 + console.log(" First:", arr2[0]); 22 + console.log(" Last:", arr2[4]); 23 + 24 + // Test 3: Parse nested object 25 + console.log("\nTest 3: Parse nested object"); 26 + let jsonStr3 = '{"user":{"name":"Alice","age":25},"active":true}'; 27 + console.log(" Input:", jsonStr3); 28 + let obj3 = JSON.parse(jsonStr3); 29 + console.log(" Parsed:", obj3); 30 + console.log(" User:", obj3.user); 31 + console.log(" User name:", obj3.user.name); 32 + console.log(" Active:", obj3.active); 33 + 34 + // Test 4: Parse array of objects 35 + console.log("\nTest 4: Parse array of objects"); 36 + let jsonStr4 = '[{"id":1,"name":"Item1"},{"id":2,"name":"Item2"}]'; 37 + console.log(" Input:", jsonStr4); 38 + let arr4 = JSON.parse(jsonStr4); 39 + console.log(" Parsed:", arr4); 40 + console.log(" Length:", arr4.length); 41 + console.log(" First item:", arr4[0]); 42 + console.log(" First item name:", arr4[0].name); 43 + console.log(" Second item:", arr4[1]); 44 + console.log(" Second item id:", arr4[1].id); 45 + 46 + // Test 5: Parse with null and boolean values 47 + console.log("\nTest 5: Parse with null and boolean values"); 48 + let jsonStr5 = '{"name":"Bob","active":true,"inactive":false,"data":null}'; 49 + console.log(" Input:", jsonStr5); 50 + let obj5 = JSON.parse(jsonStr5); 51 + console.log(" Parsed:", obj5); 52 + console.log(" Name:", obj5.name); 53 + console.log(" Active:", obj5.active); 54 + console.log(" Inactive:", obj5.inactive); 55 + console.log(" Data:", obj5.data); 56 + 57 + // Test 6: Parse numbers 58 + console.log("\nTest 6: Parse numbers"); 59 + let jsonStr6 = '{"int":42,"float":3.14,"negative":-10,"zero":0}'; 60 + console.log(" Input:", jsonStr6); 61 + let obj6 = JSON.parse(jsonStr6); 62 + console.log(" Parsed:", obj6); 63 + console.log(" Integer:", obj6.int); 64 + console.log(" Float:", obj6.float); 65 + console.log(" Negative:", obj6.negative); 66 + console.log(" Zero:", obj6.zero); 67 + 68 + // Test 7: Parse empty structures 69 + console.log("\nTest 7: Parse empty structures"); 70 + let emptyObj = JSON.parse('{}'); 71 + let emptyArr = JSON.parse('[]'); 72 + console.log(" Empty object:", emptyObj); 73 + console.log(" Empty array:", emptyArr); 74 + console.log(" Empty array length:", emptyArr.length); 75 + 76 + // Test 8: Stringify array (parsed from JSON) 77 + console.log("\nTest 8: Stringify array"); 78 + let arrStr = '[10,20,30,40]'; 79 + console.log(" Input JSON:", arrStr); 80 + let arr8 = JSON.parse(arrStr); 81 + console.log(" Parsed array:", arr8); 82 + let stringified2 = JSON.stringify(arr8); 83 + console.log(" Stringified:", stringified2); 84 + 85 + // Test 9: Stringify object (parsed from JSON) 86 + console.log("\nTest 9: Stringify object"); 87 + let objStr9 = '{"name":"Charlie","age":35}'; 88 + console.log(" Input JSON:", objStr9); 89 + let obj9 = JSON.parse(objStr9); 90 + console.log(" Parsed object:", obj9); 91 + let stringified9 = JSON.stringify(obj9); 92 + console.log(" Stringified:", stringified9); 93 + 94 + // Test 10: Stringify nested object (parsed from JSON) 95 + console.log("\nTest 10: Stringify nested object"); 96 + let nestedStr = '{"user":{"name":"David","email":"david@example.com"},"count":42}'; 97 + console.log(" Input JSON:", nestedStr); 98 + let nested10 = JSON.parse(nestedStr); 99 + console.log(" Parsed:", nested10); 100 + let stringified10 = JSON.stringify(nested10); 101 + console.log(" Stringified:", stringified10); 102 + 103 + // Test 11: Stringify with various types 104 + console.log("\nTest 11: Stringify with various types"); 105 + let typesStr = '{"active":true,"inactive":false,"data":null,"count":123}'; 106 + console.log(" Input JSON:", typesStr); 107 + let types11 = JSON.parse(typesStr); 108 + console.log(" Parsed:", types11); 109 + let stringified11 = JSON.stringify(types11); 110 + console.log(" Stringified:", stringified11); 111 + 112 + // Test 12: Round-trip test (parse -> modify) 113 + console.log("\nTest 12: Round-trip test"); 114 + let original = '{"count":5,"items":["a","b","c"]}'; 115 + console.log(" Original:", original); 116 + let parsed = JSON.parse(original); 117 + console.log(" Parsed:", parsed); 118 + parsed.count = 10; 119 + console.log(" Modified count:", parsed.count); 120 + console.log(" Items:", parsed.items); 121 + console.log(" Items length:", parsed.items.length); 122 + 123 + // Test 13: Parse and access properties 124 + console.log("\nTest 13: Parse and access properties"); 125 + let configStr = '{"host":"localhost","port":8080,"ssl":true}'; 126 + console.log(" Config:", configStr); 127 + let config = JSON.parse(configStr); 128 + console.log(" Host:", config.host); 129 + console.log(" Port:", config.port); 130 + console.log(" SSL:", config.ssl); 131 + 132 + // Test 14: Array operations after parse 133 + console.log("\nTest 14: Array operations after parse"); 134 + let numbersStr = '[5,10,15,20,25]'; 135 + console.log(" Numbers:", numbersStr); 136 + let numbers = JSON.parse(numbersStr); 137 + console.log(" Parsed:", numbers); 138 + console.log(" Length:", numbers.length); 139 + 140 + let sum = 0; 141 + for (let i = 0; i < numbers.length; i = i + 1) { 142 + sum = sum + numbers[i]; 143 + } 144 + console.log(" Sum:", sum); 145 + 146 + // Test 15: Parse and re-stringify array 147 + console.log("\nTest 15: Parse and re-stringify array"); 148 + let arrayStr15 = '[1,2,3,4,5]'; 149 + console.log(" Original:", arrayStr15); 150 + let myArray = JSON.parse(arrayStr15); 151 + console.log(" Parsed:", myArray); 152 + console.log(" Length:", myArray.length); 153 + let reStringified = JSON.stringify(myArray); 154 + console.log(" Re-stringified:", reStringified); 155 + 156 + // Test 16: Parse string values 157 + console.log("\nTest 16: Parse string values"); 158 + let stringsObj = '{"greeting":"Hello","message":"World"}'; 159 + console.log(" Input:", stringsObj); 160 + let strings = JSON.parse(stringsObj); 161 + console.log(" Greeting:", strings.greeting); 162 + console.log(" Message:", strings.message); 163 + console.log(" Combined:", strings.greeting + " " + strings.message); 164 + 165 + // Test 17: Complex nested structure 166 + console.log("\nTest 17: Complex nested structure"); 167 + let complexStr = '{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}],"total":2}'; 168 + console.log(" Input:", complexStr); 169 + let complex = JSON.parse(complexStr); 170 + console.log(" Total users:", complex.total); 171 + console.log(" First user:", complex.users[0].name); 172 + console.log(" Second user:", complex.users[1].name); 173 + 174 + // Test 18: Parse, modify, and re-stringify 175 + console.log("\nTest 18: Parse, modify, and re-stringify"); 176 + let modStr = '{"id":123,"name":"Test"}'; 177 + console.log(" Original:", modStr); 178 + let newObj = JSON.parse(modStr); 179 + console.log(" Parsed:", newObj); 180 + newObj.active = true; 181 + console.log(" After modification:", newObj); 182 + console.log(" Active property:", newObj.active); 183 + 184 + // Test 19: Parse whitespace-heavy JSON 185 + console.log("\nTest 19: Parse JSON with whitespace"); 186 + let spacedJson = ' { "key" : "value" } '; 187 + console.log(" Input:", spacedJson); 188 + let spacedParsed = JSON.parse(spacedJson); 189 + console.log(" Parsed:", spacedParsed); 190 + console.log(" Key:", spacedParsed.key); 191 + 192 + // Test 20: Practical example - API response 193 + console.log("\nTest 20: Practical example - API response"); 194 + let apiResponse = '{"status":"success","data":{"user":"john","token":"abc123"},"timestamp":1234567890}'; 195 + console.log(" API Response:", apiResponse); 196 + let response = JSON.parse(apiResponse); 197 + console.log(" Status:", response.status); 198 + console.log(" User:", response.data.user); 199 + console.log(" Token:", response.data.token); 200 + console.log(" Timestamp:", response.timestamp); 201 + 202 + console.log("\n=== All JSON tests completed ===");