UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

170 lines (141 loc) 4.85 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/wasi.js import { codes as __codes__ } from "nstdlib/lib/internal/errors"; import { emitExperimentalWarning, kEmptyObject, } from "nstdlib/lib/internal/util"; import { validateArray, validateBoolean, validateFunction, validateInt32, validateObject, validateString, validateUndefined, } from "nstdlib/lib/internal/validators"; const { ERR_INVALID_ARG_VALUE, ERR_WASI_ALREADY_STARTED } = __codes__; const kExitCode = Symbol("kExitCode"); const kSetMemory = Symbol("kSetMemory"); const kStarted = Symbol("kStarted"); const kInstance = Symbol("kInstance"); const kBindingName = Symbol("kBindingName"); emitExperimentalWarning("WASI"); function setupInstance(self, instance) { validateObject(instance, "instance"); validateObject(instance.exports, "instance.exports"); self[kInstance] = instance; self[kSetMemory](instance.exports.memory); } class WASI { constructor(options = kEmptyObject) { validateObject(options, "options"); let _WASI; validateString(options.version, "options.version"); switch (options.version) { case "unstable": ({ WASI: _WASI } = require("binding/wasi")); this[kBindingName] = "wasi_unstable"; break; case "preview1": ({ WASI: _WASI } = require("binding/wasi")); this[kBindingName] = "wasi_snapshot_preview1"; break; // When adding support for additional wasi versions add case here default: throw new ERR_INVALID_ARG_VALUE( "options.version", options.version, "unsupported WASI version", ); } if (options.args !== undefined) validateArray(options.args, "options.args"); const args = Array.prototype.map.call(options.args || [], String); const env = []; if (options.env !== undefined) { validateObject(options.env, "options.env"); Array.prototype.forEach.call( Object.entries(options.env), ({ 0: key, 1: value }) => { if (value !== undefined) Array.prototype.push.call(env, `${key}=${value}`); }, ); } const preopens = []; if (options.preopens !== undefined) { validateObject(options.preopens, "options.preopens"); Array.prototype.forEach.call( Object.entries(options.preopens), ({ 0: key, 1: value }) => Array.prototype.push.call(preopens, String(key), String(value)), ); } const { stdin = 0, stdout = 1, stderr = 2 } = options; validateInt32(stdin, "options.stdin", 0); validateInt32(stdout, "options.stdout", 0); validateInt32(stderr, "options.stderr", 0); const stdio = [stdin, stdout, stderr]; const wrap = new _WASI(args, env, preopens, stdio); for (const prop in wrap) { wrap[prop] = Function.prototype.bind.call(wrap[prop], wrap); } let returnOnExit = true; if (options.returnOnExit !== undefined) { validateBoolean(options.returnOnExit, "options.returnOnExit"); returnOnExit = options.returnOnExit; } if (returnOnExit) wrap.proc_exit = Function.prototype.bind.call(wasiReturnOnProcExit, this); this[kSetMemory] = wrap._setMemory; delete wrap._setMemory; this.wasiImport = wrap; this[kStarted] = false; this[kExitCode] = 0; this[kInstance] = undefined; } // Must not export _initialize, must export _start start(instance) { if (this[kStarted]) { throw new ERR_WASI_ALREADY_STARTED(); } this[kStarted] = true; setupInstance(this, instance); const { _start, _initialize } = this[kInstance].exports; validateFunction(_start, "instance.exports._start"); validateUndefined(_initialize, "instance.exports._initialize"); try { _start(); } catch (err) { if (err !== kExitCode) { throw err; } } return this[kExitCode]; } // Must not export _start, may optionally export _initialize initialize(instance) { if (this[kStarted]) { throw new ERR_WASI_ALREADY_STARTED(); } this[kStarted] = true; setupInstance(this, instance); const { _start, _initialize } = this[kInstance].exports; validateUndefined(_start, "instance.exports._start"); if (_initialize !== undefined) { validateFunction(_initialize, "instance.exports._initialize"); _initialize(); } } getImportObject() { return { [this[kBindingName]]: this.wasiImport }; } } export { WASI }; function wasiReturnOnProcExit(rval) { // If __wasi_proc_exit() does not terminate the process, an assertion is // triggered in the wasm runtime. Node can sidestep the assertion and return // an exit code by recording the exit code, and throwing a JavaScript // exception that WebAssembly cannot catch. this[kExitCode] = rval; throw kExitCode; }