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.

at master 182 lines 6.0 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <libgen.h> 7 8#include "ant.h" 9#include "errors.h" 10#include "internal.h" 11#include "esm/loader.h" 12#include "esm/library.h" 13#include "modules/symbol.h" 14 15typedef struct { ant_t *js; ant_value_t arr; } builtin_iter_ctx_t; 16 17static void push_builtin_name(const char *name, void *ud) { 18 builtin_iter_ctx_t *ctx = (builtin_iter_ctx_t *)ud; 19 js_arr_push(ctx->js, ctx->arr, js_mkstr(ctx->js, name, strlen(name))); 20} 21 22static ant_value_t builtin_createRequire_call(ant_t *js, ant_value_t *args, int nargs) { 23 if (nargs < 1 || vtype(args[0]) != T_STR) 24 return js_mkerr(js, "require() expects a string specifier"); 25 26 ant_value_t fn = js_getcurrentfunc(js); 27 ant_value_t data = js_get_slot(fn, SLOT_DATA); 28 const char *base_path = js_module_eval_active_filename(js); 29 30 if (vtype(data) == T_STR) { 31 ant_offset_t plen = 0; 32 ant_offset_t poff = vstr(js, data, &plen); 33 base_path = (const char *)(uintptr_t)(poff); 34 } 35 36 ant_value_t ns = js_esm_import_sync_from(js, args[0], base_path); 37 if (is_err(ns)) return ns; 38 39 if (vtype(ns) == T_OBJ) { 40 ant_value_t default_export = js_get_slot(ns, SLOT_DEFAULT); 41 if (vtype(default_export) != T_UNDEF) return default_export; 42 } 43 44 return ns; 45} 46 47static ant_value_t resolve_strip_file_url(ant_t *js, ant_value_t resolved) { 48 if (is_err(resolved) || vtype(resolved) != T_STR) return resolved; 49 50 ant_offset_t len = 0; 51 ant_offset_t off = vstr(js, resolved, &len); 52 53 const char *s = (const char *)(uintptr_t)(off); 54 static const char *prefix = "file://"; 55 56 if ((size_t)len >= strlen(prefix) && strncmp(s, prefix, strlen(prefix)) == 0) { 57 const char *path_part = s + strlen(prefix); 58 size_t plen = (size_t)len - strlen(prefix); 59 return js_mkstr(js, path_part, plen); 60 } 61 62 return resolved; 63} 64 65// require.resolve(specifier, options?) 66static ant_value_t builtin_createRequire_resolve(ant_t *js, ant_value_t *args, int nargs) { 67 if (nargs < 1 || vtype(args[0]) != T_STR) 68 return js_mkerr(js, "require.resolve() expects a string specifier"); 69 70 ant_value_t fn = js_getcurrentfunc(js); 71 ant_value_t data = js_get_slot(fn, SLOT_DATA); 72 const char *base_path = js_module_eval_active_filename(js); 73 74 if (vtype(data) == T_STR) { 75 ant_offset_t dlen = 0; 76 ant_offset_t doff = vstr(js, data, &dlen); 77 base_path = (const char *)(uintptr_t)(doff); 78 } 79 80 ant_value_t paths_val = (nargs >= 2 && is_object_type(args[1])) 81 ? js_get(js, args[1], "paths") : js_mkundef(); 82 83 if (vtype(paths_val) != T_ARR) { 84 ant_value_t resolved = js_esm_resolve_specifier(js, args[0], base_path); 85 return resolve_strip_file_url(js, resolved); 86 } 87 88 ant_offset_t path_count = js_arr_len(js, paths_val); 89 for (ant_offset_t i = 0; i < path_count; i++) { 90 ant_value_t p = js_arr_get(js, paths_val, i); 91 if (vtype(p) != T_STR) continue; 92 93 char *dir = js_getstr(js, p, NULL); 94 if (!dir) continue; 95 96 ant_value_t resolved = js_esm_resolve_specifier(js, args[0], dir); 97 if (!is_err(resolved) && vtype(resolved) == T_STR) 98 return resolve_strip_file_url(js, resolved); 99 } 100 101 return js_mkerr(js, "Cannot resolve module"); 102} 103 104// createRequire(filename) 105static ant_value_t builtin_createRequire(ant_t *js, ant_value_t *args, int nargs) { 106 if (nargs < 1) return js_mkerr(js, "createRequire() requires a filename argument"); 107 108 ant_value_t filename_val = args[0]; 109 if (vtype(filename_val) != T_STR) 110 return js_mkerr(js, "createRequire() filename must be a string"); 111 112 size_t fname_len; 113 char *fname = js_getstr(js, filename_val, &fname_len); 114 if (!fname) return js_mkerr(js, "createRequire() invalid filename"); 115 116 const char *path = fname; 117 size_t path_len = fname_len; 118 119 static const char *file_prefix = "file://"; 120 size_t prefix_len = strlen(file_prefix); 121 122 if (path_len >= prefix_len && strncmp(path, file_prefix, prefix_len) == 0) { 123 path += prefix_len; 124 path_len -= prefix_len; 125 } 126 127 ant_value_t path_val = js_mkstr(js, path, path_len); 128 ant_value_t require_fn = js_heavy_mkfun(js, builtin_createRequire_call, path_val); 129 ant_value_t resolve_fn = js_heavy_mkfun(js, builtin_createRequire_resolve, path_val); 130 js_set(js, require_fn, "resolve", resolve_fn); 131 132 return require_fn; 133} 134 135// Module._resolveFilename(request, parent) 136static ant_value_t builtin_resolveFilename(ant_t *js, ant_value_t *args, int nargs) { 137 if (nargs < 1 || vtype(args[0]) != T_STR) 138 return js_mkerr(js, "Module._resolveFilename() requires a string request"); 139 140 const char *base_path = js_module_eval_active_filename(js); 141 if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 142 ant_value_t parent_filename = js_get(js, args[1], "filename"); 143 if (vtype(parent_filename) == T_STR) { 144 ant_offset_t plen = 0; 145 ant_offset_t poff = vstr(js, parent_filename, &plen); 146 base_path = (const char *)(uintptr_t)(poff); 147 } 148 } 149 150 ant_value_t resolved = js_esm_resolve_specifier(js, args[0], base_path); 151 if (is_err(resolved)) return resolved; 152 if (vtype(resolved) != T_STR) return resolved; 153 154 ant_offset_t len = 0; 155 ant_offset_t off = vstr(js, resolved, &len); 156 157 const char *s = (const char *)(uintptr_t)(off); 158 static const char *prefix = "file://"; 159 160 if ((size_t)len >= strlen(prefix) && strncmp(s, prefix, strlen(prefix)) == 0) { 161 const char *path_part = s + strlen(prefix); 162 size_t plen = (size_t)len - strlen(prefix); 163 return js_mkstr(js, path_part, plen); 164 } 165 166 return resolved; 167} 168 169ant_value_t module_library(ant_t *js) { 170 ant_value_t lib = js_mkobj(js); 171 js_set(js, lib, "createRequire", js_mkfun(builtin_createRequire)); 172 173 ant_value_t modules_arr = js_mkarr(js); 174 builtin_iter_ctx_t ctx = { js, modules_arr }; 175 ant_library_foreach(push_builtin_name, &ctx); 176 177 js_set(js, lib, "builtinModules", modules_arr); 178 js_set(js, lib, "_resolveFilename", js_mkfun(builtin_resolveFilename)); 179 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "Module", 6)); 180 181 return lib; 182}