diff --git a/src/compiler/compile.js b/src/compiler/compile.js index fb431645042..b5edb81352b 100644 --- a/src/compiler/compile.js +++ b/src/compiler/compile.js @@ -1,4 +1,4 @@ -const IRGenerator = require('./irgen'); +const {IRGenerator} = require('./irgen'); const JSGenerator = require('./jsgen'); const compile = thread => { diff --git a/src/compiler/irgen.js b/src/compiler/irgen.js index b5c4fd3bfdf..880aaa82eaf 100644 --- a/src/compiler/irgen.js +++ b/src/compiler/irgen.js @@ -1693,4 +1693,7 @@ class IRGenerator { } } -module.exports = IRGenerator; +module.exports = { + ScriptTreeGenerator, + IRGenerator +}; diff --git a/src/engine/thread.js b/src/engine/thread.js index a4e55504f98..c8cf6cb1c13 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -514,4 +514,7 @@ class Thread { } } +// for extensions +Thread._StackFrame = _StackFrame; + module.exports = Thread; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index fd218be46b2..e1a1fcdea9e 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -220,7 +220,17 @@ class VirtualMachine extends EventEmitter { this.exports = { Sprite, RenderedTarget, - JSZip + JSZip, + + i_will_not_ask_for_help_when_these_break: () => { + console.warn('You are using unsupported APIs. WHEN your code breaks, do not expect help.'); + return ({ + JSGenerator: require('./compiler/jsgen.js'), + IRGenerator: require('./compiler/irgen.js').IRGenerator, + ScriptTreeGenerator: require('./compiler/irgen.js').ScriptTreeGenerator, + Thread: require('./engine/thread.js') + }); + } }; } diff --git a/test/fixtures/tw-block-returning-promise-like.sb3 b/test/fixtures/tw-block-returning-promise-like.sb3 index d7c232ca21a..4ef6f8076e6 100644 Binary files a/test/fixtures/tw-block-returning-promise-like.sb3 and b/test/fixtures/tw-block-returning-promise-like.sb3 differ diff --git a/test/integration/tw_block_returning_promise_like.js b/test/integration/tw_block_returning_promise_like.js index a0e95e8c3e7..e212ef42663 100644 --- a/test/integration/tw_block_returning_promise_like.js +++ b/test/integration/tw_block_returning_promise_like.js @@ -21,13 +21,13 @@ class TestExtension { }; } test () { - // returns a PromiseLike that calls handler immediately. + // returns a PromiseLike that calls handler immediately instead of in next microtask. const promise = { then (callbackFn) { callbackFn(); return promise; } - // intentionally omit catch() as that is not part of PromiseLike + // intentionally omit catch() as that is not part of PromiseLike, so it should not be used }; return promise; } @@ -45,6 +45,10 @@ for (const compilerEnabled of [false, true]) { }); t.equal(vm.runtime.compilerOptions.enabled, compilerEnabled, 'sanity check'); + vm.runtime.on('COMPILE_ERROR', () => { + t.fail('Compile error'); + }); + vm.loadProject(fixture).then(() => { let ended = 0; vm.runtime.on('SAY', (target, type, text) => { diff --git a/test/unit/tw_sandboxed_extensions.js b/test/unit/tw_sandboxed_extensions.js index a763c8b6167..ec0fb4b5620 100644 --- a/test/unit/tw_sandboxed_extensions.js +++ b/test/unit/tw_sandboxed_extensions.js @@ -9,6 +9,9 @@ global.fetch = (url, options = {}) => ( Promise.resolve(`[Response ${url instanceof Request ? url.url : url} options=${JSON.stringify(options)}]`) ); +// Remove navigator object from Node 21 and later +delete global.navigator; + // Need to trick the extension API to think it's running in a worker // It will not actually use this object ever. global.self = {}; diff --git a/test/unit/tw_translate.js b/test/unit/tw_translate.js index 8ac5dc7053c..3e9c9ccf2c5 100644 --- a/test/unit/tw_translate.js +++ b/test/unit/tw_translate.js @@ -6,9 +6,12 @@ global.fetch = () => Promise.reject(new Error('Simulated network error')); const Scratch3TranslateBlocks = require('../../src/extensions/scratch3_translate/index'); -global.navigator = { - language: 'en' -}; +// Node 21 and later defines a navigator object, but we want to override that for the test +Object.defineProperty(global, 'navigator', { + value: { + language: 'en-US' + } +}); // Translate tries to access AbortController from window, but does not require it to exist. global.window = {}; diff --git a/test/unit/tw_unsandboxed_extensions.js b/test/unit/tw_unsandboxed_extensions.js index a4bfdeec4bb..48cf89c12ed 100644 --- a/test/unit/tw_unsandboxed_extensions.js +++ b/test/unit/tw_unsandboxed_extensions.js @@ -52,6 +52,9 @@ global.window = { open: (url, target, features) => `[Window ${url} target=${target || ''} features=${features || ''}]` }; +// Remove navigator object from Node 21 and later +delete global.navigator; + tap.beforeEach(() => { scriptCallbacks.clear(); global.location = {