soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
7.06 kB
const BlockType = require('../../extension-support/block-type');
const ArgumentType = require('../../extension-support/argument-type');
const SandboxRunner = require('../../util/sandboxed-javascript-runner');
const Cast = require('../../util/cast');
/**
* Class
* oh yea you cant access util in the runner anymore
* im not adding it because im done with implementing eval in PM since it was done like 3 times
* @constructor
*/
class jgJavascript {
constructor(runtime) {
/**
* The runtime instantiating this block package.
* @type {runtime}
*/
this.runtime = runtime;
this.runningEditorUnsandboxed = false;
}
/**
* @returns {object} metadata for this extension and its blocks.
*/
getInfo() {
return {
id: 'jgJavascript',
name: 'JavaScript',
isDynamic: true,
// color1: '#EFC900', look like doo doo
blocks: [
{
opcode: 'unsandbox',
text: 'Run Unsandboxed',
blockType: BlockType.BUTTON,
hideFromPalette: this.runningEditorUnsandboxed
},
{
opcode: 'sandbox',
text: 'Run Sandboxed',
blockType: BlockType.BUTTON,
hideFromPalette: !this.runningEditorUnsandboxed
},
{
opcode: 'javascriptHat',
text: 'when javascript [CODE] == true',
blockType: BlockType.HAT,
hideFromPalette: !this.runningEditorUnsandboxed, // this block seems to cause strange behavior because of how sandboxed eval is done
arguments: {
CODE: {
type: ArgumentType.STRING,
defaultValue: "Math.round(Math.random()) === 1"
}
}
},
{
opcode: 'javascriptStack',
text: 'javascript [CODE]',
blockType: BlockType.COMMAND,
arguments: {
CODE: {
type: ArgumentType.STRING,
defaultValue: "alert('Hello!')"
}
}
},
{
opcode: 'javascriptString',
text: 'javascript [CODE]',
blockType: BlockType.REPORTER,
disableMonitor: true,
arguments: {
CODE: {
type: ArgumentType.STRING,
defaultValue: "Math.random()"
}
}
},
{
opcode: 'javascriptBool',
text: 'javascript [CODE]',
blockType: BlockType.BOOLEAN,
disableMonitor: true,
arguments: {
CODE: {
type: ArgumentType.STRING,
defaultValue: "Math.round(Math.random()) === 1"
}
}
},
{
blockType: BlockType.LABEL,
text: 'You can run unsandboxed',
hideFromPalette: !this.runningEditorUnsandboxed
},
{
blockType: BlockType.LABEL,
text: 'when packaging the project.',
hideFromPalette: !this.runningEditorUnsandboxed
},
{
blockType: BlockType.LABEL,
text: '⠀',
hideFromPalette: !this.runningEditorUnsandboxed
},
{
blockType: BlockType.LABEL,
text: 'Player Options >',
hideFromPalette: !this.runningEditorUnsandboxed
},
{
blockType: BlockType.LABEL,
text: 'Remove sandbox on the JavaScript Ext.',
hideFromPalette: !this.runningEditorUnsandboxed
},
]
};
}
async unsandbox() {
const unsandbox = await this.runtime.vm.securityManager.canUnsandbox('JavaScript');
if (!unsandbox) return;
this.runningEditorUnsandboxed = true;
this.runtime.vm.emitWorkspaceUpdate();
}
sandbox() {
this.runningEditorUnsandboxed = false;
this.runtime.vm.emitWorkspaceUpdate();
}
// util
evaluateCode(code, args, util, realBlockInfo) {
// used for packager
if (this.runtime.extensionRuntimeOptions.javascriptUnsandboxed === true || this.runningEditorUnsandboxed) {
let result;
try {
// eslint-disable-next-line no-eval
result = eval(code);
} catch (err) {
result = err;
}
return result;
}
// we are not packaged
return new Promise((resolve) => {
SandboxRunner.execute(code).then(result => {
// result is { value: any, success: boolean }
// in PM, we always ignore errors
return resolve(result.value);
})
})
}
// blocks
javascriptStack(args, util, realBlockInfo) {
const code = Cast.toString(args.CODE);
return this.evaluateCode(code, args, util, realBlockInfo);
}
javascriptString(args, util, realBlockInfo) {
const code = Cast.toString(args.CODE);
return this.evaluateCode(code, args, util, realBlockInfo);
}
javascriptBool(args, util, realBlockInfo) {
const code = Cast.toString(args.CODE);
const possiblePromise = this.evaluateCode(code, args, util, realBlockInfo);
if (possiblePromise && typeof possiblePromise.then === 'function') {
return (async () => {
const value = await possiblePromise;
return Boolean(value); // this is a JavaScript extension, we should use the JavaScript way of determining booleans
})();
}
return Boolean(possiblePromise);
}
javascriptHat(...args) {
if (!this.runtime.extensionRuntimeOptions.javascriptUnsandboxed && !this.runningEditorUnsandboxed) {
return false; // we will cause issues otherwise, edging hats cause weird issues when waiting for promises each frame
}
const possiblePromise = this.javascriptBool(...args);
if (possiblePromise && typeof possiblePromise.then === 'function') {
return false; // we will cause issues otherwise, edging hats cause weird issues when waiting for promises each frame
}
return possiblePromise;
}
}
module.exports = jgJavascript;