From 5deed5a1944ae241a82195d4bcc513896ea750a9 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 17 Nov 2021 08:39:00 -0800 Subject: [PATCH] chore: fix or ignore remaining lint (#5709) * chore: fix or ignore remaining lint * chore: fix bad annotations * chore: use push for array concatenation * chore: revert use of spread for array operations --- .eslintrc.json | 6 ++- blocks/lists.js | 91 ++++++++++++++++++++++----------- blocks/math.js | 14 +++-- blocks/procedures.js | 3 ++ blocks/text.js | 28 +++++++--- core/blockly.js | 2 +- core/comment.js | 18 +++++-- core/contextmenu.js | 2 + core/extensions.js | 40 +++++++++------ core/flyout_base.js | 15 +++--- core/interfaces/i_serializer.js | 1 + core/rendered_connection.js | 4 +- core/serialization/blocks.js | 1 + core/serialization/variables.js | 1 + core/trashcan.js | 4 ++ core/workspace_comment_svg.js | 4 ++ tests/mocha/.eslintrc.json | 3 +- 17 files changed, 164 insertions(+), 73 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 0db17830b..9203209e3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -60,7 +60,11 @@ // Keep them for legacy reasons. "new-cap": ["off"], // Mostly use default rules for brace style, but allow single-line blocks. - "brace-style": ["error", "1tbs", { "allowSingleLine": true }] + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + // Blockly uses objects as maps, but uses Object.create(null) to + // instantiate them. + "guard-for-in": ["off"], + "prefer-spread": ["off"] }, "env": { "es6": true, diff --git a/blocks/lists.js b/blocks/lists.js index 0c8f4a490..fe4972fee 100644 --- a/blocks/lists.js +++ b/blocks/lists.js @@ -334,10 +334,16 @@ Blockly.Blocks['lists_getIndex'] = { ]; this.setHelpUrl(Blockly.Msg['LISTS_GET_INDEX_HELPURL']); this.setStyle('list_blocks'); - const modeMenu = new Blockly.FieldDropdown(MODE, function(value) { - const isStatement = (value === 'REMOVE'); - this.getSourceBlock().updateStatement_(isStatement); - }); + const modeMenu = new Blockly.FieldDropdown(MODE, + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + */ + function(value) { + const isStatement = (value === 'REMOVE'); + this.getSourceBlock().updateStatement_(isStatement); + } + ); this.appendValueInput('VALUE') .setCheck('Array') .appendField(Blockly.Msg['LISTS_GET_INDEX_INPUT_IN_LIST']); @@ -484,18 +490,28 @@ Blockly.Blocks['lists_getIndex'] = { } else { this.appendDummyInput('AT'); } - const menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) { - const newAt = (value === 'FROM_START') || (value === 'FROM_END'); - // The 'isAt' variable is available due to this function being a closure. - if (newAt !== isAt) { - const block = this.getSourceBlock(); - block.updateAt_(newAt); - // This menu has been destroyed and replaced. Update the replacement. - block.setFieldValue(value, 'WHERE'); - return null; - } - return undefined; - }); + const menu = new Blockly.FieldDropdown( + this.WHERE_OPTIONS, + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + * @returns {null|undefined} Null if the field has been replaced; + * otherwise undefined. + */ + function(value) { + const newAt = (value === 'FROM_START') || (value === 'FROM_END'); + // The 'isAt' variable is available due to this function being a + // closure. + if (newAt !== isAt) { + const block = this.getSourceBlock(); + block.updateAt_(newAt); + // This menu has been destroyed and replaced. Update the + // replacement. + block.setFieldValue(value, 'WHERE'); + return null; + } + return undefined; + }); this.getInput('AT').appendField(menu, 'WHERE'); if (Blockly.Msg['LISTS_GET_INDEX_TAIL']) { this.moveInputBefore('TAIL', null); @@ -628,18 +644,28 @@ Blockly.Blocks['lists_setIndex'] = { } else { this.appendDummyInput('AT'); } - const menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) { - const newAt = (value === 'FROM_START') || (value === 'FROM_END'); - // The 'isAt' variable is available due to this function being a closure. - if (newAt !== isAt) { - const block = this.getSourceBlock(); - block.updateAt_(newAt); - // This menu has been destroyed and replaced. Update the replacement. - block.setFieldValue(value, 'WHERE'); - return null; - } - return undefined; - }); + const menu = new Blockly.FieldDropdown( + this.WHERE_OPTIONS, + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + * @returns {null|undefined} Null if the field has been replaced; + * otherwise undefined. + */ + function(value) { + const newAt = (value === 'FROM_START') || (value === 'FROM_END'); + // The 'isAt' variable is available due to this function being a + // closure. + if (newAt !== isAt) { + const block = this.getSourceBlock(); + block.updateAt_(newAt); + // This menu has been destroyed and replaced. Update the + // replacement. + block.setFieldValue(value, 'WHERE'); + return null; + } + return undefined; + }); this.moveInputBefore('AT', 'TO'); if (this.getInput('ORDINAL')) { this.moveInputBefore('ORDINAL', 'TO'); @@ -737,7 +763,14 @@ Blockly.Blocks['lists_getSublist'] = { } else { this.appendDummyInput('AT' + n); } - const menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n], + const menu = new Blockly.FieldDropdown( + this['WHERE_OPTIONS_' + n], + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + * @returns {null|undefined} Null if the field has been replaced; + * otherwise undefined. + */ function(value) { const newAt = (value === 'FROM_START') || (value === 'FROM_END'); // The 'isAt' variable is available due to this function being a diff --git a/blocks/math.js b/blocks/math.js index d94b62ca7..fdd3a93c0 100644 --- a/blocks/math.js +++ b/blocks/math.js @@ -493,10 +493,16 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = { * @package */ Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION = function() { - this.getField('PROPERTY').setValidator(function(option) { - const divisorInput = (option === 'DIVISIBLE_BY'); - this.getSourceBlock().updateShape_(divisorInput); - }); + this.getField('PROPERTY').setValidator( + /** + * @this {Blockly.FieldDropdown} + * @param {*} option The selected dropdown option. + */ + function(option) { + const divisorInput = (option === 'DIVISIBLE_BY'); + this.getSourceBlock().updateShape_(divisorInput); + } + ); }; Blockly.Extensions.registerMutator('math_is_divisibleby_mutator', diff --git a/blocks/procedures.js b/blocks/procedures.js index b7fcae229..c60059944 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -537,6 +537,9 @@ Blockly.Blocks['procedures_mutatorarg'] = { // Hack: override showEditor to do just a little bit more work. // We don't have a good place to hook into the start of a text edit. field.oldShowEditorFn_ = field.showEditor_; + /** + * @this {Blockly.FieldTextInput} + */ const newShowEditorFn = function() { this.createdVariables_ = []; this.oldShowEditorFn_(); diff --git a/blocks/text.js b/blocks/text.js index da5e5f68b..476fe2110 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -319,7 +319,14 @@ Blockly.Blocks['text_getSubstring'] = { this.appendDummyInput('TAIL') .appendField(Blockly.Msg['TEXT_GET_SUBSTRING_TAIL']); } - const menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n], + const menu = new Blockly.FieldDropdown( + this['WHERE_OPTIONS_' + n], + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + * @returns {null|undefined} Null if the field has been replaced; + * otherwise undefined. + */ function(value) { const newAt = (value === 'FROM_START') || (value === 'FROM_END'); // The 'isAt' variable is available due to this function being a @@ -922,13 +929,18 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = { */ Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() { const dropdown = this.getField('WHERE'); - dropdown.setValidator(function(value) { - const newAt = (value === 'FROM_START') || (value === 'FROM_END'); - if (newAt !== this.isAt_) { - const block = this.getSourceBlock(); - block.updateAt_(newAt); - } - }); + dropdown.setValidator( + /** + * @param {*} value The input value. + * @this {Blockly.FieldDropdown} + */ + function(value) { + const newAt = (value === 'FROM_START') || (value === 'FROM_END'); + if (newAt !== this.isAt_) { + const block = this.getSourceBlock(); + block.updateAt_(newAt); + } + }); this.updateAt_(true); // Assign 'this' to a variable for use in the tooltip closure below. const thisBlock = this; diff --git a/core/blockly.js b/core/blockly.js index 5b1206f39..54245816b 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -382,7 +382,7 @@ exports.getMainWorkspace = common.getMainWorkspace; * of jsonDef. */ const jsonInitFactory = function(jsonDef) { - return function() { + return /** @this {Block} */ function() { this.jsonInit(jsonDef); }; }; diff --git a/core/comment.js b/core/comment.js index 0e3fbce3e..8dc56bdb8 100644 --- a/core/comment.js +++ b/core/comment.js @@ -181,16 +181,26 @@ Comment.prototype.createEditor_ = function() { browserEvents.conditionalBind(textarea, 'wheel', this, function(e) { e.stopPropagation(); }); - this.onChangeWrapper_ = - browserEvents.conditionalBind(textarea, 'change', this, function(_e) { + this.onChangeWrapper_ = browserEvents.conditionalBind( + textarea, 'change', this, + /** + * @this {Comment} + * @param {Event} _e Unused event parameter. + */ + function(_e) { if (this.cachedText_ !== this.model_.text) { eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))( this.block_, 'comment', null, this.cachedText_, this.model_.text)); } }); - this.onInputWrapper_ = - browserEvents.conditionalBind(textarea, 'input', this, function(_e) { + this.onInputWrapper_ = browserEvents.conditionalBind( + textarea, 'input', this, + /** + * @this {Comment} + * @param {Event} _e Unused event parameter. + */ + function(_e) { this.model_.text = textarea.value; }); diff --git a/core/contextmenu.js b/core/contextmenu.js index b3fedda1f..6a0697d14 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -149,6 +149,8 @@ const populate_ = function(options, rtl) { menuItem.setEnabled(option.enabled); if (option.enabled) { const actionHandler = function(_menuItem) { + // TODO: Create a type for option that can be used in an @this tag. + /* eslint-disable-next-line no-invalid-this */ const option = this; hide(); option.callback(option.scope); diff --git a/core/extensions.js b/core/extensions.js index 5d8b1695e..d0c219d4f 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -71,9 +71,12 @@ const registerMixin = function(name, mixinObj) { if (!mixinObj || typeof mixinObj !== 'object') { throw Error('Error: Mixin "' + name + '" must be a object'); } - register(name, function() { - this.mixin(mixinObj); - }); + register( + name, + /** @this {Block} */ + function() { + this.mixin(mixinObj); + }); }; exports.registerMixin = registerMixin; @@ -102,21 +105,24 @@ const registerMutator = function(name, mixinObj, opt_helperFn, opt_blockList) { } // Sanity checks passed. - register(name, function() { - if (hasMutatorDialog) { - const {Mutator} = goog.module.get('Blockly.Mutator'); - if (!Mutator) { - throw Error(errorPrefix + 'Missing require for Blockly.Mutator'); - } - this.setMutator(new Mutator(opt_blockList || [])); - } - // Mixin the object. - this.mixin(mixinObj); + register( + name, + /** @this {Block} */ + function() { + if (hasMutatorDialog) { + const {Mutator} = goog.module.get('Blockly.Mutator'); + if (!Mutator) { + throw Error(errorPrefix + 'Missing require for Blockly.Mutator'); + } + this.setMutator(new Mutator(opt_blockList || [])); + } + // Mixin the object. + this.mixin(mixinObj); - if (opt_helperFn) { - opt_helperFn.apply(this); - } - }); + if (opt_helperFn) { + opt_helperFn.apply(this); + } + }); }; exports.registerMutator = registerMutator; diff --git a/core/flyout_base.js b/core/flyout_base.js index 203459bb6..d1484ffa8 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -547,12 +547,14 @@ Flyout.prototype.show = function(flyoutDef) { // IE 11 is an incompetent browser that fails to fire mouseout events. // When the mouse is over the background, deselect all blocks. - const deselectAll = function() { - const topBlocks = this.workspace_.getTopBlocks(false); - for (let i = 0, block; (block = topBlocks[i]); i++) { - block.removeSelect(); - } - }; + const deselectAll = + /** @this {Flyout} */ + function() { + const topBlocks = this.workspace_.getTopBlocks(false); + for (let i = 0, block; (block = topBlocks[i]); i++) { + block.removeSelect(); + } + }; this.listeners_.push(browserEvents.conditionalBind( this.svgBackground_, 'mouseover', this, deselectAll)); @@ -597,6 +599,7 @@ Flyout.prototype.createFlyoutInfo_ = function(parsedContent) { const flyoutDef = this.getDynamicCategoryContents_(categoryName); const parsedDynamicContent = /** @type {!toolbox.FlyoutItemInfoArray} */ (toolbox.convertFlyoutDefToJsonArray(flyoutDef)); + // Replace the element at i with the dynamic content it represents. parsedContent.splice.apply( parsedContent, [i, 1].concat(parsedDynamicContent)); contentInfo = parsedContent[i]; diff --git a/core/interfaces/i_serializer.js b/core/interfaces/i_serializer.js index 05f707058..ca85842f4 100644 --- a/core/interfaces/i_serializer.js +++ b/core/interfaces/i_serializer.js @@ -29,6 +29,7 @@ const {Workspace} = goog.requireType('Blockly.Workspace'); * @alias Blockly.serialization.ISerializer.ISerializer */ class ISerializer { + /* eslint-disable-next-line require-jsdoc */ constructor() { /** * A priority value used to determine the order of deserializing state. diff --git a/core/rendered_connection.js b/core/rendered_connection.js index ca326a230..06e83e160 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -399,7 +399,7 @@ RenderedConnection.prototype.startTrackingAll = function() { // rendering takes place, since rendering requires knowing the dimensions // of lower blocks. Also, since rendering a block renders all its parents, // we only need to render the leaf nodes. - const renderList = []; + let renderList = []; if (this.type !== ConnectionType.INPUT_VALUE && this.type !== ConnectionType.NEXT_STATEMENT) { // Only spider down. @@ -423,7 +423,7 @@ RenderedConnection.prototype.startTrackingAll = function() { } if (!renderList.length) { // Leaf block. - renderList[0] = block; + renderList = [block]; } } return renderList; diff --git a/core/serialization/blocks.js b/core/serialization/blocks.js index 8f7bff913..279a0b402 100644 --- a/core/serialization/blocks.js +++ b/core/serialization/blocks.js @@ -628,6 +628,7 @@ const saveBlock = save; * @alias Blockly.serialization.blocks.BlockSerializer */ class BlockSerializer { + /* eslint-disable-next-line require-jsdoc */ constructor() { /** * The priority for deserializing blocks. diff --git a/core/serialization/variables.js b/core/serialization/variables.js index 5e1d8e4ce..04e0d567e 100644 --- a/core/serialization/variables.js +++ b/core/serialization/variables.js @@ -44,6 +44,7 @@ exports.State = State; * @alias Blockly.serialization.variables.VariableSerializer */ class VariableSerializer { + /* eslint-disable-next-line require-jsdoc */ constructor() { /** * The priority for deserializing variables. diff --git a/core/trashcan.js b/core/trashcan.js index b837c3e60..3ef5ec3c0 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -704,6 +704,10 @@ Trashcan.prototype.cleanBlockJson_ = function(json) { // Create a deep copy. json = /** @type {!blocks.State} */ (JSON.parse(JSON.stringify(json))); + /** + * Reshape JSON into a nicer format. + * @param {!blocks.State} json The JSON to clean. + */ function cleanRec(json) { if (!json) { return; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 1223f596e..24d0461bc 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -781,6 +781,10 @@ WorkspaceCommentSvg.prototype.createEditor_ = function() { }); browserEvents.conditionalBind( textarea, 'change', this, + /** + * @this {WorkspaceCommentSvg} + * @param {Event} e Unused event parameter + */ function( /* eslint-disable no-unused-vars */ e /* eslint-enable no-unused-vars */) { diff --git a/tests/mocha/.eslintrc.json b/tests/mocha/.eslintrc.json index c4ed4257a..dad7c25ca 100644 --- a/tests/mocha/.eslintrc.json +++ b/tests/mocha/.eslintrc.json @@ -34,7 +34,8 @@ // Allow uncommented helper functions in tests. "require-jsdoc": ["off"], // In mocha tests in suites, `this` is meaningful and useful. - "no-invalid-this": ["off"] + "no-invalid-this": ["off"], + "prefer-rest-params": ["off"] }, "extends": "../../.eslintrc.json" }