Blockly Style Guide

TL;DR

Follow the Google JavaScript style guide. New code should use ES6 language features like let, const, class, destructuring assignment, etc, where applicable.

Migrating to ES6

Blockly was originally written in ES5.1 in compliance with an older, then-current version of the Google JavaScript style guide. We are migrating the codebase to ES6 and the new style guide. Older browsers, including Internet Explorer 11, will continue to be supported by transpilation to ES5.1.

Do

  • Indent with spaces, not tabs.
  • Use eslint.
  • Use semicolons.
  • Use underlines at the end of protectedVariableNames_, privateVariableNames_, protectedFunctionNames_, and privateFunctionNames_.
  • Use camelCase for variables and functions.
  • Use TitleCase for classes.
  • Use ALL_CAPS for constants.
  • Use braces for all control structures.
  • Use single quotes (except when writing JSON).
  • Redeclare variables in for loops. That is, always write for (let i = 0; ...) instead of for (i = 0; ...).
    • Not doing so raises the risk that after a refactor higher up in the function the variable will be orphaned and become a surprise global.
  • Line wrap at 80 characters to make reviewing easier.
  • Indent the wrapped line with four spaces.
    • If a line is broken at multiple syntactic levels, each level should have a four space indent from the previous line / syntactic level.
  • Start comments with capital letters and end them with periods.
  • Create GitHub issues with TODOs and link them using TODO(#issueNumber).
  • Annotate everything with JSDoc.

Don't

  • Indent with tabs.
  • Use underlines at the ends of publicVariableNames and publicFunctionNames.
  • Use snake_case.
  • Use double quotes (except when writing JSON).
  • Use malformed JSDoc.
    • Our JSDoc is automatically published as part of our documentation.
  • Write TODO (username).
    • Instead create GitHub issues with TODOs and link them using TODO(#issueNumber).
  • Use string.startsWith. Use Blockly.utils.string.startsWith instead.

JSDoc

The Blockly team uses JSDoc to annotate our code and generate documentation. We expect JSDoc for all properties of classes, and for all functions.

JSDoc comments must start with /** and end with */ to be parsed correctly.

Blockly uses four visibility tags. Always use the most restricted scope possible.

  • public means that the function or property can be used by anyone, including outside developers.
  • package means that the function or property can be used by any class inside Blockly, but outside developers may not use it.
  • protected means that the function or property can be used by the owning class or subclasses of the owning class.
  • private means that the function or property can be used by the owning class, and only the owning class.

Properties

Annotations for properties should include

  • A description of the property
  • The type
  • A visibility tag: public, package, protected, or private

Preferred:

/**
 * Whether the block may be deleted by the user.
 * @type {boolean}
 * @private
 */
this.deletable_ = true;

Allowed, only when the meaning of the property is obvious.

/** @type {boolean} */
this.isInFlyout = false;

Functions

Annotations for functions should include

  • A description of the function
  • One @param tag per parameter, including
    • Type
    • Name
    • Description
  • A visibility tag: public, package, protected or private
  • A @return tag if the function will return a value, including
    • Type
    • A description of the returned value, if any

For example:

/**
 * Obtain a newly created block.
 * @param {!Blockly.Workspace} workspace The block's workspace.
 * @param {string} prototypeName Name of the language object containing
 *     type-specific functions for this block.
 * @return {!Blockly.Block} The created block.
 * @public
 * @deprecated December 2015. Will be removed Decmeber 2016. Use
 *     workspace.newBlock instead.
 */
Blockly.Block.obtain = function(workspace, prototypeName) {
  Blockly.utils.deprecation.warn(
      'Connection.prototype.checkType',
      'December 2015',
      'December 2016',
      'workspace.newBlock');
  return workspace.newBlock(prototypeName);
};