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 fs path coercing

+86 -13
+2 -1
examples/wasm/demo.sh
··· 6 6 BASE="${SRC%.c}" 7 7 8 8 emcc -O3 "$SRC" -o "${BASE}.cjs" 9 - ant "${BASE}.cjs" 9 + ./build/ant -pe "\`running ant \${Ant.version}\`" 10 + ./build/ant "${BASE}.cjs" 10 11 rm -f "${BASE}.cjs" "${BASE}.wasm"
+34 -6
src/modules/fs.c
··· 32 32 #include "modules/events.h" 33 33 #include "modules/stream.h" 34 34 #include "modules/symbol.h" 35 + #include "modules/url.h" 35 36 36 37 typedef enum { 37 38 FS_ENC_NONE = 0, ··· 1097 1098 req->error_msg = strdup(uv_strerror(uv_code)); 1098 1099 } 1099 1100 1101 + static ant_value_t fs_coerce_file_url_path(ant_t *js, ant_value_t arg) { 1102 + ant_value_t href = js_getprop_fallback(js, arg, "href"); 1103 + if (vtype(href) != T_STR) return js_mkundef(); 1104 + 1105 + const char *href_str = js_getstr(js, href, NULL); 1106 + if (!href_str) return js_mkundef(); 1107 + 1108 + url_state_t parsed = {0}; 1109 + if (parse_url_to_state(href_str, NULL, &parsed) != 0) return js_mkundef(); 1110 + 1111 + ant_value_t path = js_mkundef(); 1112 + if (parsed.protocol && strcmp(parsed.protocol, "file:") == 0) { 1113 + char *decoded = url_decode_component(parsed.pathname); 1114 + if (decoded) { 1115 + path = js_mkstr(js, decoded, strlen(decoded)); 1116 + free(decoded); 1117 + }} 1118 + 1119 + url_state_clear(&parsed); 1120 + return path; 1121 + } 1122 + 1100 1123 static ant_value_t fs_coerce_path(ant_t *js, ant_value_t arg) { 1101 1124 if (vtype(arg) == T_STR) return arg; 1102 - if (is_object_type(arg)) { 1103 - ant_value_t pathname = js_get(js, arg, "pathname"); 1104 - if (vtype(pathname) == T_STR) return pathname; 1105 - } 1125 + if (!is_object_type(arg)) return js_mkundef(); 1126 + 1127 + ant_value_t path = fs_coerce_file_url_path(js, arg); 1128 + if (!is_undefined(path)) return path; 1129 + 1130 + path = js_get(js, arg, "pathname"); 1131 + if (vtype(path) == T_STR) return path; 1132 + 1106 1133 return js_mkundef(); 1107 1134 } 1108 1135 ··· 2099 2126 static ant_value_t builtin_fs_readFile(ant_t *js, ant_value_t *args, int nargs) { 2100 2127 if (nargs < 1) return js_mkerr(js, "readFile() requires a path argument"); 2101 2128 2102 - if (vtype(args[0]) != T_STR) return js_mkerr(js, "readFile() path must be a string"); 2129 + ant_value_t path_val = fs_coerce_path(js, args[0]); 2130 + if (vtype(path_val) != T_STR) return js_mkerr(js, "readFile() path must be a string or URL"); 2103 2131 2104 2132 size_t path_len; 2105 - char *path = js_getstr(js, args[0], &path_len); 2133 + char *path = js_getstr(js, path_val, &path_len); 2106 2134 if (!path) return js_mkerr(js, "Failed to get path string"); 2107 2135 2108 2136
+6 -6
src/types/modules/fs.d.ts
··· 66 66 }; 67 67 const promises: typeof import('fs/promises'); 68 68 69 - function readFile(path: string, encoding: Encoding): Promise<string>; 70 - function readFile(path: string): Promise<Uint8Array>; 71 - function readFileSync(path: string, encoding: Encoding | { encoding: Encoding }): string; 72 - function readFileSync(path: string): Uint8Array; 69 + function readFile(path: string | URL, encoding: Encoding): Promise<string>; 70 + function readFile(path: string | URL): Promise<Uint8Array>; 71 + function readFileSync(path: string | URL, encoding: Encoding | { encoding: Encoding }): string; 72 + function readFileSync(path: string | URL): Uint8Array; 73 73 function read( 74 74 fd: number, 75 75 buffer: ArrayBufferView, ··· 245 245 O_APPEND: number; 246 246 }; 247 247 248 - function readFile(path: string, encoding: Encoding): Promise<string>; 249 - function readFile(path: string): Promise<Uint8Array>; 248 + function readFile(path: string | URL, encoding: Encoding): Promise<string>; 249 + function readFile(path: string | URL): Promise<Uint8Array>; 250 250 function open(path: string, flags?: string, mode?: number): Promise<FileHandle>; 251 251 function close(fd: number): Promise<void>; 252 252 function writeFile(path: string, data: string | ArrayBufferView): Promise<void>;
+44
tests/test_fs_readfile_url.mjs
··· 1 + import * as fs from 'node:fs'; 2 + import * as fsp from 'node:fs/promises'; 3 + import path from 'node:path'; 4 + 5 + function assert(condition, message) { 6 + if (!condition) throw new Error(message); 7 + } 8 + 9 + async function readFileCallback(url, encoding) { 10 + return await new Promise((resolve, reject) => { 11 + fs.readFile(url, encoding, (error, data) => { 12 + if (error) reject(error); 13 + else resolve(data); 14 + }); 15 + }); 16 + } 17 + 18 + async function main() { 19 + const dirPath = path.join(import.meta.dirname, '.fs url tmp'); 20 + const filePath = path.join(dirPath, 'url file.txt'); 21 + const content = 'hello from file URL reads'; 22 + 23 + fs.rmSync(dirPath, { recursive: true, force: true }); 24 + fs.mkdirSync(dirPath, { recursive: true }); 25 + fs.writeFileSync(filePath, content); 26 + const fileUrl = new URL(`file://${encodeURI(filePath)}`); 27 + 28 + try { 29 + const syncContent = fs.readFileSync(fileUrl, 'utf8'); 30 + assert(syncContent === content, `expected sync read to match, got ${JSON.stringify(syncContent)}`); 31 + 32 + const callbackContent = await readFileCallback(fileUrl, 'utf8'); 33 + assert(callbackContent === content, `expected callback read to match, got ${JSON.stringify(callbackContent)}`); 34 + 35 + const promiseContent = await fsp.readFile(fileUrl, 'utf8'); 36 + assert(promiseContent === content, `expected promise read to match, got ${JSON.stringify(promiseContent)}`); 37 + 38 + console.log('fs readFile accepts file URLs'); 39 + } finally { 40 + fs.rmSync(dirPath, { recursive: true, force: true }); 41 + } 42 + } 43 + 44 + await main();