Skip to content

Commit

Permalink
implement lowering for object rest bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jun 23, 2020
1 parent 717b448 commit 92b3a30
Show file tree
Hide file tree
Showing 8 changed files with 1,249 additions and 94 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog

## Unreleased

* Transform object rest properties

This release transforms object rest property bindings such as `let {...x} = y` when the language target is set to `--target=es2017` or earlier.

If you're using Babel to transform your source code to ES6 for older browsers, this probably means esbuild's JavaScript API could now be a suitable replacement for Babel in your case. The only remaining features that esbuild can't yet transform to ES6 are a few very rarely used features that don't matter for the vast majority of real-world code (`for async` loops and `async` generators).

## 0.5.9

* Add the `--strict:nullish-coalescing` option
Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -100,8 +100,9 @@ These syntax features are conditionally transformed for older browsers depending
| Syntax transform | Transformed when `--target` is below | Example |
|-------------------------------------------------------------------------------------|--------------------------------------|----------------------------|
| [Exponentiation operator](https://github.com/tc39/proposal-exponentiation-operator) | `es2016` | `a ** b` |
| [Async functions](https://github.com/tc39/ecmascript-asyncawait) | `es2017` | `async () => {}` |
| [Async functions](https://github.com/tc39/ecmascript-asyncawait) | `es2017` | `async () => {}` |
| [Spread properties](https://github.com/tc39/proposal-object-rest-spread) | `es2018` | `let x = {...y}` |
| [Rest properties](https://github.com/tc39/proposal-object-rest-spread) | `es2018` | `let {...x} = y` |
| [Optional catch binding](https://github.com/tc39/proposal-optional-catch-binding) | `es2019` | `try {} catch {}` |
| [Optional chaining](https://github.com/tc39/proposal-optional-chaining) | `es2020` | `a?.b` |
| [Nullish coalescing](https://github.com/tc39/proposal-nullish-coalescing) | `es2020` | `a ?? b` |
Expand Down Expand Up @@ -168,7 +169,6 @@ These syntax features are currently always passed through un-transformed:

| Syntax transform | Unsupported when `--target` is below | Example |
|-------------------------------------------------------------------------------------|--------------------------------------|-----------------------------|
| [Rest properties](https://github.com/tc39/proposal-object-rest-spread) | `es2018` | `let {...x} = y` |
| [Asynchronous iteration](https://github.com/tc39/proposal-async-iteration) | `es2018` | `for await (let x of y) {}` |
| [Async generators](https://github.com/tc39/proposal-async-iteration) | `es2018` | `async function* foo() {}` |
| [BigInt](https://github.com/tc39/proposal-bigint) | `es2020` | `123n` |
Expand Down
219 changes: 219 additions & 0 deletions internal/bundler/bundler_lower_test.go
Expand Up @@ -2181,3 +2181,222 @@ console.log(loose_default, strict_default);
},
})
}

func TestTSLowerObjectRest2017NoBundle(t *testing.T) {
expectBundled(t, bundled{
files: map[string]string{
"/entry.ts": `
const { ...local_const } = {};
let { ...local_let } = {};
var { ...local_var } = {};
let arrow_fn = ({ ...x }) => { };
let fn_expr = function ({ ...x } = default_value) {};
let class_expr = class { method(x, ...[y, { ...z }]) {} };
function fn_stmt({ a = b(), ...x }, { c = d(), ...y }) {}
class class_stmt { method({ ...x }) {} }
namespace ns { export let { ...x } = {} }
try { } catch ({ ...catch_clause }) {}
for (const { ...for_in_const } in { abc }) {}
for (let { ...for_in_let } in { abc }) {}
for (var { ...for_in_var } in { abc }) ;
for (const { ...for_of_const } of [{}]) ;
for (let { ...for_of_let } of [{}]) x()
for (var { ...for_of_var } of [{}]) x()
for (const { ...for_const } = {}; x; x = null) {}
for (let { ...for_let } = {}; x; x = null) {}
for (var { ...for_var } = {}; x; x = null) {}
for ({ ...x } in { abc }) {}
for ({ ...x } of [{}]) {}
for ({ ...x } = {}; x; x = null) {}
({ ...assign } = {});
({ obj_method({ ...x }) {} });
`,
},
entryPaths: []string{"/entry.ts"},
parseOptions: parser.ParseOptions{
IsBundling: false,
Target: parser.ES2017,
},
bundleOptions: BundleOptions{
IsBundling: false,
AbsOutputFile: "/out.js",
},
expected: map[string]string{
"/out.js": `var _o, _p;
const local_const = __rest({}, []);
let local_let = __rest({}, []);
var local_var = __rest({}, []);
let arrow_fn = (_a) => {
var x2 = __rest(_a, []);
};
let fn_expr = function(_b = default_value) {
var x2 = __rest(_b, []);
};
let class_expr = class {
method(x2, ..._c) {
var [y, _d] = _c, z = __rest(_d, []);
}
};
function fn_stmt(_e, _f) {
var {a = b()} = _e, x2 = __rest(_e, ["a"]);
var {c = d()} = _f, y = __rest(_f, ["c"]);
}
class class_stmt {
method(_g) {
var x2 = __rest(_g, []);
}
}
var ns;
(function(ns2) {
ns2.x = __rest({}, []);
})(ns || (ns = {}));
try {
} catch (_h) {
let catch_clause = __rest(_h, []);
}
for (const _i in {abc}) {
const for_in_const = __rest(_i, []);
}
for (let _j in {abc}) {
let for_in_let = __rest(_j, []);
}
for (var _k in {abc}) {
var for_in_var = __rest(_k, []);
;
}
for (const _l of [{}]) {
const for_of_const = __rest(_l, []);
;
}
for (let _m of [{}]) {
let for_of_let = __rest(_m, []);
x();
}
for (var _n of [{}]) {
var for_of_var = __rest(_n, []);
x();
}
for (const for_const = __rest({}, []); x; x = null) {
}
for (let for_let = __rest({}, []); x; x = null) {
}
for (var for_var = __rest({}, []); x; x = null) {
}
for (_o in {abc}) {
x = __rest(_o, []);
}
for (_p of [{}]) {
x = __rest(_p, []);
}
for (x = __rest({}, []); x; x = null) {
}
assign = __rest({}, []);
({obj_method(_q) {
var x2 = __rest(_q, []);
}});
`,
},
})
}

func TestTSLowerObjectRest2018NoBundle(t *testing.T) {
expectBundled(t, bundled{
files: map[string]string{
"/entry.ts": `
const { ...local_const } = {};
let { ...local_let } = {};
var { ...local_var } = {};
let arrow_fn = ({ ...x }) => { };
let fn_expr = function ({ ...x } = default_value) {};
let class_expr = class { method(x, ...[y, { ...z }]) {} };
function fn_stmt({ a = b(), ...x }, { c = d(), ...y }) {}
class class_stmt { method({ ...x }) {} }
namespace ns { export let { ...x } = {} }
try { } catch ({ ...catch_clause }) {}
for (const { ...for_in_const } in { abc }) {}
for (let { ...for_in_let } in { abc }) {}
for (var { ...for_in_var } in { abc }) ;
for (const { ...for_of_const } of [{}]) ;
for (let { ...for_of_let } of [{}]) x()
for (var { ...for_of_var } of [{}]) x()
for (const { ...for_const } = {}; x; x = null) {}
for (let { ...for_let } = {}; x; x = null) {}
for (var { ...for_var } = {}; x; x = null) {}
for ({ ...x } in { abc }) {}
for ({ ...x } of [{}]) {}
for ({ ...x } = {}; x; x = null) {}
({ ...assign } = {});
({ obj_method({ ...x }) {} });
`,
},
entryPaths: []string{"/entry.ts"},
parseOptions: parser.ParseOptions{
IsBundling: false,
Target: parser.ES2018,
},
bundleOptions: BundleOptions{
IsBundling: false,
AbsOutputFile: "/out.js",
},
expected: map[string]string{
"/out.js": `const {...local_const} = {};
let {...local_let} = {};
var {...local_var} = {};
let arrow_fn = ({...x2}) => {
};
let fn_expr = function({...x2} = default_value) {
};
let class_expr = class {
method(x2, ...[y, {...z}]) {
}
};
function fn_stmt({a = b(), ...x2}, {c = d(), ...y}) {
}
class class_stmt {
method({...x2}) {
}
}
var ns;
(function(ns2) {
({...ns2.x} = {});
})(ns || (ns = {}));
try {
} catch ({...catch_clause}) {
}
for (const {...for_in_const} in {abc}) {
}
for (let {...for_in_let} in {abc}) {
}
for (var {...for_in_var} in {abc})
;
for (const {...for_of_const} of [{}])
;
for (let {...for_of_let} of [{}])
x();
for (var {...for_of_var} of [{}])
x();
for (const {...for_const} = {}; x; x = null) {
}
for (let {...for_let} = {}; x; x = null) {
}
for (var {...for_var} = {}; x; x = null) {
}
for ({...x} in {abc}) {
}
for ({...x} of [{}]) {
}
for ({...x} = {}; x; x = null) {
}
({...assign} = {});
({obj_method({...x2}) {
}});
`,
},
})
}

0 comments on commit 92b3a30

Please sign in to comment.