Currently required:
/* eslint "operator-linebreak": ["error", "after" ] */
var x = isItGreat ?
Example.might("be") :
Example.or("not");
Proposed:
/* eslint "operator-linebreak": ["error", "before" ] */
var x = isItGreat
? Example.might("be") :
: Example.or("not");
In summary:
- Consistency with Standard JS, ESLint default, and JSLint; which nowadays all enforce the "before" style.
- Consistency with MediaWiki PHP.
- Improved readability.
- The ESLint rule to enforce this "after" style came from JSHint, which inherited it from JSLint. It existed in JSLint to support "bugs in old parsers". During the time this concern was theoretically relevant (2009-2016), we actually had it disabled and used the before style instead as we favour readability (and consistency with PHP). In 2016, the auto-fixed transition from JSCS/JSHint to ESLint, accidentally flipped this rule and started enforcing the legacy "after" JSLint style.
- Even JSLint never used this style for ternaries, only for conditionals and concatenation. The reason we enforce it on ternaries is that ESLint changed the rule at some point (with a default opt-out), and we forgot to sync our config. Another auto-fix.
- In 2017, JSLint removed their rule completely, and now enforces the same "before" style that I propose here.
History:
Between 2009-2016, the proposed style was our style in MediaWiki JS code with the operator at the start of the line (and thus line break "before" the operator), same as in PHP.
This seemingly changed by accident in 2016 the JSCS Team helped us migrate from JSHint+JSCS to ESLint. From what I can tell, they misread one of our JSCS preset keys and added this style. This appears to be based on a legacy recommendation by Crockford (author of JSLint) to avoid bugs in "old parsers" that did not implement the ECMAScript spec correctly and for some reason had trouble with line breaks before certain operators. jshint issue #60 (2011):
[Line breaks before operators] may cause problems like semi colon insertion and old javascript parsers breaking.
When we adopted JSHint for MediaWiki in 2012, we had the same convention in both PHP and JavaScript. I asked upstream at the time, how to make our coding style pass under JSHint. jshint issue #557:
You should use laxbreak. Default behavior is (historically) what Crockford recommended.
And so we did! https://gerrit.wikimedia.org/r/c/mediawiki/core/+/14017:
- "[mediawiki/core] jshint: add .jshintrc"
"laxbreak": true
The last version of wikimedia JSCS preset in 2014 contains "disallowOperatorBeforeLineBreak": ["."]
, which requires line breaks before, not after, and only for the .
operator.https://github.com/jscs-dev/node-jscs/blob/cf60723df5/presets/wikimedia.json
"operator-linebreak": ["error", "after"],
// Correct
var x = foo
.bar()
.baz();
// Incorrect
var x = foo.
bar().
baz();
The JSCS project merges into ESLint in 2016. The wikimedia preset used to be maintained within the JSCS project, and Oleg made a separate one for us at eslint-config-wikimedia v0.1.0 which set the operator-linebreak rule to enforce line breaks after operators. We deployed this a few weeks later and auto-fixed our code base:
- "[mediawiki/core] build: Replace jscs+jshint with eslint." https://gerrit.wikimedia.org/r/321732 (2016)
Now, at first, the ESLint operator-linebreak rule was mostly for operators in multi-line values (e.g. +
concatenation) and multi-line conditionals (e.g. &&
).
In 2015, someone requested a feature in upstream ESLint to be able to enforce the legacy JSLint style on ternary operators. This despite not even JSLint itself doing this for ternary operators (I guess the "old parsers" didn't have an issue with ternary operators?). ESLint lead Nicholas Zachas confirms:
I think this might have been intentionally omitted because people tend to put the
?
and:
at the front of lines even when everything else is at the end.
The next ESLint release added support for enforcing this odd style on ternaries, but, because it is believed to be unusual and to avoid regressions, upstream included a "default override". eslint issue #4294
https://eslint.org/docs/latest/rules/operator-linebreak
The default configuration is
"after", { "overrides": { "?": "before", ":": "before" } }
Unfortunately, because projects tend to hardcode the defaults, this meant anyone that configured ["error", "after"]
would see their behaviour change during an upgrade, because setting shadows any "default override". For example the JavaScript Standard Style quickly applied this opt-out to avoid a regression after upgrading ESLint. eslint-config-standard@a78c4bb, eslint-config-standard@v16.0.3
fix regression with ternary operator handling
- "operator-linebreak": ["error", "after"], + "operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" } }],
Ironically, Crockford himself has long abandoned this peculiar "after" style in 2017. JSLint (still around!) now embraces the "before" style, same as MediaWiki PHP and Standard JS. jslint-org/jslint@c08484f
[jslint] break left
Proposal:
/* eslint "operator-linebreak": ["error", "before" ] */
var x = isItGreat
? Example.might("be")
: Example.or("not");
if (
mw.foo.hasBar()
&& mw.foo.getThis() === 'that'
&& !mw.foo.getThatFrom( 'this' )
) {}
Pull request: https://github.com/wikimedia/eslint-config-wikimedia/issues/591