Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix remove hooks for Assignment/Conditional #4896

Closed
wants to merge 4 commits into from
Closed

Fix remove hooks for Assignment/Conditional #4896

wants to merge 4 commits into from

Conversation

danez
Copy link
Member

@danez danez commented Nov 26, 2016

Q A
Bug fix? yes
Breaking change? no
New feature? no
Deprecations? no
Spec compliancy? no
Tests added/pass? yes
Fixed tickets Fixes babel/minify#300 facebook/react-native#10412
License MIT
Doc PR no
Dependency Changes no

This ensures that if any subnode of ConditionalExpressions and right of AssignmentExpression are removed they get replaced by undefined (or void 0).

I'm not sure what should happen if the left-hand-side of an assignment gets removed.

x = someCall();

If now someone removes the left-hand-side we probably need to turn it into

someCall();

But I'm not sure. In certain cases, we can probably also remove the whole thing alltogether if there can be no side-effects:

x = a;

//cc @boopathi @kangax

@danez danez added the PR: Bug Fix 🐛 A type of pull request used for our changelog categories label Nov 26, 2016
const body = path.get("body");
body.remove();

assert.equal(generateCode(rootPath), "x = () => void 0;", "body should be replaced with undefined");
Copy link
Member Author

Choose a reason for hiding this comment

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

In that case we could also replace void 0 with a simple blockStatement I think?

x = () => {};

Which would also be shorter.

Copy link
Member

@boopathi boopathi Nov 26, 2016

Choose a reason for hiding this comment

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

yes 👍

@codecov-io
Copy link

codecov-io commented Nov 26, 2016

Current coverage is 89.38% (diff: 100%)

Merging #4896 into master will increase coverage by 0.03%

@@             master      #4896   diff @@
==========================================
  Files           196        196          
  Lines         14022      14022          
  Methods        1460       1460          
  Messages          0          0          
  Branches       3263       3263          
==========================================
+ Hits          12529      12534     +5   
+ Misses         1493       1488     -5   
  Partials          0          0          

Powered by Codecov. Last update 1d9e509...c3960ca

@kangax
Copy link
Member

kangax commented Nov 26, 2016

I see few options here. When we remove a node and that makes for an invalid AST, we could either:

  • Throw an error / disallow it
  • Try to replace it with something that still preserves correct AST
  • Try to remove parent nodes until the AST is valid

Since we're probably going with the 2nd one, the further options are to either:

  • Try to infer the context and replace it with something sensible (e.g. undefined in place of an Expression and empty statement in case of a Statement)
  • Give user an option to specify what to replace it with

The API such as path.remove(optionalReplacement) is an interesting option, although might be a little confusing. We also already have path.replaceWith. But it's not too terrible of an idea.

The issues with replacing expression with undefined is that it could lead to subtle behavior changes in code, such as the case with x = <deleted node>. In that case, 3rd option — where we delete parent nodes — would allow us to traverse up and delete the entire AssignmentExpression.

Another example I can think of is removing an argument from the catch clause, which isn't allowed. We can't replace it with undefined, so we need to either leave it (disallow removal) or remove entire try-catch statement.

Thoughts?

@boopathi
Copy link
Member

Throwing in places where a required Field went missing in parentNode is a better idea - tells the plugin author that you're not allowed to remove this - you can only replace it with something else, or remove the entire parent.

I think babel shouldn't decide that it can remove the parent node when the plugin intended to remove the node.

@danez
Copy link
Member Author

danez commented Nov 26, 2016

The more I think about the more it makes sense what boopathi said. Though we should still have a helper for supporting plugin authors, so we can check if it is safe to remove, and some way that the plugin knows what are valid replacement options. Not sure though how this should look like.

I think this would also not be a breaking change as the plugin already throws in this cases.

@danez
Copy link
Member Author

danez commented Jan 8, 2017

I close this for now, as I cannot come up with a solution right now.
I will open a separate PR for the change to output
() => {} instead of () => void 0 when removing the body.

@danez danez closed this Jan 8, 2017
@danez danez deleted the fix-removal branch January 8, 2017 00:40
@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Oct 6, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

path.remove sometimes throws
4 participants