@pyscript/core 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/cjs/custom-types.js +212 -0
- package/cjs/fetch-utils.js +12 -0
- package/cjs/index.js +73 -0
- package/cjs/interpreter/_python.js +16 -0
- package/cjs/interpreter/_utils.js +141 -0
- package/cjs/interpreter/micropython.js +34 -0
- package/cjs/interpreter/pyodide.js +38 -0
- package/cjs/interpreter/ruby-wasm-wasi.js +43 -0
- package/cjs/interpreter/wasmoon.js +40 -0
- package/cjs/interpreters.js +64 -0
- package/cjs/listeners.js +71 -0
- package/cjs/loader.js +43 -0
- package/cjs/package.json +1 -0
- package/cjs/plugins/pyscript.js +105 -0
- package/cjs/script-handler.js +141 -0
- package/cjs/toml.js +10 -0
- package/cjs/utils.js +19 -0
- package/cjs/worker/class.js +46 -0
- package/cjs/worker/hooks.js +2 -0
- package/cjs/worker/xworker.js +3 -0
- package/esm/custom-types.js +207 -0
- package/esm/fetch-utils.js +8 -0
- package/esm/index.js +68 -0
- package/esm/interpreter/_python.js +12 -0
- package/esm/interpreter/_utils.js +133 -0
- package/esm/interpreter/micropython.js +33 -0
- package/esm/interpreter/pyodide.js +37 -0
- package/esm/interpreter/ruby-wasm-wasi.js +42 -0
- package/esm/interpreter/wasmoon.js +39 -0
- package/esm/interpreters.js +58 -0
- package/esm/listeners.js +68 -0
- package/esm/loader.js +40 -0
- package/esm/script-handler.js +136 -0
- package/esm/toml.js +8 -0
- package/esm/utils.js +20 -0
- package/esm/worker/class.js +45 -0
- package/esm/worker/hooks.js +1 -0
- package/esm/worker/xworker.js +2 -0
- package/min.js +2 -0
- package/package.json +55 -0
- package/types/coincident/structured.d.ts +5 -0
- package/types/fetch-utils.d.ts +3 -0
- package/types/index.d.ts +2 -0
- package/types/loader.d.ts +2 -0
- package/types/plugins.d.ts +61 -0
- package/types/pyscript/pyscript.core/esm/custom-types.d.ts +54 -0
- package/types/pyscript/pyscript.core/esm/fetch-utils.d.ts +3 -0
- package/types/pyscript/pyscript.core/esm/index.d.ts +2 -0
- package/types/pyscript/pyscript.core/esm/interpreter/_python.d.ts +5 -0
- package/types/pyscript/pyscript.core/esm/interpreter/_utils.d.ts +11 -0
- package/types/pyscript/pyscript.core/esm/interpreter/micropython.d.ts +17 -0
- package/types/pyscript/pyscript.core/esm/interpreter/pyodide.d.ts +17 -0
- package/types/pyscript/pyscript.core/esm/interpreter/ruby-wasm-wasi.d.ts +15 -0
- package/types/pyscript/pyscript.core/esm/interpreter/ruby.d.ts +16 -0
- package/types/pyscript/pyscript.core/esm/interpreter/wasmoon.d.ts +21 -0
- package/types/pyscript/pyscript.core/esm/interpreters.d.ts +9 -0
- package/types/pyscript/pyscript.core/esm/listeners.d.ts +2 -0
- package/types/pyscript/pyscript.core/esm/loader.d.ts +2 -0
- package/types/pyscript/pyscript.core/esm/plugins.d.ts +54 -0
- package/types/pyscript/pyscript.core/esm/runtime/_python.d.ts +8 -0
- package/types/pyscript/pyscript.core/esm/runtime/_utils.d.ts +11 -0
- package/types/pyscript/pyscript.core/esm/runtime/micropython.d.ts +20 -0
- package/types/pyscript/pyscript.core/esm/runtime/pyodide.d.ts +20 -0
- package/types/pyscript/pyscript.core/esm/runtime/ruby.d.ts +15 -0
- package/types/pyscript/pyscript.core/esm/runtime/wasmoon.d.ts +21 -0
- package/types/pyscript/pyscript.core/esm/runtimes.d.ts +9 -0
- package/types/pyscript/pyscript.core/esm/script-handler.d.ts +4 -0
- package/types/pyscript/pyscript.core/esm/toml.d.ts +1 -0
- package/types/pyscript/pyscript.core/esm/utils.d.ts +23 -0
- package/types/pyscript/pyscript.core/esm/worker/class.d.ts +19 -0
- package/types/pyscript/pyscript.core/esm/worker/hooks.d.ts +2 -0
- package/types/pyscript/pyscript.core/esm/worker/xworker.d.ts +2 -0
- package/types/runtime/_python.d.ts +8 -0
- package/types/runtime/_utils.d.ts +11 -0
- package/types/runtime/micropython.d.ts +20 -0
- package/types/runtime/pyodide.d.ts +20 -0
- package/types/runtime/ruby.d.ts +15 -0
- package/types/runtime/wasmoon.d.ts +21 -0
- package/types/runtimes.d.ts +9 -0
- package/types/script-handler.d.ts +3 -0
- package/types/toml.d.ts +1 -0
- package/types/utils.d.ts +23 -0
- package/types/worker/class.d.ts +19 -0
- package/types/worker/hooks.d.ts +2 -0
- package/types/worker/xworker.d.ts +2 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
'use strict';
|
2
|
+
// ⚠️ Part of this file is automatically generated
|
3
|
+
// The :RUNTIMES comment is a delimiter and no code should be written/changed after
|
4
|
+
// See rollup/build_interpreters.cjs to know more
|
5
|
+
|
6
|
+
const { base } = require("./interpreter/_utils.js");
|
7
|
+
|
8
|
+
/** @type {Map<string, object>} */
|
9
|
+
const registry = new Map();
|
10
|
+
exports.registry = registry;
|
11
|
+
|
12
|
+
/** @type {Map<string, object>} */
|
13
|
+
const configs = new Map();
|
14
|
+
exports.configs = configs;
|
15
|
+
|
16
|
+
/** @type {string[]} */
|
17
|
+
const selectors = [];
|
18
|
+
exports.selectors = selectors;
|
19
|
+
|
20
|
+
/** @type {string[]} */
|
21
|
+
const prefixes = [];
|
22
|
+
exports.prefixes = prefixes;
|
23
|
+
|
24
|
+
const interpreter = new Proxy(new Map(), {
|
25
|
+
get(map, id) {
|
26
|
+
if (!map.has(id)) {
|
27
|
+
const [type, ...rest] = id.split("@");
|
28
|
+
const interpreter = registry.get(type);
|
29
|
+
const url = /^https?:\/\//i.test(rest)
|
30
|
+
? rest.join("@")
|
31
|
+
: interpreter.module(...rest);
|
32
|
+
map.set(id, {
|
33
|
+
url,
|
34
|
+
module: import(url),
|
35
|
+
engine: interpreter.engine.bind(interpreter),
|
36
|
+
});
|
37
|
+
}
|
38
|
+
const { url, module, engine } = map.get(id);
|
39
|
+
return (config, baseURL) =>
|
40
|
+
module.then((module) => {
|
41
|
+
configs.set(id, config);
|
42
|
+
const fetch = config?.fetch;
|
43
|
+
if (fetch) base.set(fetch, baseURL);
|
44
|
+
return engine(module, config, url);
|
45
|
+
});
|
46
|
+
},
|
47
|
+
});
|
48
|
+
exports.interpreter = interpreter;
|
49
|
+
|
50
|
+
const register = (interpreter) => {
|
51
|
+
for (const type of [].concat(interpreter.type)) {
|
52
|
+
registry.set(type, interpreter);
|
53
|
+
selectors.push(`script[type="${type}"]`);
|
54
|
+
prefixes.push(`${type}-`);
|
55
|
+
}
|
56
|
+
};
|
57
|
+
|
58
|
+
//:RUNTIMES
|
59
|
+
const micropython = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./interpreter/micropython.js"));
|
60
|
+
const pyodide = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./interpreter/pyodide.js"));
|
61
|
+
const ruby_wasm_wasi = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./interpreter/ruby-wasm-wasi.js"));
|
62
|
+
const wasmoon = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./interpreter/wasmoon.js"));
|
63
|
+
for (const interpreter of [micropython, pyodide, ruby_wasm_wasi, wasmoon])
|
64
|
+
register(interpreter);
|
package/cjs/listeners.js
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
'use strict';
|
2
|
+
const { $x } = require("basic-devtools");
|
3
|
+
|
4
|
+
const { interpreters } = require("./script-handler.js");
|
5
|
+
const { all, create, defineProperty } = require("./utils.js");
|
6
|
+
const { registry, prefixes } = require("./interpreters.js");
|
7
|
+
|
8
|
+
// TODO: this is ugly; need to find a better way
|
9
|
+
defineProperty(globalThis, "pyscript", {
|
10
|
+
value: {
|
11
|
+
env: new Proxy(create(null), {
|
12
|
+
get: (_, name) => awaitInterpreter(name),
|
13
|
+
}),
|
14
|
+
},
|
15
|
+
});
|
16
|
+
|
17
|
+
/* c8 ignore start */ // attributes are tested via integration / e2e
|
18
|
+
// ensure both interpreter and its queue are awaited then returns the interpreter
|
19
|
+
const awaitInterpreter = async (key) => {
|
20
|
+
if (interpreters.has(key)) {
|
21
|
+
const { interpreter, queue } = interpreters.get(key);
|
22
|
+
return (await all([interpreter, queue]))[0];
|
23
|
+
}
|
24
|
+
|
25
|
+
const available = interpreters.size
|
26
|
+
? `Available interpreters are: ${[...interpreters.keys()]
|
27
|
+
.map((r) => `"${r}"`)
|
28
|
+
.join(", ")}.`
|
29
|
+
: `There are no interpreters in this page.`;
|
30
|
+
|
31
|
+
throw new Error(`The interpreter "${key}" was not found. ${available}`);
|
32
|
+
};
|
33
|
+
|
34
|
+
const listener = async (event) => {
|
35
|
+
const { type, currentTarget } = event;
|
36
|
+
for (let { name, value, ownerElement: el } of $x(
|
37
|
+
`./@*[${prefixes.map((p) => `name()="${p}${type}"`).join(" or ")}]`,
|
38
|
+
currentTarget,
|
39
|
+
)) {
|
40
|
+
name = name.slice(0, -(type.length + 1));
|
41
|
+
const interpreter = await awaitInterpreter(
|
42
|
+
el.getAttribute(`${name}-env`) || name,
|
43
|
+
);
|
44
|
+
const handler = registry.get(name);
|
45
|
+
try {
|
46
|
+
handler.setGlobal(interpreter, "event", event);
|
47
|
+
handler.run(interpreter, value);
|
48
|
+
} finally {
|
49
|
+
handler.deleteGlobal(interpreter, "event");
|
50
|
+
}
|
51
|
+
}
|
52
|
+
};
|
53
|
+
exports.listener = listener;
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Look for known prefixes and add related listeners.
|
57
|
+
* @param {Document | Element} root
|
58
|
+
*/
|
59
|
+
const addAllListeners = (root) => {
|
60
|
+
for (let { name, ownerElement: el } of $x(
|
61
|
+
`.//@*[${prefixes
|
62
|
+
.map((p) => `starts-with(name(),"${p}")`)
|
63
|
+
.join(" or ")}]`,
|
64
|
+
root,
|
65
|
+
)) {
|
66
|
+
name = name.slice(name.lastIndexOf("-") + 1);
|
67
|
+
if (name !== "env") el.addEventListener(name, listener);
|
68
|
+
}
|
69
|
+
};
|
70
|
+
exports.addAllListeners = addAllListeners;
|
71
|
+
/* c8 ignore stop */
|
package/cjs/loader.js
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
'use strict';
|
2
|
+
const { interpreter } = require("./interpreters.js");
|
3
|
+
const { absoluteURL, resolve } = require("./utils.js");
|
4
|
+
const { parse } = require("./toml.js");
|
5
|
+
const { getJSON, getText } = require("./fetch-utils.js");
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @param {string} id the interpreter name @ version identifier
|
9
|
+
* @param {string} [config] optional config file to parse
|
10
|
+
* @returns
|
11
|
+
*/
|
12
|
+
const getRuntime = (id, config) => {
|
13
|
+
let options = {};
|
14
|
+
if (config) {
|
15
|
+
// REQUIRES INTEGRATION TEST
|
16
|
+
/* c8 ignore start */
|
17
|
+
if (config.endsWith(".json")) {
|
18
|
+
options = fetch(config).then(getJSON);
|
19
|
+
} else if (config.endsWith(".toml")) {
|
20
|
+
options = fetch(config).then(getText).then(parse);
|
21
|
+
} else {
|
22
|
+
try {
|
23
|
+
options = JSON.parse(config);
|
24
|
+
} catch (_) {
|
25
|
+
options = parse(config);
|
26
|
+
}
|
27
|
+
// make the config a URL to be able to retrieve relative paths from it
|
28
|
+
config = absoluteURL("./config.txt");
|
29
|
+
}
|
30
|
+
/* c8 ignore stop */
|
31
|
+
}
|
32
|
+
return resolve(options).then((options) => interpreter[id](options, config));
|
33
|
+
};
|
34
|
+
exports.getRuntime = getRuntime;
|
35
|
+
|
36
|
+
/**
|
37
|
+
* @param {string} type the interpreter type
|
38
|
+
* @param {string} [version] the optional interpreter version
|
39
|
+
* @returns
|
40
|
+
*/
|
41
|
+
const getRuntimeID = (type, version = "") =>
|
42
|
+
`${type}@${version}`.replace(/@$/, "");
|
43
|
+
exports.getRuntimeID = getRuntimeID;
|
package/cjs/package.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"type":"commonjs"}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
'use strict';
|
2
|
+
require("@ungap/with-resolvers");
|
3
|
+
const { $ } = require("basic-devtools");
|
4
|
+
|
5
|
+
const { define } = require("../index.js");
|
6
|
+
const { queryTarget } = require("../script-handler.js");
|
7
|
+
const { defineProperty } = require("../utils.js");
|
8
|
+
const { getText } = require("../fetch-utils.js");
|
9
|
+
|
10
|
+
// append ASAP CSS to avoid showing content
|
11
|
+
document.head.appendChild(document.createElement("style")).textContent = `
|
12
|
+
py-script, py-config {
|
13
|
+
display: none;
|
14
|
+
}
|
15
|
+
`;
|
16
|
+
|
17
|
+
// create a unique identifier when/if needed
|
18
|
+
let id = 0;
|
19
|
+
const getID = (prefix = "py-script") => `${prefix}-${id++}`;
|
20
|
+
|
21
|
+
// find the shared config for all py-script elements
|
22
|
+
let config;
|
23
|
+
let pyConfig = $("py-config");
|
24
|
+
if (pyConfig)
|
25
|
+
config = pyConfig.getAttribute("src") || pyConfig.textContent;
|
26
|
+
else {
|
27
|
+
pyConfig = $('script[type="py"]');
|
28
|
+
config = pyConfig?.getAttribute("config");
|
29
|
+
}
|
30
|
+
|
31
|
+
// generic helper to disambiguate between custom element and script
|
32
|
+
const isScript = element => element.tagName === "SCRIPT";
|
33
|
+
|
34
|
+
// helper for all script[type="py"] out there
|
35
|
+
const before = (script) => {
|
36
|
+
defineProperty(document, "currentScript", {
|
37
|
+
configurable: true,
|
38
|
+
get: () => script,
|
39
|
+
});
|
40
|
+
};
|
41
|
+
|
42
|
+
const after = () => {
|
43
|
+
delete document.currentScript;
|
44
|
+
};
|
45
|
+
|
46
|
+
// define the module as both `<script type="py">` and `<py-script>`
|
47
|
+
define("py", {
|
48
|
+
config,
|
49
|
+
env: "py-script",
|
50
|
+
interpreter: "pyodide",
|
51
|
+
codeBeforeRunWorker: `print("codeBeforeRunWorker")`,
|
52
|
+
codeAfterRunWorker: `print("codeAfterRunWorker")`,
|
53
|
+
onBeforeRun(pyodide, element) {
|
54
|
+
if (isScript(element)) before(element);
|
55
|
+
},
|
56
|
+
onBeforeRunAync(pyodide, element) {
|
57
|
+
if (isScript(element)) before(element);
|
58
|
+
},
|
59
|
+
onAfterRun(pyodide, element) {
|
60
|
+
if (isScript(element)) after();
|
61
|
+
},
|
62
|
+
onAfterRunAsync(pyodide, element) {
|
63
|
+
if (isScript(element)) after();
|
64
|
+
},
|
65
|
+
async onRuntimeReady(pyodide, element) {
|
66
|
+
if (isScript(element)) {
|
67
|
+
const {
|
68
|
+
attributes: { async: isAsync, target },
|
69
|
+
src,
|
70
|
+
} = element;
|
71
|
+
const hasTarget = !!target?.value;
|
72
|
+
const show = hasTarget ?
|
73
|
+
queryTarget(target.value) : document.createElement("script-py");
|
74
|
+
|
75
|
+
if (!hasTarget) element.after(show);
|
76
|
+
if (!show.id) show.id = getID();
|
77
|
+
|
78
|
+
// allows the code to retrieve the target element via
|
79
|
+
// document.currentScript.target if needed
|
80
|
+
defineProperty(element, "target", {value: show});
|
81
|
+
|
82
|
+
const code = src ? (await fetch(src).then(getText)) : element.textContent;
|
83
|
+
pyodide[`run${isAsync ? "Async" : ""}`](code);
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
// resolve PyScriptElement to allow connectedCallback
|
87
|
+
element._pyodide.resolve(pyodide);
|
88
|
+
}
|
89
|
+
},
|
90
|
+
});
|
91
|
+
|
92
|
+
class PyScriptElement extends HTMLElement {
|
93
|
+
constructor() {
|
94
|
+
if (!super().id) this.id = getID();
|
95
|
+
this._pyodide = Promise.withResolvers();
|
96
|
+
}
|
97
|
+
async connectedCallback() {
|
98
|
+
const { run } = await this._pyodide.promise;
|
99
|
+
const result = run(this.textContent);
|
100
|
+
if (result) this.replaceChildren(result);
|
101
|
+
this.style.display = "block";
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
customElements.define("py-script", PyScriptElement);
|
@@ -0,0 +1,141 @@
|
|
1
|
+
'use strict';
|
2
|
+
const { $ } = require("basic-devtools");
|
3
|
+
|
4
|
+
const xworker = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./worker/class.js"));
|
5
|
+
const { getRuntime, getRuntimeID } = require("./loader.js");
|
6
|
+
const { registry } = require("./interpreters.js");
|
7
|
+
const { all, resolve, defineProperty, absoluteURL } = require("./utils.js");
|
8
|
+
const { getText } = require("./fetch-utils.js");
|
9
|
+
|
10
|
+
const getRoot = (script) => {
|
11
|
+
let parent = script;
|
12
|
+
while (parent.parentNode) parent = parent.parentNode;
|
13
|
+
return parent;
|
14
|
+
};
|
15
|
+
|
16
|
+
const queryTarget = (script, idOrSelector) => {
|
17
|
+
const root = getRoot(script);
|
18
|
+
return root.getElementById(idOrSelector) || $(idOrSelector, root);
|
19
|
+
};
|
20
|
+
exports.queryTarget = queryTarget;
|
21
|
+
|
22
|
+
const targets = new WeakMap();
|
23
|
+
const targetDescriptor = {
|
24
|
+
get() {
|
25
|
+
let target = targets.get(this);
|
26
|
+
if (!target) {
|
27
|
+
target = document.createElement(`${this.type}-script`);
|
28
|
+
targets.set(this, target);
|
29
|
+
handle(this);
|
30
|
+
}
|
31
|
+
return target;
|
32
|
+
},
|
33
|
+
set(target) {
|
34
|
+
if (typeof target === "string")
|
35
|
+
targets.set(this, queryTarget(this, target));
|
36
|
+
else {
|
37
|
+
targets.set(this, target);
|
38
|
+
handle(this);
|
39
|
+
}
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
43
|
+
const handled = new WeakMap();
|
44
|
+
|
45
|
+
const interpreters = new Map();
|
46
|
+
exports.interpreters = interpreters;
|
47
|
+
|
48
|
+
const execute = async (script, source, XWorker, isAsync) => {
|
49
|
+
const module = registry.get(script.type);
|
50
|
+
/* c8 ignore next */
|
51
|
+
if (module.experimental)
|
52
|
+
console.warn(`The ${script.type} interpreter is experimental`);
|
53
|
+
const [interpreter, content] = await all([
|
54
|
+
handled.get(script).interpreter,
|
55
|
+
source,
|
56
|
+
]);
|
57
|
+
try {
|
58
|
+
// temporarily override inherited document.currentScript in a non writable way
|
59
|
+
// but it deletes it right after to preserve native behavior (as it's sync: no trouble)
|
60
|
+
defineProperty(document, "currentScript", {
|
61
|
+
configurable: true,
|
62
|
+
get: () => script,
|
63
|
+
});
|
64
|
+
module.setGlobal(interpreter, "XWorker", XWorker);
|
65
|
+
return module[isAsync ? "runAsync" : "run"](interpreter, content);
|
66
|
+
} finally {
|
67
|
+
delete document.currentScript;
|
68
|
+
module.deleteGlobal(interpreter, "XWorker");
|
69
|
+
}
|
70
|
+
};
|
71
|
+
|
72
|
+
const getValue = (ref, prefix) => {
|
73
|
+
const value = ref?.value;
|
74
|
+
return value ? prefix + value : "";
|
75
|
+
};
|
76
|
+
|
77
|
+
const getDetails = (type, id, name, version, config) => {
|
78
|
+
if (!interpreters.has(id)) {
|
79
|
+
const details = {
|
80
|
+
interpreter: getRuntime(name, config),
|
81
|
+
queue: resolve(),
|
82
|
+
XWorker: xworker(type, version),
|
83
|
+
};
|
84
|
+
interpreters.set(id, details);
|
85
|
+
// enable sane defaults when single interpreter *of kind* is used in the page
|
86
|
+
// this allows `xxx-*` attributes to refer to such interpreter without `env` around
|
87
|
+
if (!interpreters.has(type)) interpreters.set(type, details);
|
88
|
+
}
|
89
|
+
return interpreters.get(id);
|
90
|
+
};
|
91
|
+
exports.getDetails = getDetails;
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @param {HTMLScriptElement} script a special type of <script>
|
95
|
+
*/
|
96
|
+
const handle = async (script) => {
|
97
|
+
// known node, move its companion target after
|
98
|
+
// vDOM or other use cases where the script is a tracked element
|
99
|
+
if (handled.has(script)) {
|
100
|
+
const { target } = script;
|
101
|
+
if (target) {
|
102
|
+
// if the script is in the head just append target to the body
|
103
|
+
if (script.closest("head")) document.body.append(target);
|
104
|
+
// in any other case preserve the script position
|
105
|
+
else script.after(target);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
// new script to handle ... allow newly created scripts to work
|
109
|
+
// just exactly like any other script would
|
110
|
+
else {
|
111
|
+
// allow a shared config among scripts, beside interpreter,
|
112
|
+
// and/or source code with different config or interpreter
|
113
|
+
const {
|
114
|
+
attributes: { async: isAsync, config, env, target, version },
|
115
|
+
src,
|
116
|
+
type,
|
117
|
+
} = script;
|
118
|
+
const versionValue = version?.value;
|
119
|
+
const name = getRuntimeID(type, versionValue);
|
120
|
+
const targetValue = getValue(target, "");
|
121
|
+
let configValue = getValue(config, "|");
|
122
|
+
const id = getValue(env, "") || `${name}${configValue}`;
|
123
|
+
configValue = configValue.slice(1);
|
124
|
+
if (configValue) configValue = absoluteURL(configValue);
|
125
|
+
const details = getDetails(type, id, name, versionValue, configValue);
|
126
|
+
|
127
|
+
handled.set(
|
128
|
+
defineProperty(script, "target", targetDescriptor),
|
129
|
+
details,
|
130
|
+
);
|
131
|
+
|
132
|
+
if (targetValue) targets.set(script, queryTarget(script, targetValue));
|
133
|
+
|
134
|
+
// start fetching external resources ASAP
|
135
|
+
const source = src ? fetch(src).then(getText) : script.textContent;
|
136
|
+
details.queue = details.queue.then(() =>
|
137
|
+
execute(script, source, details.XWorker, !!isAsync),
|
138
|
+
);
|
139
|
+
}
|
140
|
+
};
|
141
|
+
exports.handle = handle;
|
package/cjs/toml.js
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
'use strict';
|
2
|
+
// lazy TOML parser (fast-toml might be a better alternative)
|
3
|
+
const TOML_LIB = `https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js`;
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @param {string} text TOML text to parse
|
7
|
+
* @returns {object} the resulting JS object
|
8
|
+
*/
|
9
|
+
const parse = async (text) => (await import(TOML_LIB)).parse(text);
|
10
|
+
exports.parse = parse;
|
package/cjs/utils.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
'use strict';
|
2
|
+
const { isArray } = Array;
|
3
|
+
|
4
|
+
const { assign, create, defineProperties, defineProperty } = Object;
|
5
|
+
|
6
|
+
const { all, resolve } = new Proxy(Promise, {
|
7
|
+
get: ($, name) => $[name].bind($),
|
8
|
+
});
|
9
|
+
|
10
|
+
const absoluteURL = (path, base = location.href) => new URL(path, base).href;
|
11
|
+
|
12
|
+
exports.isArray = isArray;
|
13
|
+
exports.assign = assign;
|
14
|
+
exports.create = create;
|
15
|
+
exports.defineProperties = defineProperties;
|
16
|
+
exports.defineProperty = defineProperty;
|
17
|
+
exports.all = all;
|
18
|
+
exports.resolve = resolve;
|
19
|
+
exports.absoluteURL = absoluteURL;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
'use strict';
|
2
|
+
const coincident = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("coincident/structured"));
|
3
|
+
const xworker = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./xworker.js"));
|
4
|
+
const { assign, defineProperties, absoluteURL } = require("../utils.js");
|
5
|
+
const { getText } = require("../fetch-utils.js");
|
6
|
+
const workerHooks = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("./hooks.js"));
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @typedef {Object} WorkerOptions custom configuration
|
10
|
+
* @prop {string} type the interpreter type to use
|
11
|
+
* @prop {string} [version] the optional interpreter version to use
|
12
|
+
* @prop {string} [config] the optional config to use within such interpreter
|
13
|
+
*/
|
14
|
+
|
15
|
+
module.exports = (...args) =>
|
16
|
+
/**
|
17
|
+
* A XWorker is a Worker facade able to bootstrap a channel with any desired interpreter.
|
18
|
+
* @param {string} url the remote file to evaluate on bootstrap
|
19
|
+
* @param {WorkerOptions} [options] optional arguments to define the interpreter to use
|
20
|
+
* @returns {Worker}
|
21
|
+
*/
|
22
|
+
function XWorker(url, options) {
|
23
|
+
const hooks = workerHooks.get(XWorker);
|
24
|
+
const worker = xworker();
|
25
|
+
const { postMessage } = worker;
|
26
|
+
if (args.length) {
|
27
|
+
const [type, version] = args;
|
28
|
+
options = assign({}, options || { type, version });
|
29
|
+
if (!options.type) options.type = type;
|
30
|
+
}
|
31
|
+
if (options?.config) options.config = absoluteURL(options.config);
|
32
|
+
const bootstrap = fetch(url)
|
33
|
+
.then(getText)
|
34
|
+
.then((code) => postMessage.call(worker, { options, code, hooks }));
|
35
|
+
return defineProperties(worker, {
|
36
|
+
postMessage: {
|
37
|
+
value: (data, ...rest) =>
|
38
|
+
bootstrap.then(() =>
|
39
|
+
postMessage.call(worker, data, ...rest),
|
40
|
+
),
|
41
|
+
},
|
42
|
+
sync: {
|
43
|
+
value: coincident(worker),
|
44
|
+
},
|
45
|
+
});
|
46
|
+
};
|
@@ -0,0 +1,3 @@
|
|
1
|
+
'use strict';
|
2
|
+
/* c8 ignore next */
|
3
|
+
module.exports = () => new Worker(URL.createObjectURL(new Blob(["const e=\"object\"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case\"BigInt\":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r=\"\",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if(\"object\"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case\"Array\":return[1,r];case\"Object\":return[2,r];case\"Date\":return[3,r];case\"RegExp\":return[4,r];case\"Map\":return[5,r];case\"Set\":return[6,r]}return s.includes(\"Array\")?[1,s]:s.includes(\"Error\")?[7,s]:[2,s]},a=([e,t])=>0===e&&(\"function\"===t||\"symbol\"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case\"bigint\":l=8,t=n.toString();break;case\"function\":case\"symbol\":if(e)throw new TypeError(\"unable to serialize \"+u);t=null;break;case\"undefined\":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case\"BigInt\":return i([u,n.toString()],n);case\"Boolean\":case\"Number\":case\"String\":return i([u,n.valueOf()],n)}if(t&&\"toJSON\"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))}),p=e=>({value:new Promise((t=>{let r=new Worker(\"data:application/javascript,\"+encodeURIComponent('onmessage=({data:b})=>(Atomics.wait(b,0),postMessage(\"ok\"))'));r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const d=\"eef159e0-b39b-4e0e-b711-43432daf4928\",{Int32Array:h,Map:w,SharedArrayBuffer:y,Uint16Array:g}=globalThis,{BYTES_PER_ELEMENT:m}=h,{BYTES_PER_ELEMENT:b}=g,{isArray:v}=Array,{notify:$,wait:_,waitAsync:j}=Atomics,{fromCharCode:S}=String,A=(e,t)=>e?(j||p)(t,0):(_(t,0),{value:{then:e=>e()}}),E=new WeakSet,M=new WeakMap;let k=0;const P=(e,{parse:t,stringify:r}=JSON)=>{if(!M.has(e)){const n=(t,...r)=>e.postMessage({[d]:r},{transfer:t});M.set(e,new Proxy(new w,{get:(r,s)=>\"then\"===s?null:(...r)=>{const o=k++;let a=new y(m);const i=new h(a);let c=[];E.has(r.at(-1)||c)&&E.delete(c=r.pop()),n(c,o,a,s,r);const l=e instanceof Worker;return A(l,i).value.then((()=>{const e=i[0];if(!e)return;const r=b*e;return a=new y(r+r%m),n([],o,a),A(l,new h(a)).value.then((()=>t(S(...new g(a).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new w;e.addEventListener(\"message\",(async({data:e})=>{const s=e?.[d];if(v(s)){const[e,o,...a]=s,i=new h(o);if(a.length){const[s,o]=a;if(!t.has(s))throw new Error(`Unsupported action: ${s}`);{const a=r(await t.get(s)(...o));a&&(n.set(e,a),i[0]=a.length)}}else{const t=n.get(e);n.delete(e);for(let e=new g(o),r=0;r<t.length;r++)e[r]=t.charCodeAt(r)}$(i,0)}}))}return!!t.set(n,s)}}))}return M.get(e)},O=e=>P(e,f);O.transfer=P.transfer=(...e)=>(E.add(e),e);const{isArray:x}=Array,{assign:R,create:B,defineProperties:F,defineProperty:T}=Object,{all:W,resolve:G}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),I=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const U=e=>e.arrayBuffer(),L=e=>e.json(),N=e=>e.text(),J=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),z=new WeakMap,C=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return z.set(t,r),t}}},D=e=>{const t=e.split(\"/\");return t.pop(),t.join(\"/\")},q=(e,t)=>{const r=[];for(const n of t.split(\"/\"))r.push(n),n&&e.mkdir(r.join(\"/\"))},Y=(e,t)=>{const r=[];for(const e of t.split(\"/\"))switch(e){case\"\":case\".\":break;case\"..\":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join(\"/\").replace(/^\\/+/,\"/\")},V=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,\"\"))).filter((e=>\"\"!==e&&\".\"!==e)).join(\"/\");return e[0].startsWith(\"/\")?`/${t}`:t},H=new WeakMap,K=(e,t,r)=>W((e=>{for(const{files:t,to_file:r,from:n=\"\"}of e){if(void 0!==t&&void 0!==r)throw new Error(\"Cannot use 'to_file' and 'files' parameters together!\");if(void 0===t&&void 0===r&&n.endsWith(\"/\"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e=\"\",to_folder:t=\".\",to_file:r,files:n})=>{if(x(n))return n.map((r=>({url:V([e,r]),path:V([t,r])})));const s=r||e.slice(1+e.lastIndexOf(\"/\"));return[{url:e,path:V([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(I(t,H.get(e))))(r,n).then(U).then((r=>e.writeFile(t,s,r)))))),Q=(e,t)=>e.runPython(J(t)),X=(e,t)=>e.runPythonAsync(J(t)),Z=({FS:e},t,r)=>((e,t,r)=>{const{parentPath:n,name:s}=e.analyzePath(t,!0);return e.mkdirTree(n),e.writeFile([n,s].join(\"/\"),new Uint8Array(r),{canOwn:!0})})(e,t,r);var ee={type:\"micropython\",module:(e=\"1.20.0-239\")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=C();r=r.replace(/\\.m?js$/,\".wasm\");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await K(this,a,t.fetch),a},setGlobal(e,t,r){const n=`__pyscript_${this.type}_${t}`;globalThis[n]=r,this.run(e,`from js import ${n};${t}=${n};`)},deleteGlobal(e,t){const r=`__pyscript_${this.type}_${t}`;this.run(e,`del ${r};del ${t}`),delete globalThis[r]},run:Q,runAsync:X,writeFile:Z};var te={type:\"pyodide\",module:(e=\"0.23.2\")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=C(),a=r.slice(0,r.lastIndexOf(\"/\")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await K(this,i,t.fetch),t.packages){await i.loadPackage(\"micropip\");const e=await i.pyimport(\"micropip\");await e.install(t.packages),e.destroy()}return i},setGlobal(e,t,r){e.globals.set(t,r)},deleteGlobal(e,t){e.globals.delete(t)},run:Q,runAsync:X,writeFile:Z};const re=\"ruby-wasm-wasi\";var ne={type:re,experimental:!0,module:(e=\"2.0.0\")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf(\"/\"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await K(this,o,t.fetch),o},setGlobal(e,t,r){const n=`__pyscript_ruby_wasm_wasi_${t}`;globalThis[n]=r,this.run(e,`require \"js\";$${t}=JS::eval(\"return ${n}\")`)},deleteGlobal(e,t){const r=`__pyscript_ruby_wasm_wasi_${t}`;this.run(e,`$${t}=nil`),delete globalThis[r]},run:(e,t)=>e.eval(J(t)),runAsync:(e,t)=>e.evalAsync(J(t)),writeFile:()=>{throw new Error(`writeFile is not supported in ${re}`)}};var se={type:\"wasmoon\",module:(e=\"1.15.0\")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=C(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,\"print\",s),a.global.setField(e,\"printErr\",n)})),r.fetch&&await K(this,a,r.fetch),a},setGlobal(e,t,r){e.global.set(t,r)},deleteGlobal(e,t){e.global.set(t,void 0)},run:(e,t)=>e.doStringSync(J(t)),runAsync:(e,t)=>e.doString(J(t)),writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(t=Y(e,t),q(e,D(t)),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const oe=new Map,ae=new Map,ie=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split(\"@\"),s=oe.get(r),o=/^https?:\\/\\//i.test(n)?n.join(\"@\"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{ae.set(t,e);const a=e?.fetch;return a&&H.set(a,o),s(n,e,r)}))}}),ce=e=>{for(const t of[].concat(e.type))oe.set(t,e)};for(const e of[ee,te,ne,se])ce(e);const le=async e=>(await import(\"https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js\")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error([\"Unable to use SharedArrayBuffer due insecure environment.\",\"Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements\"].join(\"\\n\"))}let ue,fe,pe;const de=(e,t)=>{addEventListener(e,t||(async t=>{await ue,pe=t,fe(`xworker.on${e}(xworker.event);`,he)}),!!t&&{once:!0})},he={sync:O(self),onerror(){},onmessage(){},onmessageerror(){},postMessage:postMessage.bind(self),get event(){const e=pe;if(!e)throw new Error(\"Unauthorized event access\");return pe=void 0,e}};de(\"message\",(({data:{options:e,code:t,hooks:r}})=>{ue=(async()=>{const{type:n,version:s,config:o,async:a}=e,i=await((e,t)=>{let r={};if(t)if(t.endsWith(\".json\"))r=fetch(t).then(L);else if(t.endsWith(\".toml\"))r=fetch(t).then(N).then(le);else{try{r=JSON.parse(t)}catch(e){r=le(t)}t=I(\"./config.txt\")}return G(r).then((r=>ie[e](r,t)))})(((e,t=\"\")=>`${e}@${t}`.replace(/@$/,\"\"))(n,s),o),c=B(oe.get(n)),l=\"run\"+(a?\"Async\":\"\");if(r){const{beforeRun:e,beforeRunAsync:t,afterRun:n,afterRunAsync:s}=r,o=n||s,a=e||t;if(o){const e=c[l].bind(c);c[l]=(t,r)=>e(t,`${r}\\n${o}`)}if(a){const e=c[l].bind(c);c[l]=(t,r)=>e(t,`${a}\\n${r}`)}}return c.setGlobal(i,\"xworker\",he),fe=c[l].bind(c,i),fe(t),i})(),de(\"error\"),de(\"message\"),de(\"messageerror\")}));\n"],{type:'application/javascript'})),{type:'module'});
|