washm
Version:
WASM shell: Bash inside WASM
102 lines (90 loc) • 3.27 kB
JavaScript
// Suppress only the WASI ExperimentalWarning (keeps other warnings intact).
// This is intentionally minimal: wrap `process.emitWarning` and drop ExperimentalWarning messages that mention 'WASI'.
const _originalEmitWarning = process.emitWarning;
process.emitWarning = function(warning, ...args) {
try {
const name = (typeof args[0] === 'string' ? args[0] : (warning && warning.name)) || '';
const message = typeof warning === 'string' ? warning : (warning && warning.message) || '';
if ((name === 'ExperimentalWarning' || /ExperimentalWarning/.test(name)) && /WASI/.test(message)) return;
} catch (e) { /* fall through to default behavior */ }
return _originalEmitWarning.call(process, warning, ...args);
};
const fs = require('fs');
const { WASI } = require('wasi');
const argv = process.argv;
async function main() {
const wasmPath = __dirname + '/washm.wasm';
const wasmBuffer = fs.readFileSync(wasmPath);
const wasi = new WASI({
args: ['washm.js', ...argv.slice(2)],
env: process.env,
preopens: (function() {
const preopens = { '/': '/' };
if (process.platform !== 'win32') return preopens;
const pathModule = require('path');
const os = require('os');
const cwdRoot = pathModule.parse(process.cwd()).root;
const homeRoot = pathModule.parse(os.homedir()).root;
[cwdRoot, homeRoot].filter(Boolean).forEach(r => {
const rootPath = r.endsWith('\\') ? r : r + '\\';
const letter = rootPath[0].toUpperCase();
preopens[`/${letter}:/`] = rootPath;
});
return preopens;
})(),
version: 'preview1'
});
const wasiSnapshot = {};
for (const key of Object.keys(wasi.wasiImport)) {
wasiSnapshot[key] = function () {
return wasiSnapshot[key].actual.apply(this, arguments);
};
wasiSnapshot[key].actual = wasi.wasiImport[key];
}
let collectEvalJS = "";
let instance;
const importObj = {
wasi_snapshot_preview1: wasiSnapshot
};
// Special handling for bootstrap FD 20251219
const origFdWrite = wasiSnapshot.fd_write.actual;
wasiSnapshot.fd_write.actual = (fd, iovs, iovsLen, nwritten) => {
if (fd === 20251219) {
const memory = new Uint8Array(instance.exports.memory.buffer);
const view = new DataView(memory.buffer);
let total = 0;
for (let i = 0; i < iovsLen; i++) {
const ptr = view.getUint32(iovs + i * 8, true);
const len = view.getUint32(iovs + i * 8 + 4, true);
const chunk = memory.slice(ptr, ptr + len);
collectEvalJS += new TextDecoder().decode(chunk);
total += len;
}
view.setUint32(nwritten, total, true);
return 0;
}
return origFdWrite(fd, iovs, iovsLen, nwritten);
};
const origFdClose = wasiSnapshot.fd_close.actual;
wasiSnapshot.fd_close.actual = (fd) => {
if (fd === 20251219) {
const js = collectEvalJS;
collectEvalJS = '';
eval(js);
return 0;
}
return origFdClose(fd);
};
const result = await WebAssembly.instantiate(wasmBuffer, importObj);
instance = result.instance;
globalThis.__washm_bootstrap = {
wasi,
importObj,
wasiSnapshot,
instance,
require,
};
wasi.start(instance);
}
main();