Skip to content

Conversation

rschamp
Copy link
Contributor

@rschamp rschamp commented Oct 24, 2016

Towards more consistent style across our JS projects, I've added a centralized ESLint configuration at https://github.com/LLK/eslint-config-scratch. This PR installs the config and updates the syntax to match its expectations.

Since it's a centralized config to be used in all our projects, the rules should be a collective decision so I assigned a bunch of people who might care. If any of these changes annoy you, let's talk about it. I just created it based on what I thought made sense, and then removed rules as I tried to lint this repo.

A few of the rules that required most of the changes:

  • 'func-style': ['error', 'expression']: Functions should be written in the form var functionName = function () {}. This ensures that functions are defined before they're used, which makes code easier to understand as it's read. It also forces the code to be written as it will be executed. The declaration style function functionName () {} relies on functions to be automatically hoisted to the top of the file.
  • 'space-before-function-paren': ['error', 'always']: This is the style we've been using elsewhere. Thankfully you can automatically apply this rule to existing code by running eslint with the --fix argument.
  • 'camelcase': ['error']: All variables should be written in "camelCase" style, without underscores. This improves consistency of naming. There is a convention in this codebase to name options with a mix of underscore and camelcase, like opt_optionName. These have been renamed optOptionName. Unfortunately there's no way to configure a pattern for allowed variable names to include the opt_ prefix.
  • 'eqeqeq': ['error']: Always using === or !== leads to fewer "wat?" errors
  • 'no-undefined': ['error']: Don't use undefined. This rule is mostly to ensure consistency in syntax across the projects in the way we use undefined, but also avoids similar errors to those avoided by the === rule.

Copy link
Contributor Author

@rschamp rschamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to explain some of the other fixes required for the new rules. The last one I left out was using minilog rather than console. This is mostly for consistency, but also gives us the ability to log somewhere other than the console if/when we want to do that, and prefixes the messages with vm, which will be useful when we have messages coming from many different projects at once.

if (runtime.ioDevices[device] && runtime.ioDevices[device][func]) {
var devObject = runtime.ioDevices[device];
return devObject[func].call(devObject, args);
return devObject[func](args);

This comment was marked as abuse.

var distLeft = Math.max(0, (stageWidth / 2) + bounds.left);
var distTop = Math.max(0, (stageHeight / 2) - bounds.top);
var distRight = Math.max(0, (stageWidth / 2) - bounds.right);
var distBottom = Math.max(0, (stageHeight / 2) + bounds.bottom);

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

// If both arguments are ints, truncate the result to an int.
if (Cast.isInt(args.FROM) && Cast.isInt(args.TO)) {
return low + parseInt(Math.random() * ((high + 1) - low));
return low + parseInt(Math.random() * ((high + 1) - low), 10);

This comment was marked as abuse.

if (typeof e !== 'object') return;
if (typeof e.xml !== 'object') return;

return domToBlocks(html.parseDOM(e.xml.outerHTML));

This comment was marked as abuse.

if (!resolvedValue) {
sequencer.retireThread(thread);
}
sequencer.retireThread(thread);

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

if (typeof currentStackFrame.reported[inputName] === 'undefined'
&& inputBlockId) {
if (typeof currentStackFrame.reported[inputName] === 'undefined' &&
inputBlockId) {

This comment was marked as abuse.

var inputCount = 0;
// Split by %n, %b, %s.
var parts = procCode.split(/(?=[^\\]\%[nbs])/);
var parts = procCode.split(/(?=[^\\]%[nbs])/);

This comment was marked as abuse.

Copy link
Contributor

@thisandagain thisandagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pulling this together @rschamp. Mostly looks good though I left a few notes inline.

.eslintrc.js Outdated
module.exports = {
extends: ['scratch', 'scratch/node'],
env: {
node: true

This comment was marked as abuse.

This comment was marked as abuse.

var Timer = require('../util/timer');

function Scratch3ControlBlocks(runtime) {
var Scratch3ControlBlocks = function (runtime) {

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

var distLeft = Math.max(0, (stageWidth / 2) + bounds.left);
var distTop = Math.max(0, (stageHeight / 2) - bounds.top);
var distRight = Math.max(0, (stageWidth / 2) - bounds.right);
var distBottom = Math.max(0, (stageHeight / 2) + bounds.bottom);

This comment was marked as abuse.

var times = Math.floor(Cast.toNumber(args.TIMES));
// Initialize loop
if (util.stackFrame.loopCounter === undefined) {
if (typeof util.stackFrame.loopCounter === 'undefined') {

This comment was marked as abuse.

Scratch3ControlBlocks.prototype.stop = function (args, util) {
var option = args.STOP_OPTION;
if (option == 'all') {
if (option === 'all') {

This comment was marked as abuse.

var tagName = (block.shadow) ? 'shadow' : 'block';
var xy = (block.topLevel) ?
' x="' + block.x +'"' + ' y="' + block.y +'"' :
' x="' + block.x +'" y="' + block.y +'"' :

This comment was marked as abuse.

This comment was marked as abuse.

if (!resolvedValue) {
sequencer.retireThread(thread);
}
sequencer.retireThread(thread);

This comment was marked as abuse.

* @constructor
*/
function List (name, contents) {
module.exports = function List (name, contents) {

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

t.deepEqual(color.decimalToRgb(16777215), {r:255,g:255,b:255});
t.deepEqual(color.decimalToRgb(-16777215), {r:0,g:0,b:1});
t.deepEqual(color.decimalToRgb(99999999), {r:245,g:224,b:255});
t.deepEqual(color.decimalToRgb(0), {r: 0,g: 0,b: 0});

This comment was marked as abuse.

This comment was marked as abuse.

@@ -0,0 +1,5 @@
module.exports = {

This comment was marked as abuse.

This comment was marked as abuse.

This comment was marked as abuse.

Copy link
Contributor

@tmickel tmickel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks sweet to me, thanks for doing all the work to investigate and apply these!!!

* @param {!Target} target Target to set costume/backdrop to.
* @param {Any} requestedCostume Costume requested, e.g., 0, 'name', etc.
* @param {boolean=} opt_zeroIndex Set to zero-index the requestedCostume.
* @param {boolean=} optZeroIndex Set to zero-index the requestedCostume.

This comment was marked as abuse.

var distLeft = Math.max(0, (stageWidth / 2) + bounds.left);
var distTop = Math.max(0, (stageHeight / 2) - bounds.top);
var distRight = Math.max(0, (stageWidth / 2) - bounds.right);
var distBottom = Math.max(0, (stageHeight / 2) + bounds.bottom);

This comment was marked as abuse.


if (!opcode) {
console.warn('Could not get opcode for block: ' + currentBlockId);
log.warn('Could not get opcode for block: ' + currentBlockId);

This comment was marked as abuse.

* @constructor
*/
function List (name, contents) {
module.exports = function List (name, contents) {

This comment was marked as abuse.

'inputName':'BEATS'
'type': 'input',
'inputOp': 'math_number',
'inputName': 'BEATS'

This comment was marked as abuse.

This comment was marked as abuse.

@tmickel tmickel removed their assignment Oct 24, 2016
We are on a fast release cycle here.
motion_pointtowards: this.pointTowards,
motion_glidesecstoxy: this.glide,
motion_ifonedgebounce: this.ifOnEdgeBounce,
motion_setrotationstyle: this.setRotationStyle,

This comment was marked as abuse.

This comment was marked as abuse.

@rschamp
Copy link
Contributor Author

rschamp commented Oct 24, 2016

Updated spaces around infix operators and enforced consistent quotes around object properties: if any of the properties need quotes, then they all need quotes. Otherwise none of them should use quotes. Also fixed the node env config @thisandagain pointed out.

@thisandagain
Copy link
Contributor

I think the only question I have left is the func-style rule / pattern consistency. Otherwise this looks 👍 to me. Any thoughts @mewtaylor @cwillisf ?

@rschamp
Copy link
Contributor Author

rschamp commented Oct 24, 2016

@thisandagain Updated to the var Foo = function () {}; ... module.exports = Foo style, this is what we mostly use elsewhere.

Copy link

@mewtaylor mewtaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! With the suggestions made by others, this looks great!

@mewtaylor mewtaylor removed their assignment Oct 24, 2016
Copy link
Contributor

@cwillisf cwillisf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall 👍 but I'm unsure about the var vs. function change and I think there's a typo in the latest version of the devObject[func] stuff.

Thanks for doing all this work! I look forward to improved consistency across our Scratch 3.0-related repositories :D

@@ -0,0 +1,3 @@
module.exports = {
extends: ['scratch', 'scratch/node']

This comment was marked as abuse.

var Timer = require('../util/timer');

function Scratch3ControlBlocks(runtime) {
var Scratch3ControlBlocks = function (runtime) {

This comment was marked as abuse.

if (doWarp) {
thread.peekStackFrame().warpMode = true;
} else {
} else if (isRecursive) {

This comment was marked as abuse.

// expressions... or something. Not exactly sure why it
// complains here.
// eslint-disable-next-line no-useless-call
return devObject[func].call(devObject[func], args);

This comment was marked as abuse.

This comment was marked as abuse.

Copy link
Contributor

@thisandagain thisandagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for wrangling all this @rschamp

@thisandagain thisandagain removed their assignment Oct 24, 2016
@cwillisf cwillisf assigned rschamp and unassigned cwillisf Oct 24, 2016
@rschamp rschamp merged commit 595be5c into scratchfoundation:develop Oct 24, 2016
@rschamp rschamp deleted the scratch-lint branch October 24, 2016 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants