question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: Allow a fixer to apply multiple fixes simultaneously

See original GitHub issue

Problem

As of ESLint 3.7, the autofixer for a rule can only perform one “fix” at a time. In this context, a “fix” is an atomic change (removal/insertion/replacement) to a single contiguous range of code.

From what I understand, this restriction was introduced when the autofixers for core rules almost exclusively fixed whitespace, and didn’t touch any tokens. The intention was to ensure that each fix was as small as possible, to increase the likelihood of any given fix getting applied.

There are cases where a rule wants to apply multiple fixes at separate locations. Nowadays, many autofixers modify tokens and the AST, not just whitespace. As a result, these multi-fix operations cannot be split into smaller atomic operations, because the syntax or runtime behavior of the code will be incorrect if only one fix gets applied without the other.

The autofixer for no-extra-parens is a good example of this:

/* eslint no-extra-parens: error */

var foo = (function () {
  // function body
});

The autofixer for no-extra-parens would like to remove the parentheses around the function, to obtain the following code:

var foo = function () {
  // function body
};

Clearly, the left and right parentheses have to be removed in the same pass of the code; if only one paren is removed without the other, the resulting syntax will be invalid. Reporting two separate errors as a workaround does not solve this issue; since the fix from any given reported error is not guaranteed to be applied, reporting an for each paren can still result in only one fix being applied under certain circumstances.

Due to these restrictions, no-extra-parens (and many other core rules, such as prefer-arrow-callback, quote-props, wrap-regex, etc.) uses a a different workaround: it replaces the entire text range between the two parens. Applied to this example, it replaces the entire range containing (function () { ... }) with function () { ... }.

This workaround works because it only applies to a single text range, so it is a single contiguous fix. However, it is not ideal. Since the resulting fix is so large, it can prevent other fixes from being applied during the same pass; this results in a larger number of passes, which hurts the performance of autofixing. The fix is also overcomplicated intuitively; for a large function, it could easily end up replacing tens of thousands of characters, even though it is only trying to remove two characters.

Proposal: Allow multiple fixes

This problem could be solved if a rule could apply multiple fixes per reported problem. For example, the no-extra-parens autofixer would apply two fixes; a single-character fix to remove the left paren, and a single-character fix to remove the right paren.

The fixes for a given reported problem would be applied atomically. In other words, there would still be no guarantee that any problem’s fixes would get applied in general, but the core engine would guarantee that all the fixes for a problem would be applied simultaneously, so the code would never end up in a state where only some of a problem’s fixes were applied.

API Changes

Currently, fixes are applied when a fixer function returns an object with range and text keys. (Usually, these fix objects are generated by helper functions such as RuleFixer#replaceText.)

To apply multiple fixes, a fixer function could instead return an array of these fix objects. Returning a single fix object would still be supported for backwards-compatibility.

For example, the fixer function for no-extra-parens would look something like this:

context.report({
  node,
  message,
  fix(fixer) {
    return [
      fixer.remove(leftParenToken),
      fixer.remove(rightParenToken)
    ];
  }
});

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:3
  • Comments:18 (16 by maintainers)

github_iconTop GitHub Comments

1reaction
platinumazurecommented, Oct 13, 2016

I’m okay with the API. I just want to make sure we agree on what the requirements of a new implementation should be (which may include things like linear time performance, atomicity of sets of fixes, etc.)

1reaction
not-an-aardvarkcommented, Oct 12, 2016

Interesting example. I’ll think about whether it’s possible to maintain linear time and atomicity, but I’m also wondering: How bad for overall performance would a quadratic-time implementation actually be?

For example, if a file has 100 fixes (probably much larger than the average), this requires updating ranges O(10000) times. I’m inclined to think that updating a range is computationally inexpensive, as it just requires a couple arithmetic operations, so even 10000 range updates would not cause a performance difference noticeable to the user. In comparison, doing another autofixing pass is very expensive, as it requires reparsing the file and running every rule again on the new AST.

In other words, even if this change would require the autofixing implementation to be O(n2) in the number of fixes, it might still improve performance overall by reducing the number of passes required (since fewer fixes would conflict with each other)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fixer-Upper Loans: Best Options - LendingTree
A fixer-upper loan may be a good option to buy a house that needs some TLC and pay for the repairs needed to...
Read more >
How Do Home Renovation Loans Work? - ValuePenguin
If you're buying a home that needs repairs, there are multiple loan ... works will depend on the type of financing you decide...
Read more >
These Loans Allow Borrowers to Roll Remodeling Costs Into ...
Each type of renovation loan works for a different type of buyer, and they each have their own benefits, drawbacks, and limitations. Here's...
Read more >
Steps to Buying and Renovating a Fixer-Upper - Sweeten.com
This handy timeline will help you understand the step-by-step of buying and renovating a fixer-upper. Find a vetted contractor at Sweeten.
Read more >
Buying a Fixer-Upper Home! | What to do First! - YouTube
Where most people go wrong is not having a plan for the home remodeling phase! Let's review your next steps together!
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found