[next] Rename all runtime(s) references to interpreter(s) (#1536)

This commit is contained in:
Andrea Giammarchi
2023-06-15 15:34:07 +02:00
committed by GitHub
parent db27d52352
commit 6284c02032
21 changed files with 214 additions and 198 deletions

View File

@@ -1,9 +1,9 @@
import { $x, $$ } from "basic-devtools";
import xworker from "./worker/class.js";
import { handle, runtimes } from "./script-handler.js";
import { handle, interpreters } from "./script-handler.js";
import { all, assign, create, defineProperty } from "./utils.js";
import { registry, selectors, prefixes } from "./runtimes.js";
import { registry, selectors, prefixes } from "./interpreters.js";
import { PLUGINS_SELECTORS, handlePlugin } from "./plugins.js";
export { registerPlugin } from "./plugins.js";
@@ -11,20 +11,20 @@ export const XWorker = xworker();
const RUNTIME_SELECTOR = selectors.join(",");
// ensure both runtime and its queue are awaited then returns the runtime
// ensure both interpreter and its queue are awaited then returns the interpreter
const awaitRuntime = async (key) => {
if (runtimes.has(key)) {
const { runtime, queue } = runtimes.get(key);
return (await all([runtime, queue]))[0];
if (interpreters.has(key)) {
const { interpreter, queue } = interpreters.get(key);
return (await all([interpreter, queue]))[0];
}
const available = runtimes.size
? `Available runtimes are: ${[...runtimes.keys()]
const available = interpreters.size
? `Available interpreters are: ${[...interpreters.keys()]
.map((r) => `"${r}"`)
.join(", ")}.`
: `There are no runtimes in this page.`;
: `There are no interpreters in this page.`;
throw new Error(`The runtime "${key}" was not found. ${available}`);
throw new Error(`The interpreter "${key}" was not found. ${available}`);
};
defineProperty(globalThis, "pyscript", {
@@ -45,13 +45,13 @@ const listener = async (event) => {
currentTarget,
)) {
name = name.slice(0, -(type.length + 1));
const runtime = await awaitRuntime(
const interpreter = await awaitRuntime(
el.getAttribute(`${name}-env`) || name,
);
const i = index++;
try {
globalThis.__events.set(i, event);
registry.get(name).runEvent(runtime, value, i);
registry.get(name).runEvent(interpreter, value, i);
} finally {
globalThis.__events.delete(i);
}

View File

@@ -2,20 +2,21 @@ import { clean, writeFile as writeFileUtil } from "./_utils.js";
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
export const run = (runtime, code) => runtime.runPython(clean(code));
export const run = (interpreter, code) => interpreter.runPython(clean(code));
export const runAsync = (runtime, code) => runtime.runPythonAsync(clean(code));
export const runAsync = (interpreter, code) =>
interpreter.runPythonAsync(clean(code));
export function runEvent(runtime, code, key) {
export function runEvent(interpreter, code, key) {
code = `import js;event=js.__events.get(${key});${code}`;
return this.run(runtime, code);
return this.run(interpreter, code);
}
const worker = (method) =>
function (runtime, code, xworker) {
function (interpreter, code, xworker) {
code = `from js import xworker;${code}`;
globalThis.xworker = xworker;
return this[method](runtime, code);
return this[method](interpreter, code);
};
export const runWorker = worker("run");

View File

@@ -24,9 +24,9 @@ export const stdio = (init) => {
stderr: (...args) => localIO.stderr(...args),
stdout: (...args) => localIO.stdout(...args),
async get(engine) {
const runtime = await engine;
io.set(runtime, localIO);
return runtime;
const interpreter = await engine;
io.set(interpreter, localIO);
return interpreter;
},
};
};
@@ -123,11 +123,11 @@ const fetchResolved = (config_fetch, url) =>
export const base = new WeakMap();
export const fetchPaths = (module, runtime, config_fetch) =>
export const fetchPaths = (module, interpreter, config_fetch) =>
all(
calculateFetchPaths(config_fetch).map(({ url, path }) =>
fetchResolved(config_fetch, url)
.then(getBuffer)
.then((buffer) => module.writeFile(runtime, path, buffer)),
.then((buffer) => module.writeFile(interpreter, path, buffer)),
),
);

View File

@@ -19,15 +19,17 @@ export default {
async engine({ loadPyodide }, config, url) {
const { stderr, stdout, get } = stdio();
const indexURL = url.slice(0, url.lastIndexOf("/"));
const runtime = await get(loadPyodide({ stderr, stdout, indexURL }));
if (config.fetch) await fetchPaths(this, runtime, config.fetch);
const interpreter = await get(
loadPyodide({ stderr, stdout, indexURL }),
);
if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
if (config.packages) {
await runtime.loadPackage("micropip");
const micropip = await runtime.pyimport("micropip");
await interpreter.loadPackage("micropip");
const micropip = await interpreter.pyimport("micropip");
await micropip.install(config.packages);
micropip.destroy();
}
return runtime;
return interpreter;
},
run,
runAsync,

View File

@@ -10,10 +10,10 @@ const type = "ruby";
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
const worker = (method) =>
function (runtime, code, xworker) {
function (interpreter, code, xworker) {
globalThis.xworker = xworker;
return this[method](
runtime,
interpreter,
`require "js";xworker=JS::eval("return xworker");${code}`,
);
};
@@ -28,15 +28,15 @@ export default {
`${url.slice(0, url.lastIndexOf("/"))}/ruby.wasm`,
);
const module = await WebAssembly.compile(await response.arrayBuffer());
const { vm: runtime } = await DefaultRubyVM(module);
if (config.fetch) await fetchPaths(this, runtime, config.fetch);
return runtime;
const { vm: interpreter } = await DefaultRubyVM(module);
if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
return interpreter;
},
run: (runtime, code) => runtime.eval(clean(code)),
runAsync: (runtime, code) => runtime.evalAsync(clean(code)),
runEvent(runtime, code, key) {
run: (interpreter, code) => interpreter.eval(clean(code)),
runAsync: (interpreter, code) => interpreter.evalAsync(clean(code)),
runEvent(interpreter, code, key) {
return this.run(
runtime,
interpreter,
`require "js";event=JS::eval("return __events.get(${key})");${code}`,
);
},

View File

@@ -0,0 +1,45 @@
import { clean, fetchPaths, stdio, writeFileShim } from "./_utils.js";
const type = "wasmoon";
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
const worker = (method) =>
function (interpreter, code, xworker) {
interpreter.global.set("xworker", xworker);
return this[method](interpreter, code);
};
export default {
type: [type, "lua"],
module: (version = "1.15.0") =>
`https://cdn.jsdelivr.net/npm/wasmoon@${version}/+esm`,
async engine({ LuaFactory, LuaLibraries }, config) {
const { stderr, stdout, get } = stdio();
const interpreter = await get(new LuaFactory().createEngine());
interpreter.global.getTable(LuaLibraries.Base, (index) => {
interpreter.global.setField(index, "print", stdout);
interpreter.global.setField(index, "printErr", stderr);
});
if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
return interpreter;
},
run: (interpreter, code) => interpreter.doStringSync(clean(code)),
runAsync: (interpreter, code) => interpreter.doString(clean(code)),
runEvent(interpreter, code, key) {
interpreter.global.set("event", globalThis.__events.get(key));
return this.run(interpreter, code);
},
runWorker: worker("run"),
runWorkerAsync: worker("runAsync"),
writeFile: (
{
cmodule: {
module: { FS },
},
},
path,
buffer,
) => writeFileShim(FS, path, buffer),
};
/* c8 ignore stop */

View File

@@ -1,8 +1,8 @@
// ⚠️ Part of this file is automatically generated
// The :RUNTIMES comment is a delimiter and no code should be written/changed after
// See rollup/build_runtimes.cjs to know more
// See rollup/build_interpreters.cjs to know more
import { base } from "./runtime/_utils.js";
import { base } from "./interpreter/_utils.js";
/** @type {Map<string, object>} */
export const registry = new Map();
@@ -16,18 +16,18 @@ export const selectors = [];
/** @type {string[]} */
export const prefixes = [];
export const runtime = new Proxy(new Map(), {
export const interpreter = new Proxy(new Map(), {
get(map, id) {
if (!map.has(id)) {
const [type, ...rest] = id.split("@");
const runtime = registry.get(type);
const interpreter = registry.get(type);
const url = /^https?:\/\//i.test(rest)
? rest[0]
: runtime.module(...rest);
: interpreter.module(...rest);
map.set(id, {
url,
module: import(url),
engine: runtime.engine.bind(runtime),
engine: interpreter.engine.bind(interpreter),
});
}
const { url, module, engine } = map.get(id);
@@ -41,17 +41,18 @@ export const runtime = new Proxy(new Map(), {
},
});
const register = (runtime) => {
for (const type of [].concat(runtime.type)) {
registry.set(type, runtime);
const register = (interpreter) => {
for (const type of [].concat(interpreter.type)) {
registry.set(type, interpreter);
selectors.push(`script[type="${type}"]`);
prefixes.push(`${type}-`);
}
};
//:RUNTIMES
import micropython from "./runtime/micropython.js";
import pyodide from "./runtime/pyodide.js";
import ruby from "./runtime/ruby.js";
import wasmoon from "./runtime/wasmoon.js";
for (const runtime of [micropython, pyodide, ruby, wasmoon]) register(runtime);
import micropython from "./interpreter/micropython.js";
import pyodide from "./interpreter/pyodide.js";
import ruby from "./interpreter/ruby.js";
import wasmoon from "./interpreter/wasmoon.js";
for (const interpreter of [micropython, pyodide, ruby, wasmoon])
register(interpreter);

View File

@@ -1,10 +1,10 @@
import { runtime } from "./runtimes.js";
import { interpreter } from "./interpreters.js";
import { absoluteURL, resolve } from "./utils.js";
import { parse } from "./toml.js";
import { getJSON, getText } from "./fetch-utils.js";
/**
* @param {string} id the runtime name @ version identifier
* @param {string} id the interpreter name @ version identifier
* @param {string} [config] optional config file to parse
* @returns
*/
@@ -28,12 +28,12 @@ export const getRuntime = (id, config) => {
}
/* c8 ignore stop */
}
return resolve(options).then((options) => runtime[id](options, config));
return resolve(options).then((options) => interpreter[id](options, config));
};
/**
* @param {string} type the runtime type
* @param {string} [version] the optional runtime version
* @param {string} type the interpreter type
* @param {string} [version] the optional interpreter version
* @returns
*/
export const getRuntimeID = (type, version = "") =>

View File

@@ -2,9 +2,9 @@ import { $$ } from "basic-devtools";
import { create } from "./utils.js";
import { getDetails } from "./script-handler.js";
import { registry, configs } from "./runtimes.js";
import { registry, configs } from "./interpreters.js";
import { getRuntimeID } from "./loader.js";
import { io } from "./runtime/_utils.js";
import { io } from "./interpreter/_utils.js";
import workerHooks from "./worker/hooks.js";
@@ -12,12 +12,12 @@ export const PLUGINS_SELECTORS = [];
/**
* @typedef {Object} Runtime plugin configuration
* @prop {string} type the runtime type
* @prop {object} runtime the bootstrapped runtime
* @prop {(url:string, options?: object) => Worker} XWorker an XWorker constructor that defaults to same runtime on the Worker.
* @prop {object} config a cloned config used to bootstrap the runtime
* @prop {(code:string) => any} run an utility to run code within the runtime
* @prop {(code:string) => Promise<any>} runAsync an utility to run code asynchronously within the runtime
* @prop {string} type the interpreter type
* @prop {object} interpreter the bootstrapped interpreter
* @prop {(url:string, options?: object) => Worker} XWorker an XWorker constructor that defaults to same interpreter on the Worker.
* @prop {object} config a cloned config used to bootstrap the interpreter
* @prop {(code:string) => any} run an utility to run code within the interpreter
* @prop {(code:string) => Promise<any>} runAsync an utility to run code asynchronously within the interpreter
* @prop {(path:string, data:ArrayBuffer) => void} writeFile an utility to write a file in the virtual FS, if available
*/
@@ -37,14 +37,14 @@ export const handlePlugin = (node) => {
const { type, version, config, env, onRuntimeReady } = options;
const name = getRuntimeID(type, version);
const id = env || `${name}${config ? `|${config}` : ""}`;
const { runtime: engine, XWorker } = getDetails(
const { interpreter: engine, XWorker } = getDetails(
type,
id,
name,
version,
config,
);
engine.then((runtime) => {
engine.then((interpreter) => {
if (!patched.has(id)) {
const module = create(registry.get(type));
const {
@@ -67,9 +67,13 @@ export const handlePlugin = (node) => {
["run", [onBeforeRun, onAfterRun]],
]) {
const method = module[name];
module[name] = function (runtime, code) {
module[name] = function (interpreter, code) {
if (before) before.call(this, resolved, node);
const result = method.call(this, runtime, code);
const result = method.call(
this,
interpreter,
code,
);
if (after) after.call(this, resolved, node);
return result;
};
@@ -80,12 +84,12 @@ export const handlePlugin = (node) => {
["runAsync", [onBeforeRunAsync, onAfterRunAsync]],
]) {
const method = module[name];
module[name] = async function (runtime, code) {
module[name] = async function (interpreter, code) {
if (before)
await before.call(this, resolved, node);
const result = await method.call(
this,
runtime,
interpreter,
code,
);
if (after)
@@ -107,12 +111,12 @@ export const handlePlugin = (node) => {
const resolved = {
type,
runtime,
interpreter,
XWorker,
io: io.get(runtime),
io: io.get(interpreter),
config: structuredClone(configs.get(name)),
run: module.run.bind(module, runtime),
runAsync: module.runAsync.bind(module, runtime),
run: module.run.bind(module, interpreter),
runAsync: module.runAsync.bind(module, interpreter),
};
patched.set(id, resolved);
@@ -132,15 +136,15 @@ const plugins = new Map();
/**
* @typedef {Object} PluginOptions plugin configuration
* @prop {string} type the runtime/interpreter type to receive
* @prop {string} [version] the optional runtime version to use
* @prop {string} [config] the optional config to use within such runtime
* @prop {string} type the interpreter/interpreter type to receive
* @prop {string} [version] the optional interpreter version to use
* @prop {string} [config] the optional config to use within such interpreter
* @prop {string} [env] the optional environment to use
* @prop {(node: Element, runtime: Runtime) => void} onRuntimeReady the callback that will be invoked once
* @prop {(node: Element, interpreter: Runtime) => void} onRuntimeReady the callback that will be invoked once
*/
/**
* Allows plugins and components on the page to receive runtimes to execute any code.
* Allows plugins and components on the page to receive interpreters to execute any code.
* @param {string} name the unique plugin name
* @param {PluginOptions} options the plugin configuration
*/

View File

@@ -1,45 +0,0 @@
import { clean, fetchPaths, stdio, writeFileShim } from "./_utils.js";
const type = "wasmoon";
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
const worker = (method) =>
function (runtime, code, xworker) {
runtime.global.set("xworker", xworker);
return this[method](runtime, code);
};
export default {
type: [type, "lua"],
module: (version = "1.15.0") =>
`https://cdn.jsdelivr.net/npm/wasmoon@${version}/+esm`,
async engine({ LuaFactory, LuaLibraries }, config) {
const { stderr, stdout, get } = stdio();
const runtime = await get(new LuaFactory().createEngine());
runtime.global.getTable(LuaLibraries.Base, (index) => {
runtime.global.setField(index, "print", stdout);
runtime.global.setField(index, "printErr", stderr);
});
if (config.fetch) await fetchPaths(this, runtime, config.fetch);
return runtime;
},
run: (runtime, code) => runtime.doStringSync(clean(code)),
runAsync: (runtime, code) => runtime.doString(clean(code)),
runEvent(runtime, code, key) {
runtime.global.set("event", globalThis.__events.get(key));
return this.run(runtime, code);
},
runWorker: worker("run"),
runWorkerAsync: worker("runAsync"),
writeFile: (
{
cmodule: {
module: { FS },
},
},
path,
buffer,
) => writeFileShim(FS, path, buffer),
};
/* c8 ignore stop */

View File

@@ -2,7 +2,7 @@ import { $ } from "basic-devtools";
import xworker from "./worker/class.js";
import { getRuntime, getRuntimeID } from "./loader.js";
import { registry } from "./runtimes.js";
import { registry } from "./interpreters.js";
import { all, resolve, defineProperty, absoluteURL } from "./utils.js";
import { getText } from "./fetch-utils.js";
@@ -40,14 +40,17 @@ const targetDescriptor = {
const handled = new WeakMap();
export const runtimes = new Map();
export const interpreters = new Map();
const execute = async (script, source, XWorker, isAsync) => {
const module = registry.get(script.type);
/* c8 ignore next */
if (module.experimental)
console.warn(`The ${script.type} runtime is experimental`);
const [runtime, content] = await all([handled.get(script).runtime, source]);
console.warn(`The ${script.type} interpreter is experimental`);
const [interpreter, content] = await all([
handled.get(script).interpreter,
source,
]);
try {
// temporarily override inherited document.currentScript in a non writable way
// but it deletes it right after to preserve native behavior (as it's sync: no trouble)
@@ -59,7 +62,7 @@ const execute = async (script, source, XWorker, isAsync) => {
configurable: true,
get: () => script,
});
return module[isAsync ? "runAsync" : "run"](runtime, content);
return module[isAsync ? "runAsync" : "run"](interpreter, content);
} finally {
delete globalThis.XWorker;
delete document.currentScript;
@@ -72,18 +75,18 @@ const getValue = (ref, prefix) => {
};
export const getDetails = (type, id, name, version, config) => {
if (!runtimes.has(id)) {
if (!interpreters.has(id)) {
const details = {
runtime: getRuntime(name, config),
interpreter: getRuntime(name, config),
queue: resolve(),
XWorker: xworker(type, version),
};
runtimes.set(id, details);
// enable sane defaults when single runtime *of kind* is used in the page
// this allows `xxx-*` attributes to refer to such runtime without `env` around
if (!runtimes.has(type)) runtimes.set(type, details);
interpreters.set(id, details);
// enable sane defaults when single interpreter *of kind* is used in the page
// this allows `xxx-*` attributes to refer to such interpreter without `env` around
if (!interpreters.has(type)) interpreters.set(type, details);
}
return runtimes.get(id);
return interpreters.get(id);
};
/**
@@ -104,8 +107,8 @@ export const handle = async (script) => {
// new script to handle ... allow newly created scripts to work
// just exactly like any other script would
else {
// allow a shared config among scripts, beside runtime,
// and/or source code with different config or runtime
// allow a shared config among scripts, beside interpreter,
// and/or source code with different config or interpreter
const {
attributes: { async: isAsync, config, env, target, version },
src,

View File

@@ -7,7 +7,7 @@
import coincident from "coincident/structured";
import { create } from "../utils.js";
import { registry } from "../runtimes.js";
import { registry } from "../interpreters.js";
import { getRuntime, getRuntimeID } from "../loader.js";
// bails out out of the box with a native/meaningful error
@@ -23,15 +23,15 @@ try {
);
}
let engine, run, runtimeEvent;
let engine, run, interpreterEvent;
const add = (type, fn) => {
addEventListener(
type,
fn ||
(async (event) => {
const runtime = await engine;
runtimeEvent = event;
run(runtime, `xworker.on${type}(xworker.event);`, xworker);
const interpreter = await engine;
interpreterEvent = event;
run(interpreter, `xworker.on${type}(xworker.event);`, xworker);
}),
!!fn && { once: true },
);
@@ -49,9 +49,9 @@ const xworker = {
// would always fail once an event has been dispatched, as that's not
// meant to be accessed in the wild, respecting the one-off event nature of JS.
get event() {
const event = runtimeEvent;
const event = interpreterEvent;
if (!event) throw new Error("Unauthorized event access");
runtimeEvent = void 0;
interpreterEvent = void 0;
return event;
},
};
@@ -74,10 +74,10 @@ add("message", ({ data: { options, code, hooks } }) => {
// append code that should be executed *after* first
if (after) {
const method = details[name];
details[name] = function (runtime, code, xworker) {
details[name] = function (interpreter, code, xworker) {
return method.call(
this,
runtime,
interpreter,
`${code}\n${after}`,
xworker,
);
@@ -87,10 +87,10 @@ add("message", ({ data: { options, code, hooks } }) => {
// prepend code that should be executed *before* (so that after is post-patched)
if (before) {
const method = details[name];
details[name] = function (runtime, code, xworker) {
details[name] = function (interpreter, code, xworker) {
return method.call(
this,
runtime,
interpreter,
`${before}\n${code}`,
xworker,
);

View File

@@ -6,16 +6,16 @@ import workerHooks from "./hooks.js";
/**
* @typedef {Object} WorkerOptions plugin configuration
* @prop {string} type the runtime/interpreter type to use
* @prop {string} [version] the optional runtime version to use
* @prop {string} [config] the optional config to use within such runtime
* @prop {string} type the interpreter type to use
* @prop {string} [version] the optional interpreter version to use
* @prop {string} [config] the optional config to use within such interpreter
*/
export default (...args) =>
/**
* A XWorker is a Worker facade able to bootstrap a channel with any desired runtime.
* A XWorker is a Worker facade able to bootstrap a channel with any desired interpreter.
* @param {string} url the remote file to evaluate on bootstrap
* @param {WorkerOptions} [options] optional arguments to define the runtime to use
* @param {WorkerOptions} [options] optional arguments to define the interpreter to use
* @returns {Worker}
*/
function XWorker(url, options) {

View File

@@ -11,7 +11,7 @@
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"coincident": "^0.4.0"
"coincident": "^0.4.1"
},
"devDependencies": {
"@node-loader/import-maps": "^1.1.0",
@@ -534,9 +534,9 @@
}
},
"node_modules/coincident": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.4.0.tgz",
"integrity": "sha512-s4uoaRx9Tbaigy3iuD9+ap92hIp16ZejiF/S4ngI4AEtcXWs5Ad5GoKoUWfjUkYXwXtGQ6hlghwUTyW8j32vXw==",
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.4.1.tgz",
"integrity": "sha512-CiHZVx/eUano0G+sSc0S0pXTBH51q0W7pMw1ScRa57BgfBw8l19pMW2Z6sVDHjOih5c9NYrP0budO8SslJv2sA==",
"dependencies": {
"@ungap/structured-clone": "^1.2.0"
}
@@ -2447,9 +2447,9 @@
}
},
"coincident": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.4.0.tgz",
"integrity": "sha512-s4uoaRx9Tbaigy3iuD9+ap92hIp16ZejiF/S4ngI4AEtcXWs5Ad5GoKoUWfjUkYXwXtGQ6hlghwUTyW8j32vXw==",
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-0.4.1.tgz",
"integrity": "sha512-CiHZVx/eUano0G+sSc0S0pXTBH51q0W7pMw1ScRa57BgfBw8l19pMW2Z6sVDHjOih5c9NYrP0budO8SslJv2sA==",
"requires": {
"@ungap/structured-clone": "^1.2.0"
}

View File

@@ -47,9 +47,9 @@
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"coincident": "^0.4.0"
"coincident": "^0.4.1"
},
"worker": {
"blob": "sha256-cyZ90yuiHhmQ0syjP+lzJYZoUaioBPzIDmKPEpGSXaU="
"blob": "sha256-TbwtN60VpzVf6WDe6PfdTcHNVyKO4Z2zUN1gi/0rJeE="
}
}

View File

@@ -0,0 +1,37 @@
// ⚠️ This files modifies at build time esm/interpreters.js so that
// it's impossible to forget to export a interpreter from esm/interpreter folder.
const { join, resolve } = require("node:path");
const { readdirSync, readFileSync, writeFileSync } = require("node:fs");
const RUNTIMES_DIR = resolve(join(__dirname, "..", "esm", "interpreter"));
const RUNTIMES_JS = resolve(join(__dirname, "..", "esm", "interpreters.js"));
const createRuntimes = () => {
const interpreters = [];
for (const file of readdirSync(RUNTIMES_DIR)) {
// ignore files starting with underscore
if (/^[a-z].+?\.js/.test(file)) interpreters.push(file.slice(0, -3));
}
// generate the output to append at the end of the file
const output = [];
for (const interpreter of interpreters)
output.push(
`import ${interpreter} from "./interpreter/${interpreter}.js";`,
);
output.push(
`
for (const interpreter of [${interpreters.join(", ")}])
register(interpreter);
`.trim(),
);
return output.join("\n");
};
writeFileSync(
RUNTIMES_JS,
// find //:RUNTIMES comment and replace anything after that
readFileSync(RUNTIMES_JS)
.toString()
.replace(/(\/\/:RUNTIMES)([\S\s]*)$/, `$1\n${createRuntimes()}\n`),
);

View File

@@ -1,32 +0,0 @@
// ⚠️ This files modifies at build time esm/runtimes.js so that
// it's impossible to forget to export a runtime from esm/runtime folder.
const { join, resolve } = require("node:path");
const { readdirSync, readFileSync, writeFileSync } = require("node:fs");
const RUNTIMES_DIR = resolve(join(__dirname, "..", "esm", "runtime"));
const RUNTIMES_JS = resolve(join(__dirname, "..", "esm", "runtimes.js"));
const createRuntimes = () => {
const runtimes = [];
for (const file of readdirSync(RUNTIMES_DIR)) {
// ignore files starting with underscore
if (/^[a-z].+?\.js/.test(file)) runtimes.push(file.slice(0, -3));
}
// generate the output to append at the end of the file
const output = [];
for (const runtime of runtimes)
output.push(`import ${runtime} from "./runtime/${runtime}.js";`);
output.push(
`for (const runtime of [${runtimes.join(", ")}]) register(runtime);`,
);
return output.join("\n");
};
writeFileSync(
RUNTIMES_JS,
// find //:RUNTIMES comment and replace anything after that
readFileSync(RUNTIMES_JS)
.toString()
.replace(/(\/\/:RUNTIMES)([\S\s]*)$/, `$1\n${createRuntimes()}\n`),
);

View File

@@ -8,7 +8,7 @@ import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import { dirname, join, resolve } from "node:path";
createRequire(import.meta.url)("./build_runtimes.cjs");
createRequire(import.meta.url)("./build_interpreters.cjs");
const WORKERS_DIR = resolve(
join(dirname(fileURLToPath(import.meta.url)), "..", "esm", "worker"),

View File

@@ -1,4 +1,4 @@
const { writeFileShim } = require("../cjs/runtime/_utils.js");
const { writeFileShim } = require("../cjs/interpreter/_utils.js");
const assert = require("./assert.js");

View File

@@ -23,7 +23,7 @@ const sharedPyodide = new Promise((resolve) => {
codeBeforeRunWorker: `print('codeBeforeRunWorker')`,
codeAfterRunWorker: `print('codeAfterRunWorker')`,
onBeforeRun(pyodide, node) {
pyodide.runtime.globals.set("XWorker", XWorker);
pyodide.interpreter.globals.set("XWorker", XWorker);
console.log("onBeforeRun", sharedRuntime === pyodide, node);
},
onAfterRun(pyodide, node) {