()
| 33 | } |
| 34 | |
| 35 | export function createHostUtils() { |
| 36 | return { |
| 37 | readFile(path: string): string { |
| 38 | const ctx = readFileStorage.getStore(); |
| 39 | if (ctx?.readFile) { |
| 40 | const relative = stripWorkingDir(path, ctx.workingDir); |
| 41 | if (relative != null) { |
| 42 | const result = ctx.readFile(relative); |
| 43 | if (result != null) return result; |
| 44 | } |
| 45 | } |
| 46 | // No readFile callback or it returned null -- do not fall through to |
| 47 | // readFileSync because the WASM module could request arbitrary host |
| 48 | // paths (e.g. via `-r /etc/passwd` in requirements.txt). |
| 49 | throw new WitResultError(`File not found: ${path}`); |
| 50 | }, |
| 51 | domainToAscii(domain: string): string { |
| 52 | try { |
| 53 | // Use the WHATWG URL parser for IDNA2008 conversion. |
| 54 | // We must validate the input to avoid URL-level parsing artifacts: |
| 55 | // colons would be interpreted as port separators, brackets as IPv6, |
| 56 | // @ as userinfo separator, # as fragment, ? as query, / as path, |
| 57 | // \ as path separator (equivalent to / in special schemes), |
| 58 | // % as percent-encoding, tab/LF/CR are silently stripped by the URL parser. |
| 59 | if (/[:#?/@[\]%\\\t\n\r]/.test(domain)) { |
| 60 | throw new Error('domain contains invalid characters'); |
| 61 | } |
| 62 | const url = new URL(`http://${domain}/`); |
| 63 | // Verify the hostname wasn't mangled by URL parsing (e.g. empty after normalization) |
| 64 | if (url.hostname === '' && domain !== '') { |
| 65 | throw new Error('domain resolved to empty hostname'); |
| 66 | } |
| 67 | return url.hostname; |
| 68 | } catch { |
| 69 | // jco expects { payload: string } for WIT result<_, string> errors |
| 70 | throw { payload: `Invalid domain: ${domain}` }; |
| 71 | } |
| 72 | }, |
| 73 | |
| 74 | domainToUnicode(domain: string): [string, boolean] { |
| 75 | // Node.js url.domainToUnicode provides full UTS #46 domain-to-unicode: |
| 76 | // punycode decoding, case folding, and NFC normalization. |
| 77 | // Node returns '' on failure; we return the input as best-effort in that |
| 78 | // case (matching upstream idna which returns a string even on error). |
| 79 | const result = nodeDomainToUnicode(domain); |
| 80 | if (result !== '' || domain === '') { |
| 81 | return [result, true]; |
| 82 | } |
| 83 | return [domain, false]; |
| 84 | }, |
| 85 | |
| 86 | nfcNormalize(s: string): string { |
| 87 | return s.normalize('NFC'); |
| 88 | }, |
| 89 | |
| 90 | nfdNormalize(s: string): string { |
| 91 | return s.normalize('NFD'); |
| 92 | }, |
no outgoing calls
no test coverage detected