|
| 1 | +import { create } from 'gc-hook'; |
| 2 | +import { dedent } from '../utils.js'; |
| 3 | +import { fetchFiles, fetchJSModules, fetchPaths } from './_utils.js'; |
| 4 | +import { io, stdio } from './_io.js'; |
| 5 | + |
| 6 | +const type = 'webr'; |
| 7 | +const r = new WeakMap(); |
| 8 | + |
| 9 | +// REQUIRES INTEGRATION TEST |
| 10 | +/* c8 ignore start */ |
| 11 | +const run = async (interpreter, code) => { |
| 12 | + const { shelter, destroy, io } = r.get(interpreter); |
| 13 | + const { output, result } = await shelter.captureR(dedent(code)); |
| 14 | + for (const { type, data } of output) io[type](data); |
| 15 | + // this is a double proxy but it's OK as the consumer |
| 16 | + // of the result here needs to invoke explicitly a conversion |
| 17 | + // or trust the `(await p.toJs()).values` returns what's expected. |
| 18 | + return create(result, destroy, { token: false }); |
| 19 | +}; |
| 20 | + |
| 21 | +export default { |
| 22 | + type, |
| 23 | + experimental: true, |
| 24 | + module: (version = '0.3.2') => |
| 25 | + `https://cdn.jsdelivr.net/npm/webr@${version}/dist/webr.mjs`, |
| 26 | + async engine(module, config) { |
| 27 | + const { get } = stdio(); |
| 28 | + const interpreter = new module.WebR(); |
| 29 | + await get(interpreter.init().then(() => interpreter)); |
| 30 | + const shelter = await new interpreter.Shelter(); |
| 31 | + r.set(interpreter, { |
| 32 | + module, |
| 33 | + shelter, |
| 34 | + destroy: shelter.destroy.bind(shelter), |
| 35 | + io: io.get(interpreter), |
| 36 | + }); |
| 37 | + if (config.files) await fetchFiles(this, interpreter, config.files); |
| 38 | + if (config.fetch) await fetchPaths(this, interpreter, config.fetch); |
| 39 | + if (config.js_modules) await fetchJSModules(config.js_modules); |
| 40 | + return interpreter; |
| 41 | + }, |
| 42 | + // Fallback to globally defined module fields (i.e. $xworker) |
| 43 | + registerJSModule(_, name) { |
| 44 | + console.warn(`Experimental interpreter: module ${name} is not supported (yet)`); |
| 45 | + // TODO: as complex JS objects / modules are not allowed |
| 46 | + // it's not clear how we can bind anything or import a module |
| 47 | + // in a context that doesn't understand methods from JS |
| 48 | + // https://docs.r-wasm.org/webr/latest/convert-js-to-r.html#constructing-r-objects-from-javascript-objects |
| 49 | + }, |
| 50 | + run, |
| 51 | + runAsync: run, |
| 52 | + async runEvent(interpreter, code, event) { |
| 53 | + // TODO: WebR cannot convert exoteric objects or any literal |
| 54 | + // to an easy to reason about data/frame ... that convertion |
| 55 | + // is reserved for the future: |
| 56 | + // https://docs.r-wasm.org/webr/latest/convert-js-to-r.html#constructing-r-objects-from-javascript-objects |
| 57 | + await interpreter.evalRVoid(`${code}(event)`, { |
| 58 | + env: { event: { type: [ event.type ] } } |
| 59 | + }); |
| 60 | + }, |
| 61 | + transform: (_, value) => { |
| 62 | + console.log('transforming', value); |
| 63 | + return value; |
| 64 | + }, |
| 65 | + writeFile: () => { |
| 66 | + // MAYBE ??? |
| 67 | + }, |
| 68 | +}; |
| 69 | +/* c8 ignore stop */ |
0 commit comments