diff --git a/test/electron/renderer.js b/test/electron/renderer.js index d662a22..6f1d6bf 100644 --- a/test/electron/renderer.js +++ b/test/electron/renderer.js @@ -16,6 +16,33 @@ ); const { PluginRegistry, createPluginContext } = await import(pathToFileURL(pmEntry).href); + // --------------------------------------------------------------------------- + // Module loader — supports both CJS (module.exports) and ESM (export default) + // --------------------------------------------------------------------------- + + /** + * Evaluates plugin source code and returns the plugin object. + * Tries CJS eval first; falls back to ESM data-URL import for ES module syntax. + * @param {string} code + * @returns {Promise} + */ + async function evalPluginCode(code) { + const isESM = /^\s*(import\s|export\s)/m.test(code); + + if (!isESM) { + // CommonJS path + const m = { exports: {} }; + // eslint-disable-next-line no-new-func + new Function('module', 'exports', code)(m, m.exports); + return m.exports?.default ?? m.exports; + } + + // ESM path — import via data URL so the JS engine handles the module syntax + const dataUrl = `data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`; + const mod = await import(dataUrl); + return mod.default ?? mod; + } + // --------------------------------------------------------------------------- // Logging helper — writes to the on-screen log panel // --------------------------------------------------------------------------- @@ -53,11 +80,7 @@ // --------------------------------------------------------------------------- const pluginPath = path.join(__dirname, 'plugins', 'example-plugin', 'index.js'); const pluginCode = fs.readFileSync(pluginPath, 'utf-8'); - const pluginExports = {}; - const mod = { exports: pluginExports }; - // eslint-disable-next-line no-new-func - new Function('module', 'exports', pluginCode)(mod, pluginExports); - const plugin = mod.exports; + const plugin = await evalPluginCode(pluginCode); // --------------------------------------------------------------------------- // Simple in-process event emitter (stands in for a real client like Matrix) @@ -209,10 +232,7 @@ async function loadPluginFromPath(filePath) { try { const code = fs.readFileSync(filePath, 'utf-8'); - const m = { exports: {} }; - // eslint-disable-next-line no-new-func - new Function('module', 'exports', code)(m, m.exports); - const p = m.exports; + const p = await evalPluginCode(code); if (!p || typeof p.onLoad !== 'function') { throw new Error('File does not export a valid plugin (needs an onLoad function)'); @@ -348,10 +368,7 @@ if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${downloadUrl}`); const code = await res.text(); - const m = { exports: {} }; - // eslint-disable-next-line no-new-func - new Function('module', 'exports', code)(m, m.exports); - const p = m.exports; + const p = await evalPluginCode(code); if (!p || typeof p.onLoad !== 'function') { throw new Error(`Plugin ${pluginId} does not export a valid plugin object`);