From c6970c0d0b90963a9b68e0f34a5e05cfd34bd329 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 31 Mar 2023 09:33:58 -0700 Subject: [PATCH 1/3] refactor(blocks): Auto-migration of blocks/loops.js to ts --- blocks/{loops.js => loops.ts} | 40 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) rename blocks/{loops.js => loops.ts} (90%) diff --git a/blocks/loops.js b/blocks/loops.ts similarity index 90% rename from blocks/loops.js rename to blocks/loops.ts index 220c17d67bb..64d1b52d2ce 100644 --- a/blocks/loops.js +++ b/blocks/loops.ts @@ -8,42 +8,42 @@ * @fileoverview Loop blocks for Blockly. * @suppress {checkTypes} */ -'use strict'; -goog.module('Blockly.libraryBlocks.loops'); +import * as goog from '../closure/goog/goog.js'; +goog.declareModuleId('Blockly.libraryBlocks.loops'); /* eslint-disable-next-line no-unused-vars */ -const AbstractEvent = goog.requireType('Blockly.Events.Abstract'); -const ContextMenu = goog.require('Blockly.ContextMenu'); -const Events = goog.require('Blockly.Events'); -const Extensions = goog.require('Blockly.Extensions'); -const Variables = goog.require('Blockly.Variables'); -const xmlUtils = goog.require('Blockly.utils.xml'); +import type * as AbstractEvent from '../core/events/events_abstract.js'; +import * as ContextMenu from '../core/contextmenu.js'; +import * as Events from '../core/events/events.js'; +import * as Extensions from '../core/extensions.js'; +import * as Variables from '../core/variables.js'; +import * as xmlUtils from '../core/utils/xml.js'; /* eslint-disable-next-line no-unused-vars */ -const {Block} = goog.requireType('Blockly.Block'); -// const {BlockDefinition} = goog.requireType('Blockly.blocks'); +import type {Block} from '../core/block.js'; +// import type {BlockDefinition} from '../core/blocks.js'; // TODO (6248): Properly import the BlockDefinition type. /* eslint-disable-next-line no-unused-vars */ const BlockDefinition = Object; -const {Msg} = goog.require('Blockly.Msg'); -const {createBlockDefinitionsFromJsonArray, defineBlocks} = goog.require('Blockly.common'); +import {Msg} from '../core/msg.js'; +import {createBlockDefinitionsFromJsonArray, defineBlocks} from '../core/common.js'; /** @suppress {extraRequire} */ -goog.require('Blockly.FieldDropdown'); +import '../core/field_dropdown.js'; /** @suppress {extraRequire} */ -goog.require('Blockly.FieldLabel'); +import '../core/field_label.js'; /** @suppress {extraRequire} */ -goog.require('Blockly.FieldNumber'); +import '../core/field_number.js'; /** @suppress {extraRequire} */ -goog.require('Blockly.FieldVariable'); +import '../core/field_variable.js'; /** @suppress {extraRequire} */ -goog.require('Blockly.Warning'); +import '../core/warning.js'; /** * A dictionary of the block definitions provided by this module. * @type {!Object} */ -const blocks = createBlockDefinitionsFromJsonArray([ +export const blocks = createBlockDefinitionsFromJsonArray([ // Block for repeat n times (external number). { 'type': 'controls_repeat_ext', @@ -213,7 +213,6 @@ const blocks = createBlockDefinitionsFromJsonArray([ ], }, ]); -exports.blocks = blocks; /** * Tooltips for the 'controls_whileUntil' block, keyed by MODE value. @@ -307,14 +306,13 @@ Extensions.register( * * @type {!Set} */ -const loopTypes = new Set([ +export const loopTypes = new Set([ 'controls_repeat', 'controls_repeat_ext', 'controls_forEach', 'controls_for', 'controls_whileUntil', ]); -exports.loopTypes = loopTypes; /** * This mixin adds a check to make sure the 'controls_flow_statements' block From e618689a5a35b3386d3729ae2b68623a6e2d935d Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 6 Apr 2023 16:58:48 -0700 Subject: [PATCH 2/3] fix(blocks): Manually migrate types and fix imports in loops.ts --- blocks/loops.ts | 76 ++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/blocks/loops.ts b/blocks/loops.ts index 64d1b52d2ce..0e71fd2f03d 100644 --- a/blocks/loops.ts +++ b/blocks/loops.ts @@ -6,42 +6,32 @@ /** * @fileoverview Loop blocks for Blockly. - * @suppress {checkTypes} */ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.libraryBlocks.loops'); -/* eslint-disable-next-line no-unused-vars */ -import type * as AbstractEvent from '../core/events/events_abstract.js'; +import type {Abstract} from '../core/events/events_abstract.js'; +import type {Block} from '../core/block.js'; +import type {BlockDefinition} from '../core/blocks.js'; import * as ContextMenu from '../core/contextmenu.js'; import * as Events from '../core/events/events.js'; import * as Extensions from '../core/extensions.js'; import * as Variables from '../core/variables.js'; import * as xmlUtils from '../core/utils/xml.js'; -/* eslint-disable-next-line no-unused-vars */ -import type {Block} from '../core/block.js'; -// import type {BlockDefinition} from '../core/blocks.js'; -// TODO (6248): Properly import the BlockDefinition type. -/* eslint-disable-next-line no-unused-vars */ -const BlockDefinition = Object; import {Msg} from '../core/msg.js'; import {createBlockDefinitionsFromJsonArray, defineBlocks} from '../core/common.js'; -/** @suppress {extraRequire} */ import '../core/field_dropdown.js'; -/** @suppress {extraRequire} */ import '../core/field_label.js'; -/** @suppress {extraRequire} */ import '../core/field_number.js'; -/** @suppress {extraRequire} */ import '../core/field_variable.js'; -/** @suppress {extraRequire} */ import '../core/warning.js'; +import {FieldVariable} from '../core/field_variable.js'; +import {WorkspaceSvg} from '../core/workspace_svg.js'; /** * A dictionary of the block definitions provided by this module. - * @type {!Object} */ export const blocks = createBlockDefinitionsFromJsonArray([ // Block for repeat n times (external number). @@ -216,6 +206,7 @@ export const blocks = createBlockDefinitionsFromJsonArray([ /** * Tooltips for the 'controls_whileUntil' block, keyed by MODE value. + * * @see {Extensions#buildTooltipForDropdown} * @readonly */ @@ -230,6 +221,7 @@ Extensions.register( /** * Tooltips for the 'controls_flow_statements' block, keyed by FLOW value. + * * @see {Extensions#buildTooltipForDropdown} * @readonly */ @@ -242,9 +234,15 @@ Extensions.register( 'controls_flow_tooltip', Extensions.buildTooltipForDropdown('FLOW', BREAK_CONTINUE_TOOLTIPS)); +/** Type of a block that has CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN */ +type CustomContextMenuBlock = Block&CustomContextMenuMixin; +interface CustomContextMenuMixin extends CustomContextMenuMixinType {}; +type CustomContextMenuMixinType = + typeof CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN; /** * Mixin to add a context menu item to create a 'variables_get' block. * Used by blocks 'controls_for' and 'controls_forEach'. + * * @mixin * @augments Block * @package @@ -254,24 +252,28 @@ const CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = { /** * Add context menu option to create getter block for the loop's variable. * (customContextMenu support limited to web BlockSvg.) - * @param {!Array} options List of menu options to add to. - * @this {Block} + * + * @param options List of menu options to add to. */ - customContextMenu: function(options) { + customContextMenu: function( + this: CustomContextMenuBlock, options: Array) { if (this.isInFlyout) { return; } - const variable = this.getField('VAR').getVariable(); + const varField = this.getField('VAR') as FieldVariable; + const variable = varField.getVariable()!; const varName = variable.name; if (!this.isCollapsed() && varName !== null) { - const option = {enabled: true}; - option.text = Msg['VARIABLES_SET_CREATE_GET'].replace('%1', varName); const xmlField = Variables.generateVariableFieldDom(variable); const xmlBlock = xmlUtils.createElement('block'); xmlBlock.setAttribute('type', 'variables_get'); xmlBlock.appendChild(xmlField); - option.callback = ContextMenu.callbackFactory(this, xmlBlock); - options.push(option); + + options.push({ + enabled: true, + text: Msg['VARIABLES_SET_CREATE_GET'].replace('%1', varName), + callback: ContextMenu.callbackFactory(this, xmlBlock) + }); } }, }; @@ -303,10 +305,8 @@ Extensions.register( * * // Else if using blockly_compressed + blockss_compressed.js in browser: * Blockly.libraryBlocks.loopTypes.add('custom_loop'); - * - * @type {!Set} */ -export const loopTypes = new Set([ +export const loopTypes: Set = new Set([ 'controls_repeat', 'controls_repeat_ext', 'controls_forEach', @@ -314,9 +314,15 @@ export const loopTypes = new Set([ 'controls_whileUntil', ]); +/** Type of a block that has CONTROL_FLOW_IN_LOOP_CHECK_MIXIN */ +type ControlFlowInLoopBlock = Block&ControlFlowInLoopMixin; +interface ControlFlowInLoopMixin extends ControlFlowInLoopMixinType {}; +type ControlFlowInLoopMixinType = typeof CONTROL_FLOW_IN_LOOP_CHECK_MIXIN; + /** * This mixin adds a check to make sure the 'controls_flow_statements' block * is contained in a loop. Otherwise a warning is added to the block. + * * @mixin * @augments Block * @public @@ -325,11 +331,11 @@ export const loopTypes = new Set([ const CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { /** * Is this block enclosed (at any level) by a loop? - * @return {Block} The nearest surrounding loop, or null if none. - * @this {Block} + * + * @returns The nearest surrounding loop, or null if none. */ - getSurroundLoop: function() { - let block = this; + getSurroundLoop: function(this: ControlFlowInLoopBlock): Block | null { + let block: Block|null = this; do { if (loopTypes.has(block.type)) { return block; @@ -342,18 +348,16 @@ const CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { /** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. - * @param {!AbstractEvent} e Move event. - * @this {Block} */ - onchange: function(e) { + onchange: function(this: ControlFlowInLoopBlock, e: Abstract) { + const ws = this.workspace as WorkspaceSvg; // Don't change state if: // * It's at the start of a drag. // * It's not a move event. - if (!this.workspace.isDragging || this.workspace.isDragging() || - e.type !== Events.BLOCK_MOVE) { + if (!ws.isDragging || ws.isDragging() || e.type !== Events.BLOCK_MOVE) { return; } - const enabled = this.getSurroundLoop(this); + const enabled = !!this.getSurroundLoop(); this.setWarningText( enabled ? null : Msg['CONTROLS_FLOW_STATEMENTS_WARNING']); if (!this.isInFlyout) { From ef59f8ef471037d27c1ac3e37c79467f53e773b3 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 18 Apr 2023 09:22:51 -0700 Subject: [PATCH 3/3] chore: respond to PR comments --- blocks/loops.ts | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/blocks/loops.ts b/blocks/loops.ts index 0e71fd2f03d..605128c64a8 100644 --- a/blocks/loops.ts +++ b/blocks/loops.ts @@ -11,9 +11,8 @@ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.libraryBlocks.loops'); -import type {Abstract} from '../core/events/events_abstract.js'; +import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js'; import type {Block} from '../core/block.js'; -import type {BlockDefinition} from '../core/blocks.js'; import * as ContextMenu from '../core/contextmenu.js'; import * as Events from '../core/events/events.js'; import * as Extensions from '../core/extensions.js'; @@ -208,7 +207,6 @@ export const blocks = createBlockDefinitionsFromJsonArray([ * Tooltips for the 'controls_whileUntil' block, keyed by MODE value. * * @see {Extensions#buildTooltipForDropdown} - * @readonly */ const WHILE_UNTIL_TOOLTIPS = { 'WHILE': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}', @@ -223,7 +221,6 @@ Extensions.register( * Tooltips for the 'controls_flow_statements' block, keyed by FLOW value. * * @see {Extensions#buildTooltipForDropdown} - * @readonly */ const BREAK_CONTINUE_TOOLTIPS = { 'BREAK': '%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}', @@ -236,17 +233,13 @@ Extensions.register( /** Type of a block that has CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN */ type CustomContextMenuBlock = Block&CustomContextMenuMixin; -interface CustomContextMenuMixin extends CustomContextMenuMixinType {}; +interface CustomContextMenuMixin extends CustomContextMenuMixinType {} type CustomContextMenuMixinType = typeof CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN; + /** * Mixin to add a context menu item to create a 'variables_get' block. * Used by blocks 'controls_for' and 'controls_forEach'. - * - * @mixin - * @augments Block - * @package - * @readonly */ const CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = { /** @@ -316,17 +309,12 @@ export const loopTypes: Set = new Set([ /** Type of a block that has CONTROL_FLOW_IN_LOOP_CHECK_MIXIN */ type ControlFlowInLoopBlock = Block&ControlFlowInLoopMixin; -interface ControlFlowInLoopMixin extends ControlFlowInLoopMixinType {}; +interface ControlFlowInLoopMixin extends ControlFlowInLoopMixinType {} type ControlFlowInLoopMixinType = typeof CONTROL_FLOW_IN_LOOP_CHECK_MIXIN; /** * This mixin adds a check to make sure the 'controls_flow_statements' block * is contained in a loop. Otherwise a warning is added to the block. - * - * @mixin - * @augments Block - * @public - * @readonly */ const CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { /** @@ -349,7 +337,7 @@ const CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. */ - onchange: function(this: ControlFlowInLoopBlock, e: Abstract) { + onchange: function(this: ControlFlowInLoopBlock, e: AbstractEvent) { const ws = this.workspace as WorkspaceSvg; // Don't change state if: // * It's at the start of a drag.