Issue 1:
Note this is the step before actual compilation occurs. I'm not sure how to debug it, but below is the output for the compilation.

Here is my babelrc

{
"presets": ["es2015", "react", "stage-0"]
}

Here is the output running with DEBUG=babel

❯ time DEBUG=babel babel -d blah button-test.js icon-test.js
babel [BABEL] button-test.js: Parse start +0ms
babel [BABEL] button-test.js: Parse stop +17ms
babel [BABEL] button-test.js: Start set AST +2ms
babel [BABEL] button-test.js: End set AST +12ms
babel [BABEL] button-test.js: Start transform traverse +0ms
babel [BABEL] button-test.js: End transform traverse +36ms
babel [BABEL] button-test.js: Generation start +1ms
babel [BABEL] button-test.js: Generation end +8ms
button-test.js -> blah/button-test.js
babel [BABEL] icon-test.js: Parse start +4ms
babel [BABEL] icon-test.js: Parse stop +6ms
babel [BABEL] icon-test.js: Start set AST +0ms
babel [BABEL] icon-test.js: End set AST +5ms
babel [BABEL] icon-test.js: Start transform traverse +1ms
babel [BABEL] icon-test.js: End transform traverse +7ms
babel [BABEL] icon-test.js: Generation start +0ms
babel [BABEL] icon-test.js: Generation end +3ms
icon-test.js -> blah/icon-test.js
DEBUG=babel babel -d blah button-test.js icon-test.js 6.40s user 1.09s system 23% cpu 31.996 total

How can I provide better information on what's happening before compilation?

Issue 2:
Inspired by babel/minify#300, babel/minify#375 and #4896 I was thinking how to properly solve all this cases. Here a short introduction to the problem:

Assuming this code:

active ? a() : b();

Now assuming a transform removes all a() calls, and the resulting code gets

active ? : b();

This is not valid js syntax anymore and babel currently throws somewhere after calling path.remove() in this case.

Currently we have babel handling some of this cases (loops, and arrow functions) but not all of them. Instead of adding more and more rules how to delete certain nodes with certain parents I propose a breaking change to the remove functionality of paths:

Changing path.remove()

I propose changing path.remove() to do what it says, removal of a node/path. If the resulting AST is not valid it should throw. Also remove the current removal-hooks for loops and arrow functions and throw instead if for example a loop ends up with the body node being null.

Introduce path.isRemovable()

A boolean method that returns true if it is safe to remove the path or false if not.

Introduce path.getSafeReplacement()

A function that returns a safe replacement for the current node. It would return a new node that is a "nullable" variant for the current node (Identifier<"undefined">, BlockStatement, ...) or throw if it is not possible (like var a = 1; Remove Identifier a here)

Introduce path.removeOrReplace();

This would more be a sum of the 3 methods I mentioned before and might not be necessary at all, but could be easier to use for plugin authors.

removeOrReplace() {
if (this.isRemovable()) {
this.remove();
} else {
this.replaceWith(this.getSafeReplacement());
}
}

The new functions could be added in 6.x and the change to remove() in 7.0, so that people can migrate.

The ultimate goal of this proposal is to make remove() do what it name says and give plugin authors the tools to handle all the edge cases where remove is not as easy and not every plugin should handle all this cases on their own and duplicate the logic of if-parent-is-ternary-operator then-replace-with-undefined otherwise-if-....

All of this is just a proposal and I would like to hear what you think about it. If you have better ideas or what you don't like about it.

I want to do more research and see how other handle that (estraverse for example).

@boopathi @kangax @loganfsmyth @DrewML