2nd try: Add loose option for es2015-parameters transformation (#5943)
* Import changes to parameters package from previous branch * Refactor plugin option access via state
This commit is contained in:
parent
a0f0411abf
commit
b83e0ec7b0
@ -72,3 +72,23 @@ require("babel-core").transform("code", {
|
||||
plugins: ["transform-es2015-parameters"]
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `loose`
|
||||
|
||||
`boolean`, defaults to `false`.
|
||||
|
||||
In loose mode, parameters with default values will be counted into the arity of the function. This is not spec behavior where these parameters do not add to function arity.
|
||||
|
||||
The `loose` implementation is a more performant solution as JavaScript engines will fully optimize a function that doesn't reference `arguments`. Please do your own benchmarking and determine if this option is the right fit for your application.
|
||||
|
||||
```javascript
|
||||
// Spec behavior
|
||||
function bar1 (arg1 = 1) {}
|
||||
bar1.length // 0
|
||||
|
||||
// Loose mode
|
||||
function bar1 (arg1 = 1) {}
|
||||
bar1.length // 1
|
||||
```
|
||||
|
||||
@ -11,6 +11,16 @@ const buildDefaultParam = template(`
|
||||
DEFAULT_VALUE;
|
||||
`);
|
||||
|
||||
const buildLooseDefaultParam = template(`
|
||||
if (ASSIGMENT_IDENTIFIER === UNDEFINED) {
|
||||
ASSIGMENT_IDENTIFIER = DEFAULT_VALUE;
|
||||
}
|
||||
`);
|
||||
|
||||
const buildLooseDestructuredDefaultParam = template(`
|
||||
let ASSIGMENT_IDENTIFIER = PARAMETER_NAME === UNDEFINED ? DEFAULT_VALUE : PARAMETER_NAME ;
|
||||
`);
|
||||
|
||||
const buildCutOff = template(`
|
||||
let $0 = $1[$2];
|
||||
`);
|
||||
@ -51,6 +61,45 @@ export const visitor = {
|
||||
// ensure it's a block, useful for arrow functions
|
||||
path.ensureBlock();
|
||||
|
||||
const params = path.get("params");
|
||||
|
||||
if (this.opts.loose) {
|
||||
const body = [];
|
||||
for (let i = 0; i < params.length; ++i) {
|
||||
const param = params[i];
|
||||
if (param.isAssignmentPattern()) {
|
||||
const left = param.get("left");
|
||||
const right = param.get("right");
|
||||
|
||||
const undefinedNode = scope.buildUndefinedNode();
|
||||
|
||||
if (left.isIdentifier()) {
|
||||
body.push(
|
||||
buildLooseDefaultParam({
|
||||
ASSIGMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(left.node);
|
||||
} else if (left.isObjectPattern() || left.isArrayPattern()) {
|
||||
const paramName = scope.generateUidIdentifier();
|
||||
body.push(
|
||||
buildLooseDestructuredDefaultParam({
|
||||
ASSIGMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
PARAMETER_NAME: paramName,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
path.get("body").unshiftContainer("body", body);
|
||||
return;
|
||||
}
|
||||
|
||||
const state = {
|
||||
iife: false,
|
||||
scope: scope,
|
||||
@ -77,7 +126,6 @@ export const visitor = {
|
||||
const lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
//
|
||||
const params = path.get("params");
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i];
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
function f(a, b = a, c = b) { return c; }
|
||||
|
||||
assert.equal(3, f(3));
|
||||
@ -0,0 +1 @@
|
||||
function test({a: b} = {}) {}
|
||||
@ -0,0 +1,4 @@
|
||||
function test(_temp) {
|
||||
var _ref = _temp === void 0 ? {} : _temp,
|
||||
b = _ref.a;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
function t([,,a] = [1,2,3]) { return a }
|
||||
@ -0,0 +1,4 @@
|
||||
function t([,,a] = [1,2,3]) { return a }
|
||||
|
||||
assert.equal(t(), 3);
|
||||
assert.equal(t([4,5,6]), 6);
|
||||
@ -0,0 +1,7 @@
|
||||
function t(_temp) {
|
||||
var _ref = _temp === void 0 ? [1, 2, 3] : _temp,
|
||||
_ref2 = babelHelpers.slicedToArray(_ref, 3),
|
||||
a = _ref2[2];
|
||||
|
||||
return a;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
function f(a, b = a, c = b) { return c; }
|
||||
|
||||
assert.equal(3, f(3));
|
||||
@ -0,0 +1,9 @@
|
||||
const bar = true;
|
||||
|
||||
function foo(a = bar, ...b) {
|
||||
const bar = false;
|
||||
assert.equal(b[0], 2);
|
||||
assert.equal(b[1], 3);
|
||||
}
|
||||
|
||||
foo(1, 2, 3);
|
||||
@ -0,0 +1,9 @@
|
||||
class Ref {
|
||||
static nextId = 0
|
||||
constructor(id = ++Ref.nextId, n = id) {
|
||||
this.id = n
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(1, new Ref().id)
|
||||
assert.equal(2, new Ref().id)
|
||||
@ -0,0 +1,7 @@
|
||||
class Ref {
|
||||
constructor(ref = Ref) {
|
||||
this.ref = ref
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(Ref, new Ref().ref)
|
||||
@ -0,0 +1,7 @@
|
||||
var t = function (e = "foo", f = 5) {
|
||||
return e + " bar " + f;
|
||||
};
|
||||
|
||||
var a = function (e, f = 5) {
|
||||
return e + " bar " + f;
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
var t = function (e, f) {
|
||||
if (e === void 0) {
|
||||
e = "foo";
|
||||
}
|
||||
|
||||
if (f === void 0) {
|
||||
f = 5;
|
||||
}
|
||||
|
||||
return e + " bar " + f;
|
||||
};
|
||||
|
||||
var a = function (e, f) {
|
||||
if (f === void 0) {
|
||||
f = 5;
|
||||
}
|
||||
|
||||
return e + " bar " + f;
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
function required(msg) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
function sum(
|
||||
{ arr = required('arr is required') } = { arr: arr = [] },
|
||||
length = arr.length
|
||||
) {
|
||||
let i = 0;
|
||||
let acc = 0;
|
||||
for (let item of arr) {
|
||||
if (i >= length) return acc;
|
||||
acc += item;
|
||||
i++;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
assert.equal(sum({arr:[1,2]}), 3);
|
||||
@ -0,0 +1,15 @@
|
||||
const a = 1;
|
||||
function rest(b = a, ...a) {
|
||||
assert.equal(b, 1);
|
||||
}
|
||||
rest(undefined, 2)
|
||||
|
||||
function rest2(b = a, ...a) {
|
||||
assert.equal(a[0], 2);
|
||||
}
|
||||
rest2(undefined, 2)
|
||||
|
||||
function rest3(b = a, ...a) {
|
||||
assert.equal(a.length, 1);
|
||||
}
|
||||
rest3(undefined, 2)
|
||||
@ -0,0 +1,3 @@
|
||||
var t = function (f = "foo") {
|
||||
return f + " bar";
|
||||
};
|
||||
@ -0,0 +1,7 @@
|
||||
var t = function (f) {
|
||||
if (f === void 0) {
|
||||
f = "foo";
|
||||
}
|
||||
|
||||
return f + " bar";
|
||||
};
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-class-properties", "external-helpers", "syntax-flow", ["transform-es2015-parameters", { "loose": true } ], "transform-es2015-block-scoping", "transform-es2015-spread", "transform-es2015-classes", "transform-es2015-destructuring", "transform-es2015-arrow-functions", "syntax-async-functions", "transform-es2015-for-of"]
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
function t(undefined = 17, a = 3) {
|
||||
return a;
|
||||
}
|
||||
|
||||
assert.equal(t(), 3);
|
||||
Loading…
x
Reference in New Issue
Block a user