diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..ecd04c2f8 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['scratch', 'scratch/node'], + env: { + node: true + } +}; diff --git a/package.json b/package.json index ac5ee4071..948e7130a 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,11 @@ "watch": "./node_modules/.bin/webpack --progress --colors --watch", "version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, - "eslintConfig": { - "extends": ["scratch"] - }, "devDependencies": { "babel-eslint": "7.0.0", "copy-webpack-plugin": "3.0.1", - "eslint": "2.7.0", - "eslint-config-scratch": "1.0.0", + "eslint": "3.8.1", + "eslint-config-scratch": "1.1.0", "expose-loader": "0.7.1", "gh-pages": "0.11.0", "highlightjs": "8.7.0", diff --git a/src/.eslintrc.js b/src/.eslintrc.js new file mode 100644 index 000000000..154e590c2 --- /dev/null +++ b/src/.eslintrc.js @@ -0,0 +1,11 @@ +module.exports = { + root: true, + extends: 'scratch', + env: { + node: false, + browser: true + }, + globals: { + Promise: true + } +}; diff --git a/src/blocks/scratch3_control.js b/src/blocks/scratch3_control.js index 934500755..09f52a427 100644 --- a/src/blocks/scratch3_control.js +++ b/src/blocks/scratch3_control.js @@ -1,13 +1,13 @@ var Cast = require('../util/cast'); var Timer = require('../util/timer'); -function Scratch3ControlBlocks (runtime) { +var Scratch3ControlBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -39,7 +39,7 @@ Scratch3ControlBlocks.prototype.getHats = function () { Scratch3ControlBlocks.prototype.repeat = function (args, util) { var times = Math.floor(Cast.toNumber(args.TIMES)); // Initialize loop - if (util.stackFrame.loopCounter === undefined) { + if (typeof util.stackFrame.loopCounter === 'undefined') { util.stackFrame.loopCounter = times; } // Only execute once per frame. @@ -104,19 +104,19 @@ Scratch3ControlBlocks.prototype.ifElse = function (args, util) { Scratch3ControlBlocks.prototype.stop = function (args, util) { var option = args.STOP_OPTION; - if (option == 'all') { + if (option === 'all') { util.stopAll(); - } else if (option == 'other scripts in sprite' || - option == 'other scripts in stage') { + } else if (option === 'other scripts in sprite' || + option === 'other scripts in stage') { util.stopOtherTargetThreads(); - } else if (option == 'this script') { + } else if (option === 'this script') { util.stopThread(); } }; Scratch3ControlBlocks.prototype.createClone = function (args, util) { var cloneTarget; - if (args.CLONE_OPTION == '_myself_') { + if (args.CLONE_OPTION === '_myself_') { cloneTarget = util.target; } else { cloneTarget = this.runtime.getSpriteTargetByName(args.CLONE_OPTION); diff --git a/src/blocks/scratch3_data.js b/src/blocks/scratch3_data.js index fa3bb379a..6b2d339f2 100644 --- a/src/blocks/scratch3_data.js +++ b/src/blocks/scratch3_data.js @@ -1,12 +1,12 @@ var Cast = require('../util/cast'); -function Scratch3DataBlocks (runtime) { +var Scratch3DataBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -54,7 +54,7 @@ Scratch3DataBlocks.prototype.getListContents = function (args, util) { for (var i = 0; i < list.contents.length; i++) { var listItem = list.contents[i]; if (!((typeof listItem === 'string') && - (listItem.length == 1))) { + (listItem.length === 1))) { allSingleLetters = false; break; } @@ -126,7 +126,7 @@ Scratch3DataBlocks.prototype.listContainsItem = function (args, util) { // Try using Scratch comparison operator on each item. // (Scratch considers the string '123' equal to the number 123). for (var i = 0; i < list.contents.length; i++) { - if (Cast.compare(list.contents[i], item) == 0) { + if (Cast.compare(list.contents[i], item) === 0) { return true; } } diff --git a/src/blocks/scratch3_event.js b/src/blocks/scratch3_event.js index ad763ce4f..a2eaded7d 100644 --- a/src/blocks/scratch3_event.js +++ b/src/blocks/scratch3_event.js @@ -1,12 +1,12 @@ var Cast = require('../util/cast'); -function Scratch3EventBlocks (runtime) { +var Scratch3EventBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -48,7 +48,7 @@ Scratch3EventBlocks.prototype.hatGreaterThanPredicate = function (args, util) { var option = Cast.toString(args.WHENGREATERTHANMENU).toLowerCase(); var value = Cast.toNumber(args.VALUE); // @todo: Other cases :) - if (option == 'timer') { + if (option === 'timer') { return util.ioQuery('clock', 'projectTimer') > value; } return false; @@ -71,7 +71,7 @@ Scratch3EventBlocks.prototype.broadcastAndWait = function (args, util) { 'BROADCAST_OPTION': broadcastOption } ); - if (util.stackFrame.startedThreads.length == 0) { + if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. return; } diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index 46310b190..b440551d0 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -1,12 +1,12 @@ var Cast = require('../util/cast'); -function Scratch3LooksBlocks (runtime) { +var Scratch3LooksBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -82,33 +82,33 @@ Scratch3LooksBlocks.prototype.hide = function (args, util) { * Matches the behavior of Scratch 2.0 for different types of arguments. * @param {!Target} target Target to set costume/backdrop to. * @param {Any} requestedCostume Costume requested, e.g., 0, 'name', etc. - * @param {boolean=} opt_zeroIndex Set to zero-index the requestedCostume. + * @param {boolean=} optZeroIndex Set to zero-index the requestedCostume. * @return {Array.} Any threads started by this switch. */ Scratch3LooksBlocks.prototype._setCostumeOrBackdrop = function (target, - requestedCostume, opt_zeroIndex) { + requestedCostume, optZeroIndex) { if (typeof requestedCostume === 'number') { - target.setCostume(opt_zeroIndex ? + target.setCostume(optZeroIndex ? requestedCostume : requestedCostume - 1); } else { var costumeIndex = target.getCostumeIndexByName(requestedCostume); if (costumeIndex > -1) { target.setCostume(costumeIndex); - } else if (costumeIndex == 'previous costume' || - costumeIndex == 'previous backdrop') { + } else if (costumeIndex === 'previous costume' || + costumeIndex === 'previous backdrop') { target.setCostume(target.currentCostume - 1); - } else if (costumeIndex == 'next costume' || - costumeIndex == 'next backdrop') { + } else if (costumeIndex === 'next costume' || + costumeIndex === 'next backdrop') { target.setCostume(target.currentCostume + 1); } else { var forcedNumber = Cast.toNumber(requestedCostume); if (!isNaN(forcedNumber)) { - target.setCostume(opt_zeroIndex ? + target.setCostume(optZeroIndex ? forcedNumber : forcedNumber - 1); } } } - if (target == this.runtime.getTargetForStage()) { + if (target === this.runtime.getTargetForStage()) { // Target is the stage - start hats. var newName = target.sprite.costumes[target.currentCostume].name; return this.runtime.startHats('event_whenbackdropswitchesto', { @@ -142,7 +142,7 @@ Scratch3LooksBlocks.prototype.switchBackdropAndWait = function (args, util) { args.BACKDROP ) ); - if (util.stackFrame.startedThreads.length == 0) { + if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. return; } diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js index 463d2b25c..3b53c02ec 100644 --- a/src/blocks/scratch3_motion.js +++ b/src/blocks/scratch3_motion.js @@ -2,13 +2,13 @@ var Cast = require('../util/cast'); var MathUtil = require('../util/math-util'); var Timer = require('../util/timer'); -function Scratch3MotionBlocks (runtime) { +var Scratch3MotionBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -149,10 +149,10 @@ Scratch3MotionBlocks.prototype.ifOnEdgeBounce = function (args, util) { // and clamped to zero when the sprite is beyond. var stageWidth = this.runtime.constructor.STAGE_WIDTH; var stageHeight = this.runtime.constructor.STAGE_HEIGHT; - var distLeft = Math.max(0, stageWidth / 2 + bounds.left); - var distTop = Math.max(0, stageHeight / 2 - bounds.top); - var distRight = Math.max(0, stageWidth / 2 - bounds.right); - var distBottom = Math.max(0, stageHeight / 2 + bounds.bottom); + var distLeft = Math.max(0, (stageWidth / 2) + bounds.left); + var distTop = Math.max(0, (stageHeight / 2) - bounds.top); + var distRight = Math.max(0, (stageWidth / 2) - bounds.right); + var distBottom = Math.max(0, (stageHeight / 2) + bounds.bottom); // Find the nearest edge. var nearestEdge = ''; var minDist = Infinity; @@ -179,13 +179,13 @@ Scratch3MotionBlocks.prototype.ifOnEdgeBounce = function (args, util) { var radians = MathUtil.degToRad(90 - util.target.direction); var dx = Math.cos(radians); var dy = -Math.sin(radians); - if (nearestEdge == 'left') { + if (nearestEdge === 'left') { dx = Math.max(0.2, Math.abs(dx)); - } else if (nearestEdge == 'top') { + } else if (nearestEdge === 'top') { dy = Math.max(0.2, Math.abs(dy)); - } else if (nearestEdge == 'right') { + } else if (nearestEdge === 'right') { dx = 0 - Math.max(0.2, Math.abs(dx)); - } else if (nearestEdge == 'bottom') { + } else if (nearestEdge === 'bottom') { dy = 0 - Math.max(0.2, Math.abs(dy)); } var newDirection = MathUtil.radToDeg(Math.atan2(dy, dx)) + 90; diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js index 2502cc1a8..4af4533cd 100644 --- a/src/blocks/scratch3_operators.js +++ b/src/blocks/scratch3_operators.js @@ -1,12 +1,12 @@ var Cast = require('../util/cast.js'); -function Scratch3OperatorsBlocks (runtime) { +var Scratch3OperatorsBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -55,7 +55,7 @@ Scratch3OperatorsBlocks.prototype.lt = function (args) { }; Scratch3OperatorsBlocks.prototype.equals = function (args) { - return Cast.compare(args.OPERAND1, args.OPERAND2) == 0; + return Cast.compare(args.OPERAND1, args.OPERAND2) === 0; }; Scratch3OperatorsBlocks.prototype.gt = function (args) { @@ -79,10 +79,10 @@ Scratch3OperatorsBlocks.prototype.random = function (args) { var nTo = Cast.toNumber(args.TO); var low = nFrom <= nTo ? nFrom : nTo; var high = nFrom <= nTo ? nTo : nFrom; - if (low == high) return low; + if (low === high) return low; // If both arguments are ints, truncate the result to an int. if (Cast.isInt(args.FROM) && Cast.isInt(args.TO)) { - return low + parseInt(Math.random() * ((high + 1) - low)); + return low + parseInt(Math.random() * ((high + 1) - low), 10); } return (Math.random() * (high - low)) + low; }; diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js index c094dc47d..d35bb9ee0 100644 --- a/src/blocks/scratch3_procedures.js +++ b/src/blocks/scratch3_procedures.js @@ -1,10 +1,10 @@ -function Scratch3ProcedureBlocks (runtime) { +var Scratch3ProcedureBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index bd77a3e91..6ee1d0813 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -1,12 +1,12 @@ var Cast = require('../util/cast'); -function Scratch3SensingBlocks (runtime) { +var Scratch3SensingBlocks = function (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; -} +}; /** * Retrieve the block primitives implemented by this package. @@ -31,11 +31,11 @@ Scratch3SensingBlocks.prototype.getPrimitives = function () { Scratch3SensingBlocks.prototype.touchingObject = function (args, util) { var requestedObject = args.TOUCHINGOBJECTMENU; - if (requestedObject == '_mouse_') { + if (requestedObject === '_mouse_') { var mouseX = util.ioQuery('mouse', 'getX'); var mouseY = util.ioQuery('mouse', 'getY'); return util.target.isTouchingPoint(mouseX, mouseY); - } else if (requestedObject == '_edge_') { + } else if (requestedObject === '_edge_') { return util.target.isTouchingEdge(); } else { return util.target.isTouchingSprite(requestedObject); @@ -114,8 +114,7 @@ Scratch3SensingBlocks.prototype.getKeyPressed = function (args, util) { return util.ioQuery('keyboard', 'getKeyIsDown', args.KEY_OPTION); }; -Scratch3SensingBlocks.prototype.daysSince2000 = function () -{ +Scratch3SensingBlocks.prototype.daysSince2000 = function () { var msPerDay = 24 * 60 * 60 * 1000; var start = new Date(2000, 1-1, 1); var today = new Date(); diff --git a/src/engine/adapter.js b/src/engine/adapter.js index 327aae5e3..027d63665 100644 --- a/src/engine/adapter.js +++ b/src/engine/adapter.js @@ -1,6 +1,34 @@ var mutationAdapter = require('./mutation-adapter'); var html = require('htmlparser2'); +/** + * Convert outer blocks DOM from a Blockly CREATE event + * to a usable form for the Scratch runtime. + * This structure is based on Blockly xml.js:`domToWorkspace` and `domToBlock`. + * @param {Element} blocksDOM DOM tree for this event. + * @return {Array.} Usable list of blocks from this CREATE event. + */ +var domToBlocks = function (blocksDOM) { + // At this level, there could be multiple blocks adjacent in the DOM tree. + var blocks = {}; + for (var i = 0; i < blocksDOM.length; i++) { + var block = blocksDOM[i]; + if (!block.name || !block.attribs) { + continue; + } + var tagName = block.name.toLowerCase(); + if (tagName === 'block' || tagName === 'shadow') { + domToBlock(block, blocks, true, null); + } + } + // Flatten blocks object into a list. + var blocksList = []; + for (var b in blocks) { + blocksList.push(blocks[b]); + } + return blocksList; +}; + /** * Adapter between block creation events and block representation which can be * used by the Scratch runtime. @@ -15,34 +43,6 @@ module.exports = function (e) { return domToBlocks(html.parseDOM(e.xml.outerHTML)); }; -/** - * Convert outer blocks DOM from a Blockly CREATE event - * to a usable form for the Scratch runtime. - * This structure is based on Blockly xml.js:`domToWorkspace` and `domToBlock`. - * @param {Element} blocksDOM DOM tree for this event. - * @return {Array.} Usable list of blocks from this CREATE event. - */ -function domToBlocks (blocksDOM) { - // At this level, there could be multiple blocks adjacent in the DOM tree. - var blocks = {}; - for (var i = 0; i < blocksDOM.length; i++) { - var block = blocksDOM[i]; - if (!block.name || !block.attribs) { - continue; - } - var tagName = block.name.toLowerCase(); - if (tagName == 'block' || tagName == 'shadow') { - domToBlock(block, blocks, true, null); - } - } - // Flatten blocks object into a list. - var blocksList = []; - for (var b in blocks) { - blocksList.push(blocks[b]); - } - return blocksList; -} - /** * Convert and an individual block DOM to the representation tree. * Based on Blockly's `domToBlockHeadless_`. @@ -50,8 +50,9 @@ function domToBlocks (blocksDOM) { * @param {Object} blocks Collection of blocks to add to. * @param {Boolean} isTopBlock Whether blocks at this level are "top blocks." * @param {?string} parent Parent block ID. + * @return {undefined} */ -function domToBlock (blockDOM, blocks, isTopBlock, parent) { +var domToBlock = function (blockDOM, blocks, isTopBlock, parent) { // Block skeleton. var block = { id: blockDOM.attribs.id, // Block ID @@ -61,7 +62,7 @@ function domToBlock (blockDOM, blocks, isTopBlock, parent) { next: null, // Next block in the stack, if one exists. topLevel: isTopBlock, // If this block starts a stack. parent: parent, // Parent block ID, if available. - shadow: blockDOM.name == 'shadow', // If this represents a shadow/slot. + shadow: blockDOM.name === 'shadow', // If this represents a shadow/slot. x: blockDOM.attribs.x, // X position of script, if top-level. y: blockDOM.attribs.y // Y position of script, if top-level. }; @@ -82,9 +83,9 @@ function domToBlock (blockDOM, blocks, isTopBlock, parent) { continue; } var grandChildNodeName = grandChildNode.name.toLowerCase(); - if (grandChildNodeName == 'block') { + if (grandChildNodeName === 'block') { childBlockNode = grandChildNode; - } else if (grandChildNodeName == 'shadow') { + } else if (grandChildNodeName === 'shadow') { childShadowNode = grandChildNode; } } @@ -117,7 +118,7 @@ function domToBlock (blockDOM, blocks, isTopBlock, parent) { case 'statement': // Recursively generate block structure for input block. domToBlock(childBlockNode, blocks, false, block.id); - if (childShadowNode && childBlockNode != childShadowNode) { + if (childShadowNode && childBlockNode !== childShadowNode) { // Also generate the shadow block. domToBlock(childShadowNode, blocks, false, block.id); } @@ -144,4 +145,4 @@ function domToBlock (blockDOM, blocks, isTopBlock, parent) { break; } } -} +}; diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 0e89025e9..736d1778e 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -8,7 +8,7 @@ var xmlEscape = require('../util/xml-escape'); * and handle updates from Scratch Blocks events. */ -function Blocks () { +var Blocks = function () { /** * All blocks in the workspace. * Keys are block IDs, values are metadata about the block. @@ -22,7 +22,7 @@ function Blocks () { * @type {Array.} */ this._scripts = []; -} +}; /** * Blockly inputs that represent statements/branch. @@ -109,8 +109,8 @@ Blocks.prototype.getInputs = function (id) { var inputs = {}; for (var input in this._blocks[id].inputs) { // Ignore blocks prefixed with branch prefix. - if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) - != Blocks.BRANCH_INPUT_PREFIX) { + if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) !== + Blocks.BRANCH_INPUT_PREFIX) { inputs[input] = this._blocks[id].inputs[input]; } } @@ -149,9 +149,9 @@ Blocks.prototype.getTopLevelScript = function (id) { Blocks.prototype.getProcedureDefinition = function (name) { for (var id in this._blocks) { var block = this._blocks[id]; - if ((block.opcode == 'procedures_defnoreturn' || - block.opcode == 'procedures_defreturn') && - block.mutation.proccode == name) { + if ((block.opcode === 'procedures_defnoreturn' || + block.opcode === 'procedures_defreturn') && + block.mutation.proccode === name) { return id; } } @@ -166,9 +166,9 @@ Blocks.prototype.getProcedureDefinition = function (name) { Blocks.prototype.getProcedureParamNames = function (name) { for (var id in this._blocks) { var block = this._blocks[id]; - if ((block.opcode == 'procedures_defnoreturn' || - block.opcode == 'procedures_defreturn') && - block.mutation.proccode == name) { + if ((block.opcode === 'procedures_defnoreturn' || + block.opcode === 'procedures_defreturn') && + block.mutation.proccode === name) { return JSON.parse(block.mutation.argumentnames); } } @@ -181,18 +181,18 @@ Blocks.prototype.getProcedureParamNames = function (name) { * Create event listener for blocks. Handles validation and serves as a generic * adapter between the blocks and the runtime interface. * @param {Object} e Blockly "block" event - * @param {?Runtime} opt_runtime Optional runtime to forward click events to. + * @param {?Runtime} optRuntime Optional runtime to forward click events to. */ -Blocks.prototype.blocklyListen = function (e, opt_runtime) { +Blocks.prototype.blocklyListen = function (e, optRuntime) { // Validate event if (typeof e !== 'object') return; if (typeof e.blockId !== 'string') return; // UI event: clicked scripts toggle in the runtime. if (e.element === 'stackclick') { - if (opt_runtime) { - opt_runtime.toggleScript(e.blockId); + if (optRuntime) { + optRuntime.toggleScript(e.blockId); } return; } @@ -232,8 +232,8 @@ Blocks.prototype.blocklyListen = function (e, opt_runtime) { return; } // Inform any runtime to forget about glows on this script. - if (opt_runtime && this._blocks[e.blockId].topLevel) { - opt_runtime.quietGlow(e.blockId); + if (optRuntime && this._blocks[e.blockId].topLevel) { + optRuntime.quietGlow(e.blockId); } this.deleteBlock({ id: e.blockId @@ -273,11 +273,11 @@ Blocks.prototype.changeBlock = function (args) { if (args.element !== 'field' && args.element !== 'mutation') return; if (typeof this._blocks[args.id] === 'undefined') return; - if (args.element == 'field') { + if (args.element === 'field') { // Update block value if (!this._blocks[args.id].fields[args.name]) return; this._blocks[args.id].fields[args.name].value = args.value; - } else if (args.element == 'mutation') { + } else if (args.element === 'mutation') { this._blocks[args.id].mutation = mutationAdapter(args.value); } }; @@ -298,9 +298,9 @@ Blocks.prototype.moveBlock = function (e) { } // Remove from any old parent. - if (e.oldParent !== undefined) { + if (typeof e.oldParent !== 'undefined') { var oldParent = this._blocks[e.oldParent]; - if (e.oldInput !== undefined && + if (typeof e.oldInput !== 'undefined' && oldParent.inputs[e.oldInput].block === e.id) { // This block was connected to the old parent's input. oldParent.inputs[e.oldInput].block = null; @@ -312,13 +312,16 @@ Blocks.prototype.moveBlock = function (e) { } // Has the block become a top-level block? - if (e.newParent === undefined) { + if (typeof e.newParent === 'undefined') { this._addScript(e.id); } else { // Remove script, if one exists. this._deleteScript(e.id); // Otherwise, try to connect it in its new place. - if (e.newInput !== undefined) { + if (typeof e.newInput === 'undefined') { + // Moved to the new parent's next connection. + this._blocks[e.newParent].next = e.id; + } else { // Moved to the new parent's input. // Don't obscure the shadow block. var oldShadow = null; @@ -330,9 +333,6 @@ Blocks.prototype.moveBlock = function (e) { block: e.id, shadow: oldShadow }; - } else { - // Moved to the new parent's next connection. - this._blocks[e.newParent].next = e.id; } this._blocks[e.id].parent = e.newParent; } @@ -399,7 +399,7 @@ Blocks.prototype.blockToXML = function (blockId) { // Encode properties of this block. var tagName = (block.shadow) ? 'shadow' : 'block'; var xy = (block.topLevel) ? - ' x="' + block.x +'"' + ' y="' + block.y +'"' : + ' x="' + block.x +'" y="' + block.y +'"' : ''; var xmlString = ''; xmlString += '<' + tagName + @@ -420,7 +420,7 @@ Blocks.prototype.blockToXML = function (blockId) { if (blockInput.block) { xmlString += this.blockToXML(blockInput.block); } - if (blockInput.shadow && blockInput.shadow != blockInput.block) { + if (blockInput.shadow && blockInput.shadow !== blockInput.block) { // Obscured shadow. xmlString += this.blockToXML(blockInput.shadow); } @@ -453,7 +453,7 @@ Blocks.prototype.blockToXML = function (blockId) { Blocks.prototype.mutationToXML = function (mutation) { var mutationString = '<' + mutation.tagName; for (var prop in mutation) { - if (prop == 'children' || prop == 'tagName') continue; + if (prop === 'children' || prop === 'tagName') continue; var mutationValue = (typeof mutation[prop] === 'string') ? xmlEscape(mutation[prop]) : mutation[prop]; mutationString += ' ' + prop + '="' + mutationValue + '"'; diff --git a/src/engine/execute.js b/src/engine/execute.js index 70ee2e2eb..9017ff240 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -76,12 +76,10 @@ var execute = function (sequencer, thread) { if (!edgeWasActivated) { sequencer.retireThread(thread); } - } else { + } else if (!resolvedValue) { // Not an edge-activated hat: retire the thread // if predicate was false. - if (!resolvedValue) { - sequencer.retireThread(thread); - } + sequencer.retireThread(thread); } } else { // In a non-hat, report the value visually if necessary if @@ -105,8 +103,8 @@ var execute = function (sequencer, thread) { // Skip through the block (hat with no predicate). return; } else { - if (Object.keys(fields).length == 1 && - Object.keys(inputs).length == 0) { + if (Object.keys(fields).length === 1 && + Object.keys(inputs).length === 0) { // One field and no inputs - treat as arg. for (var fieldKey in fields) { // One iteration. handleReport(fields[fieldKey].value); @@ -133,8 +131,8 @@ var execute = function (sequencer, thread) { var input = inputs[inputName]; var inputBlockId = input.block; // Is there no value for this input waiting in the stack frame? - if (typeof currentStackFrame.reported[inputName] === 'undefined' - && inputBlockId) { + if (typeof currentStackFrame.reported[inputName] === 'undefined' && + inputBlockId) { // If there's not, we need to evaluate the block. // Push to the stack to evaluate the reporter block. thread.pushStack(inputBlockId); @@ -197,16 +195,16 @@ var execute = function (sequencer, thread) { getParam: function (paramName) { return thread.getParam(paramName); }, - startHats: function (requestedHat, opt_matchFields, opt_target) { + startHats: function (requestedHat, optMatchFields, optTarget) { return ( - runtime.startHats(requestedHat, opt_matchFields, opt_target) + runtime.startHats(requestedHat, optMatchFields, optTarget) ); }, ioQuery: function (device, func, args) { // Find the I/O device and execute the query/function call. if (runtime.ioDevices[device] && runtime.ioDevices[device][func]) { var devObject = runtime.ioDevices[device]; - return devObject[func].call(devObject, args); + return devObject[func](args); } } }); @@ -226,12 +224,12 @@ var execute = function (sequencer, thread) { // Promise handlers primitiveReportedValue.then(function (resolvedValue) { handleReport(resolvedValue); - if (typeof resolvedValue !== 'undefined') { - thread.popStack(); - } else { + if (typeof resolvedValue === 'undefined') { var popped = thread.popStack(); var nextBlockId = thread.target.blocks.getNextBlock(popped); thread.pushStack(nextBlockId); + } else { + thread.popStack(); } }, function (rejectionReason) { // Promise rejected: the primitive had some error. diff --git a/src/engine/list.js b/src/engine/list.js index 8ef082cde..de04fbac5 100644 --- a/src/engine/list.js +++ b/src/engine/list.js @@ -8,9 +8,7 @@ * @param {Array} contents Contents of the list, as an array. * @constructor */ -function List (name, contents) { +module.exports = function List (name, contents) { this.name = name; this.contents = contents; -} - -module.exports = List; +}; diff --git a/src/engine/mutation-adapter.js b/src/engine/mutation-adapter.js index 12dc123e1..b18dbb8a7 100644 --- a/src/engine/mutation-adapter.js +++ b/src/engine/mutation-adapter.js @@ -1,5 +1,26 @@ var html = require('htmlparser2'); +/** + * Convert a part of a mutation DOM to a mutation VM object, recursively. + * @param {Object} dom DOM object for mutation tag. + * @return {Object} Object representing useful parts of this mutation. + */ +var mutatorTagToObject = function (dom) { + var obj = Object.create(null); + obj.tagName = dom.name; + obj.children = []; + for (var prop in dom.attribs) { + if (prop === 'xmlns') continue; + obj[prop] = dom.attribs[prop]; + } + for (var i = 0; i < dom.children.length; i++) { + obj.children.push( + mutatorTagToObject(dom.children[i]) + ); + } + return obj; +}; + /** * Adapter between mutator XML or DOM and block representation which can be * used by the Scratch runtime. @@ -16,24 +37,3 @@ module.exports = function (mutation) { } return mutatorTagToObject(mutationParsed); }; - -/** - * Convert a part of a mutation DOM to a mutation VM object, recursively. - * @param {Object} dom DOM object for mutation tag. - * @return {Object} Object representing useful parts of this mutation. - */ -function mutatorTagToObject (dom) { - var obj = Object.create(null); - obj.tagName = dom.name; - obj.children = []; - for (var prop in dom.attribs) { - if (prop == 'xmlns') continue; - obj[prop] = dom.attribs[prop]; - } - for (var i = 0; i < dom.children.length; i++) { - obj.children.push( - mutatorTagToObject(dom.children[i]) - ); - } - return obj; -} diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 717283d76..7a2363182 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -23,7 +23,7 @@ var defaultBlockPackages = { /** * Manages targets, scripts, and the sequencer. */ -function Runtime () { +var Runtime = function () { // Bind event emitter EventEmitter.call(this); @@ -143,7 +143,7 @@ function Runtime () { 'keyboard': new Keyboard(this), 'mouse': new Mouse(this) }; -} +}; /** * Inherit from EventEmitter @@ -346,7 +346,7 @@ Runtime.prototype.isActiveThread = function (thread) { Runtime.prototype.toggleScript = function (topBlockId) { // Remove any existing thread. for (var i = 0; i < this.threads.length; i++) { - if (this.threads[i].topBlock == topBlockId) { + if (this.threads[i].topBlock === topBlockId) { this._removeThread(this.threads[i]); return; } @@ -361,12 +361,12 @@ Runtime.prototype.toggleScript = function (topBlockId) { * - the top block ID of the script. * - the target that owns the script. * @param {!Function} f Function to call for each script. - * @param {Target=} opt_target Optionally, a target to restrict to. + * @param {Target=} optTarget Optionally, a target to restrict to. */ -Runtime.prototype.allScriptsDo = function (f, opt_target) { +Runtime.prototype.allScriptsDo = function (f, optTarget) { var targets = this.targets; - if (opt_target) { - targets = [opt_target]; + if (optTarget) { + targets = [optTarget]; } for (var t = 0; t < targets.length; t++) { var target = targets[t]; @@ -381,12 +381,12 @@ Runtime.prototype.allScriptsDo = function (f, opt_target) { /** * Start all relevant hats. * @param {!string} requestedHatOpcode Opcode of hats to start. - * @param {Object=} opt_matchFields Optionally, fields to match on the hat. - * @param {Target=} opt_target Optionally, a target to restrict to. + * @param {Object=} optMatchFields Optionally, fields to match on the hat. + * @param {Target=} optTarget Optionally, a target to restrict to. * @return {Array.} List of threads started by this function. */ Runtime.prototype.startHats = function (requestedHatOpcode, - opt_matchFields, opt_target) { + optMatchFields, optTarget) { if (!this._hats.hasOwnProperty(requestedHatOpcode)) { // No known hat with this opcode. return; @@ -406,10 +406,10 @@ Runtime.prototype.startHats = function (requestedHatOpcode, // (i.e., before the predicate can be run) because "broadcast and wait" // needs to have a precise collection of started threads. var hatFields = target.blocks.getFields(topBlockId); - if (opt_matchFields) { - for (var matchField in opt_matchFields) { + if (optMatchFields) { + for (var matchField in optMatchFields) { if (hatFields[matchField].value !== - opt_matchFields[matchField]) { + optMatchFields[matchField]) { // Field mismatch. return; } @@ -422,7 +422,7 @@ Runtime.prototype.startHats = function (requestedHatOpcode, // any existing threads starting with the top block. for (var i = 0; i < instance.threads.length; i++) { if (instance.threads[i].topBlock === topBlockId && - instance.threads[i].target == target) { + instance.threads[i].target === target) { instance._removeThread(instance.threads[i]); } } @@ -431,7 +431,7 @@ Runtime.prototype.startHats = function (requestedHatOpcode, // give up if any threads with the top block are running. for (var j = 0; j < instance.threads.length; j++) { if (instance.threads[j].topBlock === topBlockId && - instance.threads[j].target == target) { + instance.threads[j].target === target) { // Some thread is already running. return; } @@ -439,7 +439,7 @@ Runtime.prototype.startHats = function (requestedHatOpcode, } // Start the thread with this top block. newThreads.push(instance._pushThread(topBlockId, target)); - }, opt_target); + }, optTarget); return newThreads; }; @@ -468,15 +468,15 @@ Runtime.prototype.disposeTarget = function (disposingTarget) { /** * Stop any threads acting on the target. * @param {!Target} target Target to stop threads for. - * @param {Thread=} opt_threadException Optional thread to skip. + * @param {Thread=} optThreadException Optional thread to skip. */ -Runtime.prototype.stopForTarget = function (target, opt_threadException) { +Runtime.prototype.stopForTarget = function (target, optThreadException) { // Stop any threads on the target. for (var i = 0; i < this.threads.length; i++) { - if (this.threads[i] === opt_threadException) { + if (this.threads[i] === optThreadException) { continue; } - if (this.threads[i].target == target) { + if (this.threads[i].target === target) { this._removeThread(this.threads[i]); } } @@ -562,13 +562,13 @@ Runtime.prototype.setCompatibilityMode = function (compatibilityModeOn) { /** * Emit glows/glow clears for scripts after a single tick. * Looks at `this.threads` and notices which have turned on/off new glows. - * @param {Array.=} opt_extraThreads Optional list of inactive threads. + * @param {Array.=} optExtraThreads Optional list of inactive threads. */ -Runtime.prototype._updateGlows = function (opt_extraThreads) { +Runtime.prototype._updateGlows = function (optExtraThreads) { var searchThreads = []; searchThreads.push.apply(searchThreads, this.threads); - if (opt_extraThreads) { - searchThreads.push.apply(searchThreads, opt_extraThreads); + if (optExtraThreads) { + searchThreads.push.apply(searchThreads, optExtraThreads); } // Set of scripts that request a glow this frame. var requestedGlowsThisFrame = []; @@ -578,7 +578,7 @@ Runtime.prototype._updateGlows = function (opt_extraThreads) { for (var i = 0; i < searchThreads.length; i++) { var thread = searchThreads[i]; var target = thread.target; - if (target == this._editingTarget) { + if (target === this._editingTarget) { var blockForThread = thread.blockGlowInFrame; if (thread.requestScriptGlowInFrame) { var script = target.blocks.getTopLevelScript(blockForThread); @@ -672,7 +672,7 @@ Runtime.prototype.visualReport = function (blockId, value) { Runtime.prototype.getTargetById = function (targetId) { for (var i = 0; i < this.targets.length; i++) { var target = this.targets[i]; - if (target.id == targetId) { + if (target.id === targetId) { return target; } } @@ -686,7 +686,7 @@ Runtime.prototype.getTargetById = function (targetId) { Runtime.prototype.getSpriteTargetByName = function (spriteName) { for (var i = 0; i < this.targets.length; i++) { var target = this.targets[i]; - if (target.sprite && target.sprite.name == spriteName) { + if (target.sprite && target.sprite.name === spriteName) { return target; } } diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index dbfa1f5f4..46cc3ebcd 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -2,7 +2,7 @@ var Timer = require('../util/timer'); var Thread = require('./thread'); var execute = require('./execute.js'); -function Sequencer (runtime) { +var Sequencer = function (runtime) { /** * A utility timer for timing thread sequencing. * @type {!Timer} @@ -14,7 +14,7 @@ function Sequencer (runtime) { * @type {!Runtime} */ this.runtime = runtime; -} +}; /** * Time to run a warp-mode thread, in ms. @@ -219,11 +219,9 @@ Sequencer.prototype.stepToProcedure = function (thread, procedureCode) { var doWarp = definitionBlock.mutation.warp; if (doWarp) { thread.peekStackFrame().warpMode = true; - } else { + } else if (isRecursive) { // In normal-mode threads, yield any time we have a recursive call. - if (isRecursive) { - thread.status = Thread.STATUS_YIELD; - } + thread.status = Thread.STATUS_YIELD; } } }; diff --git a/src/engine/target.js b/src/engine/target.js index d5a59b47a..f8f99f47d 100644 --- a/src/engine/target.js +++ b/src/engine/target.js @@ -13,7 +13,7 @@ var uid = require('../util/uid'); * @param {?Blocks} blocks Blocks instance for the blocks owned by this target. * @constructor */ -function Target (blocks) { +var Target = function (blocks) { if (!blocks) { blocks = new Blocks(this); } @@ -39,7 +39,7 @@ function Target (blocks) { * @type {Object.} */ this.lists = {}; -} +}; /** * Called when the project receives a "green flag." @@ -109,8 +109,6 @@ Target.prototype.lookupOrCreateList = function (name) { * Call to destroy a target. * @abstract */ -Target.prototype.dispose = function () { - -}; +Target.prototype.dispose = function () {}; module.exports = Target; diff --git a/src/engine/thread.js b/src/engine/thread.js index 5ad6e72bb..765f48b71 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -3,7 +3,7 @@ * @param {?string} firstBlock First block to execute in the thread. * @constructor */ -function Thread (firstBlock) { +var Thread = function (firstBlock) { /** * ID of top block of the thread * @type {!string} @@ -53,7 +53,7 @@ function Thread (firstBlock) { * @type {?Timer} */ this.warpTimer = null; -} +}; /** * Thread status for initialized or running thread. @@ -225,8 +225,8 @@ Thread.prototype.isRecursiveCall = function (procedureCode) { var sp = this.stack.length - 1; for (var i = sp - 1; i >= 0; i--) { var block = this.target.blocks.getBlock(this.stack[i]); - if (block.opcode == 'procedures_callnoreturn' && - block.mutation.proccode == procedureCode) { + if (block.opcode === 'procedures_callnoreturn' && + block.mutation.proccode === procedureCode) { return true; } if (--callCount < 0) return false; diff --git a/src/engine/variable.js b/src/engine/variable.js index 4e5e5e6e3..e28170d4d 100644 --- a/src/engine/variable.js +++ b/src/engine/variable.js @@ -9,10 +9,8 @@ * @param {boolean} isCloud Whether the variable is stored in the cloud. * @constructor */ -function Variable (name, value, isCloud) { +module.exports = function Variable (name, value, isCloud) { this.name = name; this.value = value; this.isCloud = isCloud; -} - -module.exports = Variable; +}; diff --git a/src/import/sb2import.js b/src/import/sb2import.js index 927fb650d..a2526c3d0 100644 --- a/src/import/sb2import.js +++ b/src/import/sb2import.js @@ -14,22 +14,6 @@ var specMap = require('./sb2specmap'); var Variable = require('../engine/variable'); var List = require('../engine/list'); -/** - * Top-level handler. Parse provided JSON, - * and process the top-level object (the stage object). - * @param {!string} json SB2-format JSON to load. - * @param {!Runtime} runtime Runtime object to load all structures into. - * @param {Boolean=} opt_forceSprite If set, treat as sprite (Sprite2). - * @return {?Target} Top-level target created (stage or sprite). - */ -function sb2import (json, runtime, opt_forceSprite) { - return parseScratchObject( - JSON.parse(json), - runtime, - !opt_forceSprite - ); -} - /** * Parse a single "Scratch object" and create all its in-memory VM objects. * @param {!Object} object From-JSON "Scratch object:" sprite, stage, watcher. @@ -37,7 +21,7 @@ function sb2import (json, runtime, opt_forceSprite) { * @param {boolean} topLevel Whether this is the top-level object (stage). * @return {?Target} Target created (stage or sprite). */ -function parseScratchObject (object, runtime, topLevel) { +var parseScratchObject = function (object, runtime, topLevel) { if (!object.hasOwnProperty('objName')) { // Watcher/monitor - skip this object until those are implemented in VM. // @todo @@ -57,8 +41,8 @@ function parseScratchObject (object, runtime, topLevel) { var costume = object.costumes[i]; // @todo: Make sure all the relevant metadata is being pulled out. sprite.costumes.push({ - skin: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' - + costume.baseLayerMD5 + '/get/', + skin: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' + + costume.baseLayerMD5 + '/get/', name: costume.costumeName, bitmapResolution: costume.bitmapResolution, rotationCenterX: costume.rotationCenterX, @@ -115,11 +99,11 @@ function parseScratchObject (object, runtime, topLevel) { target.currentCostume = Math.round(object.currentCostumeIndex); } if (object.hasOwnProperty('rotationStyle')) { - if (object.rotationStyle == 'none') { + if (object.rotationStyle === 'none') { target.rotationStyle = Clone.ROTATION_STYLE_NONE; - } else if (object.rotationStyle == 'leftRight') { + } else if (object.rotationStyle === 'leftRight') { target.rotationStyle = Clone.ROTATION_STYLE_LEFT_RIGHT; - } else if (object.rotationStyle == 'normal') { + } else if (object.rotationStyle === 'normal') { target.rotationStyle = Clone.ROTATION_STYLE_ALL_AROUND; } } @@ -132,7 +116,23 @@ function parseScratchObject (object, runtime, topLevel) { } } return target; -} +}; + +/** + * Top-level handler. Parse provided JSON, + * and process the top-level object (the stage object). + * @param {!string} json SB2-format JSON to load. + * @param {!Runtime} runtime Runtime object to load all structures into. + * @param {Boolean=} optForceSprite If set, treat as sprite (Sprite2). + * @return {?Target} Top-level target created (stage or sprite). + */ +var sb2import = function (json, runtime, optForceSprite) { + return parseScratchObject( + JSON.parse(json), + runtime, + !optForceSprite + ); +}; /** * Parse a Scratch object's scripts into VM blocks. @@ -140,7 +140,7 @@ function parseScratchObject (object, runtime, topLevel) { * @param {!Object} scripts Scripts object from SB2 JSON. * @param {!Blocks} blocks Blocks object to load parsed blocks into. */ -function parseScripts (scripts, blocks) { +var parseScripts = function (scripts, blocks) { for (var i = 0; i < scripts.length; i++) { var script = scripts[i]; var scriptX = script[0]; @@ -162,7 +162,7 @@ function parseScripts (scripts, blocks) { blocks.createBlock(convertedBlocks[j]); } } -} +}; /** * Parse any list of blocks from SB2 JSON into a list of VM-format blocks. @@ -172,7 +172,7 @@ function parseScripts (scripts, blocks) { * @param {Array.} blockList SB2 JSON-format block list. * @return {Array.} Scratch VM-format block list. */ -function parseBlockList (blockList) { +var parseBlockList = function (blockList) { var resultingList = []; var previousBlock = null; // For setting next. for (var i = 0; i < blockList.length; i++) { @@ -186,7 +186,7 @@ function parseBlockList (blockList) { resultingList.push(parsedBlock); } return resultingList; -} +}; /** * Flatten a block tree into a block list. @@ -194,7 +194,7 @@ function parseBlockList (blockList) { * @param {Array.} blocks list generated by `parseBlockList`. * @return {Array.} Flattened list to be passed to `blocks.createBlock`. */ -function flatten (blocks) { +var flatten = function (blocks) { var finalBlocks = []; for (var i = 0; i < blocks.length; i++) { var block = blocks[i]; @@ -205,7 +205,7 @@ function flatten (blocks) { delete block.children; } return finalBlocks; -} +}; /** * Convert a Scratch 2.0 procedure string (e.g., "my_procedure %s %b %n") @@ -214,39 +214,39 @@ function flatten (blocks) { * @param {string} procCode Scratch 2.0 procedure string. * @return {Object} Argument map compatible with those in sb2specmap. */ -function parseProcedureArgMap (procCode) { +var parseProcedureArgMap = function (procCode) { var argMap = [ {} // First item in list is op string. ]; var INPUT_PREFIX = 'input'; var inputCount = 0; // Split by %n, %b, %s. - var parts = procCode.split(/(?=[^\\]\%[nbs])/); + var parts = procCode.split(/(?=[^\\]%[nbs])/); for (var i = 0; i < parts.length; i++) { var part = parts[i].trim(); - if (part.substring(0, 1) == '%') { + if (part.substring(0, 1) === '%') { var argType = part.substring(1, 2); var arg = { type: 'input', inputName: INPUT_PREFIX + (inputCount++) }; - if (argType == 'n') { + if (argType === 'n') { arg.inputOp = 'math_number'; - } else if (argType == 's') { + } else if (argType === 's') { arg.inputOp = 'text'; } argMap.push(arg); } } return argMap; -} +}; /** * Parse a single SB2 JSON-formatted block and its children. * @param {!Object} sb2block SB2 JSON-formatted block. * @return {Object} Scratch VM format block. */ -function parseBlock (sb2block) { +var parseBlock = function (sb2block) { // First item in block object is the old opcode (e.g., 'forward:'). var oldOpcode = sb2block[0]; // Convert the block using the specMap. See sb2specmap.js. @@ -266,7 +266,7 @@ function parseBlock (sb2block) { children: [] // Store any generated children, flattened in `flatten`. }; // For a procedure call, generate argument map from proc string. - if (oldOpcode == 'call') { + if (oldOpcode === 'call') { blockMetadata.argMap = parseProcedureArgMap(sb2block[1]); } // Look at the expected arguments in `blockMetadata.argMap.` @@ -278,7 +278,7 @@ function parseBlock (sb2block) { // Whether the input is obscuring a shadow. var shadowObscured = false; // Positional argument is an input. - if (expectedArg.type == 'input') { + if (expectedArg.type === 'input') { // Create a new block and input metadata. var inputUid = uid(); activeBlock.inputs[expectedArg.inputName] = { @@ -286,10 +286,10 @@ function parseBlock (sb2block) { block: null, shadow: null }; - if (typeof providedArg == 'object' && providedArg) { + if (typeof providedArg === 'object' && providedArg) { // Block or block list occupies the input. var innerBlocks; - if (typeof providedArg[0] == 'object' && providedArg[0]) { + if (typeof providedArg[0] === 'object' && providedArg[0]) { // Block list occupies the input. innerBlocks = parseBlockList(providedArg); } else { @@ -298,7 +298,7 @@ function parseBlock (sb2block) { } var previousBlock = null; for (var j = 0; j < innerBlocks.length; j++) { - if (j == 0) { + if (j === 0) { innerBlocks[j].parent = activeBlock.id; } else { innerBlocks[j].parent = previousBlock; @@ -324,22 +324,22 @@ function parseBlock (sb2block) { var fieldValue = providedArg; // Shadows' field names match the input name, except for these: var fieldName = expectedArg.inputName; - if (expectedArg.inputOp == 'math_number' || - expectedArg.inputOp == 'math_whole_number' || - expectedArg.inputOp == 'math_positive_number' || - expectedArg.inputOp == 'math_integer' || - expectedArg.inputOp == 'math_angle') { + if (expectedArg.inputOp === 'math_number' || + expectedArg.inputOp === 'math_whole_number' || + expectedArg.inputOp === 'math_positive_number' || + expectedArg.inputOp === 'math_integer' || + expectedArg.inputOp === 'math_angle') { fieldName = 'NUM'; // Fields are given Scratch 2.0 default values if obscured. if (shadowObscured) { fieldValue = 10; } - } else if (expectedArg.inputOp == 'text') { + } else if (expectedArg.inputOp === 'text') { fieldName = 'TEXT'; if (shadowObscured) { fieldValue = ''; } - } else if (expectedArg.inputOp == 'colour_picker') { + } else if (expectedArg.inputOp === 'colour_picker') { // Convert SB2 color to hex. fieldValue = Color.decimalToHex(providedArg); fieldName = 'COLOUR'; @@ -367,7 +367,7 @@ function parseBlock (sb2block) { if (!activeBlock.inputs[expectedArg.inputName].block) { activeBlock.inputs[expectedArg.inputName].block = inputUid; } - } else if (expectedArg.type == 'field') { + } else if (expectedArg.type === 'field') { // Add as a field on this block. activeBlock.fields[expectedArg.fieldName] = { name: expectedArg.fieldName, @@ -376,18 +376,18 @@ function parseBlock (sb2block) { } } // Special cases to generate mutations. - if (oldOpcode == 'stopScripts') { + if (oldOpcode === 'stopScripts') { // Mutation for stop block: if the argument is 'other scripts', // the block needs a next connection. - if (sb2block[1] == 'other scripts in sprite' || - sb2block[1] == 'other scripts in stage') { + if (sb2block[1] === 'other scripts in sprite' || + sb2block[1] === 'other scripts in stage') { activeBlock.mutation = { tagName: 'mutation', hasnext: 'true', children: [] }; } - } else if (oldOpcode == 'procDef') { + } else if (oldOpcode === 'procDef') { // Mutation for procedure definition: // store all 2.0 proc data. var procData = sb2block.slice(1); @@ -399,7 +399,7 @@ function parseBlock (sb2block) { warp: procData[3], // Warp mode, e.g., true/false. children: [] }; - } else if (oldOpcode == 'call') { + } else if (oldOpcode === 'call') { // Mutation for procedure call: // string for proc code (e.g., "abc %n %b %s"). activeBlock.mutation = { @@ -407,7 +407,7 @@ function parseBlock (sb2block) { children: [], proccode: sb2block[1] }; - } else if (oldOpcode == 'getParam') { + } else if (oldOpcode === 'getParam') { // Mutation for procedure parameter. activeBlock.mutation = { tagName: 'mutation', @@ -417,6 +417,6 @@ function parseBlock (sb2block) { }; } return activeBlock; -} +}; module.exports = sb2import; diff --git a/src/index.js b/src/index.js index 06add3b41..786bc383e 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,7 @@ var Blocks = require('./engine/blocks'); * * @author Andrew Sliwinski */ -function VirtualMachine () { +var VirtualMachine = function () { var instance = this; // Bind event emitter and runtime to VM instance EventEmitter.call(instance); @@ -45,7 +45,7 @@ function VirtualMachine () { this.blockListener = this.blockListener.bind(this); this.flyoutBlockListener = this.flyoutBlockListener.bind(this); -} +}; /** * Inherit from EventEmitter @@ -107,11 +107,11 @@ VirtualMachine.prototype.getPlaygroundData = function () { var instance = this; // Only send back thread data for the current editingTarget. var threadData = this.runtime.threads.filter(function (thread) { - return thread.target == instance.editingTarget; + return thread.target === instance.editingTarget; }); // Remove the target key, since it's a circular reference. var filteredThreadData = JSON.stringify(threadData, function (key, value) { - if (key == 'target') return undefined; + if (key === 'target') return; return value; }, 2); this.emit('playgroundData', { @@ -273,7 +273,7 @@ VirtualMachine.prototype.flyoutBlockListener = function (e) { */ VirtualMachine.prototype.setEditingTarget = function (targetId) { // Has the target id changed? If not, exit. - if (targetId == this.editingTarget.id) { + if (targetId === this.editingTarget.id) { return; } var target = this.runtime.getTargetById(targetId); diff --git a/src/io/clock.js b/src/io/clock.js index ce4c8f553..aaefa9d5a 100644 --- a/src/io/clock.js +++ b/src/io/clock.js @@ -1,6 +1,6 @@ var Timer = require('../util/timer'); -function Clock (runtime) { +var Clock = function (runtime) { this._projectTimer = new Timer(); this._projectTimer.start(); this._pausedTime = null; @@ -10,7 +10,7 @@ function Clock (runtime) { * @type{!Runtime} */ this.runtime = runtime; -} +}; Clock.prototype.projectTimer = function () { if (this._paused) { diff --git a/src/io/keyboard.js b/src/io/keyboard.js index ea423fd40..290d24348 100644 --- a/src/io/keyboard.js +++ b/src/io/keyboard.js @@ -1,6 +1,6 @@ var Cast = require('../util/cast'); -function Keyboard (runtime) { +var Keyboard = function (runtime) { /** * List of currently pressed keys. * @type{Array.} @@ -12,7 +12,7 @@ function Keyboard (runtime) { * @type{!Runtime} */ this.runtime = runtime; -} +}; /** * Convert a Scratch key name to a DOM keyCode. @@ -20,7 +20,7 @@ function Keyboard (runtime) { * @return {number} Key code corresponding to a DOM event. */ Keyboard.prototype._scratchKeyToKeyCode = function (keyName) { - if (typeof keyName == 'number') { + if (typeof keyName === 'number') { // Key codes placed in with number blocks. return keyName; } @@ -75,7 +75,7 @@ Keyboard.prototype.postData = function (data) { }; Keyboard.prototype.getKeyIsDown = function (key) { - if (key == 'any') { + if (key === 'any') { return this._keysPressed.length > 0; } var keyCode = this._scratchKeyToKeyCode(key); diff --git a/src/io/mouse.js b/src/io/mouse.js index 58df9df1f..c54c97511 100644 --- a/src/io/mouse.js +++ b/src/io/mouse.js @@ -1,6 +1,6 @@ var MathUtil = require('../util/math-util'); -function Mouse (runtime) { +var Mouse = function (runtime) { this._x = 0; this._y = 0; this._isDown = false; @@ -10,14 +10,14 @@ function Mouse (runtime) { * @type{!Runtime} */ this.runtime = runtime; -} +}; Mouse.prototype.postData = function (data) { if (data.x) { - this._x = data.x - data.canvasWidth / 2; + this._x = data.x - (data.canvasWidth / 2); } if (data.y) { - this._y = data.y - data.canvasHeight / 2; + this._y = data.y - (data.canvasHeight / 2); } if (typeof data.isDown !== 'undefined') { this._isDown = data.isDown; @@ -33,7 +33,7 @@ Mouse.prototype._activateClickHats = function (x, y) { for (var i = 0; i < this.runtime.targets.length; i++) { var target = this.runtime.targets[i]; if (target.hasOwnProperty('drawableID') && - target.drawableID == drawableID) { + target.drawableID === drawableID) { this.runtime.startHats('event_whenthisspriteclicked', null, target); return; diff --git a/src/sprites/clone.js b/src/sprites/clone.js index 79ead30e4..c5e8e0ca6 100644 --- a/src/sprites/clone.js +++ b/src/sprites/clone.js @@ -8,7 +8,7 @@ var Target = require('../engine/target'); * @param {Runtime} runtime Reference to the runtime. * @constructor */ -function Clone (sprite, runtime) { +var Clone = function (sprite, runtime) { Target.call(this, sprite.blocks); this.runtime = runtime; /** @@ -43,7 +43,7 @@ function Clone (sprite, runtime) { 'brightness': 0, 'ghost': 0 }; -} +}; util.inherits(Clone, Target); /** @@ -166,7 +166,7 @@ Clone.prototype._getRenderedDirectionAndScale = function () { // Default: no changes to `this.direction` or `this.scale`. var finalDirection = this.direction; var finalScale = [this.size, this.size]; - if (this.rotationStyle == Clone.ROTATION_STYLE_NONE) { + if (this.rotationStyle === Clone.ROTATION_STYLE_NONE) { // Force rendered direction to be 90. finalDirection = 90; } else if (this.rotationStyle === Clone.ROTATION_STYLE_LEFT_RIGHT) { @@ -319,11 +319,11 @@ Clone.prototype.setCostume = function (index) { * @param {!string} rotationStyle New rotation style. */ Clone.prototype.setRotationStyle = function (rotationStyle) { - if (rotationStyle == Clone.ROTATION_STYLE_NONE) { + if (rotationStyle === Clone.ROTATION_STYLE_NONE) { this.rotationStyle = Clone.ROTATION_STYLE_NONE; - } else if (rotationStyle == Clone.ROTATION_STYLE_ALL_AROUND) { + } else if (rotationStyle === Clone.ROTATION_STYLE_ALL_AROUND) { this.rotationStyle = Clone.ROTATION_STYLE_ALL_AROUND; - } else if (rotationStyle == Clone.ROTATION_STYLE_LEFT_RIGHT) { + } else if (rotationStyle === Clone.ROTATION_STYLE_LEFT_RIGHT) { this.rotationStyle = Clone.ROTATION_STYLE_LEFT_RIGHT; } if (this.renderer) { @@ -345,7 +345,7 @@ Clone.prototype.setRotationStyle = function (rotationStyle) { */ Clone.prototype.getCostumeIndexByName = function (costumeName) { for (var i = 0; i < this.sprite.costumes.length; i++) { - if (this.sprite.costumes[i].name == costumeName) { + if (this.sprite.costumes[i].name === costumeName) { return i; } } @@ -408,8 +408,8 @@ Clone.prototype.isTouchingPoint = function (x, y) { // Limits test to this Drawable, so this will return true // even if the clone is obscured by another Drawable. var pickResult = this.runtime.renderer.pick( - x + this.runtime.constructor.STAGE_WIDTH / 2, - -y + this.runtime.constructor.STAGE_HEIGHT / 2, + x + (this.runtime.constructor.STAGE_WIDTH / 2), + -y + (this.runtime.constructor.STAGE_HEIGHT / 2), null, null, [this.drawableID] ); @@ -506,11 +506,11 @@ Clone.prototype.goBackLayers = function (nLayers) { * Keep a desired position within a fence. * @param {number} newX New desired X position. * @param {number} newY New desired Y position. - * @param {Object=} opt_fence Optional fence with left, right, top bottom. + * @param {Object=} optFence Optional fence with left, right, top bottom. * @return {Array.} Fenced X and Y coordinates. */ -Clone.prototype.keepInFence = function (newX, newY, opt_fence) { - var fence = opt_fence; +Clone.prototype.keepInFence = function (newX, newY, optFence) { + var fence = optFence; if (!fence) { fence = { left: -this.runtime.constructor.STAGE_WIDTH / 2, diff --git a/src/sprites/sprite.js b/src/sprites/sprite.js index 2afb25e5e..351d40a3f 100644 --- a/src/sprites/sprite.js +++ b/src/sprites/sprite.js @@ -8,7 +8,7 @@ var Blocks = require('../engine/blocks'); * @param {Runtime} runtime Reference to the runtime. * @constructor */ -function Sprite (blocks, runtime) { +var Sprite = function (blocks, runtime) { this.runtime = runtime; if (!blocks) { // Shared set of blocks for all clones. @@ -38,7 +38,7 @@ function Sprite (blocks, runtime) { * @type {Array.} */ this.clones = []; -} +}; /** * Create a clone of this sprite. @@ -46,7 +46,7 @@ function Sprite (blocks, runtime) { */ Sprite.prototype.createClone = function () { var newClone = new Clone(this, this.runtime); - newClone.isOriginal = this.clones.length == 0; + newClone.isOriginal = this.clones.length === 0; this.clones.push(newClone); if (newClone.isOriginal) { newClone.initDrawable(); diff --git a/src/util/cast.js b/src/util/cast.js index dda55bf8e..f14e97df5 100644 --- a/src/util/cast.js +++ b/src/util/cast.js @@ -1,6 +1,6 @@ var Color = require('../util/color'); -function Cast () {} +var Cast = function () {}; /** * @fileoverview @@ -44,9 +44,9 @@ Cast.toBoolean = function (value) { } if (typeof value === 'string') { // These specific strings are treated as false in Scratch. - if ((value == '') || - (value == '0') || - (value.toLowerCase() == 'false')) { + if ((value === '') || + (value === '0') || + (value.toLowerCase() === 'false')) { return false; } // All other strings treated as true. @@ -72,7 +72,7 @@ Cast.toString = function (value) { */ Cast.toRgbColorList = function (value) { var color; - if (typeof value == 'string' && value.substring(0, 1) == '#') { + if (typeof value === 'string' && value.substring(0, 1) === '#') { color = Color.hexToRgb(value); } else { color = Color.decimalToRgb(Cast.toNumber(value)); @@ -114,7 +114,7 @@ Cast.isInt = function (val) { return true; } // True if it's "round" (e.g., 2.0 and 2). - return val == parseInt(val); + return val === parseInt(val, 10); } else if (typeof val === 'boolean') { // `True` and `false` always represent integer after Scratch cast. return true; @@ -138,15 +138,15 @@ Cast.LIST_ALL = 'ALL'; */ Cast.toListIndex = function (index, length) { if (typeof index !== 'number') { - if (index == 'all') { + if (index === 'all') { return Cast.LIST_ALL; } - if (index == 'last') { + if (index === 'last') { if (length > 0) { return length; } return Cast.LIST_INVALID; - } else if (index == 'random' || index == 'any') { + } else if (index === 'random' || index === 'any') { if (length > 0) { return 1 + Math.floor(Math.random() * length); } diff --git a/src/util/color.js b/src/util/color.js index 6660ccf29..3e5054652 100644 --- a/src/util/color.js +++ b/src/util/color.js @@ -1,4 +1,4 @@ -function Color () {} +var Color = function () {}; /** * Convert a Scratch decimal color to a hex string, #RRGGBB. diff --git a/src/util/math-util.js b/src/util/math-util.js index 14ebb450e..c27e730bb 100644 --- a/src/util/math-util.js +++ b/src/util/math-util.js @@ -1,4 +1,4 @@ -function MathUtil () {} +var MathUtil = function () {}; /** * Convert a value from degrees to radians. @@ -42,7 +42,7 @@ MathUtil.clamp = function (n, min, max) { */ MathUtil.wrapClamp = function (n, min, max) { var range = (max - min) + 1; - return n - Math.floor((n - min) / range) * range; + return n - (Math.floor((n - min) / range) * range); }; module.exports = MathUtil; diff --git a/src/util/timer.js b/src/util/timer.js index 48dd223d5..17c66a567 100644 --- a/src/util/timer.js +++ b/src/util/timer.js @@ -15,7 +15,7 @@ /** * @constructor */ -function Timer () {} +var Timer = function () {}; /** * Used to store the start time of a timer action. diff --git a/test/.eslintrc.js b/test/.eslintrc.js new file mode 100644 index 000000000..666194097 --- /dev/null +++ b/test/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'no-undefined': [0] + } +}; diff --git a/test/unit/engine_adapter.js b/test/unit/engine_adapter.js index 58a820743..7c6cd2da1 100644 --- a/test/unit/engine_adapter.js +++ b/test/unit/engine_adapter.js @@ -61,7 +61,7 @@ test('create with branch', function (t) { // Find actual branch block var branchBlock = null; for (var i = 0; i < result.length; i++) { - if (result[i].id == branchBlockId) { + if (result[i].id === branchBlockId) { branchBlock = result[i]; } } @@ -93,10 +93,10 @@ test('create with two branches', function (t) { var firstBranchBlock = null; var secondBranchBlock = null; for (var i = 0; i < result.length; i++) { - if (result[i].id == firstBranchBlockId) { + if (result[i].id === firstBranchBlockId) { firstBranchBlock = result[i]; } - if (result[i].id == secondBranchBlockId) { + if (result[i].id === secondBranchBlockId) { secondBranchBlock = result[i]; } }