├── .browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── deploy.yml │ └── node.js.yml ├── .gitignore ├── .jsdoc.json ├── .npmignore ├── .nvmrc ├── .tx └── config ├── CHANGELOG.md ├── LICENSE ├── README.md ├── TRADEMARK ├── docs └── extensions.md ├── package-lock.json ├── package.json ├── release.config.js ├── renovate.json5 ├── src ├── .eslintrc.js ├── blocks │ ├── scratch3_control.js │ ├── scratch3_core_example.js │ ├── scratch3_data.js │ ├── scratch3_event.js │ ├── scratch3_looks.js │ ├── scratch3_motion.js │ ├── scratch3_operators.js │ ├── scratch3_procedures.js │ ├── scratch3_sensing.js │ └── scratch3_sound.js ├── cli │ └── index.js ├── compiler │ ├── compat-block-utility.js │ ├── compat-blocks.js │ ├── compile.js │ ├── environment.js │ ├── intermediate.js │ ├── irgen.js │ ├── jsexecute.js │ ├── jsgen.js │ └── variable-pool.js ├── dispatch │ ├── central-dispatch.js │ ├── shared-dispatch.js │ └── worker-dispatch.js ├── engine │ ├── adapter.js │ ├── block-utility.js │ ├── blocks-execute-cache.js │ ├── blocks-runtime-cache.js │ ├── blocks.js │ ├── comment.js │ ├── execute.js │ ├── monitor-record.js │ ├── mutation-adapter.js │ ├── profiler.js │ ├── runtime.js │ ├── scratch-blocks-constants.js │ ├── sequencer.js │ ├── stage-layering.js │ ├── target.js │ ├── thread.js │ ├── tw-font-manager.js │ ├── tw-frame-loop.js │ ├── tw-interpolate.js │ ├── tw-platform.js │ └── variable.js ├── extension-support │ ├── argument-type.js │ ├── block-type.js │ ├── define-messages.js │ ├── extension-manager.js │ ├── extension-metadata.js │ ├── extension-worker.js │ ├── reporter-scope.js │ ├── target-type.js │ ├── tw-block-shape.js │ ├── tw-default-extension-urls.js │ ├── tw-extension-api-common.js │ ├── tw-extension-worker-context.js │ ├── tw-iframe-extension-worker-entry.js │ ├── tw-iframe-extension-worker.js │ ├── tw-jquery-shim.js │ ├── tw-l10n.js │ ├── tw-load-script-as-plain-text.js │ ├── tw-scratchx-compatibility-layer.js │ ├── tw-scratchx-utilities.js │ ├── tw-security-manager.js │ └── tw-unsandboxed-extension-runner.js ├── extensions │ ├── scratch3_boost │ │ └── index.js │ ├── scratch3_ev3 │ │ └── index.js │ ├── scratch3_gdx_for │ │ ├── index.js │ │ └── scratch-link-device-adapter.js │ ├── scratch3_makeymakey │ │ └── index.js │ ├── scratch3_microbit │ │ └── index.js │ ├── scratch3_music │ │ ├── assets │ │ │ ├── drums │ │ │ │ ├── 1-snare.mp3 │ │ │ │ ├── 10-wood-block.mp3 │ │ │ │ ├── 11-cowbell.mp3 │ │ │ │ ├── 12-triangle.mp3 │ │ │ │ ├── 13-bongo.mp3 │ │ │ │ ├── 14-conga.mp3 │ │ │ │ ├── 15-cabasa.mp3 │ │ │ │ ├── 16-guiro.mp3 │ │ │ │ ├── 17-vibraslap.mp3 │ │ │ │ ├── 18-cuica.mp3 │ │ │ │ ├── 2-bass-drum.mp3 │ │ │ │ ├── 3-side-stick.mp3 │ │ │ │ ├── 4-crash-cymbal.mp3 │ │ │ │ ├── 5-open-hi-hat.mp3 │ │ │ │ ├── 6-closed-hi-hat.mp3 │ │ │ │ ├── 7-tambourine.mp3 │ │ │ │ ├── 8-hand-clap.mp3 │ │ │ │ └── 9-claves.mp3 │ │ │ └── instruments │ │ │ │ ├── 1-piano │ │ │ │ ├── 108.mp3 │ │ │ │ ├── 24.mp3 │ │ │ │ ├── 36.mp3 │ │ │ │ ├── 48.mp3 │ │ │ │ ├── 60.mp3 │ │ │ │ ├── 72.mp3 │ │ │ │ ├── 84.mp3 │ │ │ │ └── 96.mp3 │ │ │ │ ├── 10-clarinet │ │ │ │ ├── 48.mp3 │ │ │ │ └── 60.mp3 │ │ │ │ ├── 11-saxophone │ │ │ │ ├── 36.mp3 │ │ │ │ ├── 60.mp3 │ │ │ │ └── 84.mp3 │ │ │ │ ├── 12-flute │ │ │ │ ├── 60.mp3 │ │ │ │ └── 72.mp3 │ │ │ │ ├── 13-wooden-flute │ │ │ │ ├── 60.mp3 │ │ │ │ └── 72.mp3 │ │ │ │ ├── 14-bassoon │ │ │ │ ├── 36.mp3 │ │ │ │ ├── 48.mp3 │ │ │ │ └── 60.mp3 │ │ │ │ ├── 15-choir │ │ │ │ ├── 48.mp3 │ │ │ │ ├── 60.mp3 │ │ │ │ └── 72.mp3 │ │ │ │ ├── 16-vibraphone │ │ │ │ ├── 60.mp3 │ │ │ │ └── 72.mp3 │ │ │ │ ├── 17-music-box │ │ │ │ └── 60.mp3 │ │ │ │ ├── 18-steel-drum │ │ │ │ └── 60.mp3 │ │ │ │ ├── 19-marimba │ │ │ │ └── 60.mp3 │ │ │ │ ├── 2-electric-piano │ │ │ │ └── 60.mp3 │ │ │ │ ├── 20-synth-lead │ │ │ │ └── 60.mp3 │ │ │ │ ├── 21-synth-pad │ │ │ │ └── 60.mp3 │ │ │ │ ├── 3-organ │ │ │ │ └── 60.mp3 │ │ │ │ ├── 4-guitar │ │ │ │ └── 60.mp3 │ │ │ │ ├── 5-electric-guitar │ │ │ │ └── 60.mp3 │ │ │ │ ├── 6-bass │ │ │ │ ├── 36.mp3 │ │ │ │ └── 48.mp3 │ │ │ │ ├── 7-pizzicato │ │ │ │ └── 60.mp3 │ │ │ │ ├── 8-cello │ │ │ │ ├── 36.mp3 │ │ │ │ ├── 48.mp3 │ │ │ │ └── 60.mp3 │ │ │ │ └── 9-trombone │ │ │ │ ├── 36.mp3 │ │ │ │ ├── 48.mp3 │ │ │ │ └── 60.mp3 │ │ ├── index.js │ │ └── manifest.js │ ├── scratch3_pen │ │ └── index.js │ ├── scratch3_speech2text │ │ └── index.js │ ├── scratch3_text2speech │ │ └── index.js │ ├── scratch3_translate │ │ └── index.js │ ├── scratch3_video_sensing │ │ ├── debug.js │ │ ├── index.js │ │ ├── library.js │ │ ├── math.js │ │ └── view.js │ ├── scratch3_wedo2 │ │ └── index.js │ └── tw │ │ └── index.js ├── import │ ├── load-costume.js │ └── load-sound.js ├── index.js ├── io │ ├── ble.js │ ├── bt.js │ ├── clock.js │ ├── cloud.js │ ├── keyboard.js │ ├── mouse.js │ ├── mouseWheel.js │ ├── userData.js │ └── video.js ├── playground │ ├── benchmark.css │ ├── benchmark.js │ ├── index.html │ ├── suite.css │ ├── suite.html │ ├── suite.js │ ├── video-sensing.html │ └── video-sensing.js ├── serialization │ ├── deserialize-assets.js │ ├── sb2.js │ ├── sb2_specmap.js │ ├── sb3.js │ ├── serialize-assets.js │ ├── tw-compress-sb3.js │ └── tw-costume-import-export.js ├── sprites │ ├── rendered-target.js │ └── sprite.js ├── util │ ├── async-limiter.js │ ├── base64-util.js │ ├── cast.js │ ├── clone.js │ ├── color.js │ ├── fetch-with-timeout.js │ ├── get-monitor-id.js │ ├── jsonrpc.js │ ├── log.js │ ├── math-util.js │ ├── maybe-format-message.js │ ├── new-block-ids.js │ ├── rateLimiter.js │ ├── scratch-link-websocket.js │ ├── string-util.js │ ├── task-queue.js │ ├── timer.js │ ├── tw-asset-util.js │ ├── tw-static-fetch.js │ ├── uid.js │ ├── variable-util.js │ └── xml-escape.js └── virtual-machine.js ├── test ├── .eslintrc.js ├── fixtures │ ├── block-to-workspace-comments-without-scripts.sb2 │ ├── block-to-workspace-comments.sb2 │ ├── broadcast_special_chars.sb2 │ ├── broadcast_special_chars.sb3 │ ├── cat.sprite2 │ ├── cat.sprite3 │ ├── clone-cleanup.sb2 │ ├── cloud_variables_exceeded_limit.sb2 │ ├── cloud_variables_exceeded_limit.sb3 │ ├── cloud_variables_limit.sb2 │ ├── cloud_variables_limit.sb3 │ ├── cloud_variables_local.sb2 │ ├── cloud_variables_local.sb3 │ ├── cloud_variables_simple.sb2 │ ├── cloud_variables_simple.sb3 │ ├── comments.sb2 │ ├── comments.sb3 │ ├── comments_no_duplicate_id_serialization.sb3 │ ├── complex.sb2 │ ├── control.sb2 │ ├── corrupt_png.sb2 │ ├── corrupt_png.sb3 │ ├── corrupt_png.sprite2 │ ├── corrupt_png.sprite3 │ ├── corrupt_sound.sb3 │ ├── corrupt_svg.sb2 │ ├── corrupt_svg.sb3 │ ├── corrupt_svg.sprite2 │ ├── corrupt_svg.sprite3 │ ├── data.sb2 │ ├── default.sb2 │ ├── default.sb3 │ ├── default_nested.sb2 │ ├── demo.json │ ├── dispatch-test-service.js │ ├── dispatch-test-worker-shim.js │ ├── dispatch-test-worker.js │ ├── draggable.sb3 │ ├── edge-triggered-hat.sb3 │ ├── event.sb2 │ ├── events.json │ ├── example_sprite.sprite2 │ ├── execute │ │ ├── README.md │ │ ├── broadcast-wait-arg-change.sb2 │ │ ├── control-if-false-then-else.sb2 │ │ ├── control-if-false-then.sb2 │ │ ├── control-if-true-then-else.sb2 │ │ ├── control-if-true-then.sb2 │ │ ├── control-stop-all-leaks.sb2 │ │ ├── data-operators-global.sb2 │ │ ├── data-operators-local.sb2 │ │ ├── data-reporter-contents-global.sb2 │ │ ├── data-reporter-contents-local.sb2 │ │ ├── event-broadcast-and-wait-can-continue-same-tick.sb2 │ │ ├── event-when-green-flag.sb2 │ │ ├── events-broadcast-and-wait-yields-a-tick.sb2 │ │ ├── hat-thread-execution.sb2 │ │ ├── monitors-stage-name.sb2 │ │ ├── operators-not-blank.sb2 │ │ ├── order-changes-back-2-broadcast-wait.sb2 │ │ ├── order-changes-backwards-2-broadcast-and-wait-repeat-message.sb2 │ │ ├── order-changes-backwards-2-broadcast-and-wait.sb2 │ │ ├── order-changes-backwards-2-broadcast-no-wait.sb2 │ │ ├── order-changes-backwards-2-broadcast-wait.sb2 │ │ ├── order-changes-backwards-2-continuous.sb2 │ │ ├── order-changes-backwards-2-threads-broadcast-wait.sb2 │ │ ├── order-changes-forewards-2-broadcast-wait.sb2 │ │ ├── order-changes-front-2-broadcast-wait.sb2 │ │ ├── order-clones-backwards-2-broadcast-wait.sb2 │ │ ├── order-clones-backwards-broadcast-wait.sb2 │ │ ├── order-clones-static-2.sb2 │ │ ├── order-immobile-stage.sb2 │ │ ├── order-library-reverse.sb2 │ │ ├── order-library-reverse.sb3 │ │ ├── order-library.sb2 │ │ ├── order-library.sb3 │ │ ├── procedures-boolean-reporter-bug.sb2 │ │ ├── procedures-nested-missing-boolean-param.sb2 │ │ ├── procedures-nested-missing-no-param.sb2 │ │ ├── procedures-nested-missing-number-param.sb2 │ │ ├── procedures-nested-missing-string-param.sb2 │ │ ├── procedures-number-number-boolean.sb2 │ │ ├── procedures-param-outside-boolean.sb2 │ │ ├── procedures-param-outside-number.sb2 │ │ ├── procedures-param-outside-string.sb2 │ │ ├── procedures-recursive-default-boolean.sb2 │ │ ├── procedures-recursive-default-number.sb2 │ │ ├── procedures-recursive-default-string.sb2 │ │ ├── sensing-get-attribute-of-stage-alt-name.sb2 │ │ ├── sprite-number-name.sb2 │ │ ├── tw-NaN.sb3 │ │ ├── tw-add-can-return-nan.sb3 │ │ ├── tw-all-at-once.sb3 │ │ ├── tw-automatic-variable-creation-literal-null-id.sb3 │ │ ├── tw-block-with-null-for-variable-id.sb3 │ │ ├── tw-boolean-arguments-are-not-cast.sb3 │ │ ├── tw-broadcast-id-and-name-desync.sb3 │ │ ├── tw-change-size-does-not-use-rounded-size.sb3 │ │ ├── tw-color-input-returns-hex.sb3 │ │ ├── tw-comparison-matrix-inline.sb3 │ │ ├── tw-comparison-matrix-runtime.sb3 │ │ ├── tw-compatibility-layer-type-barrier.sb3 │ │ ├── tw-coordinate-precision.sb3 │ │ ├── tw-counter.sb3 │ │ ├── tw-custom-report-repeat.sb3 │ │ ├── tw-forkphorus-515-boolean-number-comparison.sb3 │ │ ├── tw-forkphorus-515-non-finite-direction.sb3 │ │ ├── tw-forkphorus-515-random-with-invalid-number-with-period.sb3 │ │ ├── tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3 │ │ ├── tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3 │ │ ├── tw-generate-comparison-matrix-inline.js │ │ ├── tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3 │ │ ├── tw-gh-249-quicksort.sb3 │ │ ├── tw-list-any.sb3 │ │ ├── tw-obsolete-blocks.sb3 │ │ ├── tw-one-divide-negative-zero.sb3 │ │ ├── tw-preciseProjectTimer-drift-453118719.sb3 │ │ ├── tw-prefers-first-occurence-of-procedure-387608267.sb3 │ │ ├── tw-procedure-arguments-with-same-name.sb3 │ │ ├── tw-procedure-call-resets-variable-input-types-430811055.sb3 │ │ ├── tw-procedure-prototype-exists-but-not-definition-549160843.sb3 │ │ ├── tw-procedure-return-non-existant.sb3 │ │ ├── tw-procedure-return-non-existent.sb3 │ │ ├── tw-procedure-return-recursion.sb3 │ │ ├── tw-procedure-return-simple.sb3 │ │ ├── tw-procedure-return-stops-scripts.sb3 │ │ ├── tw-procedure-return-warp.sb3 │ │ ├── tw-promise-loop-double-yield-kouzeru.sb3 │ │ ├── tw-restart-broadcast-threads.sb3 │ │ ├── tw-safe-procedure-argument-casting.sb3 │ │ ├── tw-self-restarting-script-keeps-running-until-yield.sb3 │ │ ├── tw-sensing-of.sb3 │ │ ├── tw-stage-cannot-move-layers.sb3 │ │ ├── tw-subtract-can-return-nan.sb3 │ │ ├── tw-tab-equals-zero.sb3 │ │ ├── tw-tangent.sb3 │ │ ├── tw-unsafe-equals.sb3 │ │ ├── tw-warp-repeat-until-timer-greater-than.sb3 │ │ ├── tw-when-backdrop-switches-to-next-backdrop.sb3 │ │ ├── tw-when-backdrop-switches-to-switch-backdrop-to.sb3 │ │ └── tw-zombie-cube-escape-284516654.sb3 │ ├── fake-bitmap-adapter.js │ ├── fake-renderer.js │ ├── hat-execution-order.sb2 │ ├── invisible-tempo-monitor-no-other-music-blocks.sb2 │ ├── invisible-video-monitor.sb2 │ ├── list-monitor-rename.sb3 │ ├── load-extensions │ │ ├── README.md │ │ ├── confirm-load │ │ │ ├── ev3-simple-project.sb3 │ │ │ ├── microbit-simple-project.sb3 │ │ │ ├── music-simple-project.sb2 │ │ │ ├── music-simple-project.sb3 │ │ │ ├── pen-dolphin-3d.sb2 │ │ │ ├── pen-dolphin-3d.sb3 │ │ │ ├── pen-simple-project.sb2 │ │ │ ├── pen-simple-project.sb3 │ │ │ ├── text2speech-simple-project.sb3 │ │ │ ├── videoSensing-simple-project.sb2 │ │ │ ├── videoSensing-simple-project.sb3 │ │ │ ├── wedo2-simple-project.sb2 │ │ │ └── wedo2-simple-project.sb3 │ │ ├── music-visible-monitor-no-blocks.sb2 │ │ └── video-state │ │ │ ├── videoState-off.sb2 │ │ │ └── videoState-on-transparency-0.sb2 │ ├── looks.sb2 │ ├── make-test-storage.js │ ├── missing_png.sb2 │ ├── missing_png.sb3 │ ├── missing_png.sprite2 │ ├── missing_png.sprite3 │ ├── missing_sound.sb3 │ ├── missing_svg.sb2 │ ├── missing_svg.sb3 │ ├── missing_svg.sprite2 │ ├── missing_svg.sprite3 │ ├── mock-timer.js │ ├── monitored_variables.sb3 │ ├── monitors.sb2 │ ├── monitors.sb3 │ ├── motion.sb2 │ ├── offline-custom-assets.sb2 │ ├── ordering.sb2 │ ├── origin-absent.sb3 │ ├── origin.sb3 │ ├── pen.sb2 │ ├── procedure.sb2 │ ├── readProjectFile.js │ ├── saythink-and-wait.sb2 │ ├── sb2-from-sb1-missing-backdrop-image.sb2 │ ├── sensing.sb2 │ ├── simple-stack.js │ ├── single_sound.sb │ ├── sound.sb2 │ ├── sprite.json │ ├── stack-click.sb2 │ ├── test-compare.js │ ├── timer-greater-than-hat.sb2 │ ├── timer-monitor.sb3 │ ├── top-level-reporters.sb3 │ ├── top-level-variable-reporter.sb2 │ ├── tw-add-builtin-extension.sb3 │ ├── tw-addon-blocks.sb3 │ ├── tw-asset-progress.sb │ ├── tw-asset-progress.sb2 │ ├── tw-asset-progress.sb3 │ ├── tw-beyond-branchCount.sb3 │ ├── tw-block-returning-promise-like.sb3 │ ├── tw-block-stop-thread.sb3 │ ├── tw-conditional.sb3 │ ├── tw-edge-activated-hat-returns-promise.sb3 │ ├── tw-empty-project.sb3 │ ├── tw-extension-storage-no-data.sb3 │ ├── tw-extension-storage.sb3 │ ├── tw-glide.sb3 │ ├── tw-hats-and-events.sb3 │ ├── tw-last-block-in-loop-returns-promise.sb3 │ ├── tw-loop.sb3 │ ├── tw-mixed-file-formats.sb3 │ ├── tw-project-using-xml-extension.sb3 │ ├── tw-project-with-extensions.sb3 │ ├── tw-rejected-promise-command.sb3 │ ├── tw-rejected-promise-reporter.sb3 │ ├── tw-save-project-sb3.sb3 │ ├── tw-serialize-asset-order.sb3 │ ├── tw-slow-custom-reporter-stack-click.sb3 │ ├── tw-stackframe-op.sb3 │ ├── tw-stored-settings │ │ ├── empty-comment.sb3 │ │ ├── no-comment.sb3 │ │ ├── sprite.sb3 │ │ └── turbo-mode.sb3 │ ├── tw-very-long-comments.sb3 │ ├── tw_mock_blob.js │ ├── unknown-opcode-as-reporter-block.sb2 │ ├── unknown-opcode-in-c-block.sb2 │ ├── unknown-opcode.sb2 │ ├── variable_characters.sb2 │ ├── variable_characters.sb3 │ ├── visible-tempo-monitor-no-other-music-blocks.sb2 │ ├── visible-video-monitor-and-video-blocks.sb2 │ ├── visible-video-monitor-no-other-video-blocks.sb2 │ └── when-clicked.sb2 ├── integration │ ├── addSprite.js │ ├── block_to_workspace_comment_import.js │ ├── block_to_workspace_comment_import_no_scripts.js │ ├── broadcast_special_chars_sb2.js │ ├── broadcast_special_chars_sb3.js │ ├── clone-cleanup.js │ ├── cloud_variables_sb2.js │ ├── cloud_variables_sb3.js │ ├── comments.js │ ├── comments_sb3.js │ ├── complex.js │ ├── control.js │ ├── data.js │ ├── delete-and-restore-sprite.js │ ├── event.js │ ├── execute.js │ ├── hat-execution-order.js │ ├── hat-threads-run-every-frame.js │ ├── import-sb.js │ ├── import-sb2-from-object.js │ ├── import_nested_sb2.js │ ├── import_sb2.js │ ├── internal-extension.js │ ├── list-monitor-rename.js │ ├── load-extensions.js │ ├── load-sb2-originally-sb1-without-backdrop-image.js │ ├── looks.js │ ├── monitor-threads-run-every-frame.js │ ├── monitors_sb2.js │ ├── monitors_sb2_to_sb3.js │ ├── monitors_sb3.js │ ├── motion.js │ ├── offline-custom-assets.js │ ├── pen.js │ ├── procedure.js │ ├── runId.js │ ├── running_project_changed_state.js │ ├── saythink-and-wait.js │ ├── sb2-import-extension-monitors.js │ ├── sb2_corrupted_png.js │ ├── sb2_corrupted_svg.js │ ├── sb2_missing_png.js │ ├── sb2_missing_svg.js │ ├── sb3-roundtrip.js │ ├── sb3_corrupted_png.js │ ├── sb3_corrupted_sound.js │ ├── sb3_corrupted_svg.js │ ├── sb3_missing_png.js │ ├── sb3_missing_sound.js │ ├── sb3_missing_svg.js │ ├── sensing.js │ ├── sound.js │ ├── sprite2_corrupted_png.js │ ├── sprite2_corrupted_svg.js │ ├── sprite2_missing_png.js │ ├── sprite2_missing_svg.js │ ├── sprite3_corrupted_png.js │ ├── sprite3_corrupted_svg.js │ ├── sprite3_missing_png.js │ ├── sprite3_missing_svg.js │ ├── stack-click.js │ ├── tw-block-stop-thread.js │ ├── tw-snapshots.js │ ├── tw_add_builtin_extension.js │ ├── tw_addon_blocks.js │ ├── tw_allow_drop_anywhere.js │ ├── tw_asset_progress.js │ ├── tw_automatic_variable_creation.js │ ├── tw_block_returning_promise_like.js │ ├── tw_compat_block_utility_stackframe_exposed.js │ ├── tw_compression_per_file_type.js │ ├── tw_conditional_and_loop.js │ ├── tw_default_extension_url.js │ ├── tw_deterministic_sb3.js │ ├── tw_edge_activated_hat_returns_promise.js │ ├── tw_extension_and_block_xml.js │ ├── tw_extension_buttons.js │ ├── tw_extension_storage.js │ ├── tw_font_manager.js │ ├── tw_get_exported_costume.js │ ├── tw_hats_and_events.js │ ├── tw_import_sbx.js │ ├── tw_label_block.js │ ├── tw_last_block_in_loop_returns_promise.js │ ├── tw_load_svg_with_stored_center.js │ ├── tw_packaged_runtime.js │ ├── tw_platform.js │ ├── tw_privacy.js │ ├── tw_rejected_promise.js │ ├── tw_save_project_sb3.js │ ├── tw_security_manager.js │ ├── tw_serialize_asset_order.js │ ├── tw_serialize_extension_only_used_by_monitor.js │ ├── tw_serialize_extensions.js │ ├── tw_serialize_hidden_monitors.js │ ├── tw_slow_custom_reporter_stack_click.js │ ├── tw_stackframe_op.js │ ├── tw_standalone_blocks.js │ ├── tw_step_events.js │ ├── tw_very_long_comments.js │ ├── tw_xml_block.js │ ├── unknown-opcode-as-reporter-block.js │ ├── unknown-opcode-in-c-block.js │ ├── unknown-opcode.js │ ├── variable_monitor_reset.js │ ├── variable_special_chars_sb2.js │ └── variable_special_chars_sb3.js ├── snapshot │ ├── README.md │ ├── __snapshots__ │ │ ├── order-library-reverse.sb3.tw-snapshot │ │ ├── order-library.sb3.tw-snapshot │ │ ├── tw-NaN.sb3.tw-snapshot │ │ ├── tw-add-can-return-nan.sb3.tw-snapshot │ │ ├── tw-all-at-once.sb3.tw-snapshot │ │ ├── tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot │ │ ├── tw-block-with-null-for-variable-id.sb3.tw-snapshot │ │ ├── tw-boolean-arguments-are-not-cast.sb3.tw-snapshot │ │ ├── tw-broadcast-id-and-name-desync.sb3.tw-snapshot │ │ ├── tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot │ │ ├── tw-color-input-returns-hex.sb3.tw-snapshot │ │ ├── tw-comparison-matrix-inline.sb3.tw-snapshot │ │ ├── tw-comparison-matrix-runtime.sb3.tw-snapshot │ │ ├── tw-compatibility-layer-type-barrier.sb3.tw-snapshot │ │ ├── tw-coordinate-precision.sb3.tw-snapshot │ │ ├── tw-counter.sb3.tw-snapshot │ │ ├── tw-custom-report-repeat.sb3.tw-snapshot │ │ ├── tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot │ │ ├── tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot │ │ ├── tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot │ │ ├── tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot │ │ ├── tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot │ │ ├── tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot │ │ ├── tw-gh-249-quicksort.sb3.tw-snapshot │ │ ├── tw-list-any.sb3.tw-snapshot │ │ ├── tw-loop-custom-reporter.sb3.tw-snapshot │ │ ├── tw-obsolete-blocks.sb3.tw-snapshot │ │ ├── tw-one-divide-negative-zero.sb3.tw-snapshot │ │ ├── tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot │ │ ├── tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot │ │ ├── tw-procedure-arguments-with-same-name.sb3.tw-snapshot │ │ ├── tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot │ │ ├── tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot │ │ ├── tw-procedure-return-non-existant.sb3.tw-snapshot │ │ ├── tw-procedure-return-non-existent.sb3.tw-snapshot │ │ ├── tw-procedure-return-recursion.sb3.tw-snapshot │ │ ├── tw-procedure-return-simple.sb3.tw-snapshot │ │ ├── tw-procedure-return-stops-scripts.sb3.tw-snapshot │ │ ├── tw-procedure-return-warp.sb3.tw-snapshot │ │ ├── tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot │ │ ├── tw-restart-broadcast-threads.sb3.tw-snapshot │ │ ├── tw-safe-procedure-argument-casting.sb3.tw-snapshot │ │ ├── tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot │ │ ├── tw-sensing-of.sb3.tw-snapshot │ │ ├── tw-stage-cannot-move-layers.sb3.tw-snapshot │ │ ├── tw-subtract-can-return-nan.sb3.tw-snapshot │ │ ├── tw-tab-equals-zero.sb3.tw-snapshot │ │ ├── tw-tangent.sb3.tw-snapshot │ │ ├── tw-unsafe-equals.sb3.tw-snapshot │ │ ├── tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot │ │ ├── tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot │ │ ├── tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot │ │ ├── tw-zombie-cube-escape-284516654.sb3.tw-snapshot │ │ └── warp-timer │ │ │ ├── order-library-reverse.sb3.tw-snapshot │ │ │ ├── order-library.sb3.tw-snapshot │ │ │ ├── tw-NaN.sb3.tw-snapshot │ │ │ ├── tw-add-can-return-nan.sb3.tw-snapshot │ │ │ ├── tw-all-at-once.sb3.tw-snapshot │ │ │ ├── tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot │ │ │ ├── tw-block-with-null-for-variable-id.sb3.tw-snapshot │ │ │ ├── tw-boolean-arguments-are-not-cast.sb3.tw-snapshot │ │ │ ├── tw-broadcast-id-and-name-desync.sb3.tw-snapshot │ │ │ ├── tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot │ │ │ ├── tw-color-input-returns-hex.sb3.tw-snapshot │ │ │ ├── tw-comparison-matrix-inline.sb3.tw-snapshot │ │ │ ├── tw-comparison-matrix-runtime.sb3.tw-snapshot │ │ │ ├── tw-compatibility-layer-type-barrier.sb3.tw-snapshot │ │ │ ├── tw-coordinate-precision.sb3.tw-snapshot │ │ │ ├── tw-counter.sb3.tw-snapshot │ │ │ ├── tw-custom-report-repeat.sb3.tw-snapshot │ │ │ ├── tw-forkphorus-515-boolean-number-comparison.sb3.tw-snapshot │ │ │ ├── tw-forkphorus-515-non-finite-direction.sb3.tw-snapshot │ │ │ ├── tw-forkphorus-515-random-with-invalid-number-with-period.sb3.tw-snapshot │ │ │ ├── tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot │ │ │ ├── tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3.tw-snapshot │ │ │ ├── tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot │ │ │ ├── tw-gh-249-quicksort.sb3.tw-snapshot │ │ │ ├── tw-list-any.sb3.tw-snapshot │ │ │ ├── tw-loop-custom-reporter.sb3.tw-snapshot │ │ │ ├── tw-obsolete-blocks.sb3.tw-snapshot │ │ │ ├── tw-one-divide-negative-zero.sb3.tw-snapshot │ │ │ ├── tw-preciseProjectTimer-drift-453118719.sb3.tw-snapshot │ │ │ ├── tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot │ │ │ ├── tw-procedure-arguments-with-same-name.sb3.tw-snapshot │ │ │ ├── tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot │ │ │ ├── tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-non-existant.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-non-existent.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-recursion.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-simple.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-stops-scripts.sb3.tw-snapshot │ │ │ ├── tw-procedure-return-warp.sb3.tw-snapshot │ │ │ ├── tw-promise-loop-double-yield-kouzeru.sb3.tw-snapshot │ │ │ ├── tw-restart-broadcast-threads.sb3.tw-snapshot │ │ │ ├── tw-safe-procedure-argument-casting.sb3.tw-snapshot │ │ │ ├── tw-self-restarting-script-keeps-running-until-yield.sb3.tw-snapshot │ │ │ ├── tw-sensing-of.sb3.tw-snapshot │ │ │ ├── tw-stage-cannot-move-layers.sb3.tw-snapshot │ │ │ ├── tw-subtract-can-return-nan.sb3.tw-snapshot │ │ │ ├── tw-tab-equals-zero.sb3.tw-snapshot │ │ │ ├── tw-tangent.sb3.tw-snapshot │ │ │ ├── tw-unsafe-equals.sb3.tw-snapshot │ │ │ ├── tw-warp-repeat-until-timer-greater-than.sb3.tw-snapshot │ │ │ ├── tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot │ │ │ ├── tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot │ │ │ └── tw-zombie-cube-escape-284516654.sb3.tw-snapshot │ ├── index.js │ └── lib.js └── unit │ ├── blocks_control.js │ ├── blocks_data.js │ ├── blocks_data_infinity.js │ ├── blocks_event.js │ ├── blocks_looks.js │ ├── blocks_motion.js │ ├── blocks_operators.js │ ├── blocks_operators_infinity.js │ ├── blocks_pen_tw.js │ ├── blocks_procedures.js │ ├── blocks_sensing.js │ ├── blocks_sound_tw.js │ ├── blocks_sounds.js │ ├── dispatch.js │ ├── engine_adapter.js │ ├── engine_blocks.js │ ├── engine_mutation-adapter.js │ ├── engine_runtime.js │ ├── engine_runtime_tw.js │ ├── engine_sequencer.js │ ├── engine_target.js │ ├── engine_thread.js │ ├── engine_variable.js │ ├── extension_conversion.js │ ├── extension_microbit.js │ ├── extension_music.js │ ├── extension_text_to_speech.js │ ├── extension_video_sensing.js │ ├── extension_video_sensing_center.png │ ├── extension_video_sensing_down-10.png │ ├── extension_video_sensing_left-10.png │ ├── extension_video_sensing_left-5.png │ ├── io_clock.js │ ├── io_cloud.js │ ├── io_keyboard.js │ ├── io_keyboard_tw.js │ ├── io_mouse.js │ ├── io_mouse_tw.js │ ├── io_mousewheel.js │ ├── io_scratchBLE.js │ ├── io_scratchBT.js │ ├── io_userData.js │ ├── maybe_format_message.js │ ├── mock-timer.js │ ├── project_changed_state.js │ ├── project_changed_state_blocks.js │ ├── project_load_changed_state.js │ ├── serialization_sb2.js │ ├── serialization_sb3.js │ ├── spec.js │ ├── sprites_rendered-target.js │ ├── tw_asset_util.js │ ├── tw_block_colors.js │ ├── tw_block_extensions.js │ ├── tw_block_shape.js │ ├── tw_branch_icon_uri.js │ ├── tw_cast.js │ ├── tw_clones.js │ ├── tw_compress.js │ ├── tw_costume_and_sound_inputs.js │ ├── tw_costume_import_export.js │ ├── tw_extension_api_common.js │ ├── tw_extension_manager.js │ ├── tw_extension_monitors.js │ ├── tw_extension_music.js │ ├── tw_jsexecute.js │ ├── tw_mouse.js │ ├── tw_number_argument.js │ ├── tw_performance_measure_error.js │ ├── tw_sandboxed_extensions.js │ ├── tw_scratchx.js │ ├── tw_static_fetch.js │ ├── tw_stop_this_script.js │ ├── tw_stored_settings.js │ ├── tw_translate.js │ ├── tw_unsandboxed_extensions.js │ ├── tw_util_async_limiter.js │ ├── tw_util_string.js │ ├── tw_vm_exports.js │ ├── util_base64.js │ ├── util_cast.js │ ├── util_color.js │ ├── util_jsonrpc-web-socket.js │ ├── util_jsonrpc.js │ ├── util_math.js │ ├── util_new-block-ids.js │ ├── util_rateLimiter.js │ ├── util_string.js │ ├── util_task-queue.js │ ├── util_timer.js │ ├── util_variable.js │ ├── util_xml.js │ ├── virtual-machine.js │ ├── virtual-machine_tw.js │ └── vm_collectAssets.js └── webpack.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | chrome >= 70 2 | chromeandroid >= 70 3 | ios >= 12 4 | safari >= 12 5 | edge >= 17 6 | firefox >= 68 -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | 10 | [*.{js,html}] 11 | indent_style = space 12 | 13 | [.circleci/config.yml] 14 | indent_size = 2 15 | indent_style = space 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | dist/* 3 | node_modules/* 4 | playground/* 5 | benchmark/* 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['scratch', 'scratch/node', 'scratch/es6'] 3 | }; 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly specify line endings for as many files as possible. 5 | # People who (for example) rsync between Windows and Linux need this. 6 | 7 | # File types which we know are binary 8 | *.sb2 binary 9 | 10 | # Prefer LF for most file types 11 | *.css text eol=lf 12 | *.frag text eol=lf 13 | *.htm text eol=lf 14 | *.html text eol=lf 15 | *.iml text eol=lf 16 | *.js text eol=lf 17 | *.js.map text eol=lf 18 | *.json text eol=lf 19 | *.json5 text eol=lf 20 | *.md text eol=lf 21 | *.vert text eol=lf 22 | *.xml text eol=lf 23 | *.yml text eol=lf 24 | 25 | # Prefer LF for these files 26 | .editorconfig text eol=lf 27 | .eslintignore text eol=lf 28 | .eslintrc text eol=lf 29 | .gitattributes text eol=lf 30 | .gitignore text eol=lf 31 | .gitmodules text eol=lf 32 | .npmignore text eol=lf 33 | LICENSE text eol=lf 34 | Makefile text eol=lf 35 | README text eol=lf 36 | TRADEMARK text eol=lf 37 | 38 | # Use CRLF for Windows-specific file types 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected Behavior 2 | 3 | _Please describe what should happen_ 4 | 5 | ### Actual Behavior 6 | 7 | _Describe what actually happens_ 8 | 9 | ### Steps to Reproduce 10 | 11 | _Explain what someone needs to do in order to see what's described in *Actual behavior* above_ 12 | 13 | ### Operating System and Browser 14 | 15 | _e.g. Mac OS 10.11.6 Safari 10.0_ 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Resolves 2 | 3 | _What Github issue does this resolve (please include link)?_ 4 | 5 | ### Proposed Changes 6 | 7 | _Describe what this Pull Request does_ 8 | 9 | ### Reason for Changes 10 | 11 | _Explain why these changes should be made_ 12 | 13 | ### Test Coverage 14 | 15 | _Please show how you have added tests to cover your changes_ 16 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | persist-credentials: false 14 | - name: Install Node.js 15 | uses: actions/setup-node@v4 16 | with: 17 | node-version: 22 18 | cache: npm 19 | - run: npm ci 20 | - run: npm run lint 21 | - run: npm run build 22 | - run: npm run tap 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS 2 | .DS_Store 3 | 4 | # NPM 5 | /node_modules 6 | npm-* 7 | 8 | # Testing 9 | /.nyc_output 10 | /coverage 11 | 12 | # Editor 13 | /.idea 14 | /.vscode 15 | 16 | # Build 17 | /dist 18 | /playground 19 | /benchmark 20 | 21 | # Localization 22 | /translations 23 | -------------------------------------------------------------------------------- /.jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["plugins/markdown"], 3 | "templates": { 4 | "default": { 5 | "includeDate": false, 6 | "outputSourceFiles": false 7 | } 8 | }, 9 | "source": { 10 | "include": ["src"] 11 | }, 12 | "opts": { 13 | "destination": "playground/docs", 14 | "pedantic": true, 15 | "private": true, 16 | "readme": "README.md", 17 | "recurse": true, 18 | "template": "node_modules/docdash" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Development files 2 | .eslintrc.js 3 | /.editorconfig 4 | /.eslintignore 5 | /.gitattributes 6 | /.github 7 | /.travis.yml 8 | /.tx 9 | /test 10 | 11 | # Build created files 12 | /playground 13 | 14 | # Coverage created files 15 | /.nyc_output 16 | /coverage 17 | 18 | # Exclude already built packages from testing with npm pack 19 | /scratch-vm-*.{tar,tgz} 20 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16 2 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [scratch-editor.extensions] 5 | file_filter = translations/core/.json 6 | source_file = translations/core/en.json 7 | source_lang = en 8 | type = CHROME 9 | -------------------------------------------------------------------------------- /TRADEMARK: -------------------------------------------------------------------------------- 1 | The Scratch trademarks, including the Scratch name, logo, the Scratch Cat, Gobo, Pico, Nano, Tera and Giga graphics (the "Marks"), are property of the Massachusetts Institute of Technology (MIT). Marks may not be used to endorse or promote products derived from this software without specific prior written permission. 2 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'scratch-semantic-release-config', 3 | branches: [ 4 | { 5 | name: 'develop' 6 | // default channel 7 | }, 8 | { 9 | name: 'hotfix/*', 10 | channel: 'hotfix' 11 | } 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | 4 | "extends": [ 5 | "github>LLK/scratch-renovate-config:conservative" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['scratch', 'scratch/es6'], 4 | env: { 5 | browser: true 6 | }, 7 | rules: { 8 | 'valid-jsdoc': 'off' 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/cli/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const VirtualMachine = require('../index'); 3 | 4 | /* eslint-env node */ 5 | /* eslint-disable no-console */ 6 | 7 | const file = process.argv[2]; 8 | if (!file) { 9 | throw new Error('Invalid file'); 10 | } 11 | 12 | const runProject = async buffer => { 13 | const vm = new VirtualMachine(); 14 | vm.runtime.on('SAY', (target, type, text) => { 15 | console.log(text); 16 | }); 17 | vm.setCompatibilityMode(true); 18 | vm.clear(); 19 | await vm.loadProject(buffer); 20 | vm.start(); 21 | vm.greenFlag(); 22 | await new Promise(resolve => { 23 | const interval = setInterval(() => { 24 | let active = 0; 25 | const threads = vm.runtime.threads; 26 | for (let i = 0; i < threads.length; i++) { 27 | if (!threads[i].updateMonitor) { 28 | active += 1; 29 | } 30 | } 31 | if (active === 0) { 32 | clearInterval(interval); 33 | resolve(); 34 | } 35 | }, 50); 36 | }); 37 | vm.stopAll(); 38 | vm.quit(); 39 | }; 40 | 41 | runProject(fs.readFileSync(file)); 42 | -------------------------------------------------------------------------------- /src/compiler/compat-blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview List of blocks to be supported in the compiler compatibility layer. 3 | * This is only for native blocks. Extensions should not be listed here. 4 | */ 5 | 6 | // Please keep these lists alphabetical. 7 | 8 | const stacked = [ 9 | 'looks_changestretchby', 10 | 'looks_hideallsprites', 11 | 'looks_say', 12 | 'looks_sayforsecs', 13 | 'looks_setstretchto', 14 | 'looks_switchbackdroptoandwait', 15 | 'looks_think', 16 | 'looks_thinkforsecs', 17 | 'motion_align_scene', 18 | 'motion_glidesecstoxy', 19 | 'motion_glideto', 20 | 'motion_goto', 21 | 'motion_pointtowards', 22 | 'motion_scroll_right', 23 | 'motion_scroll_up', 24 | 'sensing_askandwait', 25 | 'sensing_setdragmode', 26 | 'sound_changeeffectby', 27 | 'sound_changevolumeby', 28 | 'sound_cleareffects', 29 | 'sound_play', 30 | 'sound_playuntildone', 31 | 'sound_seteffectto', 32 | 'sound_setvolumeto', 33 | 'sound_stopallsounds' 34 | ]; 35 | 36 | const inputs = [ 37 | 'motion_xscroll', 38 | 'motion_yscroll', 39 | 'sensing_loud', 40 | 'sensing_loudness', 41 | 'sensing_userid', 42 | 'sound_volume' 43 | ]; 44 | 45 | module.exports = { 46 | stacked, 47 | inputs 48 | }; 49 | -------------------------------------------------------------------------------- /src/compiler/compile.js: -------------------------------------------------------------------------------- 1 | const {IRGenerator} = require('./irgen'); 2 | const JSGenerator = require('./jsgen'); 3 | 4 | const compile = thread => { 5 | const irGenerator = new IRGenerator(thread); 6 | const ir = irGenerator.generate(); 7 | 8 | const procedures = {}; 9 | const target = thread.target; 10 | 11 | const compileScript = script => { 12 | if (script.cachedCompileResult) { 13 | return script.cachedCompileResult; 14 | } 15 | 16 | const compiler = new JSGenerator(script, ir, target); 17 | const result = compiler.compile(); 18 | script.cachedCompileResult = result; 19 | return result; 20 | }; 21 | 22 | const entry = compileScript(ir.entry); 23 | 24 | for (const procedureVariant of Object.keys(ir.procedures)) { 25 | const procedureData = ir.procedures[procedureVariant]; 26 | const procedureTree = compileScript(procedureData); 27 | procedures[procedureVariant] = procedureTree; 28 | } 29 | 30 | return { 31 | startingFunction: entry, 32 | procedures, 33 | executableHat: ir.entry.executableHat 34 | }; 35 | }; 36 | 37 | module.exports = compile; 38 | -------------------------------------------------------------------------------- /src/compiler/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-eval */ 2 | 3 | /** 4 | * @returns {boolean} true if the nullish coalescing operator (x ?? y) is supported. 5 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator 6 | */ 7 | const supportsNullishCoalescing = () => { 8 | try { 9 | // eslint-disable-next-line no-unused-vars 10 | const fn = new Function('undefined ?? 3'); 11 | // if function construction succeeds, the browser understood the syntax. 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | }; 17 | 18 | module.exports = { 19 | supportsNullishCoalescing: supportsNullishCoalescing() 20 | }; 21 | -------------------------------------------------------------------------------- /src/compiler/variable-pool.js: -------------------------------------------------------------------------------- 1 | class VariablePool { 2 | /** 3 | * @param {string} prefix The prefix at the start of the variable name. 4 | */ 5 | constructor (prefix) { 6 | if (prefix.trim().length === 0) { 7 | throw new Error('prefix cannot be empty'); 8 | } 9 | this.prefix = prefix; 10 | /** 11 | * @private 12 | */ 13 | this.count = 0; 14 | } 15 | 16 | next () { 17 | return `${this.prefix}${this.count++}`; 18 | } 19 | } 20 | 21 | module.exports = VariablePool; 22 | -------------------------------------------------------------------------------- /src/engine/blocks-execute-cache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview 3 | * Access point for private method shared between blocks.js and execute.js for 4 | * caching execute information. 5 | */ 6 | 7 | /** 8 | * A private method shared with execute to build an object containing the block 9 | * information execute needs and that is reset when other cached Blocks info is 10 | * reset. 11 | * @param {Blocks} blocks Blocks containing the expected blockId 12 | * @param {string} blockId blockId for the desired execute cache 13 | */ 14 | exports.getCached = function () { 15 | throw new Error('blocks.js has not initialized BlocksExecuteCache'); 16 | }; 17 | 18 | // Call after the default throwing getCached is assigned for Blocks to replace. 19 | require('./blocks'); 20 | -------------------------------------------------------------------------------- /src/engine/monitor-record.js: -------------------------------------------------------------------------------- 1 | const {Record} = require('immutable'); 2 | 3 | const MonitorRecord = Record({ 4 | id: null, // Block Id 5 | /** Present only if the monitor is sprite-specific, such as x position */ 6 | spriteName: null, 7 | /** Present only if the monitor is sprite-specific, such as x position */ 8 | targetId: null, 9 | opcode: null, 10 | value: null, 11 | params: null, 12 | mode: 'default', 13 | sliderMin: 0, 14 | sliderMax: 100, 15 | isDiscrete: true, 16 | x: null, // (x: null, y: null) Indicates that the monitor should be auto-positioned 17 | y: null, 18 | width: 0, 19 | height: 0, 20 | visible: true 21 | }); 22 | 23 | module.exports = MonitorRecord; 24 | -------------------------------------------------------------------------------- /src/engine/scratch-blocks-constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * These constants are copied from scratch-blocks/core/constants.js 3 | * @TODO find a way to require() these straight from scratch-blocks... maybe make a scratch-blocks/dist/constants.js? 4 | * @readonly 5 | * @enum {int} 6 | */ 7 | const ScratchBlocksConstants = { 8 | /** 9 | * ENUM for output shape: hexagonal (booleans/predicates). 10 | * @const 11 | */ 12 | OUTPUT_SHAPE_HEXAGONAL: 1, 13 | 14 | /** 15 | * ENUM for output shape: rounded (numbers). 16 | * @const 17 | */ 18 | OUTPUT_SHAPE_ROUND: 2, 19 | 20 | /** 21 | * ENUM for output shape: squared (any/all values; strings). 22 | * @const 23 | */ 24 | OUTPUT_SHAPE_SQUARE: 3 25 | }; 26 | 27 | module.exports = ScratchBlocksConstants; 28 | -------------------------------------------------------------------------------- /src/engine/stage-layering.js: -------------------------------------------------------------------------------- 1 | class StageLayering { 2 | static get BACKGROUND_LAYER () { 3 | return 'background'; 4 | } 5 | 6 | static get VIDEO_LAYER () { 7 | return 'video'; 8 | } 9 | 10 | static get PEN_LAYER () { 11 | return 'pen'; 12 | } 13 | 14 | static get SPRITE_LAYER () { 15 | return 'sprite'; 16 | } 17 | 18 | // Order of layer groups relative to each other, 19 | static get LAYER_GROUPS () { 20 | return [ 21 | StageLayering.BACKGROUND_LAYER, 22 | StageLayering.VIDEO_LAYER, 23 | StageLayering.PEN_LAYER, 24 | StageLayering.SPRITE_LAYER 25 | ]; 26 | } 27 | } 28 | 29 | module.exports = StageLayering; 30 | -------------------------------------------------------------------------------- /src/engine/tw-platform.js: -------------------------------------------------------------------------------- 1 | // Forks should change this. 2 | // This can be accessed externally on `vm.runtime.platform` 3 | 4 | module.exports = { 5 | name: 'TurboWarp', 6 | url: 'https://turbowarp.org/' 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-support/argument-type.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Block argument types 3 | * @enum {string} 4 | */ 5 | const ArgumentType = { 6 | /** 7 | * Numeric value with angle picker 8 | */ 9 | ANGLE: 'angle', 10 | 11 | /** 12 | * Boolean value with hexagonal placeholder 13 | */ 14 | BOOLEAN: 'Boolean', 15 | 16 | /** 17 | * Numeric value with color picker 18 | */ 19 | COLOR: 'color', 20 | 21 | /** 22 | * Numeric value with text field 23 | */ 24 | NUMBER: 'number', 25 | 26 | /** 27 | * String value with text field 28 | */ 29 | STRING: 'string', 30 | 31 | /** 32 | * String value with matrix field 33 | */ 34 | MATRIX: 'matrix', 35 | 36 | /** 37 | * MIDI note number with note picker (piano) field 38 | */ 39 | NOTE: 'note', 40 | 41 | /** 42 | * Inline image on block (as part of the label) 43 | */ 44 | IMAGE: 'image', 45 | 46 | /** 47 | * Name of costume in the current target 48 | */ 49 | COSTUME: 'costume', 50 | 51 | /** 52 | * Name of sound in the current target 53 | */ 54 | SOUND: 'sound' 55 | }; 56 | 57 | module.exports = ArgumentType; 58 | -------------------------------------------------------------------------------- /src/extension-support/define-messages.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {object} MessageDescriptor 3 | * @property {string} id - the translator-friendly unique ID of this message. 4 | * @property {string} default - the message text in the default language (English). 5 | * @property {string} [description] - a description of this message to help translators understand the context. 6 | */ 7 | 8 | /** 9 | * This is a hook for extracting messages from extension source files. 10 | * This function simply returns the message descriptor map object that's passed in. 11 | * @param {object.} messages - the messages to be defined 12 | * @return {object.} - the input, unprocessed 13 | */ 14 | const defineMessages = function (messages) { 15 | return messages; 16 | }; 17 | 18 | module.exports = defineMessages; 19 | -------------------------------------------------------------------------------- /src/extension-support/reporter-scope.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Indicate the scope for a reporter's value. 3 | * @enum {string} 4 | */ 5 | const ReporterScope = { 6 | /** 7 | * This reporter's value is global and does not depend on context. 8 | */ 9 | GLOBAL: 'global', 10 | 11 | /** 12 | * This reporter's value is specific to a particular target/sprite. 13 | * Another target may have a different value or may not even have a value. 14 | */ 15 | TARGET: 'target' 16 | }; 17 | 18 | module.exports = ReporterScope; 19 | -------------------------------------------------------------------------------- /src/extension-support/target-type.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Default types of Target supported by the VM 3 | * @enum {string} 4 | */ 5 | const TargetType = { 6 | /** 7 | * Rendered target which can move, change costumes, etc. 8 | */ 9 | SPRITE: 'sprite', 10 | 11 | /** 12 | * Rendered target which cannot move but can change backdrops 13 | */ 14 | STAGE: 'stage' 15 | }; 16 | 17 | module.exports = TargetType; 18 | -------------------------------------------------------------------------------- /src/extension-support/tw-block-shape.js: -------------------------------------------------------------------------------- 1 | // Use the constants instead of manually redefining them again 2 | const ScratchBlocksConstants = require('../engine/scratch-blocks-constants'); 3 | 4 | /** 5 | * Types of block shapes 6 | * @enum {number} 7 | */ 8 | const BlockShape = { 9 | /** 10 | * Output shape: hexagonal (booleans/predicates). 11 | */ 12 | HEXAGONAL: ScratchBlocksConstants.OUTPUT_SHAPE_HEXAGONAL, 13 | 14 | /** 15 | * Output shape: rounded (numbers). 16 | */ 17 | ROUND: ScratchBlocksConstants.OUTPUT_SHAPE_ROUND, 18 | 19 | /** 20 | * Output shape: squared (any/all values; strings). 21 | */ 22 | SQUARE: ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE 23 | }; 24 | 25 | module.exports = BlockShape; 26 | -------------------------------------------------------------------------------- /src/extension-support/tw-default-extension-urls.js: -------------------------------------------------------------------------------- 1 | // If a project uses an extension but does not specify a URL, it will default to 2 | // the URLs given here, if it exists. This is useful for compatibility with other mods. 3 | 4 | const defaults = new Map(); 5 | 6 | // Box2D (`griffpatch`) is not listed here because our extension is not actually 7 | // compatible with the original version due to fields vs inputs. 8 | 9 | // Scratch Lab Animated Text - https://lab.scratch.mit.edu/text/ 10 | defaults.set('text', 'https://extensions.turbowarp.org/lab/text.js'); 11 | 12 | // Turboloader's AudioStream 13 | defaults.set('audiostr', 'https://extensions.turbowarp.org/turboloader/audiostream.js'); 14 | 15 | module.exports = defaults; 16 | -------------------------------------------------------------------------------- /src/extension-support/tw-extension-api-common.js: -------------------------------------------------------------------------------- 1 | const ArgumentType = require('./argument-type'); 2 | const BlockType = require('./block-type'); 3 | const BlockShape = require('./tw-block-shape'); 4 | const TargetType = require('./target-type'); 5 | const Cast = require('../util/cast'); 6 | 7 | const Scratch = { 8 | ArgumentType, 9 | BlockType, 10 | BlockShape, 11 | TargetType, 12 | Cast 13 | }; 14 | 15 | module.exports = Scratch; 16 | -------------------------------------------------------------------------------- /src/extension-support/tw-extension-worker-context.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | isWorker: true, 3 | // centralDispatchService is the object to call postMessage() on to send a message to parent. 4 | centralDispatchService: self 5 | }; 6 | -------------------------------------------------------------------------------- /src/extension-support/tw-iframe-extension-worker-entry.js: -------------------------------------------------------------------------------- 1 | const context = require('./tw-extension-worker-context'); 2 | 3 | const jQuery = require('./tw-jquery-shim'); 4 | global.$ = jQuery; 5 | global.jQuery = jQuery; 6 | 7 | const id = window.__WRAPPED_IFRAME_ID__; 8 | 9 | context.isWorker = false; 10 | context.centralDispatchService = { 11 | postMessage (message, transfer) { 12 | const data = { 13 | vmIframeId: id, 14 | message 15 | }; 16 | if (transfer) { 17 | window.parent.postMessage(data, '*', transfer); 18 | } else { 19 | window.parent.postMessage(data, '*'); 20 | } 21 | } 22 | }; 23 | 24 | require('./extension-worker'); 25 | 26 | window.parent.postMessage({ 27 | vmIframeId: id, 28 | ready: true 29 | }, '*'); 30 | -------------------------------------------------------------------------------- /src/extension-support/tw-load-script-as-plain-text.js: -------------------------------------------------------------------------------- 1 | // Based on https://github.com/webpack-contrib/worker-loader/tree/v2.0.0 2 | 3 | const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); 4 | 5 | module.exports.pitch = function (request) { 6 | // Technically this loader does work in other environments, but our use case does not want that. 7 | if (this.target !== 'web') { 8 | return 'throw new Error("Not supported in non-web environment");'; 9 | } 10 | this.cacheable(false); 11 | const callback = this.async(); 12 | const compiler = this._compilation.createChildCompiler('extension worker', {}); 13 | new SingleEntryPlugin(this.context, `!!${request}`, 'extension worker').apply(compiler); 14 | compiler.runAsChild((err, entries, compilation) => { 15 | if (err) return callback(err); 16 | const file = entries[0].files[0]; 17 | const source = `module.exports = ${JSON.stringify(compilation.assets[file].source())};`; 18 | return callback(null, source); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /src/extension-support/tw-scratchx-utilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview 3 | * General ScratchX-related utilities used in multiple places. 4 | * Changing these functions may break projects. 5 | */ 6 | 7 | /** 8 | * @param {string} scratchXName 9 | * @returns {string} 10 | */ 11 | const generateExtensionId = scratchXName => { 12 | const sanitizedName = scratchXName.replace(/[^a-z0-9]/gi, '').toLowerCase(); 13 | return `sbx${sanitizedName}`; 14 | }; 15 | 16 | /** 17 | * @param {number} i 0-indexed index of argument in list 18 | * @returns {string} Scratch 3 argument name 19 | */ 20 | const argumentIndexToId = i => i.toString(); 21 | 22 | module.exports = { 23 | generateExtensionId, 24 | argumentIndexToId 25 | }; 26 | -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/1-snare.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/1-snare.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/10-wood-block.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/11-cowbell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/12-triangle.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/12-triangle.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/13-bongo.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/13-bongo.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/14-conga.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/14-conga.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/15-cabasa.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/16-guiro.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/16-guiro.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/18-cuica.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/18-cuica.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/3-side-stick.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/7-tambourine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/drums/9-claves.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/drums/9-claves.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3 -------------------------------------------------------------------------------- /src/extensions/scratch3_video_sensing/debug.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A debug "index" module exporting VideoMotion and VideoMotionView to debug 3 | * VideoMotion directly. 4 | * @file debug.js 5 | */ 6 | 7 | const VideoMotion = require('./library'); 8 | const VideoMotionView = require('./view'); 9 | 10 | module.exports = { 11 | VideoMotion, 12 | VideoMotionView 13 | }; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const VirtualMachine = require('./virtual-machine'); 2 | 3 | module.exports = VirtualMachine; 4 | -------------------------------------------------------------------------------- /src/io/clock.js: -------------------------------------------------------------------------------- 1 | const Timer = require('../util/timer'); 2 | 3 | class Clock { 4 | constructor (runtime) { 5 | this._projectTimer = new Timer({now: () => runtime.currentMSecs}); 6 | this._projectTimer.start(); 7 | this._pausedTime = null; 8 | this._paused = false; 9 | /** 10 | * Reference to the owning Runtime. 11 | * @type{!Runtime} 12 | */ 13 | this.runtime = runtime; 14 | } 15 | 16 | projectTimer () { 17 | if (this._paused) { 18 | return this._pausedTime / 1000; 19 | } 20 | return this._projectTimer.timeElapsed() / 1000; 21 | } 22 | 23 | pause () { 24 | this._paused = true; 25 | this._pausedTime = this._projectTimer.timeElapsed(); 26 | } 27 | 28 | resume () { 29 | this._paused = false; 30 | const dt = this._projectTimer.timeElapsed() - this._pausedTime; 31 | this._projectTimer.startTime += dt; 32 | } 33 | 34 | resetProjectTimer () { 35 | this._projectTimer.start(); 36 | } 37 | } 38 | 39 | module.exports = Clock; 40 | -------------------------------------------------------------------------------- /src/io/mouseWheel.js: -------------------------------------------------------------------------------- 1 | class MouseWheel { 2 | constructor (runtime) { 3 | /** 4 | * Reference to the owning Runtime. 5 | * @type{!Runtime} 6 | */ 7 | this.runtime = runtime; 8 | } 9 | 10 | /** 11 | * Mouse wheel DOM event handler. 12 | * @param {object} data Data from DOM event. 13 | */ 14 | postData (data) { 15 | const matchFields = {}; 16 | if (data.deltaY < 0) { 17 | matchFields.KEY_OPTION = 'up arrow'; 18 | } else if (data.deltaY > 0) { 19 | matchFields.KEY_OPTION = 'down arrow'; 20 | } else { 21 | return; 22 | } 23 | 24 | this.runtime.startHats('event_whenkeypressed', matchFields); 25 | } 26 | } 27 | 28 | module.exports = MouseWheel; 29 | -------------------------------------------------------------------------------- /src/io/userData.js: -------------------------------------------------------------------------------- 1 | class UserData { 2 | constructor () { 3 | this._username = ''; 4 | } 5 | 6 | /** 7 | * Handler for updating the username 8 | * @param {object} data Data posted to this ioDevice. 9 | * @property {!string} username The new username. 10 | */ 11 | postData (data) { 12 | this._username = data.username; 13 | } 14 | 15 | /** 16 | * Getter for username. Initially empty string, until set via postData. 17 | * @returns {!string} The current username 18 | */ 19 | getUsername () { 20 | return this._username; 21 | } 22 | } 23 | 24 | module.exports = UserData; 25 | -------------------------------------------------------------------------------- /src/playground/suite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scratch VM Benchmark Suite 7 | 8 | 9 | 10 |
11 |

Scratch VM Benchmark Suite

12 |
13 | 14 |
15 |
16 | 17 |
18 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/playground/video-sensing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Video Motion Test Playground 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/util/async-limiter.js: -------------------------------------------------------------------------------- 1 | class AsyncLimiter { 2 | constructor (callback, maxConcurrent) { 3 | this.callback = callback; 4 | this.maxConcurrent = maxConcurrent; 5 | this._current = 0; 6 | this._queue = []; 7 | } 8 | 9 | do (...args) { 10 | return new Promise((resolve, reject) => { 11 | this._queue.push([resolve, reject, args]); 12 | this._startNext(); 13 | }); 14 | } 15 | 16 | _startNext () { 17 | if (this._current >= this.maxConcurrent || this._queue.length === 0) { 18 | return; 19 | } 20 | this._current++; 21 | const [resolve, reject, args] = this._queue.shift(); 22 | this.callback.apply(null, args) 23 | .then(result => { 24 | resolve(result); 25 | this._current--; 26 | this._startNext(); 27 | }) 28 | .catch(error => { 29 | reject(error); 30 | this._current--; 31 | this._startNext(); 32 | }); 33 | } 34 | } 35 | 36 | module.exports = AsyncLimiter; 37 | -------------------------------------------------------------------------------- /src/util/clone.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Methods for cloning JavaScript objects. 3 | * @type {object} 4 | */ 5 | class Clone { 6 | /** 7 | * Deep-clone a "simple" object: one which can be fully expressed with JSON. 8 | * Non-JSON values, such as functions, will be stripped from the clone. 9 | * @param {object} original - the object to be cloned. 10 | * @returns {object} a deep clone of the original object. 11 | */ 12 | static simple (original) { 13 | return JSON.parse(JSON.stringify(original)); 14 | } 15 | } 16 | 17 | module.exports = Clone; 18 | -------------------------------------------------------------------------------- /src/util/log.js: -------------------------------------------------------------------------------- 1 | const nanolog = require('@turbowarp/nanolog'); 2 | nanolog.enable(); 3 | 4 | module.exports = nanolog('vm'); 5 | -------------------------------------------------------------------------------- /src/util/maybe-format-message.js: -------------------------------------------------------------------------------- 1 | const formatMessage = require('format-message'); 2 | 3 | /** 4 | * Check if `maybeMessage` looks like a message object, and if so pass it to `formatMessage`. 5 | * Otherwise, return `maybeMessage` as-is. 6 | * @param {*} maybeMessage - something that might be a message descriptor object. 7 | * @param {object} [args] - the arguments to pass to `formatMessage` if it gets called. 8 | * @param {string} [locale] - the locale to pass to `formatMessage` if it gets called. 9 | * @return {string|*} - the formatted message OR the original `maybeMessage` input. 10 | */ 11 | const maybeFormatMessage = function (maybeMessage, args, locale) { 12 | if (maybeMessage && maybeMessage.id && maybeMessage.default) { 13 | return formatMessage(maybeMessage, args, locale); 14 | } 15 | return maybeMessage; 16 | }; 17 | 18 | module.exports = maybeFormatMessage; 19 | -------------------------------------------------------------------------------- /src/util/new-block-ids.js: -------------------------------------------------------------------------------- 1 | const uid = require('./uid'); 2 | 3 | /** 4 | * Mutate the given blocks to have new IDs and update all internal ID references. 5 | * Does not return anything to make it clear that the blocks are updated in-place. 6 | * @param {array} blocks - blocks to be mutated. 7 | */ 8 | module.exports = blocks => { 9 | const oldToNew = {}; 10 | 11 | // First update all top-level IDs and create old-to-new mapping 12 | for (let i = 0; i < blocks.length; i++) { 13 | const newId = uid(); 14 | const oldId = blocks[i].id; 15 | blocks[i].id = oldToNew[oldId] = newId; 16 | } 17 | 18 | // Then go back through and update inputs (block/shadow) 19 | // and next/parent properties 20 | for (let i = 0; i < blocks.length; i++) { 21 | for (const key in blocks[i].inputs) { 22 | const input = blocks[i].inputs[key]; 23 | input.block = oldToNew[input.block]; 24 | input.shadow = oldToNew[input.shadow]; 25 | } 26 | if (blocks[i].parent) { 27 | blocks[i].parent = oldToNew[blocks[i].parent]; 28 | } 29 | if (blocks[i].next) { 30 | blocks[i].next = oldToNew[blocks[i].next]; 31 | } 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/util/tw-static-fetch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview 3 | * The new URL() and fetch() provided by the browser tend to buckle when dealing with URLs that are 4 | * tens of megabytes in length, which can be common when working with data: URLs in extensions. 5 | * 6 | * To help avoid that, this file can "statically" parse some data: URLs without going through 7 | * unreliable browser APIs. 8 | */ 9 | 10 | const Base64Util = require('./base64-util'); 11 | 12 | /** 13 | * @param {string} url 14 | * @returns {Response|null} 15 | */ 16 | const staticFetch = url => { 17 | try { 18 | const simpleDataUrlMatch = url.match(/^data:([/-\w\d]*);base64,/i); 19 | if (simpleDataUrlMatch) { 20 | const contentType = simpleDataUrlMatch[1].toLowerCase(); 21 | const base64 = url.substring(simpleDataUrlMatch[0].length); 22 | const decoded = Base64Util.base64ToUint8Array(base64); 23 | return new Response(decoded, { 24 | headers: { 25 | 'content-type': contentType, 26 | 'content-length': decoded.byteLength 27 | } 28 | }); 29 | } 30 | } catch (e) { 31 | // not robust enough yet to care about these errors 32 | } 33 | return null; 34 | }; 35 | 36 | module.exports = staticFetch; 37 | -------------------------------------------------------------------------------- /src/util/uid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview UID generator, from Blockly. 3 | */ 4 | 5 | /** 6 | * Legal characters for the unique ID. 7 | * Should be all on a US keyboard. No XML special characters or control codes. 8 | * Removed $ due to issue 251. 9 | * @private 10 | */ 11 | const soup_ = '!#%()*+,-./:;=?@[]^_`{|}~' + 12 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 13 | 14 | /** 15 | * Generate a unique ID, from Blockly. This should be globally unique. 16 | * 87 characters ^ 20 length > 128 bits (better than a UUID). 17 | * @return {string} A globally unique ID string. 18 | */ 19 | const uid = function () { 20 | const length = 20; 21 | const soupLength = soup_.length; 22 | const id = []; 23 | for (let i = 0; i < length; i++) { 24 | id[i] = soup_.charAt(Math.random() * soupLength); 25 | } 26 | return id.join(''); 27 | }; 28 | 29 | module.exports = uid; 30 | -------------------------------------------------------------------------------- /src/util/xml-escape.js: -------------------------------------------------------------------------------- 1 | const log = require('./log'); 2 | 3 | /** 4 | * Escape a string to be safe to use in XML content. 5 | * CC-BY-SA: hgoebl 6 | * https://stackoverflow.com/questions/7918868/ 7 | * how-to-escape-xml-entities-in-javascript 8 | * @param {!string | !Array.} unsafe Unsafe string. 9 | * @return {string} XML-escaped string, for use within an XML tag. 10 | */ 11 | const xmlEscape = function (unsafe) { 12 | if (typeof unsafe !== 'string') { 13 | if (Array.isArray(unsafe)) { 14 | // This happens when we have hacked blocks from 2.0 15 | // See #1030 16 | unsafe = String(unsafe); 17 | } else { 18 | log.error('Unexpected input recieved in replaceUnsafeChars'); 19 | return unsafe; 20 | } 21 | } 22 | return unsafe.replace(/[<>&'"]/g, c => { 23 | switch (c) { 24 | case '<': return '<'; 25 | case '>': return '>'; 26 | case '&': return '&'; 27 | case '\'': return '''; 28 | case '"': return '"'; 29 | } 30 | }); 31 | }; 32 | 33 | module.exports = xmlEscape; 34 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'no-undefined': [0] 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /test/fixtures/block-to-workspace-comments-without-scripts.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/block-to-workspace-comments-without-scripts.sb2 -------------------------------------------------------------------------------- /test/fixtures/block-to-workspace-comments.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/block-to-workspace-comments.sb2 -------------------------------------------------------------------------------- /test/fixtures/broadcast_special_chars.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/broadcast_special_chars.sb2 -------------------------------------------------------------------------------- /test/fixtures/broadcast_special_chars.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/broadcast_special_chars.sb3 -------------------------------------------------------------------------------- /test/fixtures/cat.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cat.sprite2 -------------------------------------------------------------------------------- /test/fixtures/cat.sprite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cat.sprite3 -------------------------------------------------------------------------------- /test/fixtures/clone-cleanup.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/clone-cleanup.sb2 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_exceeded_limit.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_exceeded_limit.sb2 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_exceeded_limit.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_exceeded_limit.sb3 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_limit.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_limit.sb2 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_limit.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_limit.sb3 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_local.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_local.sb2 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_local.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_local.sb3 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_simple.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_simple.sb2 -------------------------------------------------------------------------------- /test/fixtures/cloud_variables_simple.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/cloud_variables_simple.sb3 -------------------------------------------------------------------------------- /test/fixtures/comments.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/comments.sb2 -------------------------------------------------------------------------------- /test/fixtures/comments.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/comments.sb3 -------------------------------------------------------------------------------- /test/fixtures/comments_no_duplicate_id_serialization.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/comments_no_duplicate_id_serialization.sb3 -------------------------------------------------------------------------------- /test/fixtures/complex.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/complex.sb2 -------------------------------------------------------------------------------- /test/fixtures/control.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/control.sb2 -------------------------------------------------------------------------------- /test/fixtures/corrupt_png.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_png.sb2 -------------------------------------------------------------------------------- /test/fixtures/corrupt_png.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_png.sb3 -------------------------------------------------------------------------------- /test/fixtures/corrupt_png.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_png.sprite2 -------------------------------------------------------------------------------- /test/fixtures/corrupt_png.sprite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_png.sprite3 -------------------------------------------------------------------------------- /test/fixtures/corrupt_sound.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_sound.sb3 -------------------------------------------------------------------------------- /test/fixtures/corrupt_svg.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_svg.sb2 -------------------------------------------------------------------------------- /test/fixtures/corrupt_svg.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_svg.sb3 -------------------------------------------------------------------------------- /test/fixtures/corrupt_svg.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_svg.sprite2 -------------------------------------------------------------------------------- /test/fixtures/corrupt_svg.sprite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/corrupt_svg.sprite3 -------------------------------------------------------------------------------- /test/fixtures/data.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/data.sb2 -------------------------------------------------------------------------------- /test/fixtures/default.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/default.sb2 -------------------------------------------------------------------------------- /test/fixtures/default.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/default.sb3 -------------------------------------------------------------------------------- /test/fixtures/default_nested.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/default_nested.sb2 -------------------------------------------------------------------------------- /test/fixtures/dispatch-test-service.js: -------------------------------------------------------------------------------- 1 | class DispatchTestService { 2 | returnFortyTwo () { 3 | return 42; 4 | } 5 | 6 | doubleArgument (x) { 7 | return 2 * x; 8 | } 9 | 10 | throwException () { 11 | throw new Error('This is a test exception thrown by DispatchTest'); 12 | } 13 | } 14 | 15 | module.exports = DispatchTestService; 16 | -------------------------------------------------------------------------------- /test/fixtures/dispatch-test-worker-shim.js: -------------------------------------------------------------------------------- 1 | const Module = require('module'); 2 | 3 | const callsite = require('callsite'); 4 | const path = require('path'); 5 | 6 | const oldRequire = Module.prototype.require; 7 | Module.prototype.require = function (target) { 8 | if (target.indexOf('/') === -1 || target.startsWith('@')) { 9 | // we really do just want to forward the arguments here 10 | // eslint-disable-next-line prefer-rest-params 11 | return oldRequire.apply(this, arguments); 12 | } 13 | 14 | const stack = callsite(); 15 | const callerFile = stack[2].getFileName(); 16 | const callerDir = path.dirname(callerFile); 17 | target = path.resolve(callerDir, target); 18 | return oldRequire.call(this, target); 19 | }; 20 | 21 | oldRequire(path.resolve(__dirname, 'dispatch-test-worker')); 22 | -------------------------------------------------------------------------------- /test/fixtures/dispatch-test-worker.js: -------------------------------------------------------------------------------- 1 | const dispatch = require('../../src/dispatch/worker-dispatch'); 2 | const DispatchTestService = require('./dispatch-test-service'); 3 | const log = require('../../src/util/log'); 4 | 5 | dispatch.setService('RemoteDispatchTest', new DispatchTestService()); 6 | 7 | dispatch.waitForConnection.then(() => { 8 | dispatch.call('test', 'onWorkerReady').catch(e => { 9 | log(`Test worker failed to call onWorkerReady: ${JSON.stringify(e)}`); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /test/fixtures/draggable.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/draggable.sb3 -------------------------------------------------------------------------------- /test/fixtures/edge-triggered-hat.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/edge-triggered-hat.sb3 -------------------------------------------------------------------------------- /test/fixtures/event.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/event.sb2 -------------------------------------------------------------------------------- /test/fixtures/example_sprite.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/example_sprite.sprite2 -------------------------------------------------------------------------------- /test/fixtures/execute/README.md: -------------------------------------------------------------------------------- 1 | Tests in this folder are run in scratch by integration/execute.js. The tests can SAY test messages that map to tap methods. Read integration/execute.js for more. 2 | 3 | Tests whose names start with `tw-` are added by TurboWarp. Some of these tests are based on real projects from the scratch.mit.edu website, in which case their filename contains the original project ID and additional credits are within the project's scripts. We believe our use of these projects is fair use as the projects have been sufficiently modified and stripped down such that the project found here bears not even a slight resemblance to the original project. 4 | -------------------------------------------------------------------------------- /test/fixtures/execute/broadcast-wait-arg-change.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/broadcast-wait-arg-change.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/control-if-false-then-else.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/control-if-false-then-else.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/control-if-false-then.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/control-if-false-then.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/control-if-true-then-else.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/control-if-true-then-else.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/control-if-true-then.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/control-if-true-then.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/control-stop-all-leaks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/control-stop-all-leaks.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/data-operators-global.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/data-operators-global.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/data-operators-local.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/data-operators-local.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/data-reporter-contents-global.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/data-reporter-contents-global.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/data-reporter-contents-local.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/data-reporter-contents-local.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/event-broadcast-and-wait-can-continue-same-tick.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/event-broadcast-and-wait-can-continue-same-tick.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/event-when-green-flag.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/event-when-green-flag.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/events-broadcast-and-wait-yields-a-tick.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/events-broadcast-and-wait-yields-a-tick.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/hat-thread-execution.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/hat-thread-execution.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/monitors-stage-name.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/monitors-stage-name.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/operators-not-blank.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/operators-not-blank.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-back-2-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-back-2-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-broadcast-and-wait-repeat-message.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-broadcast-and-wait-repeat-message.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-broadcast-and-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-broadcast-and-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-broadcast-no-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-broadcast-no-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-continuous.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-continuous.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-backwards-2-threads-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-backwards-2-threads-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-forewards-2-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-forewards-2-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-changes-front-2-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-changes-front-2-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-clones-backwards-2-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-clones-backwards-2-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-clones-backwards-broadcast-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-clones-backwards-broadcast-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-clones-static-2.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-clones-static-2.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-immobile-stage.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-immobile-stage.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-library-reverse.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-library-reverse.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-library-reverse.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-library-reverse.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/order-library.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-library.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/order-library.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/order-library.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-boolean-reporter-bug.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-boolean-reporter-bug.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-nested-missing-boolean-param.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-nested-missing-boolean-param.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-nested-missing-no-param.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-nested-missing-no-param.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-nested-missing-number-param.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-nested-missing-number-param.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-nested-missing-string-param.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-nested-missing-string-param.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-number-number-boolean.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-number-number-boolean.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-param-outside-boolean.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-param-outside-boolean.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-param-outside-number.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-param-outside-number.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-param-outside-string.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-param-outside-string.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-recursive-default-boolean.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-recursive-default-boolean.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-recursive-default-number.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-recursive-default-number.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/procedures-recursive-default-string.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/procedures-recursive-default-string.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/sensing-get-attribute-of-stage-alt-name.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/sensing-get-attribute-of-stage-alt-name.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/sprite-number-name.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/sprite-number-name.sb2 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-NaN.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-NaN.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-add-can-return-nan.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-add-can-return-nan.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-all-at-once.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-all-at-once.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-block-with-null-for-variable-id.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-block-with-null-for-variable-id.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-boolean-arguments-are-not-cast.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-boolean-arguments-are-not-cast.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-broadcast-id-and-name-desync.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-broadcast-id-and-name-desync.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-change-size-does-not-use-rounded-size.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-change-size-does-not-use-rounded-size.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-color-input-returns-hex.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-color-input-returns-hex.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-comparison-matrix-inline.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-comparison-matrix-inline.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-comparison-matrix-runtime.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-comparison-matrix-runtime.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-compatibility-layer-type-barrier.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-compatibility-layer-type-barrier.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-coordinate-precision.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-coordinate-precision.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-counter.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-counter.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-custom-report-repeat.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-custom-report-repeat.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-forkphorus-515-boolean-number-comparison.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-forkphorus-515-boolean-number-comparison.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-forkphorus-515-non-finite-direction.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-forkphorus-515-non-finite-direction.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-forkphorus-515-random-with-invalid-number-with-period.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-forkphorus-515-random-with-invalid-number-with-period.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-forkphorus-515-wait-zero-seconds-in-warp-mode.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-gh-249-quicksort.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-gh-249-quicksort.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-list-any.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-list-any.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-obsolete-blocks.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-obsolete-blocks.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-one-divide-negative-zero.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-one-divide-negative-zero.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-preciseProjectTimer-drift-453118719.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-preciseProjectTimer-drift-453118719.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-prefers-first-occurence-of-procedure-387608267.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-prefers-first-occurence-of-procedure-387608267.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-arguments-with-same-name.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-arguments-with-same-name.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-call-resets-variable-input-types-430811055.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-call-resets-variable-input-types-430811055.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-prototype-exists-but-not-definition-549160843.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-prototype-exists-but-not-definition-549160843.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-non-existant.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-non-existant.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-non-existent.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-non-existent.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-recursion.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-recursion.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-simple.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-simple.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-stops-scripts.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-stops-scripts.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-procedure-return-warp.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-procedure-return-warp.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-promise-loop-double-yield-kouzeru.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-promise-loop-double-yield-kouzeru.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-restart-broadcast-threads.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-restart-broadcast-threads.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-safe-procedure-argument-casting.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-safe-procedure-argument-casting.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-self-restarting-script-keeps-running-until-yield.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-self-restarting-script-keeps-running-until-yield.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-sensing-of.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-sensing-of.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-stage-cannot-move-layers.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-stage-cannot-move-layers.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-subtract-can-return-nan.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-subtract-can-return-nan.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-tab-equals-zero.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-tab-equals-zero.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-tangent.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-tangent.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-unsafe-equals.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-unsafe-equals.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-warp-repeat-until-timer-greater-than.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-warp-repeat-until-timer-greater-than.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-when-backdrop-switches-to-next-backdrop.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-when-backdrop-switches-to-next-backdrop.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-when-backdrop-switches-to-switch-backdrop-to.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-when-backdrop-switches-to-switch-backdrop-to.sb3 -------------------------------------------------------------------------------- /test/fixtures/execute/tw-zombie-cube-escape-284516654.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/execute/tw-zombie-cube-escape-284516654.sb3 -------------------------------------------------------------------------------- /test/fixtures/fake-bitmap-adapter.js: -------------------------------------------------------------------------------- 1 | const FakeBitmapAdapter = require('@turbowarp/scratch-svg-renderer').BitmapAdapter; 2 | 3 | FakeBitmapAdapter.prototype.resize = function (canvas) { 4 | return canvas; 5 | }; 6 | 7 | module.exports = FakeBitmapAdapter; 8 | -------------------------------------------------------------------------------- /test/fixtures/hat-execution-order.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/hat-execution-order.sb2 -------------------------------------------------------------------------------- /test/fixtures/invisible-tempo-monitor-no-other-music-blocks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/invisible-tempo-monitor-no-other-music-blocks.sb2 -------------------------------------------------------------------------------- /test/fixtures/invisible-video-monitor.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/invisible-video-monitor.sb2 -------------------------------------------------------------------------------- /test/fixtures/list-monitor-rename.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/list-monitor-rename.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/ev3-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/ev3-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/microbit-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/microbit-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/music-simple-project.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/music-simple-project.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/music-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/music-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/pen-dolphin-3d.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/pen-dolphin-3d.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/pen-dolphin-3d.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/pen-dolphin-3d.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/pen-simple-project.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/pen-simple-project.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/pen-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/pen-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/text2speech-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/text2speech-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/videoSensing-simple-project.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/videoSensing-simple-project.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/videoSensing-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/videoSensing-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/wedo2-simple-project.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/wedo2-simple-project.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/confirm-load/wedo2-simple-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/confirm-load/wedo2-simple-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/music-visible-monitor-no-blocks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/music-visible-monitor-no-blocks.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/video-state/videoState-off.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/video-state/videoState-off.sb2 -------------------------------------------------------------------------------- /test/fixtures/load-extensions/video-state/videoState-on-transparency-0.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/load-extensions/video-state/videoState-on-transparency-0.sb2 -------------------------------------------------------------------------------- /test/fixtures/looks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/looks.sb2 -------------------------------------------------------------------------------- /test/fixtures/missing_png.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_png.sb2 -------------------------------------------------------------------------------- /test/fixtures/missing_png.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_png.sb3 -------------------------------------------------------------------------------- /test/fixtures/missing_png.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_png.sprite2 -------------------------------------------------------------------------------- /test/fixtures/missing_png.sprite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_png.sprite3 -------------------------------------------------------------------------------- /test/fixtures/missing_sound.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_sound.sb3 -------------------------------------------------------------------------------- /test/fixtures/missing_svg.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_svg.sb2 -------------------------------------------------------------------------------- /test/fixtures/missing_svg.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_svg.sb3 -------------------------------------------------------------------------------- /test/fixtures/missing_svg.sprite2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_svg.sprite2 -------------------------------------------------------------------------------- /test/fixtures/missing_svg.sprite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/missing_svg.sprite3 -------------------------------------------------------------------------------- /test/fixtures/monitored_variables.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/monitored_variables.sb3 -------------------------------------------------------------------------------- /test/fixtures/monitors.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/monitors.sb2 -------------------------------------------------------------------------------- /test/fixtures/monitors.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/monitors.sb3 -------------------------------------------------------------------------------- /test/fixtures/motion.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/motion.sb2 -------------------------------------------------------------------------------- /test/fixtures/offline-custom-assets.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/offline-custom-assets.sb2 -------------------------------------------------------------------------------- /test/fixtures/ordering.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/ordering.sb2 -------------------------------------------------------------------------------- /test/fixtures/origin-absent.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/origin-absent.sb3 -------------------------------------------------------------------------------- /test/fixtures/origin.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/origin.sb3 -------------------------------------------------------------------------------- /test/fixtures/pen.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/pen.sb2 -------------------------------------------------------------------------------- /test/fixtures/procedure.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/procedure.sb2 -------------------------------------------------------------------------------- /test/fixtures/readProjectFile.js: -------------------------------------------------------------------------------- 1 | const AdmZip = require('adm-zip'); 2 | const fs = require('fs'); 3 | 4 | module.exports = { 5 | readFileToBuffer: function (path) { 6 | return Buffer.from(fs.readFileSync(path)); 7 | }, 8 | extractProjectJson: function (path) { 9 | const zip = new AdmZip(path); 10 | const projectEntry = zip.getEntries().find(item => item.entryName.match(/project\.json/)); 11 | if (projectEntry) { 12 | return JSON.parse(zip.readAsText(projectEntry.entryName, 'utf8')); 13 | } 14 | return null; 15 | }, 16 | extractAsset: function (path, assetFileName) { 17 | const zip = new AdmZip(path); 18 | const assetEntry = zip.getEntries().find(item => item.entryName.match(assetFileName)); 19 | return assetEntry.getData(); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /test/fixtures/saythink-and-wait.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/saythink-and-wait.sb2 -------------------------------------------------------------------------------- /test/fixtures/sb2-from-sb1-missing-backdrop-image.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/sb2-from-sb1-missing-backdrop-image.sb2 -------------------------------------------------------------------------------- /test/fixtures/sensing.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/sensing.sb2 -------------------------------------------------------------------------------- /test/fixtures/single_sound.sb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/single_sound.sb -------------------------------------------------------------------------------- /test/fixtures/sound.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/sound.sb2 -------------------------------------------------------------------------------- /test/fixtures/sprite.json: -------------------------------------------------------------------------------- 1 | { 2 | "objName": "Sprite1", 3 | "sounds": [{ 4 | "soundName": "meow", 5 | "soundID": 0, 6 | "md5": "83c36d806dc92327b9e7049a565c6bff.wav", 7 | "sampleCount": 18688, 8 | "rate": 22050, 9 | "format": "" 10 | }], 11 | "costumes": [{ 12 | "costumeName": "costume1", 13 | "baseLayerID": 0, 14 | "baseLayerMD5": "f9a1c175dbe2e5dee472858dd30d16bb.svg", 15 | "bitmapResolution": 1, 16 | "rotationCenterX": 47, 17 | "rotationCenterY": 55 18 | }, 19 | { 20 | "costumeName": "costume2", 21 | "baseLayerID": 1, 22 | "baseLayerMD5": "6e8bd9ae68fdb02b7e1e3df656a75635.svg", 23 | "bitmapResolution": 1, 24 | "rotationCenterX": 47, 25 | "rotationCenterY": 55 26 | }], 27 | "currentCostumeIndex": 0, 28 | "scratchX": 0, 29 | "scratchY": 0, 30 | "scale": 1, 31 | "direction": 90, 32 | "rotationStyle": "normal", 33 | "isDraggable": false, 34 | "indexInLibrary": 100000, 35 | "visible": true, 36 | "spriteInfo": { 37 | } 38 | } -------------------------------------------------------------------------------- /test/fixtures/stack-click.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/stack-click.sb2 -------------------------------------------------------------------------------- /test/fixtures/test-compare.js: -------------------------------------------------------------------------------- 1 | const testCompare = (t, lhs, op, rhs, message) => { 2 | const details = `Expected: ${lhs} ${op} ${rhs}`; 3 | const extra = {details}; 4 | switch (op) { 5 | case '<': return t.ok(lhs < rhs, message, extra); 6 | case '<=': return t.ok(lhs <= rhs, message, extra); 7 | case '===': return t.ok(lhs === rhs, message, extra); 8 | case '!==': return t.ok(lhs !== rhs, message, extra); 9 | case '>=': return t.ok(lhs >= rhs, message, extra); 10 | case '>': return t.ok(lhs > rhs, message, extra); 11 | default: return t.fail(`Unrecognized op: ${op}`); 12 | } 13 | }; 14 | 15 | module.exports = testCompare; 16 | -------------------------------------------------------------------------------- /test/fixtures/timer-greater-than-hat.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/timer-greater-than-hat.sb2 -------------------------------------------------------------------------------- /test/fixtures/timer-monitor.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/timer-monitor.sb3 -------------------------------------------------------------------------------- /test/fixtures/top-level-reporters.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/top-level-reporters.sb3 -------------------------------------------------------------------------------- /test/fixtures/top-level-variable-reporter.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/top-level-variable-reporter.sb2 -------------------------------------------------------------------------------- /test/fixtures/tw-add-builtin-extension.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-add-builtin-extension.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-addon-blocks.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-addon-blocks.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-asset-progress.sb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-asset-progress.sb -------------------------------------------------------------------------------- /test/fixtures/tw-asset-progress.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-asset-progress.sb2 -------------------------------------------------------------------------------- /test/fixtures/tw-asset-progress.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-asset-progress.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-beyond-branchCount.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-beyond-branchCount.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-block-returning-promise-like.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-block-returning-promise-like.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-block-stop-thread.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-block-stop-thread.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-conditional.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-conditional.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-edge-activated-hat-returns-promise.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-edge-activated-hat-returns-promise.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-empty-project.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-empty-project.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-extension-storage-no-data.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-extension-storage-no-data.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-extension-storage.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-extension-storage.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-glide.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-glide.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-hats-and-events.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-hats-and-events.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-last-block-in-loop-returns-promise.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-last-block-in-loop-returns-promise.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-loop.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-loop.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-mixed-file-formats.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-mixed-file-formats.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-project-using-xml-extension.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-project-using-xml-extension.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-project-with-extensions.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-project-with-extensions.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-rejected-promise-command.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-rejected-promise-command.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-rejected-promise-reporter.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-rejected-promise-reporter.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-save-project-sb3.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-save-project-sb3.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-serialize-asset-order.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-serialize-asset-order.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-slow-custom-reporter-stack-click.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-slow-custom-reporter-stack-click.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-stackframe-op.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-stackframe-op.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-stored-settings/empty-comment.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-stored-settings/empty-comment.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-stored-settings/no-comment.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-stored-settings/no-comment.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-stored-settings/sprite.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-stored-settings/sprite.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-stored-settings/turbo-mode.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-stored-settings/turbo-mode.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw-very-long-comments.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/tw-very-long-comments.sb3 -------------------------------------------------------------------------------- /test/fixtures/tw_mock_blob.js: -------------------------------------------------------------------------------- 1 | class MockBlob { 2 | constructor (objects = [], options = {}) { 3 | this.size = objects.reduce((a, i) => a + i.byteLength, 0); 4 | this.type = options || options.type; 5 | 6 | this._objects = objects; 7 | } 8 | 9 | _readAsBuffer () { 10 | const result = Buffer.alloc(this.size); 11 | let i = 0; 12 | for (const object of this._objects) { 13 | const view = new Uint8Array(object); 14 | result.set(view, i); 15 | i += object.byteLength; 16 | } 17 | return result; 18 | } 19 | } 20 | 21 | global.Blob = MockBlob; 22 | -------------------------------------------------------------------------------- /test/fixtures/unknown-opcode-as-reporter-block.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/unknown-opcode-as-reporter-block.sb2 -------------------------------------------------------------------------------- /test/fixtures/unknown-opcode-in-c-block.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/unknown-opcode-in-c-block.sb2 -------------------------------------------------------------------------------- /test/fixtures/unknown-opcode.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/unknown-opcode.sb2 -------------------------------------------------------------------------------- /test/fixtures/variable_characters.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/variable_characters.sb2 -------------------------------------------------------------------------------- /test/fixtures/variable_characters.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/variable_characters.sb3 -------------------------------------------------------------------------------- /test/fixtures/visible-tempo-monitor-no-other-music-blocks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/visible-tempo-monitor-no-other-music-blocks.sb2 -------------------------------------------------------------------------------- /test/fixtures/visible-video-monitor-and-video-blocks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/visible-video-monitor-and-video-blocks.sb2 -------------------------------------------------------------------------------- /test/fixtures/visible-video-monitor-no-other-video-blocks.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/visible-video-monitor-no-other-video-blocks.sb2 -------------------------------------------------------------------------------- /test/fixtures/when-clicked.sb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/fixtures/when-clicked.sb2 -------------------------------------------------------------------------------- /test/integration/control.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/control.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('control', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length > 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | }); 31 | }); 32 | 33 | // After two seconds, get playground data and stop 34 | setTimeout(() => { 35 | vm.getPlaygroundData(); 36 | vm.stopAll(); 37 | }, 2000); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/data.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/data.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('data', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', () => { 16 | // @todo Additional tests 17 | vm.quit(); 18 | t.end(); 19 | }); 20 | 21 | // Start VM, load project, and run 22 | t.doesNotThrow(() => { 23 | vm.start(); 24 | vm.clear(); 25 | vm.setCompatibilityMode(false); 26 | vm.setTurboMode(false); 27 | vm.loadProject(project).then(() => { 28 | vm.greenFlag(); 29 | 30 | // After two seconds, get playground data and stop 31 | setTimeout(() => { 32 | vm.getPlaygroundData(); 33 | vm.stopAll(); 34 | }, 2000); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/integration/event.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/event.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('event', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length > 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | 31 | // After two seconds, get playground data and stop 32 | setTimeout(() => { 33 | vm.getPlaygroundData(); 34 | vm.stopAll(); 35 | }, 2000); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/looks.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/looks.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('looks', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length === 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | 31 | // After two seconds, get playground data and stop 32 | setTimeout(() => { 33 | vm.getPlaygroundData(); 34 | vm.stopAll(); 35 | }, 2000); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/motion.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/motion.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('motion', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length > 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | 31 | // After two seconds, get playground data and stop 32 | setTimeout(() => { 33 | vm.getPlaygroundData(); 34 | vm.stopAll(); 35 | }, 2000); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/procedure.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/procedure.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('procedure', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length === 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | 31 | // After two seconds, get playground data and stop 32 | setTimeout(() => { 33 | vm.getPlaygroundData(); 34 | vm.stopAll(); 35 | }, 2000); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/sensing.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const test = require('tap').test; 3 | const makeTestStorage = require('../fixtures/make-test-storage'); 4 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 5 | const VirtualMachine = require('../../src/index'); 6 | 7 | const uri = path.resolve(__dirname, '../fixtures/sensing.sb2'); 8 | const project = readFileToBuffer(uri); 9 | 10 | test('sensing', t => { 11 | const vm = new VirtualMachine(); 12 | vm.attachStorage(makeTestStorage()); 13 | 14 | // Evaluate playground data and exit 15 | vm.on('playgroundData', e => { 16 | const threads = JSON.parse(e.threads); 17 | t.ok(threads.length > 0); 18 | vm.quit(); 19 | t.end(); 20 | }); 21 | 22 | // Start VM, load project, and run 23 | t.doesNotThrow(() => { 24 | vm.start(); 25 | vm.clear(); 26 | vm.setCompatibilityMode(false); 27 | vm.setTurboMode(false); 28 | vm.loadProject(project).then(() => { 29 | vm.greenFlag(); 30 | 31 | // After two seconds, get playground data and stop 32 | setTimeout(() => { 33 | vm.getPlaygroundData(); 34 | vm.stopAll(); 35 | }, 2000); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/tw-snapshots.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const Snapshots = require('../snapshot/lib'); 3 | 4 | for (const testCase of Snapshots.tests) { 5 | // eslint-disable-next-line no-loop-func 6 | test(testCase.id, async t => { 7 | const expected = Snapshots.getExpectedSnapshot(testCase); 8 | const actual = await Snapshots.generateActualSnapshot(testCase); 9 | const result = Snapshots.compareSnapshots(expected, actual); 10 | if (result === 'VALID') { 11 | t.pass('matches'); 12 | } else if (result === 'INPUT_MODIFIED') { 13 | t.fail('input project changed; run: node test/snapshot --update'); 14 | } else if (result === 'MISSING_SNAPSHOT') { 15 | t.fail('snapshot is missing; run: node test/snapshot --update'); 16 | } else { 17 | // This assertion will always fail, but tap will print out the snapshots 18 | // for easier comparison. 19 | t.equal(expected, actual, 'did not match; you may have to run: node test/snapshot --update'); 20 | } 21 | t.end(); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /test/integration/tw_allow_drop_anywhere.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const Runtime = require('../../src/engine/runtime'); 3 | const BlockType = require('../../src/extension-support/block-type'); 4 | 5 | test('allowDropAnywhere', t => { 6 | t.plan(2); 7 | 8 | const rt = new Runtime(); 9 | 10 | rt.on('EXTENSION_ADDED', json => { 11 | t.equal(json.blocks[0].json.output, 'String'); 12 | t.equal(json.blocks[1].json.output, null); 13 | t.end(); 14 | }); 15 | 16 | rt._registerExtensionPrimitives({ 17 | id: 'testextension', 18 | name: 'test', 19 | blocks: [ 20 | { 21 | opcode: 'drop1', 22 | text: 'drop not anywhere', 23 | blockType: BlockType.REPORTER 24 | }, 25 | { 26 | opcode: 'drop2', 27 | text: 'drop anywhere', 28 | blockType: BlockType.REPORTER, 29 | allowDropAnywhere: true 30 | } 31 | ] 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/integration/tw_compat_block_utility_stackframe_exposed.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const VM = require('../../src/virtual-machine'); 5 | const Timer = require('../../src/util/timer'); 6 | 7 | test('compatibility stack frame is exposed on thread', t => { 8 | const vm = new VM(); 9 | vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-glide.sb3'))).then(() => { 10 | vm.greenFlag(); 11 | vm.runtime._step(); 12 | t.ok(vm.runtime.threads[0].compatibilityStackFrame.timer instanceof Timer); 13 | t.end(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/integration/tw_deterministic_sb3.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const VM = require('../../src/virtual-machine'); 3 | 4 | test('saveProjectSb3 is deterministic over time', t => { 5 | const vm = new VM(); 6 | Promise.all([ 7 | vm.saveProjectSb3('nodebuffer'), 8 | // Zip modification time is only accurate to the second 9 | new Promise(resolve => setTimeout(resolve, 1000)).then(() => vm.saveProjectSb3('nodebuffer')) 10 | ]).then(([a, b]) => { 11 | t.same(a, b); 12 | t.end(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/integration/tw_get_exported_costume.js: -------------------------------------------------------------------------------- 1 | const VM = require('../../src/virtual-machine'); 2 | const {test} = require('tap'); 3 | 4 | // The actual logic of the costume exporting and importing is tested elsewhere. 5 | // This is just to make sure that the VM's shims are going to the right place. 6 | 7 | test('getExportedCostume', t => { 8 | const vm = new VM(); 9 | t.same( 10 | vm.getExportedCostume({ 11 | asset: { 12 | data: new Uint8Array([97, 98, 99]) 13 | }, 14 | dataFormat: 'png' 15 | }), 16 | new Uint8Array([97, 98, 99]) 17 | ); 18 | t.end(); 19 | }); 20 | 21 | test('getExportedCostumeBase64', t => { 22 | // We'll just make sure that the output is being base64 encoded. 23 | const vm = new VM(); 24 | t.same( 25 | vm.getExportedCostumeBase64({ 26 | asset: { 27 | data: new Uint8Array([97, 98, 99]) 28 | }, 29 | dataFormat: 'png' 30 | }), 31 | // btoa("abc") 32 | 'YWJj' 33 | ); 34 | t.end(); 35 | }); 36 | -------------------------------------------------------------------------------- /test/integration/tw_serialize_hidden_monitors.js: -------------------------------------------------------------------------------- 1 | const Runtime = require('../../src/engine/runtime'); 2 | const {test} = require('tap'); 3 | const {serialize} = require('../../src/serialization/sb3'); 4 | const MonitorRecord = require('../../src/engine/monitor-record'); 5 | 6 | test('does not serialize hidden monitors from extensions', t => { 7 | const rt = new Runtime(); 8 | rt.requestAddMonitor(MonitorRecord({ 9 | id: 'timer', 10 | opcode: 'sensing_timer', 11 | visible: true 12 | })); 13 | rt.requestAddMonitor(MonitorRecord({ 14 | id: 'other_monitor', 15 | opcode: 'tw_someOpcodeThatIsntPartOfACoreExtension', 16 | visible: true 17 | })); 18 | 19 | const monitorsWhenVisible = serialize(rt).monitors; 20 | t.ok(monitorsWhenVisible[0].id === 'timer'); 21 | t.ok(monitorsWhenVisible[1].id === 'other_monitor'); 22 | t.equal(monitorsWhenVisible.length, 2); 23 | 24 | rt.requestHideMonitor('timer'); 25 | rt.requestHideMonitor('other_monitor'); 26 | const monitorsWhenHidden = serialize(rt).monitors; 27 | t.ok(monitorsWhenHidden[0].id === 'timer'); 28 | t.equal(monitorsWhenHidden.length, 1); 29 | 30 | t.end(); 31 | }); 32 | -------------------------------------------------------------------------------- /test/integration/tw_stackframe_op.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const {test} = require('tap'); 4 | const VirtualMachine = require('../../src/virtual-machine'); 5 | 6 | const projectPath = path.join(__dirname, '..', 'fixtures', 'tw-stackframe-op.sb3'); 7 | 8 | test('util.thread.peekStackFrame().op', t => { 9 | const vm = new VirtualMachine(); 10 | 11 | vm.runtime.setCompilerOptions({ 12 | enabled: false 13 | }); 14 | 15 | // Easiest way to test this is to overwrite an existing block 16 | vm.runtime._primitives.operator_add = function (args, util) { 17 | const op = util.thread.peekStackFrame().op; 18 | t.equal(op.id, 'c'); 19 | t.end(); 20 | 21 | // return value not used 22 | return 4; 23 | }; 24 | 25 | vm.loadProject(fs.readFileSync(projectPath)).then(() => { 26 | vm.greenFlag(); 27 | vm.runtime._step(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/integration/tw_step_events.js: -------------------------------------------------------------------------------- 1 | const Runtime = require('../../src/engine/runtime'); 2 | const {test} = require('tap'); 3 | 4 | test('step events', t => { 5 | const events = []; 6 | const rt = new Runtime(); 7 | rt.sequencer.stepThreads = () => { 8 | events.push('sequencer.stepThreads()'); 9 | return []; 10 | }; 11 | rt.on('BEFORE_EXECUTE', () => { 12 | events.push('BEFORE_EXECUTE'); 13 | }); 14 | rt.on('AFTER_EXECUTE', () => { 15 | events.push('AFTER_EXECUTE'); 16 | }); 17 | rt._step(); 18 | t.same(events, [ 19 | 'BEFORE_EXECUTE', 20 | 'sequencer.stepThreads()', 21 | 'AFTER_EXECUTE' 22 | ]); 23 | t.end(); 24 | }); 25 | -------------------------------------------------------------------------------- /test/integration/tw_xml_block.js: -------------------------------------------------------------------------------- 1 | const htmlparser = require('htmlparser2'); 2 | const {test} = require('tap'); 3 | const VirtualMachine = require('../../src/virtual-machine'); 4 | const BlockType = require('../../src/extension-support/block-type'); 5 | 6 | test('XML blocks', t => { 7 | const vm = new VirtualMachine(); 8 | vm.extensionManager._registerInternalExtension({ 9 | getInfo: () => ({ 10 | id: 'testxml', 11 | name: 'XML Test', 12 | blocks: [ 13 | { 14 | blockType: BlockType.XML, 15 | xml: '!' 16 | } 17 | ] 18 | }) 19 | }); 20 | 21 | const xmlList = vm.runtime.getBlocksXML(); 22 | t.equal(xmlList.length, 1); 23 | 24 | const parsedXML = htmlparser.parseDOM(xmlList[0].xml); 25 | t.equal(parsedXML.length, 1); 26 | 27 | const category = parsedXML[0]; 28 | t.equal(category.name, 'category'); 29 | t.equal(category.children.length, 1); 30 | 31 | const label = category.children[0]; 32 | t.equal(label.name, 'test'); 33 | t.equal(label.attribs.it, 'works'); 34 | t.equal(label.children.length, 1); 35 | t.equal(label.children[0].data, '!'); 36 | 37 | t.end(); 38 | }); 39 | -------------------------------------------------------------------------------- /test/snapshot/README.md: -------------------------------------------------------------------------------- 1 | # Snapshot tests 2 | 3 | Snapshot testing runs the compiler on many of the test projects in test/fixtures/execute and verifies that the compiled output is identical to a pre-calculated "snapshot". This verifies: 4 | 5 | - The compiler is deterministic (mostly) 6 | - The compiler's output does not change unexpectedly 7 | - Optimizations and type analysis in the generated code are working properly 8 | 9 | These snapshots are automatically verified as part of the integration tests. There is also a more readable CLI for humans. To verify the snapshots: 10 | 11 | ``` 12 | node test/snapshot 13 | ``` 14 | 15 | When the compiler's output or the test projects have intentionally changed, run: 16 | 17 | ``` 18 | node test/snapshot --update 19 | ``` 20 | 21 | Verify that the snapshot diff is what you expect, then commit the changes. 22 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-add-can-return-nan.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: b435d9356099286cb062435cc2eb968544bcbcd9213e2b6da902eb3bb689f425 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); 9 | if (!((Infinity + -Infinity) <= 0)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-all-at-once.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 428175715a6d8670b809c69bdda12e5043eff9921ccdd908507636a625938702 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "1TRvh{mBarwY!BX8`o$R", null); 9 | if (true) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "K|r`QjC126S.93lMawiD", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "QaZ%(g:;bB~D+24z:U?l", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 4764ae15e39b22b1a071c9ac79f8758f24ef41855802db8674e200fd26139ed0 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = target.variables["null"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); 10 | b1.value = 5; 11 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); 12 | retire(); return; 13 | }; }) 14 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 9ecff9e3c4b1dcdf3e23d0e49c0a2da3de446b6d626a2b5ee39d761be20344ca 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "f", null); 9 | yield* thread.procedures["ZBlock A %s"]("Hai!!!"); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Sprite1 ZBlock A %s 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | const b0 = runtime.getOpcodeFunction("looks_say"); 17 | return function* genXYZ_Block_A_ (p0) { 18 | if ((("" + p0).toLowerCase() === "Hai!!!".toLowerCase())) { 19 | yield* executeInCompatibilityLayer({"MESSAGE":"pass did not cast",}, b0, false, false, "m", null); 20 | } else { 21 | yield* executeInCompatibilityLayer({"MESSAGE":"fail was casted",}, b0, false, false, "n", null); 22 | } 23 | return ""; 24 | }; }) 25 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-broadcast-id-and-name-desync.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: f2d984762d77ff375ba3e39b5d57190b71a131f0d8620d2becb2735b7da116c3 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?@x?KlY[GHB#^le;O^;Z", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "*S!`s:/sOEm#Bd%7=h7E", null); 17 | yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" })); 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g#w*ISI)$Wi.45AszY|1", null); 19 | retire(); return; 20 | }; }) 21 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: d1f532866d8de3d81185db7ecb94ecaa4e7549feb4e26ee4f849cd0aaf1bb154 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()*H*UE)$Jc!c}qb{,O)", null); 10 | target.setSize(96); 11 | b1.value = 0; 12 | while (!(100 === Math.round(target.size))) { 13 | b1.value = ((+b1.value || 0) + 1); 14 | target.setSize(target.size + ((((100 - Math.round(target.size)) || 0) / 10) || 0)); 15 | yield; 16 | } 17 | if (((+b1.value || 0) === 20)) { 18 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); 19 | } 20 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); 21 | retire(); return; 22 | }; }) 23 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-color-input-returns-hex.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 28a59bb79ba328f31ac0b79f49143a2513080e30a7383fda80579d08021c3c82 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); 10 | b1.value = "#22388a"; 11 | if ((("" + b1.value).toLowerCase() === "#22388a".toLowerCase())) { 12 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); 13 | } 14 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); 15 | retire(); return; 16 | }; }) 17 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-custom-report-repeat.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: d293b52c4330db5d33eddb66742496017b5c96baacc41654961cfa97d08668d8 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); 10 | b1.value = 0; 11 | for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { 12 | b1.value = ((+b1.value || 0) + 1); 13 | yield; 14 | } 15 | if (((+b1.value || 0) === 40)) { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); 17 | } 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); 19 | retire(); return; 20 | }; }) 21 | 22 | // Sprite1 Zblock name 23 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 24 | return function funXYZ_block_name () { 25 | return 40; 26 | return ""; 27 | }; }) 28 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 1d02d01ddcd53c67e093bda79912f19683829f86fd23e1f77cbfc0aef03dc0f3 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = target.variables["gTtSj;o_E;Snkn620KF."]; 8 | const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; 9 | return function* genXYZ () { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); 11 | b1.value = 2; 12 | if (((+b1.value || 0) === 2)) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); 14 | } 15 | b2.value = []; 16 | b2.value.push(3); 17 | b2._monitorUpToDate = false; 18 | if (((+(b2.value[(1 | 0) - 1] ?? "") || 0) === 3)) { 19 | yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); 20 | } 21 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); 22 | retire(); return; 23 | }; }) 24 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: fd981742e0e4299bad5a89349635d3a7d0467d8163ae77ba4bafe43c97849bae 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null); 9 | thread.procedures["Zfoo %s"](""); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Sprite1 Zfoo %s 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | return function funXYZ_foo_ (p0) { 17 | return ""; 18 | return ""; 19 | }; }) 20 | 21 | // Sprite1 Zno op 22 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 23 | return function funXYZ_no_op () { 24 | return ""; 25 | }; }) 26 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-loop-custom-reporter.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 360d8b29e0e690dda9e91faed6881057d1f38d98258ed8e11c75bdd30536b560 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, null, null); 10 | b1.value = 0; 11 | for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { 12 | b1.value = ((+b1.value || 0) + 1); 13 | yield; 14 | } 15 | if (((+b1.value || 0) === 4)) { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, null, null); 17 | } 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, null, null); 19 | retire(); return; 20 | }; }) 21 | 22 | // Sprite1 block name 23 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 24 | return function funXYZ_block_name () { 25 | return 4; 26 | return ""; 27 | }; }) 28 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-one-divide-negative-zero.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 169af11f112ebea3d6768317652a72a6374c407f432537990689d46080fe2b92 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); 9 | if ((((1 / -0) || 0) === -Infinity)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 5b964fa791468016b188af74e50cadad73d482be066b104bb22faff7e4a156dc 3 | 4 | // Player script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "#0F2+kcgu;or|hdwuT9{", null); 9 | yield* thread.procedures["ZSet Costume"](); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKge)QH2e:WH6b6g@", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Player ZSet Costume 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | const b0 = runtime.getOpcodeFunction("looks_say"); 17 | return function* genXYZ_Set_Costume () { 18 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Z$W^@c(f)rHu:DL/SGuQ", null); 19 | return ""; 20 | }; }) 21 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 2afbb43dad9e66e37997e13bf3ffb90bf39effd8974c2eb1a95bed61d437b6de 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); 10 | b1.value = ""; 11 | thread.procedures["Zdo something"](); 12 | if (!compareEqual(b1.value, "")) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); 14 | } 15 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); 16 | retire(); return; 17 | }; }) 18 | 19 | // Sprite1 Zdo something 20 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 21 | const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 22 | return function funXYZ_do_something () { 23 | b0.value = "help"; 24 | return ""; 25 | }; }) 26 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 9805621c896afb4a8ed71236417a0311e5f4f38378214914625248b6157178b4 3 | 4 | // Apple script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); 9 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "f", null); 10 | retire(); return; 11 | }; }) 12 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-procedure-return-non-existent.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 2d07ab31e7f1e6f263996fa42ff79f849fed048a047d68960bd324960bcc1452 3 | 4 | // Sprite2 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); 10 | b1.value = "discard me"; 11 | b1.value = ""; 12 | if (compareEqual(b1.value, "")) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); 14 | } 15 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 16 | retire(); return; 17 | }; }) 18 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-subtract-can-return-nan.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: f54b97baf31500c1b6bd5b9865ce96b8aeef1001169bbe4550bbcbff84f2dae6 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); 9 | if (!((Infinity - Infinity) <= 0)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: ae6b920864ec07bc5a36b4af493b1646e54241abadabfa7bf962b43610ad926d 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); 17 | runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true); 18 | retire(); return; 19 | }; }) 20 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 503e54070a6a749f8ffbcfad08d64cff3c1abb9400a7519b623b3876bd97e54a 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); 17 | runtime.ext_scratch3_looks._setBackdrop(stage, "backdrop2"); 18 | retire(); return; 19 | }; }) 20 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-add-can-return-nan.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: b435d9356099286cb062435cc2eb968544bcbcd9213e2b6da902eb3bb689f425 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); 9 | if (!((Infinity + -Infinity) <= 0)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-all-at-once.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 428175715a6d8670b809c69bdda12e5043eff9921ccdd908507636a625938702 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "1TRvh{mBarwY!BX8`o$R", null); 9 | if (true) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "K|r`QjC126S.93lMawiD", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "QaZ%(g:;bB~D+24z:U?l", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-automatic-variable-creation-literal-null-id.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 4764ae15e39b22b1a071c9ac79f8758f24ef41855802db8674e200fd26139ed0 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = target.variables["null"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); 10 | b1.value = 5; 11 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "d", null); 12 | retire(); return; 13 | }; }) 14 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-boolean-arguments-are-not-cast.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 9ecff9e3c4b1dcdf3e23d0e49c0a2da3de446b6d626a2b5ee39d761be20344ca 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "f", null); 9 | yield* thread.procedures["ZBlock A %s"]("Hai!!!"); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "k", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Sprite1 ZBlock A %s 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | const b0 = runtime.getOpcodeFunction("looks_say"); 17 | return function* genXYZ_Block_A_ (p0) { 18 | if ((("" + p0).toLowerCase() === "Hai!!!".toLowerCase())) { 19 | yield* executeInCompatibilityLayer({"MESSAGE":"pass did not cast",}, b0, false, false, "m", null); 20 | } else { 21 | yield* executeInCompatibilityLayer({"MESSAGE":"fail was casted",}, b0, false, false, "n", null); 22 | } 23 | return ""; 24 | }; }) 25 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-broadcast-id-and-name-desync.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: f2d984762d77ff375ba3e39b5d57190b71a131f0d8620d2becb2735b7da116c3 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "?@x?KlY[GHB#^le;O^;Z", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "*S!`s:/sOEm#Bd%7=h7E", null); 17 | yield* waitThreads(startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: "message1" })); 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g#w*ISI)$Wi.45AszY|1", null); 19 | retire(); return; 20 | }; }) 21 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-change-size-does-not-use-rounded-size.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: d1f532866d8de3d81185db7ecb94ecaa4e7549feb4e26ee4f849cd0aaf1bb154 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "()*H*UE)$Jc!c}qb{,O)", null); 10 | target.setSize(96); 11 | b1.value = 0; 12 | while (!(100 === Math.round(target.size))) { 13 | b1.value = ((+b1.value || 0) + 1); 14 | target.setSize(target.size + ((((100 - Math.round(target.size)) || 0) / 10) || 0)); 15 | yield; 16 | } 17 | if (((+b1.value || 0) === 20)) { 18 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "FPDFR?Wwq)kLj0A$0D{@", null); 19 | } 20 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "1,vLoJ4OQBv+Q#$VoYf=", null); 21 | retire(); return; 22 | }; }) 23 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-color-input-returns-hex.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 28a59bb79ba328f31ac0b79f49143a2513080e30a7383fda80579d08021c3c82 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "c", null); 10 | b1.value = "#22388a"; 11 | if ((("" + b1.value).toLowerCase() === "#22388a".toLowerCase())) { 12 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "f", null); 13 | } 14 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "e", null); 15 | retire(); return; 16 | }; }) 17 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-custom-report-repeat.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: d293b52c4330db5d33eddb66742496017b5c96baacc41654961cfa97d08668d8 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "e", null); 10 | b1.value = 0; 11 | for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { 12 | b1.value = ((+b1.value || 0) + 1); 13 | yield; 14 | } 15 | if (((+b1.value || 0) === 40)) { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "n", null); 17 | } 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); 19 | retire(); return; 20 | }; }) 21 | 22 | // Sprite1 Zblock name 23 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 24 | return function funXYZ_block_name () { 25 | return 40; 26 | return ""; 27 | }; }) 28 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-forkphorus-515-variable-id-name-desync-name-fallback.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 1d02d01ddcd53c67e093bda79912f19683829f86fd23e1f77cbfc0aef03dc0f3 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = target.variables["gTtSj;o_E;Snkn620KF."]; 8 | const b2 = target.variables["zShM`!CD?d_|Z,]5X}N6"]; 9 | return function* genXYZ () { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 2",}, b0, false, false, "d", null); 11 | b1.value = 2; 12 | if (((+b1.value || 0) === 2)) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass variable",}, b0, false, false, "k", null); 14 | } 15 | b2.value = []; 16 | b2.value.push(3); 17 | b2._monitorUpToDate = false; 18 | if (((+(b2.value[(1 | 0) - 1] ?? "") || 0) === 3)) { 19 | yield* executeInCompatibilityLayer({"MESSAGE":"pass list",}, b0, false, false, "m", null); 20 | } 21 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "l", null); 22 | retire(); return; 23 | }; }) 24 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-gh-201-stop-script-does-not-reevaluate-arguments.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: fd981742e0e4299bad5a89349635d3a7d0467d8163ae77ba4bafe43c97849bae 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "d", null); 9 | thread.procedures["Zfoo %s"](""); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Sprite1 Zfoo %s 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | return function funXYZ_foo_ (p0) { 17 | return ""; 18 | return ""; 19 | }; }) 20 | 21 | // Sprite1 Zno op 22 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 23 | return function funXYZ_no_op () { 24 | return ""; 25 | }; }) 26 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-loop-custom-reporter.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 360d8b29e0e690dda9e91faed6881057d1f38d98258ed8e11c75bdd30536b560 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, null, null); 10 | b1.value = 0; 11 | for (var a0 = (+thread.procedures["Zblock name"]() || 0); a0 >= 0.5; a0--) { 12 | b1.value = ((+b1.value || 0) + 1); 13 | yield; 14 | } 15 | if (((+b1.value || 0) === 4)) { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, null, null); 17 | } 18 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, null, null); 19 | retire(); return; 20 | }; }) 21 | 22 | // Sprite1 block name 23 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 24 | return function funXYZ_block_name () { 25 | return 4; 26 | return ""; 27 | }; }) 28 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-one-divide-negative-zero.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 169af11f112ebea3d6768317652a72a6374c407f432537990689d46080fe2b92 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "@|B*yJ0zKh!acN`7L-N5", null); 9 | if ((((1 / -0) || 0) === -Infinity)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "=enYDFG11Nj/0BL:y56w", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",Cpv8W0RH0RgNky[1xb:", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-prefers-first-occurence-of-procedure-387608267.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 5b964fa791468016b188af74e50cadad73d482be066b104bb22faff7e4a156dc 3 | 4 | // Player script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "#0F2+kcgu;or|hdwuT9{", null); 9 | yield* thread.procedures["ZSet Costume"](); 10 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Q^(MKge)QH2e:WH6b6g@", null); 11 | retire(); return; 12 | }; }) 13 | 14 | // Player ZSet Costume 15 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 16 | const b0 = runtime.getOpcodeFunction("looks_say"); 17 | return function* genXYZ_Set_Costume () { 18 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Z$W^@c(f)rHu:DL/SGuQ", null); 19 | return ""; 20 | }; }) 21 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-procedure-call-resets-variable-input-types-430811055.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 2afbb43dad9e66e37997e13bf3ffb90bf39effd8974c2eb1a95bed61d437b6de 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "qf{MD}-f+l?U+)KA#Vnm", null); 10 | b1.value = ""; 11 | thread.procedures["Zdo something"](); 12 | if (!compareEqual(b1.value, "")) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "Sgf_#7|GOpx!R]?Q3]$s", null); 14 | } 15 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, ",vD-ZG7f{]FoJ`,))JWh", null); 16 | retire(); return; 17 | }; }) 18 | 19 | // Sprite1 Zdo something 20 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 21 | const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 22 | return function funXYZ_do_something () { 23 | b0.value = "help"; 24 | return ""; 25 | }; }) 26 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-procedure-prototype-exists-but-not-definition-549160843.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 9805621c896afb4a8ed71236417a0311e5f4f38378214914625248b6157178b4 3 | 4 | // Apple script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "a", null); 9 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "f", null); 10 | retire(); return; 11 | }; }) 12 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-procedure-return-non-existent.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 2d07ab31e7f1e6f263996fa42ff79f849fed048a047d68960bd324960bcc1452 3 | 4 | // Sprite2 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"]; 8 | return function* genXYZ () { 9 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "d", null); 10 | b1.value = "discard me"; 11 | b1.value = ""; 12 | if (compareEqual(b1.value, "")) { 13 | yield* executeInCompatibilityLayer({"MESSAGE":"pass non existent procedure returned empty string",}, b0, false, false, "h", null); 14 | } 15 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "g", null); 16 | retire(); return; 17 | }; }) 18 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-subtract-can-return-nan.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: f54b97baf31500c1b6bd5b9865ce96b8aeef1001169bbe4550bbcbff84f2dae6 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "6_?4sPB-|g:DtjdOm5Q-", null); 9 | if (!((Infinity - Infinity) <= 0)) { 10 | yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, ")-u2YbbMb;gXMPOidjPj", null); 11 | } 12 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "zqE}hdaes.b)@mO1{R;X", null); 13 | retire(); return; 14 | }; }) 15 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-next-backdrop.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: ae6b920864ec07bc5a36b4af493b1646e54241abadabfa7bf962b43610ad926d 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); 17 | runtime.ext_scratch3_looks._setBackdrop(stage, stage.currentCostume + 1, true); 18 | retire(); return; 19 | }; }) 20 | -------------------------------------------------------------------------------- /test/snapshot/__snapshots__/warp-timer/tw-when-backdrop-switches-to-switch-backdrop-to.sb3.tw-snapshot: -------------------------------------------------------------------------------- 1 | // TW Snapshot 2 | // Input SHA-256: 503e54070a6a749f8ffbcfad08d64cff3c1abb9400a7519b623b3876bd97e54a 3 | 4 | // Sprite1 script 5 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 6 | const b0 = runtime.getOpcodeFunction("looks_say"); 7 | return function* genXYZ () { 8 | yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "Ny4npe`j3|CTeaIS.:6O", null); 9 | retire(); return; 10 | }; }) 11 | 12 | // Sprite1 script 13 | (function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage(); 14 | const b0 = runtime.getOpcodeFunction("looks_say"); 15 | return function* genXYZ () { 16 | yield* executeInCompatibilityLayer({"MESSAGE":"plan 0",}, b0, false, false, "2T.vCF,K}vA=XNZ=kY+v", null); 17 | runtime.ext_scratch3_looks._setBackdrop(stage, "backdrop2"); 18 | retire(); return; 19 | }; }) 20 | -------------------------------------------------------------------------------- /test/unit/blocks_motion.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const Motion = require('../../src/blocks/scratch3_motion'); 3 | const Runtime = require('../../src/engine/runtime'); 4 | const Sprite = require('../../src/sprites/sprite.js'); 5 | const RenderedTarget = require('../../src/sprites/rendered-target.js'); 6 | 7 | test('getPrimitives', t => { 8 | const rt = new Runtime(); 9 | const motion = new Motion(rt); 10 | t.type(motion.getPrimitives(), 'object'); 11 | t.end(); 12 | }); 13 | 14 | test('Coordinates have limited precision', t => { 15 | const rt = new Runtime(); 16 | const motion = new Motion(rt); 17 | const sprite = new Sprite(null, rt); 18 | const target = new RenderedTarget(sprite, rt); 19 | const util = {target}; 20 | 21 | motion.goToXY({X: 0.999999999, Y: 0.999999999}, util); 22 | 23 | t.equals(motion.getX({}, util), 1); 24 | t.equals(motion.getY({}, util), 1); 25 | t.end(); 26 | }); 27 | -------------------------------------------------------------------------------- /test/unit/blocks_pen_tw.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | 3 | const Runtime = require('../../src/engine/runtime'); 4 | const Scratch3PenBlocks = require('../../src/extensions/scratch3_pen/index'); 5 | 6 | test('_clampPenSize', t => { 7 | const rt = new Runtime(); 8 | const pen = new Scratch3PenBlocks(rt); 9 | 10 | t.equal(pen._clampPenSize(-1), 1); 11 | t.equal(pen._clampPenSize(0), 1); 12 | t.equal(pen._clampPenSize(0.25), 1); 13 | t.equal(pen._clampPenSize(1), 1); 14 | t.equal(pen._clampPenSize(10), 10); 15 | t.equal(pen._clampPenSize(1000), 1000); 16 | t.equal(pen._clampPenSize(1200), 1200); 17 | t.equal(pen._clampPenSize(1201), 1200); 18 | 19 | rt.setRuntimeOptions({ 20 | miscLimits: false 21 | }); 22 | t.equal(pen._clampPenSize(-1), 0); 23 | t.equal(pen._clampPenSize(0), 0); 24 | t.equal(pen._clampPenSize(0.25), 0.25); 25 | t.equal(pen._clampPenSize(1), 1); 26 | t.equal(pen._clampPenSize(10), 10); 27 | t.equal(pen._clampPenSize(1000), 1000); 28 | t.equal(pen._clampPenSize(1200), 1200); 29 | t.equal(pen._clampPenSize(1201), 1201); 30 | 31 | t.end(); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/blocks_procedures.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const Procedures = require('../../src/blocks/scratch3_procedures'); 3 | 4 | const blocks = new Procedures(null); 5 | 6 | test('getPrimitives', t => { 7 | t.type(blocks.getPrimitives(), 'object'); 8 | t.end(); 9 | }); 10 | 11 | // Originally inspired by https://github.com/scratchfoundation/scratch-gui/issues/809 12 | test('calling a custom block with no definition does not throw', t => { 13 | const args = { 14 | mutation: { 15 | proccode: 'undefined proc' 16 | } 17 | }; 18 | const util = { 19 | getProcedureParamNamesIdsAndDefaults: () => null, 20 | stackFrame: { 21 | executed: false 22 | } 23 | }; 24 | t.doesNotThrow(() => { 25 | blocks.call(args, util); 26 | }); 27 | t.end(); 28 | }); 29 | -------------------------------------------------------------------------------- /test/unit/blocks_sound_tw.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | 3 | const Runtime = require('../../src/engine/runtime'); 4 | const Target = require('../../src/engine/target'); 5 | const Sprite = require('../../src/sprites/sprite'); 6 | const Scratch3SoundBlocks = require('../../src/blocks/scratch3_sound'); 7 | 8 | test('effect clamping runtime option', t => { 9 | const rt = new Runtime(); 10 | const target = new Target(rt); 11 | const sprite = new Sprite(); 12 | target.sprite = sprite; 13 | const sound = new Scratch3SoundBlocks(rt); 14 | 15 | sound.setEffect({ 16 | EFFECT: 'pitch', 17 | VALUE: 720 18 | }, { 19 | target 20 | }); 21 | t.equal(sound._getSoundState(target).effects.pitch, 360); 22 | 23 | rt.setRuntimeOptions({ 24 | miscLimits: false 25 | }); 26 | sound.setEffect({ 27 | EFFECT: 'pitch', 28 | VALUE: 720 29 | }, { 30 | target 31 | }); 32 | t.equal(sound._getSoundState(target).effects.pitch, 720); 33 | 34 | t.end(); 35 | }); 36 | -------------------------------------------------------------------------------- /test/unit/engine_mutation-adapter.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | 3 | const mutationAdapter = require('../../src/engine/mutation-adapter'); 4 | 5 | test('spec', t => { 6 | t.type(mutationAdapter, 'function'); 7 | t.end(); 8 | }); 9 | 10 | test('convert DOM to Scratch object', t => { 11 | const testStringRaw = '"arbitrary" & \'complicated\' test string'; 12 | const testStringEscaped = '\\"arbitrary\\" & 'complicated' test string'; 13 | const xml = ``; 14 | const expectedMutation = { 15 | tagName: 'mutation', 16 | children: [], 17 | blockInfo: { 18 | text: testStringRaw 19 | } 20 | }; 21 | 22 | // TODO: do we want to test passing a DOM node to `mutationAdapter`? Node.js doesn't have built-in DOM support... 23 | const mutationFromString = mutationAdapter(xml); 24 | t.deepEqual(mutationFromString, expectedMutation); 25 | t.end(); 26 | }); 27 | -------------------------------------------------------------------------------- /test/unit/extension_microbit.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | // const MicroBit = require('../../src/extensions/scratch3_microbit/index.js'); 3 | 4 | test('displayText', t => { 5 | t.end(); 6 | }); 7 | 8 | test('displayMatrix', t => { 9 | t.end(); 10 | }); 11 | 12 | // etc... 13 | -------------------------------------------------------------------------------- /test/unit/extension_video_sensing_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/unit/extension_video_sensing_center.png -------------------------------------------------------------------------------- /test/unit/extension_video_sensing_down-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/unit/extension_video_sensing_down-10.png -------------------------------------------------------------------------------- /test/unit/extension_video_sensing_left-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/unit/extension_video_sensing_left-10.png -------------------------------------------------------------------------------- /test/unit/extension_video_sensing_left-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurboWarp/scratch-vm/fa82d53a9490eec29bb7bcef214b2bb8e09e0172/test/unit/extension_video_sensing_left-5.png -------------------------------------------------------------------------------- /test/unit/io_clock.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const Clock = require('../../src/io/clock'); 3 | const Runtime = require('../../src/engine/runtime'); 4 | 5 | test('spec', t => { 6 | const rt = new Runtime(); 7 | const c = new Clock(rt); 8 | 9 | t.type(Clock, 'function'); 10 | t.type(c, 'object'); 11 | t.type(c.projectTimer, 'function'); 12 | t.type(c.pause, 'function'); 13 | t.type(c.resume, 'function'); 14 | t.type(c.resetProjectTimer, 'function'); 15 | t.end(); 16 | }); 17 | 18 | test('cycle', t => { 19 | const rt = new Runtime(); 20 | const c = new Clock(rt); 21 | 22 | t.ok(c.projectTimer() <= 0.1); 23 | setTimeout(() => { 24 | c.resetProjectTimer(); 25 | setTimeout(() => { 26 | // The timer shouldn't advance until all threads have been stepped 27 | t.ok(c.projectTimer() === 0); 28 | c.pause(); 29 | t.ok(c.projectTimer() === 0); 30 | c.resume(); 31 | t.ok(c.projectTimer() === 0); 32 | t.end(); 33 | }, 100); 34 | }, 100); 35 | rt._step(); 36 | t.ok(c.projectTimer() > 0); 37 | }); 38 | -------------------------------------------------------------------------------- /test/unit/io_mousewheel.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const MouseWheel = require('../../src/io/mouseWheel'); 3 | const Runtime = require('../../src/engine/runtime'); 4 | 5 | test('spec', t => { 6 | const rt = new Runtime(); 7 | const mw = new MouseWheel(rt); 8 | 9 | t.type(mw, 'object'); 10 | t.type(mw.postData, 'function'); 11 | t.end(); 12 | }); 13 | 14 | test('blocks activated by scrolling', t => { 15 | let _startHatsArgs; 16 | const rt = { 17 | startHats: (...args) => { 18 | _startHatsArgs = args; 19 | } 20 | }; 21 | const mw = new MouseWheel(rt); 22 | 23 | _startHatsArgs = null; 24 | mw.postData({ 25 | deltaY: -1 26 | }); 27 | t.strictEquals(_startHatsArgs[0], 'event_whenkeypressed'); 28 | t.strictEquals(_startHatsArgs[1].KEY_OPTION, 'up arrow'); 29 | 30 | _startHatsArgs = null; 31 | mw.postData({ 32 | deltaY: +1 33 | }); 34 | t.strictEquals(_startHatsArgs[0], 'event_whenkeypressed'); 35 | t.strictEquals(_startHatsArgs[1].KEY_OPTION, 'down arrow'); 36 | 37 | _startHatsArgs = null; 38 | mw.postData({ 39 | deltaY: 0 40 | }); 41 | t.strictEquals(_startHatsArgs, null); 42 | 43 | t.end(); 44 | }); 45 | -------------------------------------------------------------------------------- /test/unit/io_scratchBLE.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | // const ScratchBLE = require('../../src/io/scratchBLE'); 3 | 4 | test('constructor', t => { 5 | t.end(); 6 | }); 7 | 8 | test('waitForSocket', t => { 9 | t.end(); 10 | }); 11 | 12 | test('requestPeripheral', t => { 13 | t.end(); 14 | }); 15 | 16 | test('didReceiveCall', t => { 17 | t.end(); 18 | }); 19 | 20 | test('read', t => { 21 | t.end(); 22 | }); 23 | 24 | test('write', t => { 25 | t.end(); 26 | }); 27 | -------------------------------------------------------------------------------- /test/unit/io_scratchBT.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | // const ScratchBT = require('../../src/io/scratchBT'); 3 | 4 | test('constructor', t => { 5 | t.end(); 6 | }); 7 | 8 | test('requestPeripheral', t => { 9 | t.end(); 10 | }); 11 | 12 | test('connectPeripheral', t => { 13 | t.end(); 14 | }); 15 | 16 | test('sendMessage', t => { 17 | t.end(); 18 | }); 19 | 20 | test('didReceiveCall', t => { 21 | t.end(); 22 | }); 23 | -------------------------------------------------------------------------------- /test/unit/io_userData.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const UserData = require('../../src/io/userData'); 3 | 4 | test('spec', t => { 5 | const userData = new UserData(); 6 | 7 | t.type(userData, 'object'); 8 | t.type(userData.postData, 'function'); 9 | t.type(userData.getUsername, 'function'); 10 | t.end(); 11 | }); 12 | 13 | test('getUsername returns empty string initially', t => { 14 | const userData = new UserData(); 15 | 16 | t.strictEquals(userData.getUsername(), ''); 17 | t.end(); 18 | }); 19 | 20 | test('postData sets the username', t => { 21 | const userData = new UserData(); 22 | userData.postData({username: 'TEST'}); 23 | t.strictEquals(userData.getUsername(), 'TEST'); 24 | t.end(); 25 | }); 26 | -------------------------------------------------------------------------------- /test/unit/project_load_changed_state.js: -------------------------------------------------------------------------------- 1 | const tap = require('tap'); 2 | const path = require('path'); 3 | const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; 4 | const makeTestStorage = require('../fixtures/make-test-storage'); 5 | const VirtualMachine = require('../../src/virtual-machine'); 6 | 7 | const test = tap.test; 8 | 9 | // Test that loading a project does not emit a project change 10 | // This is in its own file so that it does not affect the test setup 11 | // and results of the other project changed state tests 12 | test('Loading a project should not emit a project changed event', t => { 13 | const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); 14 | const project = readFileToBuffer(projectUri); 15 | 16 | const vm = new VirtualMachine(); 17 | 18 | let projectChanged = false; 19 | vm.runtime.addListener('PROJECT_CHANGED', () => { 20 | projectChanged = true; 21 | }); 22 | 23 | vm.attachStorage(makeTestStorage()); 24 | return vm.loadProject(project).then(() => { 25 | t.equal(projectChanged, false); 26 | t.end(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/unit/tw_clones.js: -------------------------------------------------------------------------------- 1 | const Runtime = require('../../src/engine/runtime'); 2 | const Sprite = require('../../src/sprites/sprite'); 3 | 4 | const {test} = require('tap'); 5 | 6 | test('clone counter', t => { 7 | const rt = new Runtime(); 8 | const sprite = new Sprite(null, rt); 9 | const original = sprite.createClone(); 10 | t.equal(rt._cloneCounter, 0); 11 | const clone = original.makeClone(); 12 | t.equal(rt._cloneCounter, 1); 13 | clone.dispose(); 14 | t.equal(rt._cloneCounter, 0); 15 | original.dispose(); 16 | t.equal(rt._cloneCounter, 0); 17 | t.end(); 18 | }); 19 | -------------------------------------------------------------------------------- /test/unit/tw_extension_music.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const Music = require('../../src/extensions/scratch3_music/index.js'); 3 | const Runtime = require('../../src/engine/runtime.js'); 4 | 5 | test('_isConcurrencyLimited', t => { 6 | const rt = new Runtime(); 7 | 8 | // sanity check so that the setRuntimeOptions() call below actually does something 9 | t.equal(rt.runtimeOptions.miscLimits, true, 'misc limits enabled by default'); 10 | 11 | const blocks = new Music(rt); 12 | t.equal(blocks._isConcurrencyLimited(), false, 'not limited initially'); 13 | 14 | // logic here is slightly weird but this matches Scratch 15 | blocks._concurrencyCounter = Music.CONCURRENCY_LIMIT; 16 | t.equal(blocks._isConcurrencyLimited(), false, 'not limited at limit'); 17 | 18 | blocks._concurrencyCounter = Music.CONCURRENCY_LIMIT + 1; 19 | t.equal(blocks._isConcurrencyLimited(), true, 'limited above limit'); 20 | 21 | rt.setRuntimeOptions({ 22 | miscLimits: false 23 | }); 24 | t.equal(blocks._isConcurrencyLimited(), false, 'not limited when miscLimits: false'); 25 | 26 | t.end(); 27 | }); 28 | -------------------------------------------------------------------------------- /test/unit/tw_mouse.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const Runtime = require('../../src/engine/runtime'); 3 | 4 | test('isDown does not error before project loads', t => { 5 | const rt = new Runtime(); 6 | rt.ioDevices.mouse.postData({ 7 | isDown: true, 8 | x: 20, 9 | y: 20, 10 | canvasWidth: 100, 11 | canvasHeight: 100 12 | }); 13 | t.end(); 14 | }); 15 | -------------------------------------------------------------------------------- /test/unit/tw_performance_measure_error.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const VirtualMachine = require('../../src/virtual-machine'); 5 | 6 | global.performance = { 7 | mark () { 8 | // No-op 9 | }, 10 | measure () { 11 | throw new Error('Mock error to simulate browser garbage collecting one of the marks before this code runs'); 12 | } 13 | }; 14 | 15 | test('performance.measure() error in loadProject is ignored', async t => { 16 | const vm = new VirtualMachine(); 17 | await vm.loadProject(fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-empty-project.sb3'))); 18 | t.end(); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/tw_translate.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | 3 | // Simulate the network being down or filtered 4 | // Run this before fetch-with-timeout.js is gets loaded. 5 | global.fetch = () => Promise.reject(new Error('Simulated network error')); 6 | 7 | const Scratch3TranslateBlocks = require('../../src/extensions/scratch3_translate/index'); 8 | 9 | // Node 21 and later defines a navigator object, but we want to override that for the test 10 | Object.defineProperty(global, 'navigator', { 11 | value: { 12 | language: 'en-US' 13 | } 14 | }); 15 | 16 | // Translate tries to access AbortController from window, but does not require it to exist. 17 | global.window = {}; 18 | 19 | test('translate returns original string on network error', t => { 20 | t.plan(1); 21 | 22 | const extension = new Scratch3TranslateBlocks(); 23 | extension.getTranslate({WORDS: 'My message 123123', LANGUAGE: 'es'}) 24 | .then(message => { 25 | t.equal(message, 'My message 123123'); 26 | t.end(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/unit/tw_util_string.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const StringUtil = require('../../src/util/string-util'); 3 | 4 | test('caseInsensitiveUnusedName', t => { 5 | t.equal(StringUtil.caseInsensitiveUnusedName('test', []), 'test'); 6 | t.equal(StringUtil.caseInsensitiveUnusedName('test', ['Test']), 'test2'); 7 | t.equal(StringUtil.caseInsensitiveUnusedName('TEST3', ['test3']), 'TEST2'); 8 | t.equal(StringUtil.caseInsensitiveUnusedName('TEST', ['test', 'TESt1', 'teST2']), 'TEST3'); 9 | t.end(); 10 | }); 11 | -------------------------------------------------------------------------------- /test/unit/tw_vm_exports.js: -------------------------------------------------------------------------------- 1 | const {test} = require('tap'); 2 | const VM = require('../../src/virtual-machine'); 3 | 4 | test('exports exist', t => { 5 | const vm = new VM(); 6 | t.type(vm.exports.Sprite, 'function'); 7 | t.type(vm.exports.RenderedTarget, 'function'); 8 | t.end(); 9 | }); 10 | 11 | test('JSZip', t => { 12 | const JSZip = new VM().exports.JSZip; 13 | const zip = new JSZip(); 14 | t.type(zip.file, 'function'); 15 | t.end(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/unit/util_jsonrpc-web-socket.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | // const JSONRPCWebSocket = require('../../src/util/jsonrpc-web-socket'); 3 | 4 | test('constructor', t => { 5 | t.end(); 6 | }); 7 | 8 | test('dispose', t => { 9 | t.end(); 10 | }); 11 | -------------------------------------------------------------------------------- /test/unit/util_jsonrpc.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | // const JSONRPC = require('../../src/util/jsonrpc'); 3 | 4 | test('constructor', t => { 5 | t.end(); 6 | }); 7 | 8 | test('sendRemoteRequest', t => { 9 | t.end(); 10 | }); 11 | 12 | test('sendRemoteNotification', t => { 13 | t.end(); 14 | }); 15 | 16 | test('didReceiveCall', t => { 17 | t.end(); 18 | }); 19 | -------------------------------------------------------------------------------- /test/unit/util_rateLimiter.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | const RateLimiter = require('../../src/util/rateLimiter.js'); 3 | 4 | test('rate limiter', t => { 5 | // Create a rate limiter with maximum of 20 sends per second 6 | const rate = 20; 7 | const limiter = new RateLimiter(rate); 8 | 9 | // Simulate time passing with a stubbed timer 10 | let simulatedTime = Date.now(); 11 | limiter._timer = {timeElapsed: () => simulatedTime}; 12 | 13 | // The rate limiter starts with a number of tokens equal to the max rate 14 | t.equal(limiter._count, rate); 15 | 16 | // Running okayToSend a number of times equal to the max rate 17 | // uses up all of the tokens 18 | for (let i = 0; i < rate; i++) { 19 | t.true(limiter.okayToSend()); 20 | // Tokens are counting down 21 | t.equal(limiter._count, rate - (i + 1)); 22 | } 23 | t.false(limiter.okayToSend()); 24 | 25 | // Advance the timer enough so we get exactly one more token 26 | // One extra millisecond is required to get over the threshold 27 | simulatedTime += (1000 / rate) + 1; 28 | t.true(limiter.okayToSend()); 29 | t.false(limiter.okayToSend()); 30 | 31 | t.end(); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/vm_collectAssets.js: -------------------------------------------------------------------------------- 1 | const test = require('tap').test; 2 | 3 | const RenderedTarget = require('../../src/sprites/rendered-target'); 4 | const Sprite = require('../../src/sprites/sprite'); 5 | const VirtualMachine = require('../../src/virtual-machine'); 6 | 7 | test('collectAssets', t => { 8 | const vm = new VirtualMachine(); 9 | const sprite = new Sprite(null, vm.runtime); 10 | const target = new RenderedTarget(sprite, vm.runtime); 11 | vm.runtime.targets = [target]; 12 | const [ 13 | soundAsset1, 14 | soundAsset2, 15 | costumeAsset1 16 | ] = [{assetId: 1}, {assetId: 2}, {assetId: 3}]; 17 | sprite.sounds = [{id: 1, asset: soundAsset1}, {id: 2, asset: soundAsset2}]; 18 | sprite.costumes = [{id: 1, asset: costumeAsset1}]; 19 | const assets = vm.assets; 20 | t.type(assets.length, 'number'); 21 | t.equal(assets.length, 3); 22 | t.deepEqual(assets, [soundAsset1, soundAsset2, costumeAsset1]); 23 | t.end(); 24 | }); 25 | --------------------------------------------------------------------------------