'use strict'; const JSON = require('@ungap/structured-clone/json'); const fetch = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require('@webreflection/fetch')); const coincident = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require('coincident/window')); const xworker = (require('./xworker.js')); const { getConfigURLAndType } = require('../loader.js'); const { assign, create, defineProperties, importCSS, importJS } = require('../utils.js'); const Hook = (require('./hook.js')); /** * @typedef {Object} WorkerOptions custom configuration * @prop {string} type the interpreter type to use * @prop {string} [version] the optional interpreter version to use * @prop {string | object} [config] the optional config to use within such interpreter * @prop {string} [configURL] the optional configURL used to resolve config entries */ module.exports = (...args) => /** * 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 interpreter to use * @returns {Worker} */ function XWorker(url, options) { const worker = xworker(); const { postMessage } = worker; const isHook = this instanceof Hook; if (args.length) { const [type, version] = args; options = assign({}, options || { type, version }); if (!options.type) options.type = type; } // provide a base url to fetch or load config files from a Worker // because there's no location at all in the Worker as it's embedded. // fallback to a generic, ignored, config.txt file to still provide a URL. const [ config ] = getConfigURLAndType(options.config, options.configURL); const bootstrap = fetch(url) .text() .then(code => { const hooks = isHook ? this.toJSON() : void 0; postMessage.call(worker, { options, config, code, hooks }); }); const sync = assign( coincident(worker, JSON).proxy, { importJS, importCSS }, ); const resolver = Promise.withResolvers(); defineProperties(worker, { sync: { value: sync }, ready: { value: resolver.promise }, postMessage: { value: (data, ...rest) => bootstrap.then(() => postMessage.call(worker, data, ...rest), ), }, onerror: { writable: true, configurable: true, value: console.error } }); worker.addEventListener('message', event => { const { data } = event; const isError = data instanceof Error; if (isError || data === 'polyscript:done') { event.stopImmediatePropagation(); if (isError) { resolver.reject(data); worker.onerror(create(event, { type: { value: 'error' }, error: { value: data } })); } else resolver.resolve(worker); } }); if (isHook) this.onWorker?.(this.interpreter, worker); return worker; };