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.

update ant core to be typesafe

+290 -681
+6 -1
.gitignore
··· 18 18 *.trace 19 19 20 20 spec.txt 21 - todo.txt 21 + todo.txt 22 + 23 + node_modules 24 + bun.lock 25 + pnpm-lock.yaml 26 + package-lock.json
+6 -6
examples/demo/events.js
··· 15 15 }); 16 16 17 17 console.log('\nExample 3: Object Events'); 18 - const button = createEventTarget(); 18 + const button = new EventTarget(); 19 19 button.name = 'MyButton'; 20 20 21 21 button.addEventListener('click', event => { ··· 27 27 button.dispatchEvent('click'); 28 28 29 29 console.log('\nExample 4: Multiple Event Targets'); 30 - const user = createEventTarget(); 30 + const user = new EventTarget(); 31 31 user.name = 'Alice'; 32 32 33 - const socket = createEventTarget(); 33 + const socket = new EventTarget(); 34 34 socket.id = 'socket-123'; 35 35 36 36 user.addEventListener('statusChange', event => { ··· 45 45 socket.dispatchEvent('message', { data: 'Hello!' }); 46 46 47 47 console.log('\nExample 5: Once Listeners'); 48 - const startup = createEventTarget(); 48 + const startup = new EventTarget(); 49 49 let initCount = 0; 50 50 51 51 startup.addEventListener( ··· 65 65 console.log('\nExample 6: Event Emitter Pattern'); 66 66 class MyEmitter { 67 67 constructor() { 68 - const target = createEventTarget(); 68 + const target = new EventTarget(); 69 69 this.on = target.addEventListener.bind(target); 70 70 this.off = target.removeEventListener.bind(target); 71 71 this.emit = target.dispatchEvent.bind(target); ··· 82 82 emitter.emit('data', { value: 'hello', type: 'string' }); 83 83 84 84 console.log('\nExample 7: Removing Listeners'); 85 - const temp = createEventTarget(); 85 + const temp = new EventTarget(); 86 86 87 87 function handler(event) { 88 88 console.log(' Handler called with:', event.detail);
+12 -11
meson.build
··· 96 96 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 97 97 98 98 version_conf = configuration_data() 99 - version_conf.set('ANT_VERSION', '0.3.2.43') 99 + version_conf.set('ANT_VERSION', '0.3.3.6') 100 100 version_conf.set('ANT_GIT_HASH', git_hash) 101 101 version_conf.set('ANT_BUILD_DATE', build_date) 102 102 ··· 120 120 add_project_link_arguments('-no-pie', language: 'c') 121 121 endif 122 122 123 - gen_snapshot = executable( 124 - 'gen_snapshot', 125 - files('src/tools/gen_snapshot.c'), 126 - include_directories: [include, build_include], 127 - c_args: ['-D ANT_SNAPSHOT_GENERATOR'], 128 - native: true 129 - ) 123 + node = find_program('node', required: true) 124 + gen_snapshot = files('src/tools/gen_snapshot.js') 125 + 126 + core_files = run_command('sh', '-c', 127 + 'cd "$MESON_SOURCE_ROOT" && find src/core -name "*.js" ! -name "index.js" | sort', 128 + check: true 129 + ).stdout().strip().split() 130 130 131 131 snapshot_h = custom_target( 132 132 'snapshot', 133 - input: 'src/core/index.js', 133 + input: ['src/core/index.ts'] + files(core_files), 134 134 output: 'snapshot_data.h', 135 135 command: [ 136 - gen_snapshot, 137 - '@INPUT@', 136 + node, 137 + gen_snapshot, 138 + '@INPUT0@', 138 139 '@OUTPUT@', 139 140 'VERSION=' + version_conf.get('ANT_VERSION'), 140 141 'GIT_HASH=' + version_conf.get('ANT_GIT_HASH'),
-7
src/core/events.js
··· 1 - function createEventTarget() { 2 - const obj = {}; 3 - obj.addEventListener = EventTargetPrototype.addEventListener; 4 - obj.removeEventListener = EventTargetPrototype.removeEventListener; 5 - obj.dispatchEvent = EventTargetPrototype.dispatchEvent; 6 - return obj; 7 - }
+1 -3
src/core/index.js src/core/ant.ts
··· 1 - snapshot_inline('./events.js'); 2 - 3 1 Ant.version = '{{VERSION}}'; 4 2 Ant.revision = '{{GIT_HASH}}'; 5 3 Ant.buildDate = '{{BUILD_DATE}}'; ··· 26 24 T_PROPREF: 'propref', 27 25 T_SYMBOL: 'symbol', 28 26 T_GENERATOR: 'generator' 29 - }; 27 + } as const; 30 28 31 29 const names = Object.values(types); 32 30 return value < names.length ? names[value] : '??';
+1
src/core/index.ts
··· 1 + snapshot_inline('./ant.ts');
+13 -12
src/modules/events.c
··· 635 635 return lib; 636 636 } 637 637 638 + static jsval_t EventTarget(struct js *js, jsval_t *args, int nargs) { 639 + (void)args; (void)nargs; 640 + 641 + jsval_t obj = js_mkobj(js); 642 + js_set(js, obj, "addEventListener", js_mkfun(js_add_event_listener_method)); 643 + js_set(js, obj, "removeEventListener", js_mkfun(js_remove_event_listener_method)); 644 + js_set(js, obj, "dispatchEvent", js_mkfun(js_dispatch_event_method)); 645 + js_set(js, obj, get_toStringTag_sym_key(), js_mkstr(js, "EventTarget", 11)); 646 + 647 + return obj; 648 + } 649 + 638 650 void init_events_module() { 639 651 struct js *js = rt->js; 640 652 jsval_t global = js_glob(js); ··· 643 655 js_set(js, global, "removeEventListener", js_mkfun(js_remove_event_listener)); 644 656 js_set(js, global, "dispatchEvent", js_mkfun(js_dispatch_event)); 645 657 js_set(js, global, "getEventListeners", js_mkfun(js_get_event_listeners)); 646 - 647 - jsval_t event_target_proto = js_mkobj(js); 648 - js_set(js, event_target_proto, "addEventListener", js_mkfun(js_add_event_listener_method)); 649 - js_set(js, event_target_proto, "removeEventListener", js_mkfun(js_remove_event_listener_method)); 650 - js_set(js, event_target_proto, "dispatchEvent", js_mkfun(js_dispatch_event_method)); 651 - js_set(js, event_target_proto, get_toStringTag_sym_key(), js_mkstr(js, "EventTarget", 11)); 652 - 653 - jsval_t event_target = js_mkobj(js); 654 - js_setprop_nonconfigurable(js, event_target, "prototype", 9, event_target_proto); 655 - js_set(js, global, "EventTarget", event_target); 658 + js_set(js, global, "EventTarget", js_mkfun(EventTarget)); 656 659 } 657 - 658 -
-641
src/tools/gen_snapshot.c
··· 1 - #include <stdio.h> 2 - #include <stdlib.h> 3 - #include <string.h> 4 - #include <libgen.h> 5 - #include <limits.h> 6 - 7 - typedef struct { 8 - char *placeholder; 9 - char *value; 10 - } replacement_t; 11 - 12 - typedef struct { 13 - char **paths; 14 - int count; 15 - int capacity; 16 - } module_cache_t; 17 - 18 - static char *resolve_path(const char *base_path, const char *import_path) { 19 - char *resolved = malloc(PATH_MAX); 20 - if (!resolved) return NULL; 21 - 22 - char *base_dir = strdup(base_path); 23 - char *dir = dirname(base_dir); 24 - 25 - snprintf(resolved, PATH_MAX, "%s/%s", dir, import_path); 26 - free(base_dir); 27 - 28 - return resolved; 29 - } 30 - 31 - static char *read_file(const char *path, size_t *len) { 32 - FILE *f = fopen(path, "r"); 33 - if (!f) return NULL; 34 - 35 - fseek(f, 0, SEEK_END); 36 - long size = ftell(f); 37 - fseek(f, 0, SEEK_SET); 38 - 39 - char *content = malloc(size + 1); 40 - if (!content) { 41 - fclose(f); 42 - return NULL; 43 - } 44 - 45 - fread(content, 1, size, f); 46 - content[size] = '\0'; 47 - fclose(f); 48 - 49 - if (len) *len = size; 50 - return content; 51 - } 52 - 53 - static int module_already_processed(module_cache_t *cache, const char *path) { 54 - for (int i = 0; i < cache->count; i++) { 55 - if (strcmp(cache->paths[i], path) == 0) { 56 - return 1; 57 - } 58 - } 59 - return 0; 60 - } 61 - 62 - static void add_to_cache(module_cache_t *cache, const char *path) { 63 - if (cache->count >= cache->capacity) { 64 - cache->capacity = cache->capacity == 0 ? 10 : cache->capacity * 2; 65 - cache->paths = realloc(cache->paths, sizeof(char *) * cache->capacity); 66 - } 67 - 68 - cache->paths[cache->count] = strdup(path); 69 - cache->count++; 70 - } 71 - 72 - static char *process_snapshot_includes(const char *file_path, const char *content, size_t content_len, module_cache_t *cache, size_t *output_len); 73 - 74 - static char *wrap_module(const char *content, size_t content_len, size_t *output_len) { 75 - size_t output_capacity = content_len + 1024; 76 - char *output = malloc(output_capacity); 77 - if (!output) return NULL; 78 - 79 - size_t output_pos = 0; 80 - const char *pos = content; 81 - const char *end = content + content_len; 82 - 83 - const char *iife_start = "(function() {\n"; 84 - memcpy(output + output_pos, iife_start, strlen(iife_start)); 85 - output_pos += strlen(iife_start); 86 - 87 - char **exports = NULL; 88 - int export_count = 0; 89 - int export_capacity = 0; 90 - 91 - while (pos < end) { 92 - const char *export_start = strstr(pos, "export "); 93 - if (!export_start || export_start >= end) { 94 - size_t remaining = end - pos; 95 - if (output_pos + remaining >= output_capacity) { 96 - output_capacity = (output_pos + remaining) * 2; 97 - output = realloc(output, output_capacity); 98 - } 99 - memcpy(output + output_pos, pos, remaining); 100 - output_pos += remaining; 101 - break; 102 - } 103 - 104 - memcpy(output + output_pos, pos, export_start - pos); 105 - output_pos += export_start - pos; 106 - 107 - const char *decl_start = export_start + 7; 108 - while (*decl_start == ' ') decl_start++; 109 - 110 - const char *const_pos = strstr(decl_start, "const "); 111 - const char *let_pos = strstr(decl_start, "let "); 112 - const char *var_pos = strstr(decl_start, "var "); 113 - const char *function_pos = strstr(decl_start, "function "); 114 - 115 - const char *keyword_start = NULL; 116 - const char *name_start = NULL; 117 - 118 - if (const_pos == decl_start) { 119 - keyword_start = const_pos; 120 - name_start = const_pos + 6; 121 - } else if (let_pos == decl_start) { 122 - keyword_start = let_pos; 123 - name_start = let_pos + 4; 124 - } else if (var_pos == decl_start) { 125 - keyword_start = var_pos; 126 - name_start = var_pos + 4; 127 - } else if (function_pos == decl_start) { 128 - keyword_start = function_pos; 129 - name_start = function_pos + 9; 130 - } 131 - 132 - if (keyword_start) { 133 - while (*name_start == ' ') name_start++; 134 - 135 - const char *name_end = name_start; 136 - while (*name_end && (*name_end == '_' || (*name_end >= 'a' && *name_end <= 'z') || 137 - (*name_end >= 'A' && *name_end <= 'Z') || (*name_end >= '0' && *name_end <= '9'))) { 138 - name_end++; 139 - } 140 - 141 - size_t name_len = name_end - name_start; 142 - if (name_len > 0) { 143 - if (export_count >= export_capacity) { 144 - export_capacity = export_capacity == 0 ? 10 : export_capacity * 2; 145 - exports = realloc(exports, sizeof(char *) * export_capacity); 146 - } 147 - 148 - exports[export_count] = malloc(name_len + 1); 149 - memcpy(exports[export_count], name_start, name_len); 150 - exports[export_count][name_len] = '\0'; 151 - export_count++; 152 - } 153 - 154 - const char *stmt_start = keyword_start; 155 - const char *line_end = strchr(export_start, ';'); 156 - if (!line_end) line_end = strchr(export_start, '\n'); 157 - if (line_end) { 158 - size_t stmt_len = line_end - stmt_start + 1; 159 - if (output_pos + stmt_len >= output_capacity) { 160 - output_capacity = (output_pos + stmt_len) * 2; 161 - output = realloc(output, output_capacity); 162 - } 163 - memcpy(output + output_pos, stmt_start, stmt_len); 164 - output_pos += stmt_len; 165 - pos = line_end + 1; 166 - } else { 167 - pos = export_start + 7; 168 - } 169 - } else { 170 - pos = export_start + 7; 171 - } 172 - } 173 - 174 - if (export_count > 0) { 175 - const char *return_start = "\nreturn { "; 176 - if (output_pos + strlen(return_start) >= output_capacity) { 177 - output_capacity = (output_pos + strlen(return_start) + 1024) * 2; 178 - output = realloc(output, output_capacity); 179 - } 180 - memcpy(output + output_pos, return_start, strlen(return_start)); 181 - output_pos += strlen(return_start); 182 - 183 - for (int i = 0; i < export_count; i++) { 184 - size_t name_len = strlen(exports[i]); 185 - 186 - if (output_pos + name_len * 2 + 10 >= output_capacity) { 187 - output_capacity = (output_pos + name_len * 2 + 10) * 2; 188 - output = realloc(output, output_capacity); 189 - } 190 - 191 - memcpy(output + output_pos, exports[i], name_len); 192 - output_pos += name_len; 193 - 194 - if (i < export_count - 1) { 195 - memcpy(output + output_pos, ", ", 2); 196 - output_pos += 2; 197 - } 198 - } 199 - 200 - const char *return_end = " };\n})()"; 201 - memcpy(output + output_pos, return_end, strlen(return_end)); 202 - output_pos += strlen(return_end); 203 - } else { 204 - const char *iife_end = "})()"; 205 - memcpy(output + output_pos, iife_end, strlen(iife_end)); 206 - output_pos += strlen(iife_end); 207 - } 208 - 209 - for (int i = 0; i < export_count; i++) { 210 - free(exports[i]); 211 - } 212 - free(exports); 213 - 214 - output[output_pos] = '\0'; 215 - *output_len = output_pos; 216 - return output; 217 - } 218 - 219 - static char *process_snapshot_inlines(const char *file_path, const char *content, size_t content_len, module_cache_t *cache, size_t *output_len) { 220 - size_t output_capacity = content_len * 2; 221 - char *output = malloc(output_capacity); 222 - if (!output) return NULL; 223 - 224 - size_t output_pos = 0; 225 - const char *pos = content; 226 - const char *end = content + content_len; 227 - 228 - while (pos < end) { 229 - const char *inline_start = strstr(pos, "snapshot_inline("); 230 - if (!inline_start || inline_start >= end) { 231 - size_t remaining = end - pos; 232 - if (output_pos + remaining >= output_capacity) { 233 - output_capacity = (output_pos + remaining) * 2; 234 - output = realloc(output, output_capacity); 235 - } 236 - memcpy(output + output_pos, pos, remaining); 237 - output_pos += remaining; 238 - break; 239 - } 240 - 241 - memcpy(output + output_pos, pos, inline_start - pos); 242 - output_pos += inline_start - pos; 243 - 244 - const char *quote_start = strchr(inline_start, '\''); 245 - if (!quote_start) quote_start = strchr(inline_start, '"'); 246 - if (!quote_start) { 247 - pos = inline_start + 16; 248 - continue; 249 - } 250 - 251 - char quote_char = *quote_start; 252 - const char *quote_end = strchr(quote_start + 1, quote_char); 253 - if (!quote_end) { 254 - pos = inline_start + 16; 255 - continue; 256 - } 257 - 258 - size_t path_len = quote_end - quote_start - 1; 259 - char *import_path = malloc(path_len + 1); 260 - memcpy(import_path, quote_start + 1, path_len); 261 - import_path[path_len] = '\0'; 262 - 263 - char *resolved_path = resolve_path(file_path, import_path); 264 - free(import_path); 265 - 266 - if (!resolved_path) { 267 - pos = inline_start + 16; 268 - continue; 269 - } 270 - 271 - size_t module_len; 272 - char *module_content = read_file(resolved_path, &module_len); 273 - 274 - if (!module_content) { 275 - fprintf(stderr, "Error: Cannot read inline file: %s\n", resolved_path); 276 - free(resolved_path); 277 - free(output); 278 - return NULL; 279 - } 280 - 281 - free(resolved_path); 282 - 283 - if (output_pos + module_len >= output_capacity) { 284 - output_capacity = (output_pos + module_len) * 2; 285 - output = realloc(output, output_capacity); 286 - } 287 - 288 - memcpy(output + output_pos, module_content, module_len); 289 - output_pos += module_len; 290 - free(module_content); 291 - 292 - const char *paren_close = strchr(quote_end, ')'); 293 - if (paren_close) { 294 - pos = paren_close + 1; 295 - if (*pos == ';') pos++; 296 - } else { 297 - pos = quote_end + 1; 298 - } 299 - } 300 - 301 - output[output_pos] = '\0'; 302 - *output_len = output_pos; 303 - return output; 304 - } 305 - 306 - static char *process_snapshot_includes(const char *file_path, const char *content, size_t content_len, module_cache_t *cache, size_t *output_len) { 307 - size_t output_capacity = content_len * 2; 308 - char *output = malloc(output_capacity); 309 - if (!output) return NULL; 310 - 311 - size_t output_pos = 0; 312 - const char *pos = content; 313 - const char *end = content + content_len; 314 - 315 - while (pos < end) { 316 - const char *include_start = strstr(pos, "snapshot_include("); 317 - if (!include_start || include_start >= end) { 318 - size_t remaining = end - pos; 319 - if (output_pos + remaining >= output_capacity) { 320 - output_capacity = (output_pos + remaining) * 2; 321 - output = realloc(output, output_capacity); 322 - } 323 - memcpy(output + output_pos, pos, remaining); 324 - output_pos += remaining; 325 - break; 326 - } 327 - 328 - memcpy(output + output_pos, pos, include_start - pos); 329 - output_pos += include_start - pos; 330 - 331 - const char *quote_start = strchr(include_start, '\''); 332 - if (!quote_start) quote_start = strchr(include_start, '"'); 333 - if (!quote_start) { 334 - pos = include_start + 17; 335 - continue; 336 - } 337 - 338 - char quote_char = *quote_start; 339 - const char *quote_end = strchr(quote_start + 1, quote_char); 340 - if (!quote_end) { 341 - pos = include_start + 17; 342 - continue; 343 - } 344 - 345 - size_t path_len = quote_end - quote_start - 1; 346 - char *import_path = malloc(path_len + 1); 347 - memcpy(import_path, quote_start + 1, path_len); 348 - import_path[path_len] = '\0'; 349 - 350 - char *resolved_path = resolve_path(file_path, import_path); 351 - free(import_path); 352 - 353 - if (!resolved_path) { 354 - pos = include_start + 17; 355 - continue; 356 - } 357 - 358 - if (module_already_processed(cache, resolved_path)) { 359 - fprintf(stderr, "Warning: Circular dependency detected: %s\n", resolved_path); 360 - free(resolved_path); 361 - pos = quote_end + 2; 362 - continue; 363 - } 364 - 365 - add_to_cache(cache, resolved_path); 366 - 367 - size_t module_len; 368 - char *module_content = read_file(resolved_path, &module_len); 369 - 370 - if (!module_content) { 371 - fprintf(stderr, "Error: Cannot read module: %s\n", resolved_path); 372 - free(resolved_path); 373 - free(output); 374 - return NULL; 375 - } 376 - 377 - size_t processed_len; 378 - char *processed = process_snapshot_includes(resolved_path, module_content, module_len, cache, &processed_len); 379 - free(module_content); 380 - 381 - if (!processed) { 382 - free(resolved_path); 383 - free(output); 384 - return NULL; 385 - } 386 - 387 - size_t wrapped_len; 388 - char *wrapped = wrap_module(processed, processed_len, &wrapped_len); 389 - free(processed); 390 - free(resolved_path); 391 - 392 - if (!wrapped) { 393 - free(output); 394 - return NULL; 395 - } 396 - 397 - if (output_pos + wrapped_len >= output_capacity) { 398 - output_capacity = (output_pos + wrapped_len) * 2; 399 - output = realloc(output, output_capacity); 400 - } 401 - 402 - memcpy(output + output_pos, wrapped, wrapped_len); 403 - output_pos += wrapped_len; 404 - free(wrapped); 405 - 406 - const char *paren_close = strchr(quote_end, ')'); 407 - if (paren_close) { 408 - pos = paren_close + 1; 409 - } else { 410 - pos = quote_end + 1; 411 - } 412 - } 413 - 414 - output[output_pos] = '\0'; 415 - *output_len = output_pos; 416 - return output; 417 - } 418 - 419 - static char *replace_templates(const char *input, size_t input_len, replacement_t *replacements, int num_replacements, size_t *output_len) { 420 - size_t output_size = input_len; 421 - 422 - for (int i = 0; i < num_replacements; i++) { 423 - const char *placeholder = replacements[i].placeholder; 424 - const char *value = replacements[i].value; 425 - size_t placeholder_len = strlen(placeholder); 426 - size_t value_len = strlen(value); 427 - 428 - const char *pos = input; 429 - while ((pos = strstr(pos, placeholder)) != NULL) { 430 - output_size = output_size - placeholder_len + value_len; 431 - pos += placeholder_len; 432 - } 433 - } 434 - 435 - char *output = malloc(output_size + 1); 436 - if (!output) return NULL; 437 - 438 - const char *read_pos = input; 439 - char *write_pos = output; 440 - size_t remaining = input_len; 441 - 442 - while (remaining > 0) { 443 - const char *nearest_match = NULL; 444 - size_t nearest_match_len = 0; 445 - const char *nearest_match_value = NULL; 446 - 447 - for (int i = 0; i < num_replacements; i++) { 448 - const char *match = strstr(read_pos, replacements[i].placeholder); 449 - if (match && (!nearest_match || match < nearest_match)) { 450 - nearest_match = match; 451 - nearest_match_len = strlen(replacements[i].placeholder); 452 - nearest_match_value = replacements[i].value; 453 - } 454 - } 455 - 456 - if (nearest_match) { 457 - size_t before_len = nearest_match - read_pos; 458 - memcpy(write_pos, read_pos, before_len); 459 - write_pos += before_len; 460 - 461 - size_t value_len = strlen(nearest_match_value); 462 - memcpy(write_pos, nearest_match_value, value_len); 463 - write_pos += value_len; 464 - 465 - read_pos = nearest_match + nearest_match_len; 466 - remaining = input_len - (read_pos - input); 467 - } else { 468 - memcpy(write_pos, read_pos, remaining); 469 - write_pos += remaining; 470 - remaining = 0; 471 - } 472 - } 473 - 474 - *write_pos = '\0'; 475 - *output_len = write_pos - output; 476 - return output; 477 - } 478 - 479 - int main(int argc, char **argv) { 480 - if (argc < 3) { 481 - fprintf(stderr, "Usage: %s <input.js> <output.h> [KEY=value...]\n", argv[0]); 482 - fprintf(stderr, "Example: %s core.js snapshot.h VERSION=1.0.0 GIT_HASH=abc123\n", argv[0]); 483 - return 1; 484 - } 485 - 486 - const char *input_file = argv[1]; 487 - const char *output_file = argv[2]; 488 - 489 - int num_replacements = argc - 3; 490 - replacement_t *replacements = malloc(sizeof(replacement_t) * num_replacements); 491 - if (!replacements && num_replacements > 0) { 492 - fprintf(stderr, "Error: Failed to allocate memory for replacements\n"); 493 - return 1; 494 - } 495 - 496 - int replacement_idx = 0; 497 - for (int i = 3; i < argc; i++) { 498 - char *arg = strdup(argv[i]); 499 - char *equals = strchr(arg, '='); 500 - if (equals) { 501 - *equals = '\0'; 502 - 503 - replacements[replacement_idx].placeholder = malloc(strlen(arg) + 5); 504 - sprintf(replacements[replacement_idx].placeholder, "{{%s}}", arg); 505 - replacements[replacement_idx].value = strdup(equals + 1); 506 - 507 - printf("template replacement: %s -> %s\n", replacements[replacement_idx].placeholder, replacements[replacement_idx].value); 508 - replacement_idx++; 509 - } 510 - free(arg); 511 - } 512 - 513 - num_replacements = replacement_idx; 514 - 515 - FILE *in = fopen(input_file, "r"); 516 - if (!in) { 517 - fprintf(stderr, "Error: Cannot open input file: %s\n", input_file); 518 - return 1; 519 - } 520 - 521 - fseek(in, 0, SEEK_END); 522 - long file_size = ftell(in); 523 - fseek(in, 0, SEEK_SET); 524 - 525 - char *js_code_original = malloc(file_size + 1); 526 - if (!js_code_original) { 527 - fprintf(stderr, "Error: Memory allocation failed\n"); 528 - fclose(in); 529 - return 1; 530 - } 531 - 532 - fread(js_code_original, 1, file_size, in); 533 - js_code_original[file_size] = '\0'; 534 - fclose(in); 535 - 536 - module_cache_t cache = {0}; 537 - 538 - size_t inlined_len; 539 - char *inlined_code = process_snapshot_inlines(input_file, js_code_original, file_size, &cache, &inlined_len); 540 - 541 - if (!inlined_code) { 542 - fprintf(stderr, "Error: Inline processing failed\n"); 543 - free(js_code_original); 544 - return 1; 545 - } 546 - 547 - size_t bundled_len; 548 - char *bundled_code = process_snapshot_includes(input_file, inlined_code, inlined_len, &cache, &bundled_len); 549 - free(inlined_code); 550 - 551 - if (!bundled_code) { 552 - fprintf(stderr, "Error: Module bundling failed\n"); 553 - free(js_code_original); 554 - return 1; 555 - } 556 - 557 - size_t processed_len; 558 - char *js_code = replace_templates(bundled_code, bundled_len, replacements, num_replacements, &processed_len); 559 - 560 - if (!js_code) { 561 - fprintf(stderr, "Error: Template replacement failed\n"); 562 - free(js_code_original); 563 - free(bundled_code); 564 - return 1; 565 - } 566 - 567 - free(js_code_original); 568 - free(bundled_code); 569 - 570 - char *compacted = malloc(processed_len + 1); 571 - if (!compacted) { 572 - fprintf(stderr, "Error: Memory allocation failed for compaction\n"); 573 - free(js_code); 574 - return 1; 575 - } 576 - 577 - size_t compact_pos = 0; 578 - for (size_t i = 0; i < processed_len; i++) { 579 - if (js_code[i] != '\n' && js_code[i] != '\r') compacted[compact_pos++] = js_code[i]; 580 - } 581 - compacted[compact_pos] = '\0'; 582 - 583 - printf("%s", compacted); 584 - free(js_code); 585 - js_code = compacted; 586 - processed_len = compact_pos; 587 - 588 - for (int i = 0; i < cache.count; i++) { 589 - free(cache.paths[i]); 590 - } 591 - free(cache.paths); 592 - 593 - FILE *out = fopen(output_file, "w"); 594 - if (!out) { 595 - fprintf(stderr, "Error: Cannot open output file: %s\n", output_file); 596 - free(js_code); 597 - return 1; 598 - } 599 - 600 - fprintf(out, "/* Auto-generated snapshot from %s */\n", input_file); 601 - fprintf(out, "/* DO NOT EDIT - Generated during build */\n\n"); 602 - fprintf(out, "#ifndef ANT_SNAPSHOT_DATA_H\n"); 603 - fprintf(out, "#define ANT_SNAPSHOT_DATA_H\n\n"); 604 - fprintf(out, "#include <stddef.h>\n"); 605 - fprintf(out, "#include <stdint.h>\n\n"); 606 - 607 - fprintf(out, "static const uint8_t ant_snapshot_source[] = {"); 608 - 609 - for (size_t i = 0; i < processed_len; i++) { 610 - if (i % 16 == 0) { 611 - fprintf(out, "\n "); 612 - } 613 - fprintf(out, "0x%02x", (unsigned char)js_code[i]); 614 - if (i < processed_len - 1) { 615 - fprintf(out, ", "); 616 - } 617 - } 618 - 619 - fprintf(out, "\n};\n\n"); 620 - fprintf(out, "static const size_t ant_snapshot_source_len = %zu;\n\n", processed_len); 621 - fprintf(out, "/* bundled source size: %zu bytes */\n", processed_len); 622 - fprintf(out, "static const size_t ant_snapshot_mem_size = %zu;\n\n", processed_len); 623 - 624 - fprintf(out, "#endif /* ANT_SNAPSHOT_DATA_H */\n"); 625 - 626 - fclose(out); 627 - free(js_code); 628 - 629 - for (int i = 0; i < num_replacements; i++) { 630 - free(replacements[i].placeholder); 631 - free(replacements[i].value); 632 - } 633 - free(replacements); 634 - 635 - printf("snapshot generated successfully: %s\n", output_file); 636 - printf(" original size: %ld bytes\n", file_size); 637 - printf(" bundled size: %zu bytes\n", processed_len); 638 - printf(" replacements: %d\n", num_replacements); 639 - 640 - return 0; 641 - }
+162
src/tools/gen_snapshot.js
··· 1 + import * as esbuild from 'esbuild'; 2 + import { dirname, resolve } from 'node:path'; 3 + import { readFileSync, writeFileSync } from 'node:fs'; 4 + 5 + const processedModules = new Set(); 6 + 7 + function wrapModule(content) { 8 + const exports = []; 9 + let output = '(function() {\n'; 10 + 11 + const exportRegex = /export\s+(const|let|var|function)\s+(\w+)/g; 12 + let match; 13 + let lastIndex = 0; 14 + let processed = ''; 15 + 16 + while ((match = exportRegex.exec(content)) !== null) { 17 + processed += content.slice(lastIndex, match.index); 18 + processed += `${match[1]} ${match[2]}`; 19 + exports.push(match[2]); 20 + lastIndex = match.index + match[0].length; 21 + } 22 + 23 + processed += content.slice(lastIndex); 24 + output += processed; 25 + 26 + if (exports.length > 0) { 27 + output += `\nreturn { ${exports.join(', ')} };\n})()`; 28 + } else output += '})()'; 29 + 30 + return output; 31 + } 32 + 33 + function processInlines(filePath, content) { 34 + const dir = dirname(filePath); 35 + 36 + return content.replace(/snapshot_inline\s*\(\s*['"](.+?)['"]\s*\);?/g, (_, importPath) => { 37 + const resolved = resolve(dir, importPath); 38 + 39 + try { 40 + return readFileSync(resolved, 'utf-8'); 41 + } catch (err) { 42 + throw Error(`Error: Cannot read inline file: ${resolved}`); 43 + } 44 + }); 45 + } 46 + 47 + function processIncludes(filePath, content) { 48 + const dir = dirname(filePath); 49 + 50 + return content.replace(/snapshot_include\s*\(\s*['"](.+?)['"]\s*\)/g, (_, importPath) => { 51 + const resolved = resolve(dir, importPath); 52 + 53 + if (processedModules.has(resolved)) { 54 + console.error(`Warning: Circular dependency detected: ${resolved}`); 55 + return ''; 56 + } 57 + 58 + processedModules.add(resolved); 59 + 60 + try { 61 + let moduleContent = readFileSync(resolved, 'utf-8'); 62 + moduleContent = processIncludes(resolved, moduleContent); 63 + return wrapModule(moduleContent); 64 + } catch (err) { 65 + throw Error(`Error: Cannot read module: ${resolved}`); 66 + } 67 + }); 68 + } 69 + 70 + function replaceTemplates(content, replacements) { 71 + for (const [key, value] of Object.entries(replacements)) { 72 + content = content.replaceAll(`{{${key}}}`, value); 73 + } 74 + return content; 75 + } 76 + 77 + function generateHeader(inputFile, data) { 78 + const bytes = [...Buffer.from(data)].map(b => `0x${b.toString(16).padStart(2, '0')}`); 79 + 80 + const lines = []; 81 + for (let i = 0; i < bytes.length; i += 16) { 82 + lines.push(' ' + bytes.slice(i, i + 16).join(', ')); 83 + } 84 + 85 + return `/* Auto-generated snapshot from ${inputFile} */ 86 + /* DO NOT EDIT - Generated during build */ 87 + 88 + #ifndef ANT_SNAPSHOT_DATA_H 89 + #define ANT_SNAPSHOT_DATA_H 90 + 91 + #include <stddef.h> 92 + #include <stdint.h> 93 + 94 + static const uint8_t ant_snapshot_source[] = { 95 + ${lines.join(',\n')} 96 + }; 97 + 98 + static const size_t ant_snapshot_source_len = ${data.length}; 99 + 100 + /* bundled source size: ${data.length} bytes */ 101 + static const size_t ant_snapshot_mem_size = ${data.length}; 102 + 103 + #endif /* ANT_SNAPSHOT_DATA_H */ 104 + `; 105 + } 106 + 107 + async function main() { 108 + const args = process.argv.slice(2); 109 + 110 + if (args.length < 2) { 111 + console.error(`Usage: ${process.argv[1]} <input.js> <output.h> [KEY=value...]`); 112 + console.error(`Example: ${process.argv[1]} core.js snapshot.h VERSION=1.0.0 GIT_HASH=abc123`); 113 + process.exit(1); 114 + } 115 + 116 + const [inputFile, outputFile, ...replacementArgs] = args; 117 + 118 + const replacements = {}; 119 + for (const arg of replacementArgs) { 120 + const idx = arg.indexOf('='); 121 + if (idx !== -1) { 122 + const key = arg.slice(0, idx); 123 + const value = arg.slice(idx + 1); 124 + replacements[key] = value; 125 + console.log(`template replacement: {{${key}}} -> ${value}`); 126 + } 127 + } 128 + 129 + let content; 130 + try { 131 + content = readFileSync(inputFile, 'utf-8'); 132 + } catch (err) { 133 + throw Error(`Error: Cannot open input file: ${inputFile}`); 134 + } 135 + 136 + const originalSize = content.length; 137 + 138 + content = processInlines(inputFile, content); 139 + content = processIncludes(inputFile, content); 140 + content = replaceTemplates(content, replacements); 141 + 142 + const result = await esbuild.transform(content, { 143 + minify: true, 144 + loader: 'ts' 145 + }); 146 + 147 + const minified = result.code.trimEnd(); 148 + console.log(minified); 149 + 150 + const header = generateHeader(inputFile, minified); 151 + writeFileSync(outputFile, header); 152 + 153 + console.log(`snapshot generated successfully: ${outputFile}`); 154 + console.log(` original size: ${originalSize} bytes`); 155 + console.log(` bundled size: ${minified.length} bytes`); 156 + console.log(` replacements: ${Object.keys(replacements).length}`); 157 + } 158 + 159 + main().catch(err => { 160 + console.error(err); 161 + process.exit(1); 162 + });
+6
src/tools/package.json
··· 1 + { 2 + "type": "module", 3 + "dependencies": { 4 + "esbuild": "^0.27.2" 5 + } 6 + }
+73
src/types/ant.d.ts
··· 1 + type AntType = 2 + | 'object' 3 + | 'prop' 4 + | 'string' 5 + | 'undefined' 6 + | 'null' 7 + | 'number' 8 + | 'boolean' 9 + | 'function' 10 + | 'coderef' 11 + | 'cfunc' 12 + | 'err' 13 + | 'array' 14 + | 'promise' 15 + | 'typedarray' 16 + | 'bigint' 17 + | 'propref' 18 + | 'symbol' 19 + | 'generator'; 20 + 21 + interface AntGcResult { 22 + heapBefore: number; 23 + heapAfter: number; 24 + usedBefore: number; 25 + usedAfter: number; 26 + freed: number; 27 + arenaBefore: number; 28 + arenaAfter: number; 29 + arenaFreed: number; 30 + } 31 + 32 + interface AntAllocResult { 33 + arenaSize: number; 34 + heapSize: number; 35 + freeBytes: number; 36 + usedBytes: number; 37 + totalBytes: number; 38 + } 39 + 40 + interface AntStatsResult { 41 + arenaUsed: number; 42 + arenaLwm: number; 43 + cstack: number; 44 + gcHeapSize: number; 45 + gcFreeBytes: number; 46 + gcUsedBytes: number; 47 + } 48 + 49 + interface AntRaw { 50 + typeof(t: unknown): number; 51 + } 52 + 53 + interface AntStatic { 54 + version: string; 55 + revision: string; 56 + buildDate: string; 57 + 58 + typeof(t: unknown): AntType | '??'; 59 + raw: AntRaw; 60 + 61 + gc(): AntGcResult; 62 + alloc(): AntAllocResult; 63 + stats(): AntStatsResult; 64 + signal(signum: number, handler: (signum: number) => void): void; 65 + sleep(seconds: number): void; 66 + msleep(milliseconds: number): void; 67 + usleep(microseconds: number): void; 68 + } 69 + 70 + declare const Ant: AntStatic; 71 + 72 + export = Ant; 73 + export as namespace Ant;
+2
src/types/snapshot.d.ts
··· 1 + declare function snapshot_inline(path: string): void; 2 + declare function snapshot_include(path: string): unknown;
+8
tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "lib": ["dom", "ES2017"], 4 + "typeRoots": ["./node_modules/@types"] 5 + }, 6 + 7 + "include": ["src/types/*.d.ts", "src/core/**/*"] 8 + }