* Unify eslint/prettier config
Use a prettier config file and correctly configure trailing commas
Enable curly in babylon as in all other packages.
* Add experimental and codemods
* Properly guard for..in loops with Object#hasOwnProperty.
I noticed that babylon spends a lot of time in what we call *slow mode*
`for..in` when running in Node (on V8), and the reason for that is that
the version distributed on npm is build with *loose mode*, which turns
methods on the prototype into enumerable properties. Let's look at a
simplified example of the `State` class from `src/tokenizer/state.js`:
```js
class State {
constructor() { this.x = 1; }
clone() {
var state = new State();
for (var key in this) {
var val = this[key];
state[key] = val;
}
return state;
}
}
```
According to the specification the `State.prototype.clone` method is
non-enumerable. However when transpiling this with loose mode, we get
the following output:
```js
var State = (function() {
function State() { this.x = 1; }
State.prototype.clone = function clone() {
var state = new State();
for (var key in this) {
var val = this[key];
state[key] = val;
}
return state;
}
return State;
})();
```
So all of a sudden the `State.prototype.clone` method is enumerable.
This means that the `for..in` loop inside of that method enumerates
`x` and `clone` for `key`, whereas originally it was supposed to only
enumerate `x`. This in turn means that the shape of the result of a
call to `clone` will be different than the shape of a state that is
created via the `State` constructor. You can check this in `d8` using
the `--allow-natives-syntax` flag and this simple test driver:
```js
const s = new State;
%DebugPrint(s);
%DebugPrint(s.clone());
```
Using either the class version or the transpiled version we see:
```
$ out/Release/d8 --allow-natives-syntax state-original.js
0x2a9d7970d329 <State map = 0x2a9d40b0c751>
0x2a9d7970d3c1 <State map = 0x2a9d40b0c751>
$ out/Release/d8 --allow-natives-syntax state-loose.js
0x3729ee30d1b9 <State map = 0x3729af90c701>
0x3729ee30d251 <State map = 0x3729af90c7a1>
```
So as you can see, the transpiled version (using *loose mode*) produces
a different shape for the result of `clone`, whereas the original
version is fine. This pollutes all sites which use either a state
created from the `State` constructor or returned from the `clone`
method. The original one has only the `x` property in either case,
whereas in the transpiled version the result of `clone` has properties
`x` and `clone` on the instance.
To mitigate this effect, it's best to guard the `for..in` loops with
`Object.prototype.hasOwnProperty` calls, such that the actual body of
the loop only deals with own properties and not with properties from the
prototype chain. This change does exactly that for the two affected
`clone` functions.
In addition to the performance hit because of the unnecessary
polymorphism, there's also the performance hit because of the *slow
mode* `for..in` itself, which has to collect the properties from the
instance plus the prototype. Ideally the prototype properties shouldn't
be enumerable to avoid this whole set of problems. I see a couple of
possible solutions:
1. Distribute the original ES2015 version via npm.
2. Don't use loose mode, so that `Object.defineProperty` is used
instead, correctly passing `enumerable:false`.
3. Globally change loose mode in Babel to generate the correct and
fast `Object.defineProperty` instead.
I'd personally prefer a combination of 1. and 3. here, but I'm aware
that distributing the ES2015 code might not be an option yet. So the
mitigation of properly guarding the `for..in` here should already help.
But it'd be nice to have a discussion on using `Object.defineProperty`
in general, as I imagine that this could easily bite other applications
as well and this performance cliff is completely unobvious to
developers.
* Switch to Object.keys and Array.prototype.forEach.
* Add JSX Fragments to babel-types
* Support JSX fragments in the transform-react-jsx plugin
* Add tests JSX fragments
* Update helper-builder and transform plugin documentations for jsx fragment
* Add generator for jsx fragments
* Add test for jsx fragment generator
* Split jsx transform example into normal and fragment examples
* Remove unnecessary fields from ElementState in babel-helper-builder-react-jsx
* inline [skip ci]
* Fix OOB string character access in Printer#_maybeAddParen.
The `_maybeAddParen` method of the `Printer` class does
```js
const chaPost = str[i + 1]
```
without checking that `i + 1` is still within the bounds of `str`. It
seems like this triggers fairly often that the `str[i + 1]` access is
out of bounds. The first out of bounds access will turn the KeyedLoadIC
(in case of V8) into *MEGAMORPHIC* state, which is significantly slower
for strings (there's a fix in flight for V8 to mitigate the cost a bit
in that case). Even worse than that, the out of bounds access also
pollutes the later comparisons, namely
```js
chaPost === "/"
```
and
```js
chaPost === "*"
```
which are now no longer monomorphic on strings, since `chaPost` was
sometimes `undefined`.
This is a non-breaking performance fix, which improves babel execution
on the [web-tooling-benchmark](github.com/v8/web-tooling-benchmark)
workload by around 6-9%.
* Restructure and optimize the code a bit.
* Added tests for ifThrowNamespace flag
* JSX transformator could work with XMLNamespaces (ifThrowNamespace flag)
* Use template literal instead
* Attempt to reword the message
* Added docs
* Reworded docs
* Reworded docs
* Fixed missing space in error message
The code
```js
linesInfo && linesInfo[type]
```
performs a lot of dynamic lookups on the `Boolean.prototype`, as the
*ToBoolean* operation let's `true` pass for `linesInfo` (which might
itself be concerning that this can be a boolean). Instead of the
coercion, the code should properly check for valid objects via `typeof`
and strict equality with `null` comparison.
This is a non-breaking performance fix.
Similar to the fixes in https://github.com/babel/babel/pull/6580 and
https://github.com/babel/babel/pull/6581, accesses of the form
```js
nodesOut[nodesOut.length - 1]
```
where `nodesOut` can be an empty array, are bad for performance in Node.
In this particular case it's easy to restructure the code a bit to not
require the array access at all, but just track the current `tail` as we
go.
This is a non-breaking performance fix.
* Fix path.popContext() to not try to load "-1" from contexts array.
The current implement of popContext does
```js
this.setContext(this.contexts[this.contexts.length - 1]);
```
even if `this.contexts` can be empty, which causes it to lookup the
property `"-1"`, which is not found on the array itself and obviously
also not in the `Object.prototype` and the `Array.prototype`. However
since `"-1"` is not a valid array index, but has a valid integer
representation, this is a very expensive lookup in V8 (and probably
other engines too, but that is probably less relevant, since Babel
most often runs on Node nowadays).
* Make zero check explicit (for readability).
Similar in spirit to https://github.com/babel/babel/pull/6580, the
current implementation did
```js
node.params[node.params.length - 1]
```
where `node.params` can also be empty, which causes it to lookup the
property `"-1"`, which is not found on the array itself and obviously
also not in the `Object.prototype` and the `Array.prototype`. However
since `"-1"` is not a valid array index, but has a valid integer
representation, this is a very expensive lookup in V8 (and probably
other engines too, but that is probably less relevant, since Babel
most often runs on Node nowadays). In V8 this causes a call to
the `%SetProperty` runtime function for each of these `"-1"`
property lookups, and in addition sends the whole `KeyedLoadIC`
to `MEGAMORPHIC` state, which also penalizes other accesses
on this line.
This is a small non-breaking performance fix.