import fetch from '@webreflection/fetch'; import { $ } from 'basic-devtools'; import $xworker from './worker/class.js'; import workerURL from './worker/url.js'; import { getRuntime, getRuntimeID } from './loader.js'; import { registry } from './interpreters.js'; import { JSModules, all, dispatch, resolve, defineProperty, nodeInfo, registerJSModules } from './utils.js'; const getRoot = (script) => { let parent = script; while (parent.parentNode) parent = parent.parentNode; return parent; }; export const queryTarget = (script, idOrSelector) => { const root = getRoot(script); return root.getElementById(idOrSelector) || $(idOrSelector, root); }; const targets = new WeakMap(); const targetDescriptor = { get() { let target = targets.get(this); if (!target) { target = document.createElement(`${this.type}-script`); targets.set(this, target); handle(this); } return target; }, set(target) { if (typeof target === 'string') targets.set(this, queryTarget(this, target)); else { targets.set(this, target); handle(this); } }, }; const handled = new WeakMap(); export const interpreters = new Map(); const execute = async (currentScript, source, XWorker, isAsync) => { const { type } = currentScript; const module = registry.get(type); /* c8 ignore start */ if (module.experimental) console.warn(`The ${type} interpreter is experimental`); const [interpreter, content] = await all([ handled.get(currentScript).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) defineProperty(document, 'currentScript', { configurable: true, get: () => currentScript, }); registerJSModules(type, module, interpreter, JSModules); module.registerJSModule(interpreter, 'polyscript', { XWorker, currentScript, js_modules: JSModules, }); dispatch(currentScript, type, 'ready'); const result = module[isAsync ? 'runAsync' : 'run'](interpreter, content); const done = dispatch.bind(null, currentScript, type, 'done'); if (isAsync) result.then(done); else done(); return result; } finally { delete document.currentScript; } /* c8 ignore stop */ }; const getValue = (ref, prefix) => { const value = ref?.value; return value ? prefix + value : ''; }; export const getDetails = (type, id, name, version, config, configURL, runtime = type) => { if (!interpreters.has(id)) { const details = { interpreter: getRuntime(name, config, configURL), queue: resolve(), XWorker: $xworker(type, version), }; 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 /* c8 ignore start *//* this is tested very well in PyScript */ if (!interpreters.has(type)) interpreters.set(type, details); if (!interpreters.has(runtime)) interpreters.set(runtime, details); /* c8 ignore stopt */ } return interpreters.get(id); }; /** * @param {HTMLScriptElement} script a special type of