Skip to content

Commit

Permalink
[Google Blockly] strip user code (#57903)
Browse files Browse the repository at this point in the history
* [Google Blockly] strip user code

* revert use GetWorkspaceCode to get student JavaScript

reverts 3c8902b
  • Loading branch information
mikeharv committed Apr 10, 2024
1 parent 2380364 commit ea90eee
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 47 deletions.
45 changes: 6 additions & 39 deletions apps/src/blockly/cdoBlocklyWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,14 @@ import {
setHasIncompatibleSources,
} from '@cdo/apps/redux/blockly';
import * as blockUtils from '../block_utils';
import {handleCodeGenerationFailure} from './utils';
import {
INFINITE_LOOP_TRAP,
LOOP_HIGHLIGHT,
handleCodeGenerationFailure,
strip,
} from './utils';
import {MetricEvent} from '@cdo/apps/lib/metrics/events';

const INFINITE_LOOP_TRAP =
' executionInfo.checkTimeout(); if (executionInfo.isTerminated()){return;}\n';

const LOOP_HIGHLIGHT = 'loopHighlight();\n';
const LOOP_HIGHLIGHT_RE = new RegExp(
LOOP_HIGHLIGHT.replace(/\(.*\)/, '\\(.*\\)') + '\\s*',
'g'
);

/**
* Wrapper class for https://github.com/code-dot-org/blockly
* This wrapper will facilitate migrating from CDO Blockly to Google Blockly
Expand Down Expand Up @@ -53,35 +49,6 @@ const BlocklyWrapper = function (blocklyInstance) {
};
};

function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

/**
* Extract the user's code as raw JavaScript.
* @param {string} code Generated code.
* @return {string} The code without serial numbers and timeout checks.
*/
function strip(code) {
return (
code
// Strip out serial numbers.
.replace(/(,\s*)?'block_id_\d+'\)/g, ')')
// Remove timeouts.
.replace(new RegExp(escapeRegExp(INFINITE_LOOP_TRAP), 'g'), '')
// Strip out loop highlight
.replace(LOOP_HIGHLIGHT_RE, '')
// Strip out class namespaces.
.replace(/(StudioApp|Maze|Turtle)\./g, '')
// Strip out particular helper functions.
.replace(/^function (colour_random)[\s\S]*?^}/gm, '')
// Collapse consecutive blank lines.
.replace(/\n\n+/gm, '\n\n')
// Trim.
.replace(/^\s+|\s+$/g, '')
);
}

/**
* Given a type string for a field input, returns an appropriate change handler function
* for that type, which customizes the input field and provides validation on blur.
Expand Down
11 changes: 7 additions & 4 deletions apps/src/blockly/googleBlocklyWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ import {
import {initializeScrollbarPair} from './addons/cdoScrollbar';
import {getStore} from '@cdo/apps/redux';
import {setFailedToGenerateCode} from '@cdo/apps/redux/blockly';
import {handleCodeGenerationFailure} from './utils';
import {
INFINITE_LOOP_TRAP,
LOOP_HIGHLIGHT,
handleCodeGenerationFailure,
strip,
} from './utils';
import {MetricEvent} from '@cdo/apps/lib/metrics/events';
import {
BlocklyWrapperType,
Expand All @@ -104,11 +109,8 @@ const options = {
const plugin = new CrossTabCopyPaste();
plugin.init(options);

const INFINITE_LOOP_TRAP =
' executionInfo.checkTimeout(); if (executionInfo.isTerminated()){return;}\n';
const MAX_GET_CODE_RETRIES = 2;
const RETRY_GET_CODE_INTERVAL_MS = 500;
const LOOP_HIGHLIGHT = 'loopHighlight();\n';

/**
* Wrapper class for https://github.com/google/blockly
Expand Down Expand Up @@ -224,6 +226,7 @@ function initializeBlocklyWrapper(blocklyInstance: GoogleBlocklyInstance) {
if (hiddenWorkspace) {
workspaceCode += Blockly.JavaScript.workspaceToCode(hiddenWorkspace);
}
workspaceCode = strip(workspaceCode);
getStore().dispatch(setFailedToGenerateCode(false));
} catch (e) {
if (retryCount < MAX_GET_CODE_RETRIES) {
Expand Down
37 changes: 37 additions & 0 deletions apps/src/blockly/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,40 @@ export function getBaseName(themeName: Themes) {
return themeName.replace(DARK_THEME_SUFFIX, '');
}
}
export const INFINITE_LOOP_TRAP =
' executionInfo.checkTimeout(); if (executionInfo.isTerminated()){return;}\n';

export const LOOP_HIGHLIGHT = 'loopHighlight();\n';
const LOOP_HIGHLIGHT_RE = new RegExp(
LOOP_HIGHLIGHT.replace(/\(.*\)/, '\\(.*\\)') + '\\s*',
'g'
);

function escapeRegExp(str: string) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

/**
* Extract the user's code as raw JavaScript.
* @param {string} code Generated code.
* @return {string} The code without serial numbers and timeout checks.
*/
export function strip(code: string) {
return (
code
// Strip out serial numbers.
.replace(/(,\s*)?'block_id_[^']+'\)/g, ')')
// Remove timeouts.
.replace(new RegExp(escapeRegExp(INFINITE_LOOP_TRAP), 'g'), '')
// Strip out loop highlight
.replace(LOOP_HIGHLIGHT_RE, '')
// Strip out class namespaces.
.replace(/(StudioApp|Maze|Turtle)\./g, '')
// Strip out particular helper functions.
.replace(/^function (colour_random)[\s\S]*?^}/gm, '')
// Collapse consecutive blank lines.
.replace(/\n\n+/gm, '\n\n')
// Trim.
.replace(/^\s+|\s+$/g, '')
);
}
8 changes: 7 additions & 1 deletion apps/src/craft/agent/craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,13 @@ export default class Craft {
});

// Run user generated code, calling appCodeOrgAPI
const code = Blockly.getWorkspaceCode();
let code = '';
let codeBlocks = Blockly.mainBlockSpace.getTopBlocks(true);
if (studioApp().initializationBlocks) {
codeBlocks = studioApp().initializationBlocks.concat(codeBlocks);
}

code = Blockly.Generator.blocksToCode('JavaScript', codeBlocks);
CustomMarshalingInterpreter.evalWith(code, {
moveForward: function (blockID) {
appCodeOrgAPI.moveForward(
Expand Down
3 changes: 2 additions & 1 deletion apps/src/craft/aquatic/craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,8 @@ Craft.executeUserCode = function () {
};

// Run user code.
code += Blockly.getWorkspaceCode();
let codeBlocks = Blockly.mainBlockSpace.getTopBlocks(true);
code += Blockly.Generator.blocksToCode('JavaScript', codeBlocks);
interpreter = CustomMarshalingInterpreter.evalWith(
code,
{
Expand Down
6 changes: 5 additions & 1 deletion apps/src/craft/designer/craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,11 @@ Craft.executeUserCode = function () {
var appCodeOrgAPI = Craft.gameController.codeOrgAPI;
appCodeOrgAPI.startCommandCollection();
// Run user generated code, calling appCodeOrgAPI
const code = Blockly.getWorkspaceCode();
let codeBlocks = Blockly.mainBlockSpace.getTopBlocks(true);
if (studioApp().initializationBlocks) {
codeBlocks = studioApp().initializationBlocks.concat(codeBlocks);
}
const code = Blockly.Generator.blocksToCode('JavaScript', codeBlocks);

const evalApiMethods = {
moveForward: function (blockID) {
Expand Down
8 changes: 7 additions & 1 deletion apps/src/craft/simple/craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,13 @@ Craft.executeUserCode = function () {
});

// Run user generated code, calling appCodeOrgAPI
const code = Blockly.getWorkspaceCode();
let code = '';
let codeBlocks = Blockly.mainBlockSpace.getTopBlocks(true);
if (studioApp().initializationBlocks) {
codeBlocks = studioApp().initializationBlocks.concat(codeBlocks);
}

code = Blockly.Generator.blocksToCode('JavaScript', codeBlocks);

CustomMarshalingInterpreter.evalWith(
code,
Expand Down

0 comments on commit ea90eee

Please sign in to comment.