diff --git a/blocks/math.js b/blocks/math.ts similarity index 82% rename from blocks/math.js rename to blocks/math.ts index b6ade7f894e..1fdaf380720 100644 --- a/blocks/math.js +++ b/blocks/math.ts @@ -6,37 +6,28 @@ /** * @fileoverview Math blocks for Blockly. - * @suppress {checkTypes} */ -'use strict'; - -goog.module('Blockly.libraryBlocks.math'); - -const Extensions = goog.require('Blockly.Extensions'); -// N.B.: Blockly.FieldDropdown needed for type AND side-effects. -/* eslint-disable-next-line no-unused-vars */ -const FieldDropdown = goog.require('Blockly.FieldDropdown'); -const xmlUtils = goog.require('Blockly.utils.xml'); -/* eslint-disable-next-line no-unused-vars */ -const {Block} = goog.requireType('Blockly.Block'); -// const {BlockDefinition} = goog.requireType('Blockly.blocks'); -// TODO (6248): Properly import the BlockDefinition type. -/* eslint-disable-next-line no-unused-vars */ -const BlockDefinition = Object; -const {createBlockDefinitionsFromJsonArray, defineBlocks} = goog.require('Blockly.common'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldLabel'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldNumber'); -/** @suppress {extraRequire} */ -goog.require('Blockly.FieldVariable'); + +import * as goog from '../closure/goog/goog.js'; +goog.declareModuleId('Blockly.libraryBlocks.math'); + +import * as Extensions from '../core/extensions.js'; +import type {Field} from '../core/field.js'; +import type {FieldDropdown} from '../core/field_dropdown.js'; +import * as xmlUtils from '../core/utils/xml.js'; +import type {Block} from '../core/block.js'; +import type {BlockDefinition} from '../core/blocks.js'; +import {createBlockDefinitionsFromJsonArray, defineBlocks} from '../core/common.js'; +import '../core/field_dropdown.js'; +import '../core/field_label.js'; +import '../core/field_number.js'; +import '../core/field_variable.js'; /** * A dictionary of the block definitions provided by this module. - * @type {!Object} */ -const blocks = createBlockDefinitionsFromJsonArray([ +export const blocks = createBlockDefinitionsFromJsonArray([ // Block for numeric value. { 'type': 'math_number', @@ -391,11 +382,11 @@ const blocks = createBlockDefinitionsFromJsonArray([ 'helpUrl': '%{BKY_MATH_ATAN2_HELPURL}', }, ]); -exports.blocks = blocks; /** * Mapping of math block OP value to tooltip message for blocks * math_arithmetic, math_simple, math_trig, and math_on_lists. + * * @see {Extensions#buildTooltipForDropdown} * @package * @readonly @@ -440,10 +431,15 @@ Extensions.register( 'math_op_tooltip', Extensions.buildTooltipForDropdown('OP', TOOLTIPS_BY_OP)); +/** Type of a block that has IS_DIVISBLEBY_MUTATOR_MIXIN */ +type DivisiblebyBlock = Block&DivisiblebyMixin; +interface DivisiblebyMixin extends DivisiblebyMixinType {}; +type DivisiblebyMixinType = typeof IS_DIVISIBLEBY_MUTATOR_MIXIN; /** * Mixin for mutator functions in the 'math_is_divisibleby_mutator' * extension. + * * @mixin * @augments Block * @package @@ -452,22 +448,22 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { /** * Create XML to represent whether the 'divisorInput' should be present. * Backwards compatible serialization implementation. - * @return {!Element} XML storage element. - * @this {Block} + * + * @returns XML storage element. */ - mutationToDom: function() { + mutationToDom: function(this: DivisiblebyBlock): Element { const container = xmlUtils.createElement('mutation'); const divisorInput = (this.getFieldValue('PROPERTY') === 'DIVISIBLE_BY'); - container.setAttribute('divisor_input', divisorInput); + container.setAttribute('divisor_input', String(divisorInput)); return container; }, /** * Parse XML to restore the 'divisorInput'. * Backwards compatible serialization implementation. - * @param {!Element} xmlElement XML storage element. - * @this {Block} + * + * @param xmlElement XML storage element. */ - domToMutation: function(xmlElement) { + domToMutation: function(this: DivisiblebyBlock, xmlElement: Element) { const divisorInput = (xmlElement.getAttribute('divisor_input') === 'true'); this.updateShape_(divisorInput); }, @@ -479,11 +475,10 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { /** * Modify this block to have (or not have) an input for 'is divisible by'. - * @param {boolean} divisorInput True if this block has a divisor input. - * @private - * @this {Block} + * + * @param divisorInput True if this block has a divisor input. */ - updateShape_: function(divisorInput) { + updateShape_: function(this: DivisiblebyBlock, divisorInput: boolean) { // Add or remove a Value Input. const inputExists = this.getInput('DIVISOR'); if (divisorInput) { @@ -500,20 +495,15 @@ const IS_DIVISIBLEBY_MUTATOR_MIXIN = { * 'math_is_divisibleby_mutator' extension to the 'math_property' block that * can update the block shape (add/remove divisor input) based on whether * property is "divisible by". - * @this {Block} - * @package */ -const IS_DIVISIBLE_MUTATOR_EXTENSION = function() { - this.getField('PROPERTY') - .setValidator( - /** - * @this {FieldDropdown} - * @param {*} option The selected dropdown option. - */ - function(option) { - const divisorInput = (option === 'DIVISIBLE_BY'); - this.getSourceBlock().updateShape_(divisorInput); - }); +const IS_DIVISIBLE_MUTATOR_EXTENSION = function(this: DivisiblebyBlock) { + this.getField('PROPERTY')!.setValidator( + /** @param option The selected dropdown option. */ + function(this: FieldDropdown, option: string) { + const divisorInput = (option === 'DIVISIBLE_BY'); + (this.getSourceBlock() as DivisiblebyBlock).updateShape_(divisorInput); + return undefined; // FieldValidators can't be void. Use option as-is. + }); }; Extensions.registerMutator( @@ -525,35 +515,35 @@ Extensions.register( 'math_change_tooltip', Extensions.buildTooltipWithFieldText('%{BKY_MATH_CHANGE_TOOLTIP}', 'VAR')); +/** Type of a block that has LIST_MODES_MUTATOR_MIXIN */ +type ListModesBlock = Block&ListModesMixin; +interface ListModesMixin extends ListModesMixinType {}; +type ListModesMixinType = typeof LIST_MODES_MUTATOR_MIXIN; + /** * Mixin with mutator methods to support alternate output based if the * 'math_on_list' block uses the 'MODE' operation. - * @mixin - * @augments Block - * @package - * @readonly */ const LIST_MODES_MUTATOR_MIXIN = { /** * Modify this block to have the correct output type. - * @param {string} newOp Either 'MODE' or some op than returns a number. - * @private - * @this {Block} + * + * @param newOp Either 'MODE' or some op than returns a number. */ - updateType_: function(newOp) { + updateType_: function(this: ListModesBlock, newOp: string) { if (newOp === 'MODE') { - this.outputConnection.setCheck('Array'); + this.outputConnection!.setCheck('Array'); } else { - this.outputConnection.setCheck('Number'); + this.outputConnection!.setCheck('Number'); } }, /** * Create XML to represent the output type. * Backwards compatible serialization implementation. - * @return {!Element} XML storage element. - * @this {Block} + * + * @returns XML storage element. */ - mutationToDom: function() { + mutationToDom: function(this: ListModesBlock): Element { const container = xmlUtils.createElement('mutation'); container.setAttribute('op', this.getFieldValue('OP')); return container; @@ -561,11 +551,13 @@ const LIST_MODES_MUTATOR_MIXIN = { /** * Parse XML to restore the output type. * Backwards compatible serialization implementation. - * @param {!Element} xmlElement XML storage element. - * @this {Block} + * + * @param xmlElement XML storage element. */ - domToMutation: function(xmlElement) { - this.updateType_(xmlElement.getAttribute('op')); + domToMutation: function(this: ListModesBlock, xmlElement: Element) { + const op = xmlElement.getAttribute('op'); + if (op === null) throw new TypeError('xmlElement had no op attribute'); + this.updateType_(op); }, // This block does not need JSO serialization hooks (saveExtraState and @@ -577,13 +569,13 @@ const LIST_MODES_MUTATOR_MIXIN = { /** * Extension to 'math_on_list' blocks that allows support of * modes operation (outputs a list of numbers). - * @this {Block} - * @package */ -const LIST_MODES_MUTATOR_EXTENSION = function() { - this.getField('OP').setValidator(function(newOp) { - this.updateType_(newOp); - }.bind(this)); +const LIST_MODES_MUTATOR_EXTENSION = function(this: ListModesBlock) { + this.getField('OP')!.setValidator( + function(this: ListModesBlock, newOp: string) { + this.updateType_(newOp); + return undefined; + }.bind(this)); }; Extensions.registerMutator(