From 8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c Mon Sep 17 00:00:00 2001 From: Christopher Willis-Ford <7019101+cwillisf@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:25:23 -0800 Subject: [PATCH] style: fix hasOwnProperty lint complaints --- src/blocks/scratch3_looks.js | 2 +- src/blocks/scratch3_procedures.js | 2 +- src/blocks/scratch3_sound.js | 4 +- src/dispatch/central-dispatch.js | 2 +- src/dispatch/worker-dispatch.js | 2 +- src/engine/adapter.js | 2 +- src/engine/blocks-runtime-cache.js | 2 +- src/engine/blocks.js | 45 +++++------ src/engine/runtime.js | 26 +++---- src/engine/target.js | 20 ++--- src/engine/thread.js | 2 +- src/extension-support/extension-manager.js | 4 +- src/extensions/scratch3_makeymakey/index.js | 2 +- src/extensions/scratch3_pen/index.js | 2 +- src/extensions/scratch3_translate/index.js | 4 +- src/io/mouse.js | 2 +- src/serialization/sb2.js | 54 ++++++------- src/serialization/sb3.js | 76 ++++++++++--------- src/sprites/rendered-target.js | 24 +++--- src/util/jsonrpc.js | 2 +- src/util/task-queue.js | 6 +- src/virtual-machine.js | 12 +-- .../broadcast_special_chars_sb2.js | 4 +- .../broadcast_special_chars_sb3.js | 4 +- .../integration/variable_special_chars_sb2.js | 14 ++-- .../integration/variable_special_chars_sb3.js | 16 ++-- test/unit/engine_target.js | 8 +- test/unit/extension_conversion.js | 42 +++++----- test/unit/sprites_rendered-target.js | 2 +- 29 files changed, 207 insertions(+), 180 deletions(-) diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index c121df71d..18e163a9a 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -540,7 +540,7 @@ class Scratch3LooksBlocks { changeEffect (args, util) { const effect = Cast.toString(args.EFFECT).toLowerCase(); const change = Cast.toNumber(args.CHANGE); - if (!util.target.effects.hasOwnProperty(effect)) return; + if (!Object.prototype.hasOwnProperty.call(util.target.effects, effect)) return; let newValue = change + util.target.effects[effect]; newValue = this.clampEffect(effect, newValue); util.target.setEffect(effect, newValue); diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js index 56d3f3e7c..0f2ec3642 100644 --- a/src/blocks/scratch3_procedures.js +++ b/src/blocks/scratch3_procedures.js @@ -43,7 +43,7 @@ class Scratch3ProcedureBlocks { // at earlier stack frames for the values of a given parameter (#1729) util.initParams(); for (let i = 0; i < paramIds.length; i++) { - if (args.hasOwnProperty(paramIds[i])) { + if (Object.prototype.hasOwnProperty.call(args, paramIds[i])) { util.pushParam(paramNames[i], args[paramIds[i]]); } else { util.pushParam(paramNames[i], paramDefaults[i]); diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index 237db6123..26df698e6 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -267,7 +267,7 @@ class Scratch3SoundBlocks { const value = Cast.toNumber(args.VALUE); const soundState = this._getSoundState(util.target); - if (!soundState.effects.hasOwnProperty(effect)) return; + if (!Object.prototype.hasOwnProperty.call(soundState.effects, effect)) return; if (change) { soundState.effects[effect] += value; @@ -297,7 +297,7 @@ class Scratch3SoundBlocks { _clearEffectsForTarget (target) { const soundState = this._getSoundState(target); for (const effect in soundState.effects) { - if (!soundState.effects.hasOwnProperty(effect)) continue; + if (!Object.prototype.hasOwnProperty.call(soundState.effects, effect)) continue; soundState.effects[effect] = 0; } this._syncEffectsForTarget(target); diff --git a/src/dispatch/central-dispatch.js b/src/dispatch/central-dispatch.js index fe4987a6e..dde5c7c10 100644 --- a/src/dispatch/central-dispatch.js +++ b/src/dispatch/central-dispatch.js @@ -62,7 +62,7 @@ class CentralDispatch extends SharedDispatch { * @param {object} provider - a local object which provides this service. */ setServiceSync (service, provider) { - if (this.services.hasOwnProperty(service)) { + if (Object.prototype.hasOwnProperty.call(this.services, service)) { log.warn(`Central dispatch replacing existing service provider for ${service}`); } this.services[service] = provider; diff --git a/src/dispatch/worker-dispatch.js b/src/dispatch/worker-dispatch.js index 10542af46..b93aac123 100644 --- a/src/dispatch/worker-dispatch.js +++ b/src/dispatch/worker-dispatch.js @@ -58,7 +58,7 @@ class WorkerDispatch extends SharedDispatch { * @returns {Promise} - a promise which will resolve once the service is registered. */ setService (service, provider) { - if (this.services.hasOwnProperty(service)) { + if (Object.prototype.hasOwnProperty.call(this.services, service)) { log.warn(`Worker dispatch replacing existing service provider for ${service}`); } this.services[service] = provider; diff --git a/src/engine/adapter.js b/src/engine/adapter.js index 873974f8c..d10c6874a 100644 --- a/src/engine/adapter.js +++ b/src/engine/adapter.js @@ -153,7 +153,7 @@ const domToBlocks = function (blocksDOM) { // Flatten blocks object into a list. const blocksList = []; for (const b in blocks) { - if (!blocks.hasOwnProperty(b)) continue; + if (!Object.prototype.hasOwnProperty.call(blocks, b)) continue; blocksList.push(blocks[b]); } return blocksList; diff --git a/src/engine/blocks-runtime-cache.js b/src/engine/blocks-runtime-cache.js index cc30e8345..3a3241e97 100644 --- a/src/engine/blocks-runtime-cache.js +++ b/src/engine/blocks-runtime-cache.js @@ -44,7 +44,7 @@ class RuntimeScriptCache { if (Object.keys(fields).length === 0) { const inputs = container.getInputs(block); for (const input in inputs) { - if (!inputs.hasOwnProperty(input)) continue; + if (!Object.prototype.hasOwnProperty.call(inputs, input)) continue; const id = inputs[input].block; const inputBlock = container.getBlock(id); const inputFields = container.getFields(inputBlock); diff --git a/src/engine/blocks.js b/src/engine/blocks.js index c276564ed..cf1b2b7c4 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -231,7 +231,7 @@ class Blocks { } for (const id in this._blocks) { - if (!this._blocks.hasOwnProperty(id)) continue; + if (!Object.prototype.hasOwnProperty.call(this._blocks, id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_definition') { const internal = this._getCustomBlockInternal(block); @@ -267,7 +267,7 @@ class Blocks { } for (const id in this._blocks) { - if (!this._blocks.hasOwnProperty(id)) continue; + if (!Object.prototype.hasOwnProperty.call(this._blocks, id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_prototype' && block.mutation.proccode === name) { @@ -357,7 +357,7 @@ class Blocks { case 'delete': // Don't accept delete events for missing blocks, // or shadow blocks being obscured. - if (!this._blocks.hasOwnProperty(e.blockId) || + if (!Object.prototype.hasOwnProperty.call(this._blocks, e.blockId) || this._blocks[e.blockId].shadow) { return; } @@ -397,7 +397,7 @@ class Blocks { } break; case 'var_rename': - if (editingTarget && editingTarget.variables.hasOwnProperty(e.varId)) { + if (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) { // This is a local variable, rename on the current target editingTarget.renameVariable(e.varId, e.newName); // Update all the blocks on the current target that use @@ -416,7 +416,7 @@ class Blocks { this.emitProjectChanged(); break; case 'var_delete': { - const target = (editingTarget && editingTarget.variables.hasOwnProperty(e.varId)) ? + const target = (editingTarget && Object.prototype.hasOwnProperty.call(editingTarget.variables, e.varId)) ? editingTarget : stage; target.deleteVariable(e.varId); this.emitProjectChanged(); @@ -445,20 +445,21 @@ class Blocks { case 'comment_change': if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); - if (!currTarget.comments.hasOwnProperty(e.commentId)) { + if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); return; } const comment = currTarget.comments[e.commentId]; const change = e.newContents_; - if (change.hasOwnProperty('minimized')) { + if (Object.prototype.hasOwnProperty.call(change, 'minimized')) { comment.minimized = change.minimized; } - if (change.hasOwnProperty('width') && change.hasOwnProperty('height')){ + if (Object.prototype.hasOwnProperty.call(change, 'width') && + Object.prototype.hasOwnProperty.call(change, 'height')) { comment.width = change.width; comment.height = change.height; } - if (change.hasOwnProperty('text')) { + if (Object.prototype.hasOwnProperty.call(change, 'text')) { comment.text = change.text; } this.emitProjectChanged(); @@ -467,7 +468,7 @@ class Blocks { case 'comment_move': if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); - if (currTarget && !currTarget.comments.hasOwnProperty(e.commentId)) { + if (currTarget && !Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); return; } @@ -482,7 +483,7 @@ class Blocks { case 'comment_delete': if (this.runtime.getEditingTarget()) { const currTarget = this.runtime.getEditingTarget(); - if (!currTarget.comments.hasOwnProperty(e.commentId)) { + if (!Object.prototype.hasOwnProperty.call(currTarget.comments, e.commentId)) { // If we're in this state, we have probably received // a delete event from a workspace that we switched from // (e.g. a delete event for a comment on sprite a's workspace @@ -536,7 +537,7 @@ class Blocks { createBlock (block) { // Does the block already exist? // Could happen, e.g., for an unobscured shadow. - if (this._blocks.hasOwnProperty(block.id)) { + if (Object.prototype.hasOwnProperty.call(this._blocks, block.id)) { return; } // Create new block. @@ -650,7 +651,7 @@ class Blocks { } const isSpriteSpecific = isSpriteLocalVariable || - (this.runtime.monitorBlockInfo.hasOwnProperty(block.opcode) && + (Object.prototype.hasOwnProperty.call(this.runtime.monitorBlockInfo, block.opcode) && this.runtime.monitorBlockInfo[block.opcode].isSpriteSpecific); if (isSpriteSpecific) { // If creating a new sprite specific monitor, the only possible target is @@ -692,7 +693,7 @@ class Blocks { * @param {!object} e Blockly move event to be processed */ moveBlock (e) { - if (!this._blocks.hasOwnProperty(e.id)) { + if (!Object.prototype.hasOwnProperty.call(this._blocks, e.id)) { return; } @@ -740,7 +741,7 @@ class Blocks { // Moved to the new parent's input. // Don't obscure the shadow block. let oldShadow = null; - if (this._blocks[e.newParent].inputs.hasOwnProperty(e.newInput)) { + if (Object.prototype.hasOwnProperty.call(this._blocks[e.newParent].inputs, e.newInput)) { oldShadow = this._blocks[e.newParent].inputs[e.newInput].shadow; } @@ -990,7 +991,7 @@ class Blocks { */ _getCostumeField (blockId) { const block = this.getBlock(blockId); - if (block && block.fields.hasOwnProperty('COSTUME')) { + if (block && Object.prototype.hasOwnProperty.call(block.fields, 'COSTUME')) { return block.fields.COSTUME; } return null; @@ -1005,7 +1006,7 @@ class Blocks { */ _getSoundField (blockId) { const block = this.getBlock(blockId); - if (block && block.fields.hasOwnProperty('SOUND_MENU')) { + if (block && Object.prototype.hasOwnProperty.call(block.fields, 'SOUND_MENU')) { return block.fields.SOUND_MENU; } return null; @@ -1020,7 +1021,7 @@ class Blocks { */ _getBackdropField (blockId) { const block = this.getBlock(blockId); - if (block && block.fields.hasOwnProperty('BACKDROP')) { + if (block && Object.prototype.hasOwnProperty.call(block.fields, 'BACKDROP')) { return block.fields.BACKDROP; } return null; @@ -1042,7 +1043,7 @@ class Blocks { 'DISTANCETOMENU', 'TOUCHINGOBJECTMENU', 'CLONE_OPTION']; for (let i = 0; i < spriteMenuNames.length; i++) { const menuName = spriteMenuNames[i]; - if (block.fields.hasOwnProperty(menuName)) { + if (Object.prototype.hasOwnProperty.call(block.fields, menuName)) { return block.fields[menuName]; } } @@ -1085,7 +1086,7 @@ class Blocks { const commentId = block.comment; if (commentId) { if (comments) { - if (comments.hasOwnProperty(commentId)) { + if (Object.prototype.hasOwnProperty.call(comments, commentId)) { xmlString += comments[commentId].toXML(); } else { log.warn(`Could not find comment with id: ${commentId} in provided comment descriptions.`); @@ -1100,7 +1101,7 @@ class Blocks { } // Add any inputs on this block. for (const input in block.inputs) { - if (!block.inputs.hasOwnProperty(input)) continue; + if (!Object.prototype.hasOwnProperty.call(block.inputs, input)) continue; const blockInput = block.inputs[input]; // Only encode a value tag if the value input is occupied. if (blockInput.block || blockInput.shadow) { @@ -1117,7 +1118,7 @@ class Blocks { } // Add any fields on this block. for (const field in block.fields) { - if (!block.fields.hasOwnProperty(field)) continue; + if (!Object.prototype.hasOwnProperty.call(block.fields, field)) continue; const blockField = block.fields[field]; xmlString += `<field name="${blockField.name}"`; const fieldId = blockField.id; diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 29c14d3aa..f5a54d621 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -764,14 +764,14 @@ class Runtime extends EventEmitter { */ _registerBlockPackages () { for (const packageName in defaultBlockPackages) { - if (defaultBlockPackages.hasOwnProperty(packageName)) { + if (Object.prototype.hasOwnProperty.call(defaultBlockPackages, packageName)) { // @todo pass a different runtime depending on package privilege? const packageObject = new (defaultBlockPackages[packageName])(this); // Collect primitives from package. if (packageObject.getPrimitives) { const packagePrimitives = packageObject.getPrimitives(); for (const op in packagePrimitives) { - if (packagePrimitives.hasOwnProperty(op)) { + if (Object.prototype.hasOwnProperty.call(packagePrimitives, op)) { this._primitives[op] = packagePrimitives[op].bind(packageObject); } @@ -781,7 +781,7 @@ class Runtime extends EventEmitter { if (packageObject.getHats) { const packageHats = packageObject.getHats(); for (const hatName in packageHats) { - if (packageHats.hasOwnProperty(hatName)) { + if (Object.prototype.hasOwnProperty.call(packageHats, hatName)) { this._hats[hatName] = packageHats[hatName]; } } @@ -851,7 +851,7 @@ class Runtime extends EventEmitter { this._fillExtensionCategory(categoryInfo, extensionInfo); for (const fieldTypeName in categoryInfo.customFieldTypes) { - if (extensionInfo.customFieldTypes.hasOwnProperty(fieldTypeName)) { + if (Object.prototype.hasOwnProperty.call(extensionInfo.customFieldTypes, fieldTypeName)) { const fieldTypeInfo = categoryInfo.customFieldTypes[fieldTypeName]; // Emit events for custom field types from extension @@ -894,7 +894,7 @@ class Runtime extends EventEmitter { categoryInfo.menuInfo = {}; for (const menuName in extensionInfo.menus) { - if (extensionInfo.menus.hasOwnProperty(menuName)) { + if (Object.prototype.hasOwnProperty.call(extensionInfo.menus, menuName)) { const menuInfo = extensionInfo.menus[menuName]; const convertedMenu = this._buildMenuForScratchBlocks(menuName, menuInfo, categoryInfo); categoryInfo.menus.push(convertedMenu); @@ -902,7 +902,7 @@ class Runtime extends EventEmitter { } } for (const fieldTypeName in extensionInfo.customFieldTypes) { - if (extensionInfo.customFieldTypes.hasOwnProperty(fieldTypeName)) { + if (Object.prototype.hasOwnProperty.call(extensionInfo.customFieldTypes, fieldTypeName)) { const fieldType = extensionInfo.customFieldTypes[fieldTypeName]; const fieldTypeInfo = this._buildCustomFieldInfo( fieldTypeName, @@ -1138,7 +1138,7 @@ class Runtime extends EventEmitter { break; case BlockType.HAT: case BlockType.EVENT: - if (!blockInfo.hasOwnProperty('isEdgeActivated')) { + if (!Object.prototype.hasOwnProperty.call(blockInfo, 'isEdgeActivated')) { // if absent, this property defaults to true blockInfo.isEdgeActivated = true; } @@ -1584,7 +1584,7 @@ class Runtime extends EventEmitter { * @return {boolean} True if the op is known to be a hat. */ getIsHat (opcode) { - return this._hats.hasOwnProperty(opcode); + return Object.prototype.hasOwnProperty.call(this._hats, opcode); } /** @@ -1593,7 +1593,7 @@ class Runtime extends EventEmitter { * @return {boolean} True if the op is known to be a edge-activated hat. */ getIsEdgeActivatedHat (opcode) { - return this._hats.hasOwnProperty(opcode) && + return Object.prototype.hasOwnProperty.call(this._hats, opcode) && this._hats[opcode].edgeActivated; } @@ -1817,7 +1817,7 @@ class Runtime extends EventEmitter { */ startHats (requestedHatOpcode, optMatchFields, optTarget) { - if (!this._hats.hasOwnProperty(requestedHatOpcode)) { + if (!Object.prototype.hasOwnProperty.call(this._hats, requestedHatOpcode)) { // No known hat with this opcode. return; } @@ -1827,7 +1827,7 @@ class Runtime extends EventEmitter { const hatMeta = instance._hats[requestedHatOpcode]; for (const opts in optMatchFields) { - if (!optMatchFields.hasOwnProperty(opts)) continue; + if (!Object.prototype.hasOwnProperty.call(optMatchFields, opts)) continue; optMatchFields[opts] = optMatchFields[opts].toUpperCase(); } @@ -2062,7 +2062,7 @@ class Runtime extends EventEmitter { const newTargets = []; for (let i = 0; i < this.targets.length; i++) { this.targets[i].onStopAll(); - if (this.targets[i].hasOwnProperty('isOriginal') && + if (Object.prototype.hasOwnProperty.call(this.targets[i], 'isOriginal') && !this.targets[i].isOriginal) { this.targets[i].dispose(); } else { @@ -2097,7 +2097,7 @@ class Runtime extends EventEmitter { // Find all edge-activated hats, and add them to threads to be evaluated. for (const hatType in this._hats) { - if (!this._hats.hasOwnProperty(hatType)) continue; + if (!Object.prototype.hasOwnProperty.call(this._hats, hatType)) continue; const hat = this._hats[hatType]; if (hat.edgeActivated) { this.startHats(hatType); diff --git a/src/engine/target.js b/src/engine/target.js index 0f1895a3c..166e44369 100644 --- a/src/engine/target.js +++ b/src/engine/target.js @@ -101,7 +101,7 @@ class Target extends EventEmitter { } hasEdgeActivatedValue (blockId) { - return this._edgeActivatedHatValues.hasOwnProperty(blockId); + return Object.prototype.hasOwnProperty.call(this._edgeActivatedHatValues, blockId); } /** @@ -186,13 +186,13 @@ class Target extends EventEmitter { */ lookupVariableById (id) { // If we have a local copy, return it. - if (this.variables.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(this.variables, id)) { return this.variables[id]; } // If the stage has a global copy, return it. if (this.runtime && !this.isStage) { const stage = this.runtime.getTargetForStage(); - if (stage && stage.variables.hasOwnProperty(id)) { + if (stage && Object.prototype.hasOwnProperty.call(stage.variables, id)) { return stage.variables[id]; } } @@ -264,7 +264,7 @@ class Target extends EventEmitter { * Additional checks are made that the variable can be created as a cloud variable. */ createVariable (id, name, type, isCloud) { - if (!this.variables.hasOwnProperty(id)) { + if (!Object.prototype.hasOwnProperty.call(this.variables, id)) { const newVariable = new Variable(id, name, type, false); if (isCloud && this.isStage && this.runtime.canAddCloudVariable()) { newVariable.isCloud = true; @@ -288,7 +288,7 @@ class Target extends EventEmitter { * @param {boolean} minimized Whether the comment is minimized. */ createComment (id, blockId, text, x, y, width, height, minimized) { - if (!this.comments.hasOwnProperty(id)) { + if (!Object.prototype.hasOwnProperty.call(this.comments, id)) { const newComment = new Comment(id, text, x, y, width, height, minimized); if (blockId) { @@ -311,7 +311,7 @@ class Target extends EventEmitter { * @param {string} newName New name for the variable. */ renameVariable (id, newName) { - if (this.variables.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(this.variables, id)) { const variable = this.variables[id]; if (variable.id === id) { const oldName = variable.name; @@ -362,7 +362,7 @@ class Target extends EventEmitter { * @param {string} id Id of variable to delete. */ deleteVariable (id) { - if (this.variables.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(this.variables, id)) { // Get info about the variable before deleting it const deletedVariableName = this.variables[id].name; const deletedVariableWasCloud = this.variables[id].isCloud; @@ -408,7 +408,7 @@ class Target extends EventEmitter { * the original variable was not found. */ duplicateVariable (id, optKeepOriginalId) { - if (this.variables.hasOwnProperty(id)) { + if (Object.prototype.hasOwnProperty.call(this.variables, id)) { const originalVariable = this.variables[id]; const newVariable = new Variable( optKeepOriginalId ? id : null, // conditionally keep original id or generate a new one @@ -695,7 +695,7 @@ class Target extends EventEmitter { const unreferencedLocalVarIds = []; if (Object.keys(this.variables).length > 0) { for (const localVarId in this.variables) { - if (!this.variables.hasOwnProperty(localVarId)) continue; + if (!Object.prototype.hasOwnProperty.call(this.variables, localVarId)) continue; if (!allReferences[localVarId]) unreferencedLocalVarIds.push(localVarId); } } @@ -720,7 +720,7 @@ class Target extends EventEmitter { if (this.lookupVariableById(varId)) { // Found a variable with the id in either the target or the stage, // figure out which one. - if (this.variables.hasOwnProperty(varId)) { + if (Object.prototype.hasOwnProperty.call(this.variables, varId)) { // If the target has the variable, then check whether the stage // has one with the same name and type. If it does, then rename // this target specific variable so that there is a distinction. diff --git a/src/engine/thread.js b/src/engine/thread.js index e381dd9bf..6094a8254 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -353,7 +353,7 @@ class Thread { if (frame.params === null) { continue; } - if (frame.params.hasOwnProperty(paramName)) { + if (Object.prototype.hasOwnProperty.call(frame.params, paramName)) { return frame.params[paramName]; } return null; diff --git a/src/extension-support/extension-manager.js b/src/extension-support/extension-manager.js index a5e2c4ec8..0ed3a3e89 100644 --- a/src/extension-support/extension-manager.js +++ b/src/extension-support/extension-manager.js @@ -116,7 +116,7 @@ class ExtensionManager { * @param {string} extensionId - the ID of an internal extension */ loadExtensionIdSync (extensionId) { - if (!builtinExtensions.hasOwnProperty(extensionId)) { + if (!Object.prototype.hasOwnProperty.call(builtinExtensions, extensionId)) { log.warn(`Could not find extension ${extensionId} in the built in extensions.`); return; } @@ -140,7 +140,7 @@ class ExtensionManager { * @returns {Promise} resolved once the extension is loaded and initialized or rejected on failure */ loadExtensionURL (extensionURL) { - if (builtinExtensions.hasOwnProperty(extensionURL)) { + if (Object.prototype.hasOwnProperty.call(builtinExtensions, extensionURL)) { /** @TODO dupe handling for non-builtin extensions. See commit 670e51d33580e8a2e852b3b038bb3afc282f81b9 */ if (this.isExtensionLoaded(extensionURL)) { const message = `Rejecting attempt to load a second extension with ID ${extensionURL}`; diff --git a/src/extensions/scratch3_makeymakey/index.js b/src/extensions/scratch3_makeymakey/index.js index a83ca6616..e57bc76e8 100644 --- a/src/extensions/scratch3_makeymakey/index.js +++ b/src/extensions/scratch3_makeymakey/index.js @@ -368,7 +368,7 @@ class Scratch3MakeyMakeyBlocks { */ addSequence (sequenceString, sequenceArray) { // If we already have this sequence string, return. - if (this.sequences.hasOwnProperty(sequenceString)) { + if (Object.prototype.hasOwnProperty.call(this.sequences, sequenceString)) { return; } this.sequences[sequenceString] = { diff --git a/src/extensions/scratch3_pen/index.js b/src/extensions/scratch3_pen/index.js index ec9aa0ac8..f6175f96f 100644 --- a/src/extensions/scratch3_pen/index.js +++ b/src/extensions/scratch3_pen/index.js @@ -569,7 +569,7 @@ class Scratch3PenBlocks { penState.color = (hsv.h / 360) * 100; penState.saturation = hsv.s * 100; penState.brightness = hsv.v * 100; - if (rgb.hasOwnProperty('a')) { + if (Object.prototype.hasOwnProperty.call(rgb, 'a')) { penState.transparency = 100 * (1 - (rgb.a / 255.0)); } else { penState.transparency = 0; diff --git a/src/extensions/scratch3_translate/index.js b/src/extensions/scratch3_translate/index.js index 3964711fc..1149a3b30 100644 --- a/src/extensions/scratch3_translate/index.js +++ b/src/extensions/scratch3_translate/index.js @@ -222,11 +222,11 @@ class Scratch3TranslateBlocks { getLanguageCodeFromArg (arg) { const languageArg = Cast.toString(arg).toLowerCase(); // Check if the arg matches a language code in the menu. - if (languageNames.menuMap.hasOwnProperty(languageArg)) { + if (Object.prototype.hasOwnProperty.call(languageNames.menuMap, languageArg)) { return languageArg; } // Check for a dropped-in language name, and convert to a language code. - if (languageNames.nameMap.hasOwnProperty(languageArg)) { + if (Object.prototype.hasOwnProperty.call(languageNames.nameMap, languageArg)) { return languageNames.nameMap[languageArg]; } diff --git a/src/io/mouse.js b/src/io/mouse.js index 1c7bb81e5..9ee3202e5 100644 --- a/src/io/mouse.js +++ b/src/io/mouse.js @@ -42,7 +42,7 @@ class Mouse { const drawableID = this.runtime.renderer.pick(x, y); for (let i = 0; i < this.runtime.targets.length; i++) { const target = this.runtime.targets[i]; - if (target.hasOwnProperty('drawableID') && + if (Object.prototype.hasOwnProperty.call(target, 'drawableID') && target.drawableID === drawableID) { return target; } diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js index 2f7556341..855723d6a 100644 --- a/src/serialization/sb2.js +++ b/src/serialization/sb2.js @@ -288,7 +288,7 @@ const parseMonitorObject = (object, runtime, targets, extensions) => { let target = null; // List blocks don't come in with their target name set. // Find the target by searching for a target with matching variable name/type. - if (!object.hasOwnProperty('target')) { + if (!Object.prototype.hasOwnProperty.call(object, 'target')) { for (let i = 0; i < targets.length; i++) { const currTarget = targets[i]; const listVariables = Object.keys(currTarget.variables).filter(key => { @@ -326,7 +326,7 @@ const parseMonitorObject = (object, runtime, targets, extensions) => { block.id = getVariableId(object.param, Variable.SCALAR_TYPE); } else if (object.cmd === 'contentsOfList:') { block.id = getVariableId(object.param, Variable.LIST_TYPE); - } else if (runtime.monitorBlockInfo.hasOwnProperty(block.opcode)) { + } else if (Object.prototype.hasOwnProperty.call(runtime.monitorBlockInfo, block.opcode)) { block.id = runtime.monitorBlockInfo[block.opcode].getId(target.id, block.fields); } else { // If the opcode can't be found in the runtime monitorBlockInfo, @@ -405,7 +405,7 @@ const parseMonitorObject = (object, runtime, targets, extensions) => { * objects. */ const parseScratchAssets = function (object, runtime, topLevel, zip) { - if (!object.hasOwnProperty('objName')) { + if (!Object.prototype.hasOwnProperty.call(object, 'objName')) { // Skip parsing monitors. Or any other objects missing objName. return null; } @@ -419,7 +419,7 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) { // Costumes from JSON. const costumePromises = assets.costumePromises; - if (object.hasOwnProperty('costumes')) { + if (Object.prototype.hasOwnProperty.call(object, 'costumes')) { for (let i = 0; i < object.costumes.length; i++) { const costumeSource = object.costumes[i]; const bitmapResolution = costumeSource.bitmapResolution || 1; @@ -464,7 +464,7 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) { } // Sounds from JSON const {soundBank, soundPromises} = assets; - if (object.hasOwnProperty('sounds')) { + if (Object.prototype.hasOwnProperty.call(object, 'sounds')) { for (let s = 0; s < object.sounds.length; s++) { const soundSource = object.sounds[s]; const sound = { @@ -523,8 +523,8 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) { * @return {!Promise.<Array.<Target>>} Promise for the loaded targets when ready, or null for unsupported objects. */ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, assets) { - if (!object.hasOwnProperty('objName')) { - if (object.hasOwnProperty('listName')) { + if (!Object.prototype.hasOwnProperty.call(object, 'objName')) { + if (Object.prototype.hasOwnProperty.call(object, 'listName')) { // Shim these objects so they can be processed as monitors object.cmd = 'contentsOfList:'; object.param = object.listName; @@ -540,10 +540,10 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, // @todo: For now, load all Scratch objects (stage/sprites) as a Sprite. const sprite = new Sprite(blocks, runtime); // Sprite/stage name from JSON. - if (object.hasOwnProperty('objName')) { + if (Object.prototype.hasOwnProperty.call(object, 'objName')) { if (topLevel && object.objName !== 'Stage') { for (const child of object.children) { - if (!child.hasOwnProperty('objName') && child.target === object.objName) { + if (!Object.prototype.hasOwnProperty.call(child, 'objName') && child.target === object.objName) { child.target = 'Stage'; } } @@ -566,7 +566,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, const addBroadcastMsg = globalBroadcastMsgObj.broadcastMsgMapUpdater; // Load target properties from JSON. - if (object.hasOwnProperty('variables')) { + if (Object.prototype.hasOwnProperty.call(object, 'variables')) { for (let j = 0; j < object.variables.length; j++) { const variable = object.variables[j]; // A variable is a cloud variable if: @@ -589,7 +589,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, // If included, parse any and all comments on the object (this includes top-level // workspace comments as well as comments attached to specific blocks) const blockComments = {}; - if (object.hasOwnProperty('scriptComments')) { + if (Object.prototype.hasOwnProperty.call(object, 'scriptComments')) { const comments = object.scriptComments.map(commentDesc => { const [ commentX, @@ -624,7 +624,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, newComment.blockId = flattenedBlockIndex; // Add this comment to the block comments object with its script index // as the key - if (blockComments.hasOwnProperty(flattenedBlockIndex)) { + if (Object.prototype.hasOwnProperty.call(blockComments, flattenedBlockIndex)) { blockComments[flattenedBlockIndex].push(newComment); } else { blockComments[flattenedBlockIndex] = [newComment]; @@ -641,7 +641,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, } // If included, parse any and all scripts/blocks on the object. - if (object.hasOwnProperty('scripts')) { + if (Object.prototype.hasOwnProperty.call(object, 'scripts')) { parseScripts(object.scripts, blocks, addBroadcastMsg, getVariableId, extensions, blockComments); } @@ -664,7 +664,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, // Update stage specific blocks (e.g. sprite clicked <=> stage clicked) blocks.updateTargetSpecificBlocks(topLevel); // topLevel = isStage - if (object.hasOwnProperty('lists')) { + if (Object.prototype.hasOwnProperty.call(object, 'lists')) { for (let k = 0; k < object.lists.length; k++) { const list = object.lists[k]; const newVariable = new Variable( @@ -677,34 +677,34 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, target.variables[newVariable.id] = newVariable; } } - if (object.hasOwnProperty('scratchX')) { + if (Object.prototype.hasOwnProperty.call(object, 'scratchX')) { target.x = object.scratchX; } - if (object.hasOwnProperty('scratchY')) { + if (Object.prototype.hasOwnProperty.call(object, 'scratchY')) { target.y = object.scratchY; } - if (object.hasOwnProperty('direction')) { + if (Object.prototype.hasOwnProperty.call(object, 'direction')) { // Sometimes the direction can be outside of the range: LLK/scratch-gui#5806 // wrapClamp it (like we do on RenderedTarget.setDirection) target.direction = MathUtil.wrapClamp(object.direction, -179, 180); } - if (object.hasOwnProperty('isDraggable')) { + if (Object.prototype.hasOwnProperty.call(object, 'isDraggable')) { target.draggable = object.isDraggable; } - if (object.hasOwnProperty('scale')) { + if (Object.prototype.hasOwnProperty.call(object, 'scale')) { // SB2 stores as 1.0 = 100%; we use % in the VM. target.size = object.scale * 100; } - if (object.hasOwnProperty('visible')) { + if (Object.prototype.hasOwnProperty.call(object, 'visible')) { target.visible = object.visible; } - if (object.hasOwnProperty('currentCostumeIndex')) { + if (Object.prototype.hasOwnProperty.call(object, 'currentCostumeIndex')) { // Current costume index can sometimes be a floating // point number, use Math.floor to come up with an appropriate index // and clamp it to the actual number of costumes the object has for good measure. target.currentCostume = MathUtil.clamp(Math.floor(object.currentCostumeIndex), 0, object.costumes.length - 1); } - if (object.hasOwnProperty('rotationStyle')) { + if (Object.prototype.hasOwnProperty.call(object, 'rotationStyle')) { if (object.rotationStyle === 'none') { target.rotationStyle = RenderedTarget.ROTATION_STYLE_NONE; } else if (object.rotationStyle === 'leftRight') { @@ -713,16 +713,16 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, target.rotationStyle = RenderedTarget.ROTATION_STYLE_ALL_AROUND; } } - if (object.hasOwnProperty('tempoBPM')) { + if (Object.prototype.hasOwnProperty.call(object, 'tempoBPM')) { target.tempo = object.tempoBPM; } - if (object.hasOwnProperty('videoAlpha')) { + if (Object.prototype.hasOwnProperty.call(object, 'videoAlpha')) { // SB2 stores alpha as opacity, where 1.0 is opaque. // We convert to a percentage, and invert it so 100% is full transparency. target.videoTransparency = 100 - (100 * object.videoAlpha); } - if (object.hasOwnProperty('info')) { - if (object.info.hasOwnProperty('videoOn')) { + if (Object.prototype.hasOwnProperty.call(object, 'info')) { + if (Object.prototype.hasOwnProperty.call(object.info, 'videoOn')) { if (object.info.videoOn) { target.videoState = RenderedTarget.VIDEO_STATE.ON; } else { @@ -730,7 +730,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip, } } } - if (object.hasOwnProperty('indexInLibrary')) { + if (Object.prototype.hasOwnProperty.call(object, 'indexInLibrary')) { // Temporarily store the 'indexInLibrary' property from the sb2 file // so that we can correctly order sprites in the target pane. // This will be deleted after we are done parsing and ordering the targets list. diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 5eb60a5bf..c7db58d0b 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -173,7 +173,7 @@ const serializeFields = function (fields) { for (const fieldName in fields) { if (!hasOwnProperty.call(fields, fieldName)) continue; obj[fieldName] = [fields[fieldName].value]; - if (fields[fieldName].hasOwnProperty('id')) { + if (Object.prototype.hasOwnProperty.call(fields[fieldName], 'id')) { obj[fieldName].push(fields[fieldName].id); } } @@ -301,7 +301,7 @@ const serializeBlocks = function (blocks) { const obj = Object.create(null); const extensionIDs = new Set(); for (const blockID in blocks) { - if (!blocks.hasOwnProperty(blockID)) continue; + if (!Object.prototype.hasOwnProperty.call(blocks, blockID)) continue; obj[blockID] = serializeBlock(blocks[blockID], blocks); const extensionID = getExtensionIdForOpcode(blocks[blockID].opcode); if (extensionID) { @@ -428,7 +428,7 @@ const serializeVariables = function (variables) { const serializeComments = function (comments) { const obj = Object.create(null); for (const commentId in comments) { - if (!comments.hasOwnProperty(commentId)) continue; + if (!Object.prototype.hasOwnProperty.call(comments, commentId)) continue; const comment = comments[commentId]; const serializedComment = Object.create(null); @@ -473,13 +473,21 @@ const serializeTarget = function (target, extensions) { obj.currentCostume = target.currentCostume; obj.costumes = target.costumes.map(serializeCostume); obj.sounds = target.sounds.map(serializeSound); - if (target.hasOwnProperty('volume')) obj.volume = target.volume; - if (target.hasOwnProperty('layerOrder')) obj.layerOrder = target.layerOrder; + if (Object.prototype.hasOwnProperty.call(target, 'volume')) obj.volume = target.volume; + if (Object.prototype.hasOwnProperty.call(target, 'layerOrder')) obj.layerOrder = target.layerOrder; if (obj.isStage) { // Only the stage should have these properties - if (target.hasOwnProperty('tempo')) obj.tempo = target.tempo; - if (target.hasOwnProperty('videoTransparency')) obj.videoTransparency = target.videoTransparency; - if (target.hasOwnProperty('videoState')) obj.videoState = target.videoState; - if (target.hasOwnProperty('textToSpeechLanguage')) obj.textToSpeechLanguage = target.textToSpeechLanguage; + if (Object.prototype.hasOwnProperty.call(target, 'tempo')) { + obj.tempo = target.tempo; + } + if (Object.prototype.hasOwnProperty.call(target, 'videoTransparency')) { + obj.videoTransparency = target.videoTransparency; + } + if (Object.prototype.hasOwnProperty.call(target, 'videoState')) { + obj.videoState = target.videoState; + } + if (Object.prototype.hasOwnProperty.call(target, 'textToSpeechLanguage')) { + obj.textToSpeechLanguage = target.textToSpeechLanguage; + } } else { // The stage does not need the following properties, but sprites should obj.visible = target.visible; obj.x = target.x; @@ -852,7 +860,7 @@ const deserializeBlocks = function (blocks) { * SoundBank for the sound assets. null for unsupported objects. */ const parseScratchAssets = function (object, runtime, zip) { - if (!object.hasOwnProperty('name')) { + if (!Object.prototype.hasOwnProperty.call(object, 'name')) { // Watcher/monitor - skip this object until those are implemented in VM. // @todo return Promise.resolve(null); @@ -882,7 +890,7 @@ const parseScratchAssets = function (object, runtime, zip) { costumeSource.dataFormat || (costumeSource.assetType && costumeSource.assetType.runtimeFormat) || // older format 'png'; // if all else fails, guess that it might be a PNG - const costumeMd5Ext = costumeSource.hasOwnProperty('md5ext') ? + const costumeMd5Ext = Object.prototype.hasOwnProperty.call(costumeSource, 'md5ext') ? costumeSource.md5ext : `${costumeSource.assetId}.${dataFormat}`; costume.md5 = costumeMd5Ext; costume.dataFormat = dataFormat; @@ -936,7 +944,7 @@ const parseScratchAssets = function (object, runtime, zip) { * @return {!Promise.<Target>} Promise for the target created (stage or sprite), or null for unsupported objects. */ const parseScratchObject = function (object, runtime, extensions, zip, assets) { - if (!object.hasOwnProperty('name')) { + if (!Object.prototype.hasOwnProperty.call(object, 'name')) { // Watcher/monitor - skip this object until those are implemented in VM. // @todo return Promise.resolve(null); @@ -948,14 +956,14 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { const sprite = new Sprite(blocks, runtime); // Sprite/stage name from JSON. - if (object.hasOwnProperty('name')) { + if (Object.prototype.hasOwnProperty.call(object, 'name')) { sprite.name = object.name; } - if (object.hasOwnProperty('blocks')) { + if (Object.prototype.hasOwnProperty.call(object, 'blocks')) { deserializeBlocks(object.blocks); // Take a second pass to create objects and add extensions for (const blockId in object.blocks) { - if (!object.blocks.hasOwnProperty(blockId)) continue; + if (!Object.prototype.hasOwnProperty.call(object.blocks, blockId)) continue; const blockJSON = object.blocks[blockId]; blocks.createBlock(blockJSON); @@ -973,22 +981,22 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { // Create the first clone, and load its run-state from JSON. const target = sprite.createClone(object.isStage ? StageLayering.BACKGROUND_LAYER : StageLayering.SPRITE_LAYER); // Load target properties from JSON. - if (object.hasOwnProperty('tempo')) { + if (Object.prototype.hasOwnProperty.call(object, 'tempo')) { target.tempo = object.tempo; } - if (object.hasOwnProperty('volume')) { + if (Object.prototype.hasOwnProperty.call(object, 'volume')) { target.volume = object.volume; } - if (object.hasOwnProperty('videoTransparency')) { + if (Object.prototype.hasOwnProperty.call(object, 'videoTransparency')) { target.videoTransparency = object.videoTransparency; } - if (object.hasOwnProperty('videoState')) { + if (Object.prototype.hasOwnProperty.call(object, 'videoState')) { target.videoState = object.videoState; } - if (object.hasOwnProperty('textToSpeechLanguage')) { + if (Object.prototype.hasOwnProperty.call(object, 'textToSpeechLanguage')) { target.textToSpeechLanguage = object.textToSpeechLanguage; } - if (object.hasOwnProperty('variables')) { + if (Object.prototype.hasOwnProperty.call(object, 'variables')) { for (const varId in object.variables) { const variable = object.variables[varId]; // A variable is a cloud variable if: @@ -1008,7 +1016,7 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { target.variables[newVariable.id] = newVariable; } } - if (object.hasOwnProperty('lists')) { + if (Object.prototype.hasOwnProperty.call(object, 'lists')) { for (const listId in object.lists) { const list = object.lists[listId]; const newList = new Variable( @@ -1021,7 +1029,7 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { target.variables[newList.id] = newList; } } - if (object.hasOwnProperty('broadcasts')) { + if (Object.prototype.hasOwnProperty.call(object, 'broadcasts')) { for (const broadcastId in object.broadcasts) { const broadcast = object.broadcasts[broadcastId]; const newBroadcast = new Variable( @@ -1035,7 +1043,7 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { target.variables[newBroadcast.id] = newBroadcast; } } - if (object.hasOwnProperty('comments')) { + if (Object.prototype.hasOwnProperty.call(object, 'comments')) { for (const commentId in object.comments) { const comment = object.comments[commentId]; const newComment = new Comment( @@ -1053,39 +1061,39 @@ const parseScratchObject = function (object, runtime, extensions, zip, assets) { target.comments[newComment.id] = newComment; } } - if (object.hasOwnProperty('x')) { + if (Object.prototype.hasOwnProperty.call(object, 'x')) { target.x = object.x; } - if (object.hasOwnProperty('y')) { + if (Object.prototype.hasOwnProperty.call(object, 'y')) { target.y = object.y; } - if (object.hasOwnProperty('direction')) { + if (Object.prototype.hasOwnProperty.call(object, 'direction')) { // Sometimes the direction can be outside of the range: LLK/scratch-gui#5806 // wrapClamp it (like we do on RenderedTarget.setDirection) target.direction = MathUtil.wrapClamp(object.direction, -179, 180); } - if (object.hasOwnProperty('size')) { + if (Object.prototype.hasOwnProperty.call(object, 'size')) { target.size = object.size; } - if (object.hasOwnProperty('visible')) { + if (Object.prototype.hasOwnProperty.call(object, 'visible')) { target.visible = object.visible; } - if (object.hasOwnProperty('currentCostume')) { + if (Object.prototype.hasOwnProperty.call(object, 'currentCostume')) { target.currentCostume = MathUtil.clamp(object.currentCostume, 0, object.costumes.length - 1); } - if (object.hasOwnProperty('rotationStyle')) { + if (Object.prototype.hasOwnProperty.call(object, 'rotationStyle')) { target.rotationStyle = object.rotationStyle; } - if (object.hasOwnProperty('isStage')) { + if (Object.prototype.hasOwnProperty.call(object, 'isStage')) { target.isStage = object.isStage; } - if (object.hasOwnProperty('targetPaneOrder')) { + if (Object.prototype.hasOwnProperty.call(object, 'targetPaneOrder')) { // Temporarily store the 'targetPaneOrder' property // so that we can correctly order sprites in the target pane. // This will be deleted after we are done parsing and ordering the targets list. target.targetPaneOrder = object.targetPaneOrder; } - if (object.hasOwnProperty('draggable')) { + if (Object.prototype.hasOwnProperty.call(object, 'draggable')) { target.draggable = object.draggable; } Promise.all(costumePromises).then(costumes => { diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index b0c1ebfed..e4a12e244 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -395,7 +395,7 @@ class RenderedTarget extends Target { * @param {!number} value Numerical magnitude of effect. */ setEffect (effectName, value) { - if (!this.effects.hasOwnProperty(effectName)) return; + if (!Object.prototype.hasOwnProperty.call(this.effects, effectName)) return; this.effects[effectName] = value; if (this.renderer) { this.renderer.updateDrawableEffect(this.drawableID, effectName, value); @@ -411,12 +411,12 @@ class RenderedTarget extends Target { */ clearEffects () { for (const effectName in this.effects) { - if (!this.effects.hasOwnProperty(effectName)) continue; + if (!Object.prototype.hasOwnProperty.call(this.effects, effectName)) continue; this.effects[effectName] = 0; } if (this.renderer) { for (const effectName in this.effects) { - if (!this.effects.hasOwnProperty(effectName)) continue; + if (!Object.prototype.hasOwnProperty.call(this.effects, effectName)) continue; this.renderer.updateDrawableEffect(this.drawableID, effectName, 0); } if (this.visible) { @@ -682,7 +682,7 @@ class RenderedTarget extends Target { this.renderer.updateDrawableSkinId(this.drawableID, costume.skinId); for (const effectName in this.effects) { - if (!this.effects.hasOwnProperty(effectName)) continue; + if (!Object.prototype.hasOwnProperty.call(this.effects, effectName)) continue; this.renderer.updateDrawableEffect(this.drawableID, effectName, this.effects[effectName]); } @@ -1020,25 +1020,25 @@ class RenderedTarget extends Target { * @param {object} data An object with sprite info data to set. */ postSpriteInfo (data) { - const force = data.hasOwnProperty('force') ? data.force : null; - const isXChanged = data.hasOwnProperty('x'); - const isYChanged = data.hasOwnProperty('y'); + const force = Object.prototype.hasOwnProperty.call(data, 'force') ? data.force : null; + const isXChanged = Object.prototype.hasOwnProperty.call(data, 'x'); + const isYChanged = Object.prototype.hasOwnProperty.call(data, 'y'); if (isXChanged || isYChanged) { this.setXY(isXChanged ? data.x : this.x, isYChanged ? data.y : this.y, force); } - if (data.hasOwnProperty('direction')) { + if (Object.prototype.hasOwnProperty.call(data, 'direction')) { this.setDirection(data.direction); } - if (data.hasOwnProperty('draggable')) { + if (Object.prototype.hasOwnProperty.call(data, 'draggable')) { this.setDraggable(data.draggable); } - if (data.hasOwnProperty('rotationStyle')) { + if (Object.prototype.hasOwnProperty.call(data, 'rotationStyle')) { this.setRotationStyle(data.rotationStyle); } - if (data.hasOwnProperty('visible')) { + if (Object.prototype.hasOwnProperty.call(data, 'visible')) { this.setVisible(data.visible); } - if (data.hasOwnProperty('size')) { + if (Object.prototype.hasOwnProperty.call(data, 'size')) { this.setSize(data.size); } } diff --git a/src/util/jsonrpc.js b/src/util/jsonrpc.js index ba23a0e8f..4ab1663c3 100644 --- a/src/util/jsonrpc.js +++ b/src/util/jsonrpc.js @@ -62,7 +62,7 @@ class JSONRPC { if (json.jsonrpc !== '2.0') { throw new Error(`Bad or missing JSON-RPC version in message: ${json}`); } - if (json.hasOwnProperty('method')) { + if (Object.prototype.hasOwnProperty.call(json, 'method')) { this._handleRequest(json); } else { this._handleResponse(json); diff --git a/src/util/task-queue.js b/src/util/task-queue.js index 0b452ffb9..8a3b415ef 100644 --- a/src/util/task-queue.js +++ b/src/util/task-queue.js @@ -21,8 +21,10 @@ class TaskQueue { this._maxTokens = maxTokens; this._refillRate = refillRate; this._pendingTaskRecords = []; - this._tokenCount = options.hasOwnProperty('startingTokens') ? options.startingTokens : maxTokens; - this._maxTotalCost = options.hasOwnProperty('maxTotalCost') ? options.maxTotalCost : Infinity; + this._tokenCount = Object.prototype.hasOwnProperty.call(options, 'startingTokens') ? + options.startingTokens : maxTokens; + this._maxTotalCost = Object.prototype.hasOwnProperty.call(options, 'maxTotalCost') ? + options.maxTotalCost : Infinity; this._timer = new Timer(); this._timer.start(); this._timeout = null; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 6693a1f3a..6d84523a0 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -2,7 +2,6 @@ let _TextEncoder; if (typeof TextEncoder === 'undefined') { _TextEncoder = require('text-encoding').TextEncoder; } else { - /* global TextEncoder */ _TextEncoder = TextEncoder; } const EventEmitter = require('events'); @@ -354,7 +353,7 @@ class VirtualMachine extends EventEmitter { .then(() => this.runtime.handleProjectLoaded()) .catch(error => { // Intentionally rejecting here (want errors to be handled by caller) - if (error.hasOwnProperty('validationError')) { + if (Object.prototype.hasOwnProperty.call(error, 'validationError')) { return Promise.reject(JSON.stringify(error)); } return Promise.reject(error); @@ -612,7 +611,7 @@ class VirtualMachine extends EventEmitter { .then(() => this.runtime.emitProjectChanged()) .catch(error => { // Intentionally rejecting here (want errors to be handled by caller) - if (error.hasOwnProperty('validationError')) { + if (Object.prototype.hasOwnProperty.call(error, 'validationError')) { return Promise.reject(JSON.stringify(error)); } return Promise.reject(`${errorPrefix} ${error}`); @@ -1338,7 +1337,7 @@ class VirtualMachine extends EventEmitter { targetList: this.runtime.targets .filter( // Don't report clones. - target => !target.hasOwnProperty('isOriginal') || target.isOriginal + target => !Object.prototype.hasOwnProperty.call(target, 'isOriginal') || target.isOriginal ).map( target => target.toJSON() ), @@ -1414,7 +1413,10 @@ class VirtualMachine extends EventEmitter { */ getTargetIdForDrawableId (drawableId) { const target = this.runtime.getTargetByDrawableId(drawableId); - if (target && target.hasOwnProperty('id') && target.hasOwnProperty('isStage') && !target.isStage) { + if (target && + Object.prototype.hasOwnProperty.call(target, 'id') && + Object.prototype.hasOwnProperty.call(target, 'isStage') && + !target.isStage) { return target.id; } return null; diff --git a/test/integration/broadcast_special_chars_sb2.js b/test/integration/broadcast_special_chars_sb2.js index 63a77df6c..24988f402 100644 --- a/test/integration/broadcast_special_chars_sb2.js +++ b/test/integration/broadcast_special_chars_sb2.js @@ -57,7 +57,9 @@ test('importing sb2 project with special chars in message names', t => { t.equal(allBroadcastFields[ltPerfectMessageId].length, 1); t.equal(allBroadcastFields[abMessageId].length, 1); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); - const catMessageBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('BROADCAST_OPTION')); + const catMessageBlocks = catBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'BROADCAST_OPTION') + ); t.equal(catMessageBlocks.length, 2); t.equal(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); t.equal(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); diff --git a/test/integration/broadcast_special_chars_sb3.js b/test/integration/broadcast_special_chars_sb3.js index 968e9fc52..91050e591 100644 --- a/test/integration/broadcast_special_chars_sb3.js +++ b/test/integration/broadcast_special_chars_sb3.js @@ -57,7 +57,9 @@ test('importing sb3 project with special chars in message names', t => { t.equal(allBroadcastFields[ltPerfectMessageId].length, 1); t.equal(allBroadcastFields[abMessageId].length, 1); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); - const catMessageBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('BROADCAST_OPTION')); + const catMessageBlocks = catBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'BROADCAST_OPTION') + ); t.equal(catMessageBlocks.length, 2); t.equal(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); t.equal(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); diff --git a/test/integration/variable_special_chars_sb2.js b/test/integration/variable_special_chars_sb2.js index b0c47bdd9..ba256b034 100644 --- a/test/integration/variable_special_chars_sb2.js +++ b/test/integration/variable_special_chars_sb2.js @@ -55,12 +55,12 @@ test('importing sb2 project with special chars in variable names', t => { // There should be 3 fields, 2 on the stage, and one on the cat t.equal(allVarListFields[abVarId].length, 3); const stageBlocks = Object.keys(stage.blocks._blocks).map(blockId => stage.blocks._blocks[blockId]); - const stageListBlocks = stageBlocks.filter(block => block.fields.hasOwnProperty('LIST')); + const stageListBlocks = stageBlocks.filter(block => Object.prototype.hasOwnProperty.call(block.fields, 'LIST')); t.equal(stageListBlocks.length, 2); t.equal(stageListBlocks[0].fields.LIST.id, abVarId); t.equal(stageListBlocks[1].fields.LIST.id, abVarId); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); - const catListBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('LIST')); + const catListBlocks = catBlocks.filter(block => Object.prototype.hasOwnProperty.call(block.fields, 'LIST')); t.equal(catListBlocks.length, 1); t.equal(catListBlocks[0].fields.LIST.id, abVarId); @@ -83,10 +83,12 @@ test('importing sb2 project with special chars in variable names', t => { // Find all the references for this variable, and verify they have the correct ID // There should be only two, one on the stage and one on bananas t.equal(allVarListFields[fooVarId].length, 2); - const stageVarBlocks = stageBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const stageVarBlocks = stageBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE') + ); t.equal(stageVarBlocks.length, 1); t.equal(stageVarBlocks[0].fields.VARIABLE.id, fooVarId); - const catVarBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const catVarBlocks = catBlocks.filter(block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE')); t.equal(catVarBlocks.length, 1); t.equal(catVarBlocks[0].fields.VARIABLE.id, fooVarId); @@ -110,7 +112,9 @@ test('importing sb2 project with special chars in variable names', t => { // There should be one t.equal(allVarListFields[ltPerfectVarId].length, 1); const bananasBlocks = Object.keys(bananas.blocks._blocks).map(blockId => bananas.blocks._blocks[blockId]); - const bananasVarBlocks = bananasBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const bananasVarBlocks = bananasBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE') + ); t.equal(bananasVarBlocks.length, 1); t.equal(bananasVarBlocks[0].fields.VARIABLE.id, ltPerfectVarId); diff --git a/test/integration/variable_special_chars_sb3.js b/test/integration/variable_special_chars_sb3.js index 5fb7c7542..c4b0d0f51 100644 --- a/test/integration/variable_special_chars_sb3.js +++ b/test/integration/variable_special_chars_sb3.js @@ -55,12 +55,12 @@ test('importing sb3 project with special chars in variable names', t => { // There should be 3 fields, 2 on the stage, and one on the cat t.equal(allVarListFields[abVarId].length, 3); const stageBlocks = Object.keys(stage.blocks._blocks).map(blockId => stage.blocks._blocks[blockId]); - const stageListBlocks = stageBlocks.filter(block => block.fields.hasOwnProperty('LIST')); + const stageListBlocks = stageBlocks.filter(block => Object.prototype.hasOwnProperty.call(block.fields, 'LIST')); t.equal(stageListBlocks.length, 2); t.equal(stageListBlocks[0].fields.LIST.id, abVarId); t.equal(stageListBlocks[1].fields.LIST.id, abVarId); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); - const catListBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('LIST')); + const catListBlocks = catBlocks.filter(block => Object.prototype.hasOwnProperty.call(block.fields, 'LIST')); t.equal(catListBlocks.length, 1); t.equal(catListBlocks[0].fields.LIST.id, abVarId); @@ -83,10 +83,14 @@ test('importing sb3 project with special chars in variable names', t => { // Find all the references for this variable, and verify they have the correct ID // There should be only two, one on the stage and one on bananas t.equal(allVarListFields[fooVarId].length, 2); - const stageVarBlocks = stageBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const stageVarBlocks = stageBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE') + ); t.equal(stageVarBlocks.length, 1); t.equal(stageVarBlocks[0].fields.VARIABLE.id, fooVarId); - const catVarBlocks = catBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const catVarBlocks = catBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE') + ); t.equal(catVarBlocks.length, 1); t.equal(catVarBlocks[0].fields.VARIABLE.id, fooVarId); @@ -110,7 +114,9 @@ test('importing sb3 project with special chars in variable names', t => { // There should be one t.equal(allVarListFields[ltPerfectVarId].length, 1); const bananasBlocks = Object.keys(bananas.blocks._blocks).map(blockId => bananas.blocks._blocks[blockId]); - const bananasVarBlocks = bananasBlocks.filter(block => block.fields.hasOwnProperty('VARIABLE')); + const bananasVarBlocks = bananasBlocks.filter( + block => Object.prototype.hasOwnProperty.call(block.fields, 'VARIABLE') + ); t.equal(bananasVarBlocks.length, 1); t.equal(bananasVarBlocks[0].fields.VARIABLE.id, ltPerfectVarId); diff --git a/test/unit/engine_target.js b/test/unit/engine_target.js index b1fb6e457..54f89e4c0 100644 --- a/test/unit/engine_target.js +++ b/test/unit/engine_target.js @@ -402,10 +402,10 @@ test('duplicateVariables duplicates all variables', t => { // Should be able to find original var IDs in both this target's variables and // the duplicate variables since a blocks container was not specified. - t.equal(target.variables.hasOwnProperty('var ID 1'), true); - t.equal(target.variables.hasOwnProperty('var ID 2'), true); - t.equal(duplicateVariables.hasOwnProperty('var ID 1'), true); - t.equal(duplicateVariables.hasOwnProperty('var ID 1'), true); + t.equal(Object.prototype.hasOwnProperty.call(target.variables, 'var ID 1'), true); + t.equal(Object.prototype.hasOwnProperty.call(target.variables, 'var ID 2'), true); + t.equal(Object.prototype.hasOwnProperty.call(duplicateVariables, 'var ID 1'), true); + t.equal(Object.prototype.hasOwnProperty.call(duplicateVariables, 'var ID 1'), true); // Values of the duplicate varaiables should match the value of the original values at the time of duplication t.equal(target.variables['var ID 1'].value, duplicateVariables['var ID 1'].value); diff --git a/test/unit/extension_conversion.js b/test/unit/extension_conversion.js index e0d23b33e..876b01a62 100644 --- a/test/unit/extension_conversion.js +++ b/test/unit/extension_conversion.js @@ -142,11 +142,11 @@ const testReporter = function (t, reporter) { t.equal(reporter.json.checkboxInFlyout, true); t.equal(reporter.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); t.equal(reporter.json.output, 'String'); - t.notOk(reporter.json.hasOwnProperty('previousStatement')); - t.notOk(reporter.json.hasOwnProperty('nextStatement')); + t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'previousStatement')); + t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'nextStatement')); t.same(reporter.json.extensions, ['scratch_extension']); t.equal(reporter.json.message0, '%1 %2simple text'); // "%1 %2" from the block icon - t.notOk(reporter.json.hasOwnProperty('message1')); + t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'message1')); t.same(reporter.json.args0, [ // %1 in message0: the block icon { @@ -160,7 +160,7 @@ const testReporter = function (t, reporter) { type: 'field_vertical_separator' } ]); - t.notOk(reporter.json.hasOwnProperty('args1')); + t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'args1')); t.equal(reporter.xml, '<block type="test_reporter"></block>'); }; @@ -170,11 +170,11 @@ const testInlineImage = function (t, inlineImage) { t.equal(inlineImage.json.checkboxInFlyout, true); t.equal(inlineImage.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); t.equal(inlineImage.json.output, 'String'); - t.notOk(inlineImage.json.hasOwnProperty('previousStatement')); - t.notOk(inlineImage.json.hasOwnProperty('nextStatement')); + t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'previousStatement')); + t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'nextStatement')); t.notOk(inlineImage.json.extensions && inlineImage.json.extensions.length); // OK if it's absent or empty t.equal(inlineImage.json.message0, 'text and %1'); // block text followed by inline image - t.notOk(inlineImage.json.hasOwnProperty('message1')); + t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'message1')); t.same(inlineImage.json.args0, [ // %1 in message0: the block icon { @@ -185,7 +185,7 @@ const testInlineImage = function (t, inlineImage) { flip_rtl: false // False by default } ]); - t.notOk(inlineImage.json.hasOwnProperty('args1')); + t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'args1')); t.equal(inlineImage.xml, '<block type="test_inlineImage"></block>'); }; @@ -198,16 +198,16 @@ const testCommand = function (t, command) { t.equal(command.json.type, 'test_command'); testCategoryInfo(t, command); t.equal(command.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.assert(command.json.hasOwnProperty('previousStatement')); - t.assert(command.json.hasOwnProperty('nextStatement')); + t.assert(Object.prototype.hasOwnProperty.call(command.json, 'previousStatement')); + t.assert(Object.prototype.hasOwnProperty.call(command.json, 'nextStatement')); t.notOk(command.json.extensions && command.json.extensions.length); // OK if it's absent or empty t.equal(command.json.message0, 'text with %1 %2'); - t.notOk(command.json.hasOwnProperty('message1')); + t.notOk(Object.prototype.hasOwnProperty.call(command.json, 'message1')); t.strictSame(command.json.args0[0], { type: 'input_value', name: 'ARG' }); - t.notOk(command.json.hasOwnProperty('args1')); + t.notOk(Object.prototype.hasOwnProperty.call(command.json, 'args1')); t.equal(command.xml, '<block type="test_command"><value name="ARG"><shadow type="text"></shadow></value>' + '<value name="ARG_WITH_DEFAULT"><shadow type="text"><field name="TEXT">' + @@ -218,14 +218,14 @@ const testConditional = function (t, conditional) { t.equal(conditional.json.type, 'test_ifElse'); testCategoryInfo(t, conditional); t.equal(conditional.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.ok(conditional.json.hasOwnProperty('previousStatement')); - t.ok(conditional.json.hasOwnProperty('nextStatement')); + t.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'previousStatement')); + t.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'nextStatement')); t.notOk(conditional.json.extensions && conditional.json.extensions.length); // OK if it's absent or empty t.equal(conditional.json.message0, 'test if %1 is spiffy and if so then'); t.equal(conditional.json.message1, '%1'); // placeholder for substack #1 t.equal(conditional.json.message2, 'or elsewise'); t.equal(conditional.json.message3, '%1'); // placeholder for substack #2 - t.notOk(conditional.json.hasOwnProperty('message4')); + t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, 'message4')); t.strictSame(conditional.json.args0[0], { type: 'input_value', name: 'THING', @@ -235,12 +235,12 @@ const testConditional = function (t, conditional) { type: 'input_statement', name: 'SUBSTACK' }); - t.notOk(conditional.json.hasOwnProperty(conditional.json.args2)); + t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, conditional.json.args2)); t.strictSame(conditional.json.args3[0], { type: 'input_statement', name: 'SUBSTACK2' }); - t.notOk(conditional.json.hasOwnProperty('args4')); + t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, 'args4')); t.equal(conditional.xml, '<block type="test_ifElse"><value name="THING"></value></block>'); }; @@ -248,13 +248,13 @@ const testLoop = function (t, loop) { t.equal(loop.json.type, 'test_loop'); testCategoryInfo(t, loop); t.equal(loop.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.ok(loop.json.hasOwnProperty('previousStatement')); - t.notOk(loop.json.hasOwnProperty('nextStatement')); // isTerminal is set on this block + t.ok(Object.prototype.hasOwnProperty.call(loop.json, 'previousStatement')); + t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'nextStatement')); // isTerminal is set on this block t.notOk(loop.json.extensions && loop.json.extensions.length); // OK if it's absent or empty t.equal(loop.json.message0, 'loopty %1 loops'); t.equal(loop.json.message1, '%1'); // placeholder for substack t.equal(loop.json.message2, '%1'); // placeholder for loop arrow - t.notOk(loop.json.hasOwnProperty('message3')); + t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'message3')); t.strictSame(loop.json.args0[0], { type: 'input_value', name: 'MANY' @@ -266,7 +266,7 @@ const testLoop = function (t, loop) { t.equal(loop.json.lastDummyAlign2, 'RIGHT'); // move loop arrow to right side t.equal(loop.json.args2[0].type, 'field_image'); t.equal(loop.json.args2[0].flip_rtl, true); - t.notOk(loop.json.hasOwnProperty('args3')); + t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'args3')); t.equal(loop.xml, '<block type="test_loop"><value name="MANY"><shadow type="math_number"></shadow></value></block>'); }; diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index 681a10d86..a9823424a 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -40,7 +40,7 @@ test('blocks get new id on duplicate', t => { rt.blocks.createBlock(block); return rt.duplicate().then(duplicate => { - t.notOk(duplicate.blocks._blocks.hasOwnProperty(block.id)); + t.notOk(Object.prototype.hasOwnProperty.call(duplicate.blocks._blocks, block.id)); t.end(); }); });