diff --git a/core/generator.js b/core/generator.js index e365c69ba..112c2f8a1 100644 --- a/core/generator.js +++ b/core/generator.js @@ -11,14 +11,18 @@ */ 'use strict'; -goog.provide('Blockly.Generator'); +goog.module('Blockly.Generator'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Block'); -goog.require('Blockly.internalConstants'); -goog.require('Blockly.utils.deprecation'); - -goog.requireType('Blockly.Names'); -goog.requireType('Blockly.Workspace'); +/* eslint-disable-next-line no-unused-vars */ +const Block = goog.requireType('Blockly.Block'); +/* eslint-disable-next-line no-unused-vars */ +const Names = goog.requireType('Blockly.Names'); +/* eslint-disable-next-line no-unused-vars */ +const Workspace = goog.requireType('Blockly.Workspace'); +const internalConstants = goog.require('Blockly.internalConstants'); +const deprecation = goog.require('Blockly.utils.deprecation'); +const {getMainWorkspace} = goog.require('Blockly'); /** @@ -26,7 +30,7 @@ goog.requireType('Blockly.Workspace'); * @param {string} name Language name of this generator. * @constructor */ -Blockly.Generator = function(name) { +const Generator = function(name) { this.name_ = name; this.FUNCTION_NAME_PLACEHOLDER_REGEXP_ = new RegExp(this.FUNCTION_NAME_PLACEHOLDER_, 'g'); @@ -38,7 +42,7 @@ Blockly.Generator = function(name) { * E.g. ' checkTimeout(%1);\n' * @type {?string} */ -Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null; +Generator.prototype.INFINITE_LOOP_TRAP = null; /** * Arbitrary code to inject before every statement. @@ -46,7 +50,7 @@ Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null; * E.g. 'highlight(%1);\n' * @type {?string} */ -Blockly.Generator.prototype.STATEMENT_PREFIX = null; +Generator.prototype.STATEMENT_PREFIX = null; /** * Arbitrary code to inject after every statement. @@ -54,27 +58,27 @@ Blockly.Generator.prototype.STATEMENT_PREFIX = null; * E.g. 'highlight(%1);\n' * @type {?string} */ -Blockly.Generator.prototype.STATEMENT_SUFFIX = null; +Generator.prototype.STATEMENT_SUFFIX = null; /** * The method of indenting. Defaults to two spaces, but language generators * may override this to increase indent or change to tabs. * @type {string} */ -Blockly.Generator.prototype.INDENT = ' '; +Generator.prototype.INDENT = ' '; /** * Maximum length for a comment before wrapping. Does not account for * indenting level. * @type {number} */ -Blockly.Generator.prototype.COMMENT_WRAP = 60; +Generator.prototype.COMMENT_WRAP = 60; /** * List of outer-inner pairings that do NOT require parentheses. * @type {!Array>} */ -Blockly.Generator.prototype.ORDER_OVERRIDES = []; +Generator.prototype.ORDER_OVERRIDES = []; /** * Whether the init method has been called. @@ -83,24 +87,24 @@ Blockly.Generator.prototype.ORDER_OVERRIDES = []; * initialized. If this flag is untouched, it will have no effect. * @type {?boolean} */ -Blockly.Generator.prototype.isInitialized = null; +Generator.prototype.isInitialized = null; /** * Generate code for all blocks in the workspace to the specified language. - * @param {!Blockly.Workspace=} workspace Workspace to generate code from. + * @param {!Workspace=} workspace Workspace to generate code from. * @return {string} Generated code. */ -Blockly.Generator.prototype.workspaceToCode = function(workspace) { +Generator.prototype.workspaceToCode = function(workspace) { if (!workspace) { // Backwards compatibility from before there could be multiple workspaces. console.warn('No workspace specified in workspaceToCode call. Guessing.'); - workspace = Blockly.getMainWorkspace(); + workspace = getMainWorkspace(); } - var code = []; + let code = []; this.init(workspace); - var blocks = workspace.getTopBlocks(true); - for (var i = 0, block; (block = blocks[i]); i++) { - var line = this.blockToCode(block); + const blocks = workspace.getTopBlocks(true); + for (let i = 0, block; (block = blocks[i]); i++) { + let line = this.blockToCode(block); if (Array.isArray(line)) { // Value blocks return tuples of code and operator order. // Top-level blocks don't care about operator order. @@ -140,20 +144,20 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { * @param {string} prefix The common prefix. * @return {string} The prefixed lines of code. */ -Blockly.Generator.prototype.prefixLines = function(text, prefix) { +Generator.prototype.prefixLines = function(text, prefix) { return prefix + text.replace(/(?!\n$)\n/g, '\n' + prefix); }; /** * Recursively spider a tree of blocks, returning all their comments. - * @param {!Blockly.Block} block The block from which to start spidering. + * @param {!Block} block The block from which to start spidering. * @return {string} Concatenated list of comments. */ -Blockly.Generator.prototype.allNestedComments = function(block) { - var comments = []; - var blocks = block.getDescendants(true); - for (var i = 0; i < blocks.length; i++) { - var comment = blocks[i].getCommentText(); +Generator.prototype.allNestedComments = function(block) { + const comments = []; + const blocks = block.getDescendants(true); + for (let i = 0; i < blocks.length; i++) { + const comment = blocks[i].getCommentText(); if (comment) { comments.push(comment); } @@ -168,13 +172,13 @@ Blockly.Generator.prototype.allNestedComments = function(block) { /** * Generate code for the specified block (and attached blocks). * The generator must be initialized before calling this function. - * @param {Blockly.Block} block The block to generate code for. + * @param {Block} block The block to generate code for. * @param {boolean=} opt_thisOnly True to generate code for only this statement. * @return {string|!Array} For statement blocks, the generated code. * For value blocks, an array containing the generated code and an * operator order value. Returns '' if block is null. */ -Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { +Generator.prototype.blockToCode = function(block, opt_thisOnly) { if (this.isInitialized === false) { console.warn( 'Generator init was not called before blockToCode was called.'); @@ -191,16 +195,17 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { return opt_thisOnly ? '' : this.blockToCode(block.getChildren(false)[0]); } - var func = this[block.type]; + const func = this[block.type]; if (typeof func != 'function') { - throw Error('Language "' + this.name_ + '" does not know how to generate ' + + throw Error( + 'Language "' + this.name_ + '" does not know how to generate ' + 'code for block type "' + block.type + '".'); } // First argument to func.call is the value of 'this' in the generator. // Prior to 24 September 2013 'this' was the only way to access the block. // The current preferred method of accessing the block is through the second // argument to func.call, which becomes the first parameter to the generator. - var code = func.call(block, block); + let code = func.call(block, block); if (Array.isArray(code)) { // Value blocks return tuples of code and operator order. if (!block.outputConnection) { @@ -224,22 +229,22 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { /** * Generate code representing the specified value input. - * @param {!Blockly.Block} block The block containing the input. + * @param {!Block} block The block containing the input. * @param {string} name The name of the input. * @param {number} outerOrder The maximum binding strength (minimum order value) * of any operators adjacent to "block". * @return {string} Generated code or '' if no blocks are connected or the * specified input does not exist. */ -Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { +Generator.prototype.valueToCode = function(block, name, outerOrder) { if (isNaN(outerOrder)) { throw TypeError('Expecting valid order from block: ' + block.type); } - var targetBlock = block.getInputTargetBlock(name); + const targetBlock = block.getInputTargetBlock(name); if (!targetBlock) { return ''; } - var tuple = this.blockToCode(targetBlock); + const tuple = this.blockToCode(targetBlock); if (tuple === '') { // Disabled block. return ''; @@ -249,20 +254,20 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { if (!Array.isArray(tuple)) { throw TypeError('Expecting tuple from value block: ' + targetBlock.type); } - var code = tuple[0]; - var innerOrder = tuple[1]; + let code = tuple[0]; + const innerOrder = tuple[1]; if (isNaN(innerOrder)) { - throw TypeError('Expecting valid order from value block: ' + - targetBlock.type); + throw TypeError( + 'Expecting valid order from value block: ' + targetBlock.type); } if (!code) { return ''; } // Add parentheses if needed. - var parensNeeded = false; - var outerOrderClass = Math.floor(outerOrder); - var innerOrderClass = Math.floor(innerOrder); + let parensNeeded = false; + const outerOrderClass = Math.floor(outerOrder); + const innerOrderClass = Math.floor(innerOrder); if (outerOrderClass <= innerOrderClass) { if (outerOrderClass == innerOrderClass && (outerOrderClass == 0 || outerOrderClass == 99)) { @@ -276,7 +281,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { // wrap the code in parentheses. parensNeeded = true; // Check for special exceptions. - for (var i = 0; i < this.ORDER_OVERRIDES.length; i++) { + for (let i = 0; i < this.ORDER_OVERRIDES.length; i++) { if (this.ORDER_OVERRIDES[i][0] == outerOrder && this.ORDER_OVERRIDES[i][1] == innerOrder) { parensNeeded = false; @@ -298,17 +303,18 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { * statement input. Indent the code. * This is mainly used in generators. When trying to generate code to evaluate * look at using workspaceToCode or blockToCode. - * @param {!Blockly.Block} block The block containing the input. + * @param {!Block} block The block containing the input. * @param {string} name The name of the input. * @return {string} Generated code or '' if no blocks are connected. */ -Blockly.Generator.prototype.statementToCode = function(block, name) { - var targetBlock = block.getInputTargetBlock(name); - var code = this.blockToCode(targetBlock); +Generator.prototype.statementToCode = function(block, name) { + const targetBlock = block.getInputTargetBlock(name); + let code = this.blockToCode(targetBlock); // Value blocks must return code and order of operations info. // Statement blocks must only return code. if (typeof code != 'string') { - throw TypeError('Expecting code from statement block: ' + + throw TypeError( + 'Expecting code from statement block: ' + (targetBlock && targetBlock.type)); } if (code) { @@ -323,21 +329,24 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { * statement executes), and a statement prefix to the end of the loop block * (right before the loop statement executes). * @param {string} branch Code for loop contents. - * @param {!Blockly.Block} block Enclosing block. + * @param {!Block} block Enclosing block. * @return {string} Loop contents, with infinite loop trap added. */ -Blockly.Generator.prototype.addLoopTrap = function(branch, block) { +Generator.prototype.addLoopTrap = function(branch, block) { if (this.INFINITE_LOOP_TRAP) { - branch = this.prefixLines(this.injectId(this.INFINITE_LOOP_TRAP, block), - this.INDENT) + branch; + branch = this.prefixLines( + this.injectId(this.INFINITE_LOOP_TRAP, block), this.INDENT) + + branch; } if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) { - branch = this.prefixLines(this.injectId(this.STATEMENT_SUFFIX, block), - this.INDENT) + branch; + branch = this.prefixLines( + this.injectId(this.STATEMENT_SUFFIX, block), this.INDENT) + + branch; } if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) { - branch = branch + this.prefixLines(this.injectId(this.STATEMENT_PREFIX, - block), this.INDENT); + branch = branch + + this.prefixLines( + this.injectId(this.STATEMENT_PREFIX, block), this.INDENT); } return branch; }; @@ -346,11 +355,11 @@ Blockly.Generator.prototype.addLoopTrap = function(branch, block) { * Inject a block ID into a message to replace '%1'. * Used for STATEMENT_PREFIX, STATEMENT_SUFFIX, and INFINITE_LOOP_TRAP. * @param {string} msg Code snippet with '%1'. - * @param {!Blockly.Block} block Block which has an ID. + * @param {!Block} block Block which has an ID. * @return {string} Code snippet with ID. */ -Blockly.Generator.prototype.injectId = function(msg, block) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. +Generator.prototype.injectId = function(msg, block) { + const id = block.id.replace(/\$/g, '$$$$'); // Issue 251. return msg.replace(/%1/g, '\'' + id + '\''); }; @@ -359,33 +368,33 @@ Blockly.Generator.prototype.injectId = function(msg, block) { * @type {string} * @protected */ -Blockly.Generator.prototype.RESERVED_WORDS_ = ''; +Generator.prototype.RESERVED_WORDS_ = ''; /** * Add one or more words to the list of reserved words for this language. * @param {string} words Comma-separated list of words to add to the list. * No spaces. Duplicates are ok. */ -Blockly.Generator.prototype.addReservedWords = function(words) { +Generator.prototype.addReservedWords = function(words) { this.RESERVED_WORDS_ += words + ','; }; /** * This is used as a placeholder in functions defined using - * Blockly.Generator.provideFunction_. It must not be legal code that could + * Generator.provideFunction_. It must not be legal code that could * legitimately appear in a function definition (or comment), and it must * not confuse the regular expression parser. * @type {string} * @protected */ -Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}'; +Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}'; /** * A dictionary of definitions to be printed before the code. * @type {!Object|undefined} * @protected */ -Blockly.Generator.prototype.definitions_; +Generator.prototype.definitions_; /** * A dictionary mapping desired function names in definitions_ to actual @@ -393,36 +402,34 @@ Blockly.Generator.prototype.definitions_; * @type {!Object|undefined} * @protected */ -Blockly.Generator.prototype.functionNames_; +Generator.prototype.functionNames_; /** * A database of variable and procedure names. - * @type {!Blockly.Names|undefined} + * @type {!Names|undefined} * @protected */ -Blockly.Generator.prototype.nameDB_; +Generator.prototype.nameDB_; -Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', { +Object.defineProperty(Generator.prototype, 'variableDB_', { /** * Getter. * @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021). - * @this {Blockly.Generator} - * @return {!Blockly.Names|undefined} Name database. + * @this {Generator} + * @return {!Names|undefined} Name database. */ get: function() { - Blockly.utils.deprecation.warn( - 'variableDB_', 'May 2021', 'May 2026', 'nameDB_'); + deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_'); return this.nameDB_; }, /** * Setter. * @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021). - * @this {Blockly.Generator} - * @param {!Blockly.Names|undefined} nameDb New name database. + * @this {Generator} + * @param {!Names|undefined} nameDb New name database. */ set: function(nameDb) { - Blockly.utils.deprecation.warn( - 'variableDB_', 'May 2021', 'May 2026', 'nameDB_'); + deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_'); this.nameDB_ = nameDb; } }); @@ -439,7 +446,7 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', { * "listRandom", not "random"). There is no danger of colliding with reserved * words, or user-defined variable or procedure names. * - * The code gets output when Blockly.Generator.finish() is called. + * The code gets output when Generator.finish() is called. * * @param {string} desiredName The desired name of the function * (e.g. mathIsPrime). @@ -448,18 +455,18 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', { * from desiredName if the former has already been taken by the user. * @protected */ -Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) { +Generator.prototype.provideFunction_ = function(desiredName, code) { if (!this.definitions_[desiredName]) { - var functionName = this.nameDB_.getDistinctName( - desiredName, Blockly.internalConstants.PROCEDURE_CATEGORY_NAME); + const functionName = this.nameDB_.getDistinctName( + desiredName, internalConstants.PROCEDURE_CATEGORY_NAME); this.functionNames_[desiredName] = functionName; - var codeText = code.join('\n').replace( + let codeText = code.join('\n').replace( this.FUNCTION_NAME_PLACEHOLDER_REGEXP_, functionName); // Change all ' ' indents into the desired indent. // To avoid an infinite loop of replacements, change all indents to '\0' // character first, then replace them all with the indent. // We are assuming that no provided functions contain a literal null char. - var oldCodeText; + let oldCodeText; while (oldCodeText != codeText) { oldCodeText = codeText; codeText = codeText.replace(/^(( {2})*) {2}/gm, '$1\0'); @@ -474,9 +481,9 @@ Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) { * Hook for code to run before code generation starts. * Subclasses may override this, e.g. to initialise the database of variable * names. - * @param {!Blockly.Workspace} _workspace Workspace to generate code from. + * @param {!Workspace} _workspace Workspace to generate code from. */ -Blockly.Generator.prototype.init = function(_workspace) { +Generator.prototype.init = function(_workspace) { // Optionally override // Create a dictionary of definitions to be printed before the code. this.definitions_ = Object.create(null); @@ -492,14 +499,14 @@ Blockly.Generator.prototype.init = function(_workspace) { * Subclasses may override this, e.g. to generate code for statements following * the block, or to handle comments for the specified block and any connected * value blocks. - * @param {!Blockly.Block} _block The current block. + * @param {!Block} _block The current block. * @param {string} code The code created for this block. * @param {boolean=} _opt_thisOnly True to generate code for only this * statement. * @return {string} Code with comments and subsequent blocks added. * @protected */ -Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) { +Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) { // Optionally override return code; }; @@ -511,7 +518,7 @@ Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) { * @param {string} code Generated code. * @return {string} Completed code. */ -Blockly.Generator.prototype.finish = function(code) { +Generator.prototype.finish = function(code) { // Optionally override // Clean up temporary data. delete this.definitions_; @@ -527,7 +534,9 @@ Blockly.Generator.prototype.finish = function(code) { * @param {string} line Line of generated code. * @return {string} Legal line of code. */ -Blockly.Generator.prototype.scrubNakedValue = function(line) { +Generator.prototype.scrubNakedValue = function(line) { // Optionally override return line; }; + +exports = Generator; diff --git a/tests/deps.js b/tests/deps.js index 3f1ac7e7e..d96855422 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -65,7 +65,7 @@ goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Bl goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es5'}); goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']); goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']); -goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.Block', 'Blockly.internalConstants', 'Blockly.utils.deprecation']); +goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly', 'Blockly.internalConstants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate']); goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent']); goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom']);