Compare commits

...

101 Commits

Author SHA1 Message Date
Sebastian McKenzie
cbd6be30bf v1.13.2 2014-11-23 12:02:26 +11:00
Sebastian McKenzie
7e299470fd remove unused variables 2014-11-23 12:01:19 +11:00
Sebastian McKenzie
c794c2aede upgrade acorn-6to5 2014-11-23 11:59:57 +11:00
Sebastian McKenzie
1a58087460 use toArray inline helper instead of Array.from #203 #199 2014-11-23 11:59:18 +11:00
Sebastian McKenzie
44f6fc67f8 v1.13.1 2014-11-23 01:17:14 +11:00
Sebastian McKenzie
e4a3d222d6 fix constructor spread optimisation - thanks @zloirock 2014-11-23 01:16:09 +11:00
Sebastian McKenzie
5a96c2e015 v1.13.0 2014-11-22 23:46:00 +11:00
Sebastian McKenzie
43390c0d1f add experimental usage note about proposal changes 2014-11-22 23:45:05 +11:00
Sebastian McKenzie
d166656149 add constructor spread caveat and add additional Array.from cases 2014-11-22 23:44:47 +11:00
Sebastian McKenzie
acc4d289e4 link straight to caveats in no runtime on doc index 2014-11-22 23:44:28 +11:00
Sebastian McKenzie
717e6df407 use Array.from on single block array comprehensions - closes #199 2014-11-22 23:44:12 +11:00
Sebastian McKenzie
286404c6f2 update changelog for 1.13.0 2014-11-22 23:33:06 +11:00
Sebastian McKenzie
f191fd7883 update #203 test 2014-11-22 23:32:03 +11:00
Sebastian McKenzie
74f36cfaa0 Merge pull request #202 from RReverser/webworker-runtime
Fix runtime injection in Web Worker.
2014-11-22 23:29:07 +11:00
Sebastian McKenzie
71aed8b269 Merge branch 'ctor-spread-speedup' of https://github.com/RReverser/6to5 2014-11-22 23:28:06 +11:00
Sebastian McKenzie
9e6b0b45b3 Revert "Merge pull request #203 from RReverser/ctor-spread-speedup"
This reverts commit 714ca9fbc8, reversing
changes made to d50d4972a7.
2014-11-22 23:27:39 +11:00
Sebastian McKenzie
7bbb3725d4 bump next release version 2014-11-22 23:26:39 +11:00
Sebastian McKenzie
1210c92405 remove hound.yml 2014-11-22 23:26:39 +11:00
Sebastian McKenzie
714ca9fbc8 Merge pull request #203 from RReverser/ctor-spread-speedup
Speed up constructor spreads.
2014-11-22 23:22:53 +11:00
Ingvar Stepanyan
60713f0e5f Speed up constructor spreads.
Replace slow .bind with manual .create+.apply.
Gives up to 19x speed up depending on browser.

http://jsperf.com/apply-constructor
2014-11-22 14:22:50 +02:00
Ingvar Stepanyan
f1f5f8bb27 Speed up constructor spreads.
Replace slow .bind with manual .create+.apply.
Gives up to 19x speed up depending on browser.

http://jsperf.com/apply-constructor
2014-11-22 14:20:55 +02:00
Ingvar Stepanyan
a69f095720 Fix runtime injection in Web Worker.
Web Workers don't have `window` object but they have `self`
(which is available in regular windows as well).
2014-11-22 14:14:42 +02:00
Sebastian McKenzie
d50d4972a7 use experimental option in generation tests 2014-11-21 19:40:05 +11:00
Sebastian McKenzie
bd91bbee71 put experimental ES7 features behind a flag --experimental and experimental option 2014-11-21 19:36:35 +11:00
Sebastian McKenzie
8b46cce466 v1.12.26 2014-11-21 17:10:54 +11:00
Sebastian McKenzie
defa9108bd support computed property destructuring 2014-11-21 17:09:31 +11:00
Sebastian McKenzie
6b1d9b49b7 use generateUidIdentifier over the long form 2014-11-21 17:09:15 +11:00
Sebastian McKenzie
4e333cf357 add arrayify and regexify tests, add destructuring assignment expression statement only test 2014-11-21 17:08:56 +11:00
Sebastian McKenzie
ddcd7ab28d v1.12.25 2014-11-20 21:30:08 +11:00
Sebastian McKenzie
4b8a4492ba remove unused Scope variable 2014-11-20 21:29:00 +11:00
Sebastian McKenzie
4256a9960c update acorn-6to5 - fixes #195 2014-11-20 21:28:07 +11:00
Sebastian McKenzie
ecb695c30c add 1.12.25 changelog 2014-11-20 21:18:31 +11:00
Sebastian McKenzie
db97f665ed remove scope from generator visitor 2014-11-20 21:18:21 +11:00
Sebastian McKenzie
931b68dc5d use generateUidIdentifier instead of generateUid 2014-11-20 21:18:11 +11:00
Sebastian McKenzie
b5feaf7c2f remove dead code 2014-11-20 21:17:57 +11:00
Sebastian McKenzie
d82683f598 remova via regenerator from features 2014-11-20 21:10:35 +11:00
Sebastian McKenzie
6772f5a74f update ast-types, es6-shim, chokidar, estraverse and private 2014-11-20 21:10:23 +11:00
Sebastian McKenzie
a90f133918 update Scope arguments 2014-11-20 21:09:38 +11:00
Sebastian McKenzie
71ad511322 add File::generateUidIdentifier method 2014-11-20 21:08:33 +11:00
Sebastian McKenzie
ff6677a4b7 v1.12.24 2014-11-20 16:56:29 +11:00
Sebastian McKenzie
ac5e0ad392 add changelog for 1.12.24 2014-11-20 16:54:46 +11:00
Sebastian McKenzie
0a25618c34 collect references that haven't been declared in scope - fixes #173 and fixes #175 2014-11-20 16:53:22 +11:00
Sebastian McKenzie
984c048591 v1.12.23 2014-11-20 16:03:53 +11:00
Sebastian McKenzie
5867e24886 remove unused variables 2014-11-20 16:02:56 +11:00
Sebastian McKenzie
02d7cdc701 changelog for 1.12.23 2014-11-20 16:02:15 +11:00
Sebastian McKenzie
d3b3febfeb finish missing code examples in features 2014-11-20 16:02:10 +11:00
Sebastian McKenzie
7fccf98c10 small performance improvements 2014-11-20 15:09:20 +11:00
Sebastian McKenzie
4a1c393bdb inherit generator comments and add block hoisting - fixes #196 2014-11-20 15:09:07 +11:00
Sebastian McKenzie
afaf3fb0c0 v1.12.22 2014-11-20 00:51:26 +11:00
Sebastian McKenzie
2152ae9b17 remove unused kind variable 2014-11-20 00:50:18 +11:00
Sebastian McKenzie
b8f5693b5e add 1.12.22 changelog 2014-11-20 00:49:27 +11:00
Sebastian McKenzie
638143700b add whitespace around defineArgs 2014-11-20 00:49:12 +11:00
Sebastian McKenzie
aa7eb9c1c9 remove unused opts arg 2014-11-20 00:49:01 +11:00
Sebastian McKenzie
27ca532896 add 1.12.22 changelog 2014-11-20 00:44:12 +11:00
Sebastian McKenzie
913fbdbd87 Merge pull request #190 from webpro/amd-module-id
Make AMD module id's optional
2014-11-20 00:42:53 +11:00
Sebastian McKenzie
fb39df71eb support array destructuring on iterables - fixes #194 2014-11-19 21:10:40 +11:00
Sebastian McKenzie
102a566b1d ensure newlines at end of transformation tests 2014-11-19 21:09:50 +11:00
Lars Kappert
b924e3deb5 Rename to "--amd-module-ids" 2014-11-19 08:55:16 +01:00
Lars Kappert
ef21724a9c Update docs 2014-11-19 08:52:33 +01:00
Lars Kappert
fdad51b53b Revert "update umd and amd tests with new moduleName option"
This reverts commit 5409691a3a.
2014-11-19 08:45:58 +01:00
Lars Kappert
df0e4f6431 Reuse Formatter::getModuleName(), fix opts 2014-11-19 08:43:28 +01:00
Lars Kappert
a37f2093bc Merge branch 'master' of github.com:6to5/6to5 into amd-module-id
Conflicts:
	lib/6to5/file.js
	lib/6to5/transformation/modules/umd.js
2014-11-19 08:39:02 +01:00
Sebastian McKenzie
32b32329b2 make umd module formatter inherit amd constructor 2014-11-19 17:50:42 +11:00
Sebastian McKenzie
d4379d52a7 split up generator transformer emit and explode 2014-11-19 17:48:59 +11:00
Sebastian McKenzie
5c5d811647 bump chokidar and fs-readdir-recursive versions 2014-11-19 17:18:16 +11:00
Sebastian McKenzie
8feb17dd23 normalise whitespace after function keyword 2014-11-19 17:18:05 +11:00
Sebastian McKenzie
55b3f84a2f add sourceRoot and moduleRoot defaults to docs 2014-11-19 13:51:01 +11:00
Sebastian McKenzie
50dee1a754 v1.12.21 2014-11-19 13:49:35 +11:00
Sebastian McKenzie
f80f860bbc changelog for 1.12.21 2014-11-19 13:48:09 +11:00
Sebastian McKenzie
7fc2fe41af fix bug in let scoping resulting in unneccesary replacement - closes #193, closes #185 2014-11-19 13:46:00 +11:00
Sebastian McKenzie
a884a26402 revert acorn-6to5 2014-11-19 13:28:01 +11:00
Sebastian McKenzie
81ec1e1f42 remove unused variable in generators/meta 2014-11-19 12:54:54 +11:00
Sebastian McKenzie
1a27970376 publish acorn-6to5 as an npm package - fixes #187 2014-11-19 12:51:14 +11:00
Sebastian McKenzie
6822c854d4 add interop-require declaration 2014-11-19 12:40:44 +11:00
Sebastian McKenzie
8f4c4be821 generator: add existence check to printJoin 2014-11-19 12:40:35 +11:00
Sebastian McKenzie
5fca095149 use commonInterop module formatter in 6to5/register 2014-11-19 12:40:23 +11:00
Sebastian McKenzie
34599a21cb clean up common-interop module formatter 2014-11-19 12:40:10 +11:00
Sebastian McKenzie
d9d84c60b5 check for existence of node before checking it in let scoping 2014-11-19 12:13:00 +11:00
Sebastian McKenzie
221d78d2e2 arrayify whitelist and blacklist, inherit moduleRoot from sourceRoot and vice versa 2014-11-19 12:13:00 +11:00
Sebastian McKenzie
fa46f60655 expose util as _util 2014-11-19 12:13:00 +11:00
Sebastian McKenzie
03ce52fb7c use regexify and arrayify in register options 2014-11-19 12:13:00 +11:00
Sebastian McKenzie
0df0c696a9 add util.arrayify and util.regexify 2014-11-19 12:12:59 +11:00
Sebastian McKenzie
21b7f4120e add assertion checks into types 2014-11-19 12:12:59 +11:00
Sebastian McKenzie
f43a3dec4b more regenerator spring cleaning 2014-11-19 12:12:59 +11:00
Sebastian McKenzie
cacee5c625 Merge pull request #191 from Naddiseo/commonjs-interop
Added an interop commonjs loader.
2014-11-19 12:09:00 +11:00
Sebastian McKenzie
553c90ae75 Merge pull request #192 from Naddiseo/function-modules
Allow module transformers to be directly passed into opts.
2014-11-19 12:06:02 +11:00
Richard Eames
bc3502d695 Allow module transformers to be directly passed into opts. 2014-11-18 15:29:59 -07:00
Richard Eames
6ae03a5dce Added an interop commonjs loader. 2014-11-18 15:25:12 -07:00
Lars Kappert
9895711bf4 Improve performance 2014-11-18 22:15:02 +01:00
Lars Kappert
d2724554cc Make module id's for AMD body in UMD optional as well 2014-11-18 22:12:03 +01:00
Lars Kappert
8db466c698 Make AMD module id's optional 2014-11-18 22:04:41 +01:00
Sebastian McKenzie
68ef2d545e Merge pull request #188 from brentburg/webpack-return
Webpack doesn't like return outside of a function in a module
2014-11-19 01:14:07 +11:00
Brent Burgoyne
861b9e68d3 Deleted uneeded _runtime.js 2014-11-18 07:13:12 -07:00
Brent Burgoyne
a0eb108cd4 Remove global existence check 2014-11-18 07:10:47 -07:00
Brent Burgoyne
756aef6adc Instead of returning early, conditionally require actual runtime (./_runtime.js)
Fix this error with webpack:

ERROR in ./~/6to5/lib/6to5/transformation/transformers/generators/runtime.js
Module parse failed: /[...]/node_modules/6to5/lib/6to5/transformation/transformers/generators/runtime.js Line 12: Illegal return statement
You may need an appropriate loader to handle this file type.
|
| if (typeof global.regeneratorRuntime === "object") {
  |   return;
  |
}
|
 @ ./~/6to5/lib/6to5/polyfill.js 6:0-59
2014-11-18 06:55:39 -07:00
Sebastian McKenzie
7b74c1c8ec more generator spring cleaning 2014-11-17 17:30:41 +11:00
Sebastian McKenzie
8e115ef3ed regenerator spring cleaning 2014-11-17 17:04:04 +11:00
Sebastian McKenzie
b9a6cf35b7 Merge pull request #184 from thejameskyle/support-table
Sort comparison table by most es6 support and split into two groups
2014-11-17 16:50:24 +11:00
James Kyle
2e22de71b4 Sort comparison table by most es6 support and split into two groups 2014-11-16 21:49:19 -08:00
Sebastian McKenzie
a077c75c8c v1.12.20 2014-11-17 14:24:31 +11:00
Sebastian McKenzie
c0b03e8126 append sourceMappingURL when using bin/6to5 and output sourcemaps - fixes #183 2014-11-17 14:22:25 +11:00
187 changed files with 2470 additions and 1818 deletions

View File

@@ -1,3 +0,0 @@
java_script:
enabled: true
config_file: .jshintrc

View File

@@ -1,6 +1,54 @@
# 1.13.2
* Optimise `Array.from` usage by adding a helper method.
* Upgrade `acorn-6to5`.
# 1.13.1
* Fix constructor spread optimisation. Thanks [@zloirock](https://github.com/zloirock).
# 1.13.0
* Put experimental ES7 features behind a flag `--experimental` and `experimental` option.
* Constructor spread performance increase. Thanks [@RReverser](https://github.com/RReverser).
* Use `self` instead of `window` in the optional 6to5 runtime. Thanks [@RReverser](https://github.com/RReverser).
# 1.12.26
* Support computed property destructuring.
# 1.12.25
* Update `acorn-6to5`, `ast-types`, `es6-shim`, `chokidar`, `estraverse` and `private`.
# 1.12.24
* Collect references that haven't been declared in scope.
# 1.12.23
* Fix generator function export hoisting.
# 1.12.22
* Update `fs-readdir-recursive` and `chokidar`.
* Support array destructuring on iterables.
* Make amd module id optional. Thanks [@webpro](https://github.com/webpro).
# 1.12.21
* Fix unneccesary let scoping replacement.
* Add `commonInterop` module formatter. Thanks [@Naddiseo](https://github.com/Naddiseo).
* Fix `return` outside of function body bug. Thanks [@brentburg](https://github.com/brentburg).
* Add more flexible option types.
# 1.12.20
* Append `sourceMappingURL` when using `bin/6to5` and output sourcemaps.
# 1.12.19
* Add `comments` option and `--remove-comments` flag. Thanks @[webpro](htps://github.com/webpro)!
* Add `comments` option and `--remove-comments` flag. Thanks [@webpro](htps://github.com/webpro).
* Embed `regenerator`.
# 1.12.18
@@ -9,7 +57,7 @@
# 1.12.17
* Add `moduleName`, `sourceRoot` and `filenameRelative` options - thanks @[darvelo](https://github.com/darvelo)!
* Add `moduleName`, `sourceRoot` and `filenameRelative` options. Thanks [@darvelo](https://github.com/darvelo).
* Traversal optimisations.
# 1.12.16

View File

@@ -19,7 +19,9 @@ module.exports = function (commander, filenames, opts) {
mkdirp.sync(up);
if (commander.sourceMaps) {
fs.writeFileSync(dest + ".map", JSON.stringify(data.map));
var mapLoc = dest + ".map";
data.code = util.addSourceMappingUrl(data.code, mapLoc);
fs.writeFileSync(mapLoc, JSON.stringify(data.map));
}
fs.writeFileSync(dest, data.code);

View File

@@ -56,7 +56,9 @@ module.exports = function (commander, filenames) {
if (commander.outFile) {
if (commander.sourceMaps) {
fs.writeFileSync(commander.outFile + ".map", JSON.stringify(result.map));
var mapLoc = commander.outFile + ".map";
result.code = util.addSourceMappingUrl(result.code, mapLoc);
fs.writeFileSync(mapLoc, JSON.stringify(result.map));
}
fs.writeFileSync(commander.outFile, result.code);

View File

@@ -11,6 +11,7 @@ commander.option("-s, --source-maps", "Save source map alongside the compiled co
commander.option("-f, --filename [filename]", "Filename to use when reading from stdin - this will be used in source-maps, errors etc [stdin]", "stdin");
commander.option("-w, --watch", "Recompile files on changes");
commander.option("-r, --runtime", "Replace 6to5 declarations with references to a runtime");
commander.option("-e, --experimental", "Enable experimental support for proposed ES7 features");
commander.option("-m, --modules [modules]", "Module formatter type to use [common]", "common");
commander.option("-w, --whitelist [whitelist]", "Whitelist of transformers to ONLY use", util.list);
@@ -18,6 +19,7 @@ commander.option("-b, --blacklist [blacklist]", "Blacklist of transformers to NO
commander.option("-o, --out-file [out]", "Compile all input files into a single file");
commander.option("-d, --out-dir [out]", "Compile an input directory of modules into an output directory");
commander.option("-c, --remove-comments", "Remove comments from the compiled code", false);
commander.option("-a, --amd-module-ids", "Insert module id in AMD modules", false);
commander.on("--help", function(){
var outKeys = function (title, obj) {
@@ -86,6 +88,8 @@ if (errors.length) {
exports.opts = {
sourceMapName: commander.outFile,
amdModuleIds: commander.amdModuleIds,
experimental: commander.experimental,
blacklist: commander.blacklist,
whitelist: commander.whitelist,
sourceMap: commander.sourceMaps || commander.sourceMapsInline,

View File

@@ -1,6 +1,7 @@
var readdir = require("fs-readdir-recursive");
var index = require("./index");
var util = require("../../lib/6to5/util");
var path = require("path");
var to5 = require("../../lib/6to5");
var fs = require("fs");
var _ = require("lodash");
@@ -11,6 +12,10 @@ exports.readdirFilter = function (filename) {
});
};
exports.addSourceMappingUrl = function (code, loc) {
return code + "\n//# sourceMappingURL=" + path.basename(loc);
};
exports.transform = function (filename, code, opts) {
opts = _.extend(opts || {}, index.opts);
opts.filename = filename;

View File

@@ -8,10 +8,11 @@ var util = require("../lib/6to5/util");
var vm = require("vm");
var _ = require("lodash");
commander.option("-e, --eval [script]", "evaluate script");
commander.option("-p, --print", "evaluate script and print result");
commander.option("-i, --ignore [regex]", "ignore all files that match this regex when using the require hook");
commander.option("-x, --extensions [extensions]", "list of extensions to hook into [.es6,.js]", util.list);
commander.option("-e, --eval [script]", "Evaluate script");
commander.option("-p, --print", "Evaluate script and print result");
commander.option("-i, --ignore [regex]", "Ignore all files that match this regex when using the require hook");
commander.option("-x, --extensions [extensions]", "List of extensions to hook into [.es6,.js]");
commander.option("-r, --experimental", "Enable experimental support for proposed ES7 features");
var pkg = require("../package.json");
commander.version(pkg.version);
@@ -20,17 +21,11 @@ commander.parse(process.argv);
//
var registerOpts = {};
if (commander.ignore) {
registerOpts.ignoreRegex = new RegExp(commander.ignore);
}
if (commander.extensions && commander.extensions.length) {
registerOpts.extensions = commander.extensions;
}
to5.register(registerOpts);
to5.register({
experimental: commander.experimental,
extensions: commander.extensions,
ignore: commander.ignore
});
//

View File

@@ -5,6 +5,16 @@
The [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js)
and an [ES6 polyfill](polyfill.md) are required in order for generators to work.
### Async/Comprehensions
[Experimental support](usage.md#experimental) must be enabled for these proposed
ES7 features to work.
### Array comprehension/Array destructuring/Spread
An [ES6 polyfill](polyfill.md) is required. More specifically a polyfill for
`Array.isArray` and `Array.from`.
## Classes
Built-in classes such as `Date`, `Array` and `DOM` cannot be subclassed due to
@@ -31,13 +41,13 @@ class Bar extends Foo {
}
```
## Constructor spread
Constructor spreads do not currently support built-ins. ie.
`new Array(...items)`.
## For-of
A polyfill is required for for-of functionality that implements `Symbol` and
adds `prototype[Symbol.iterator]` behaviour to built-ins. Using the polyfills
specified in [polyfill](polyfill.md) suffices.
## Spread
An [ES6 polyfill](polyfill.md) is required in order for spread to work. More
specifically a polyfill for `Array.from`.

View File

@@ -56,31 +56,42 @@ better suited if you'd like a full ES6 environment with polyfills and all.
## Comparison to other transpilers
| | 6to5 | Traceur | esnext | es6now | es6-transpiler | jstransform |
| ---------------------------- | ---- | ------- | ------ | ------ | -------------- | ----------- |
| No runtime | ✓ | | | | ✓ | ✓ |
| Source maps | ✓ | ✓ | ✓ | | ✓ | ✓ |
| No compiler global pollution | ✓ | | ✓ | | ✓ | ✓ |
| Browser support | ✓ | | ✓ | | | |
| Array comprehension | ✓ | | | | ✓ | |
| Arrow functions | ✓ | ✓ | | ✓ | ✓ | |
| Async functions | ✓ | ✓ | ✓ | | | |
| Classes | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Computed property names | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Constants | ✓ | ✓ | | | ✓ | |
| Default parameters | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Destructuring | ✓ | ✓ | ✓ | ✓ | ✓ | |
| For-of | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Generators | ✓ | ✓ | | | | |
| Generator comprehension | ✓ | ✓ | | | | |
| Let scoping | ✓ | ✓ | | | ✓ | |
| Modules | ✓ | ✓ | | ✓ | | |
| Property method assignment | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Property name shorthand | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Rest parameters | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Spread | ✓ | ✓ | | ✓ | | |
| Template literals | ✓ | ✓ | | ✓ | | |
| Unicode regex | ✓ | ✓ | | | | |
### Features
| | 6to5 | Traceur | es6-transpiler | esnext | es6now | jstransform |
| ---------------------------- | ---- | ------- | -------------- | ------ | ------ | ----------- |
| Source maps | ✓ | | ✓ | ✓ | | ✓ |
| No compiler global pollution | ✓ | | ✓ | ✓ | | |
| No runtime | ✓ | | ✓ | | | ✓ |
| Browser support | ✓ | ✓ | | ✓ | | |
### Language Support
| | 6to5 | Traceur | es6-transpiler | esnext | es6now | jstransform |
| ---------------------------- | ----- | ------- | -------------- | ------ | ------ | ----------- |
| Array comprehension | ✓ | ✓ | ✓ | | | |
| Arrow functions | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Async functions | ✓ | ✓ | | | | |
| Classes | ✓ | ✓ | | | ✓ | |
| Computed property names | ✓ | ✓ | | ✓ | ✓ | |
| Constants | ✓ | ✓ | | | | |
| Default parameters | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Destructuring | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| For-of | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Generators | ✓ | ✓ | | ✓ | | |
| Generator comprehension | ✓ | ✓ | | | | |
| Let scoping | ✓ | ✓ | | | | |
| Modules | ✓ | ✓ | | | ✓ | |
| Property method assignment | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Property name shorthand | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Rest parameters | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Spread | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Template literals | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Unicode regex | ✓ | ✓ | ✓ | | | |
### [Traceur](https://github.com/google/traceur-compiler)

View File

@@ -1,6 +1,6 @@
# Features
## Array comprehension
## Array comprehension ([experimental](usage.md#experimental))
```javascript
var results = [for (c of customers) if (c.city == "Seattle") { name: c.name, age: c.age }]
@@ -31,7 +31,7 @@ var bob = {
};
```
## Async functions
## Async functions ([experimental](usage.md#experimental))
```javascript
async function chainAnimationsAsync(elem, animations) {
@@ -133,13 +133,31 @@ for (var i of [1, 2, 3]) {
## Generators
```javascript
function* fibonacci() {
var pre = 0, cur = 1;
for (;;) {
var temp = pre;
pre = cur;
cur += temp;
yield cur;
}
}
for (var n of fibonacci()) {
// truncate the sequence at 1000
if (n > 1000) break;
console.log(n);
}
```
## Generator comprehension
## Generator comprehension ([experimental](usage.md#experimental))
```javascript
var nums = [1, 2, 3, 4, 5, 6];
var multiples = (for (i of nums) if (i % 2) i * i);
assert.equal(multiples.next().value, 1);
assert.equal(multiples.next().value, 9);
assert.equal(multiples.next().value, 25);
```
## Let scoping
@@ -153,7 +171,17 @@ for (let i in arr) {
## Modules
```javascript
import "foo";
import foo from "foo";
import * as foo from "foo";
import {bar} from "foo";
import {foo as bar} from "foo";
export { test };
export var test = 5;
export function test() {}
export default test;
```
## Numeric literals

View File

@@ -3,7 +3,7 @@
- **Readable** - formatting is retained if possible so your generated code is as similar as possible.
- **Extensible** - with a large range of [plugins](plugins.md) and **browser support**.
- **Lossless** - **source map support** so you can debug your compiled code with ease.
- **Compact** - maps directly to the equivalent ES5 with **no runtime**[\*](caveats.md#generators).
- **Compact** - maps directly to the equivalent ES5 with **no runtime**[\*](caveats.md).
## Installation
@@ -31,8 +31,8 @@ And it doesn't end here! To see all the ways you can use 6to5, check out the
## [Features](features.md)
- [Array comprehension](features.md#array-comprehension)
- [Async functions](features.md#async-functions) via [regenerator](https://github.com/facebook/regenerator)
- [Array comprehension](features.md#array-comprehension) ([experimental](usage.md#experimental))
- [Async functions](features.md#async-functions) ([experimental](usage.md#experimental))
- [Arrow functions](features.md#arrow-functions)
- [Classes](features.md#classes)
- [Computed property names](features.md#computed-property-names)
@@ -40,8 +40,8 @@ And it doesn't end here! To see all the ways you can use 6to5, check out the
- [Default parameters](features.md#default-parameters)
- [Destructuring](features.md#destructuring)
- [For-of](features.md#for-of)
- [Generators](features.md#generators) via [regenerator](https://github.com/facebook/regenerator)
- [Generator comprehension](features.md#generator-comprehension)
- [Generators](features.md#generators)
- [Generator comprehension](features.md#generator-comprehension) ([experimental](usage.md#experimental))
- [Let scoping](features.md#let-scoping)
- [Modules](features.md#modules)
- [Numeric literals](features.md#numeric-literals)

View File

@@ -66,7 +66,7 @@ export function bar() {
**Out**
```javascript
define("filename", ["exports", "foo"], function (exports, _foo) {
define(["exports", "foo"], function (exports, _foo) {
exports.bar = bar;
var foo = _foo.default;
@@ -77,6 +77,12 @@ define("filename", ["exports", "foo"], function (exports, _foo) {
});
```
You can optionally specify to include the module id (using the `--amd-module-id` argument):
```javascript
define("filename", ["exports", "foo"], function (exports, _foo) {})
```
### UMD
**In**
@@ -94,7 +100,7 @@ export function bar() {
```javascript
(function (factory) {
if (typeof define === "function" && define.amd) {
define("filename", ["exports", "foo"], factory);
define(["exports", "foo"], factory);
} else if (typeof exports !== "undefined") {
factory(exports, require("foo"));
}

View File

@@ -115,12 +115,19 @@ to5.transformFile("filename.js", options, function (err, result) {
sourceFileName: "filename",
// The root from which all sources are relative
// Default: `moduleRoot` option.
sourceRoot: "assets/scripts",
// Optional prefix for the AMD module formatter that will be prepend to the
// filename on module definitions
// Default: `sourceRoot` option.
moduleRoot: "my-app",
// If truthy, insert an explicit id for each defined AMD module.
// By default, AMD modules are anonymous.
// Default: false
amdModuleIds: true,
// Optionally replace all 6to5 helper declarations with a referenece to this
// variable. If set to `true` then the default namespace is used "to5Runtime".
// Default: false
@@ -128,7 +135,11 @@ to5.transformFile("filename.js", options, function (err, result) {
// Output comments in generated output
// Default: true
comments: false
comments: false,
// Enable support for experimental ES7 features
// Default: false
experimental: true
}
```
@@ -174,3 +185,11 @@ require("6to5/register")({
extensions: [".js", ".es6"]
});
```
## Experimental
6to5 also has experimental support for ES7 proposals. You can enable this with
the `experimental: true` option when using the [Node API](#node) or
`--experimental` when using the [CLI](#cli).
**NOTE:** That these are subject to change as their proposal status progresses.

View File

@@ -19,26 +19,38 @@ function File(opts) {
}
File.declarations = ["extends", "class-props", "slice", "apply-constructor",
"tagged-template-literal"];
"tagged-template-literal", "interop-require", "to-array"];
File.normaliseOptions = function (opts) {
opts = _.cloneDeep(opts || {});
_.defaults(opts, {
whitespace: true,
blacklist: [],
whitelist: [],
sourceMap: false,
comments: true,
filename: "unknown",
modules: "common",
runtime: false,
code: true
experimental: false,
whitespace: true,
blacklist: [],
whitelist: [],
sourceMap: false,
comments: true,
filename: "unknown",
modules: "common",
runtime: false,
code: true
});
// normalise windows path separators to unix
opts.filename = opts.filename.replace(/\\/g, "/");
opts.blacklist = util.arrayify(opts.blacklist);
opts.whitelist = util.arrayify(opts.whitelist);
_.defaults(opts, {
moduleRoot: opts.sourceRoot
});
_.defaults(opts, {
sourceRoot: opts.moduleRoot
});
_.defaults(opts, {
filenameRelative: opts.filename
});
@@ -58,8 +70,16 @@ File.normaliseOptions = function (opts) {
return opts;
};
File.prototype.toArray = function (node) {
if (t.isArrayExpression(node)) {
return node;
} else {
return t.callExpression(this.addDeclaration("to-array"), [node]);
}
};
File.prototype.getModuleFormatter = function (type) {
var ModuleFormatter = transform.moduleFormatters[type];
var ModuleFormatter = _.isFunction(type) ? type : transform.moduleFormatters[type];
if (!ModuleFormatter) {
var loc = util.resolve(type);
@@ -136,7 +156,7 @@ File.prototype.parse = function (code) {
File.prototype.transform = function (ast) {
this.ast = ast;
this.scope = new Scope(null, ast.program);
this.scope = new Scope(ast.program);
var self = this;
@@ -185,6 +205,10 @@ File.prototype.generateUid = function (name, scope) {
return uid;
};
File.prototype.generateUidIdentifier = function (name, scope) {
return t.identifier(this.generateUid(name, scope));
};
File.prototype._generateUid = function (name) {
var uids = this.uids;
var i = uids[name] || 1;

View File

@@ -165,6 +165,8 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
};
CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
if (!nodes || !nodes.length) return;
opts = opts || {};
var self = this;

View File

@@ -78,7 +78,7 @@ exports.Literal = function (node) {
val = JSON.stringify(val);
// escape unicode characters
val = val.replace(/[\u007f-\uffff]/g, function(c) {
val = val.replace(/[\u007f-\uffff]/g, function (c) {
return "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4);
});

View File

@@ -17,6 +17,9 @@ exports.polyfill = function () {
exports.canCompile = util.canCompile;
// do not use this - this is for use by official maintained 6to5 plugins
exports._util = util;
exports.transform = transform;
exports.transformFile = function (filename, opts, callback) {

View File

@@ -1,6 +1,7 @@
require("./polyfill");
var sourceMapSupport = require("source-map-support");
var util = require("./util");
var to5 = require("./index");
var _ = require("lodash");
@@ -56,23 +57,25 @@ blacklistTest("unicodeRegex", function () { new RegExp("foo", "u"); });
//
var ignoreRegex = /node_modules/;
var transformOpts = {};
var ignoreRegex = /node_modules/;
var onlyRegex;
var whitelist = [];
var exts = {};
var maps = {};
var old = require.extensions[".js"];
var whitelist = [];
var exts = {};
var maps = {};
var old = require.extensions[".js"];
var loader = function (m, filename) {
if ((ignoreRegex && ignoreRegex.test(filename)) || (onlyRegex && !onlyRegex.test(filename))) {
return old.apply(this, arguments);
}
var result = to5.transformFileSync(filename, {
var result = to5.transformFileSync(filename, _.extend({
whitelist: whitelist,
blacklist: blacklist,
sourceMap: true
});
sourceMap: true,
modules: "commonInterop"
}, transformOpts));
maps[filename] = result.map;
@@ -100,11 +103,10 @@ module.exports = function (opts) {
if (_.isRegExp(opts)) opts = { ignore: opts };
if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex;
if (opts.only != null) onlyRegex = opts.only;
if (opts.ignore != null) ignoreRegex = opts.ignore;
if (opts.only != null) onlyRegex = util.regexify(opts.only);
if (opts.ignore != null) ignoreRegex = util.regexify(opts.ignore);
if (opts.extensions) hookExtensions(opts.extensions);
if (opts.extensions) hookExtensions(util.arrayify(opts.extensions));
if (opts.blacklist) blacklist = opts.blacklist;
if (opts.whitelist) whitelist = opts.whitelist;
_.extend(transformOpts, opts);
};

View File

@@ -8,15 +8,13 @@ module.exports = function (namespace) {
namespace = t.identifier(t.toIdentifier(namespace || "to5Runtime"));
var body = [];
var container = t.functionExpression(null, [], t.blockStatement(body));
var tree = t.program([t.expressionStatement(t.callExpression(container, []))]);
body.push(util.template("self-global", true));
var container = t.functionExpression(null, [t.identifier("global")], t.blockStatement(body));
var tree = t.program([t.expressionStatement(t.callExpression(container, [util.template("self-global")]))]);
body.push(t.variableDeclaration("var", [
t.variableDeclarator(
namespace,
t.assignmentExpression("=", t.memberExpression(t.identifier("self"), namespace), t.objectExpression([]))
t.assignmentExpression("=", t.memberExpression(t.identifier("global"), namespace), t.objectExpression([]))
)
]));

View File

@@ -1,5 +1,5 @@
(function (Constructor, args) {
var bindArgs = [null].concat(args);
var Factory = Constructor.bind.apply(Constructor, bindArgs);
return new Factory;
var instance = Object.create(Constructor.prototype);
var result = Constructor.apply(instance, args);
return result != null && (typeof result == "object" || typeof result == "function") ? result : instance;
});

View File

@@ -0,0 +1 @@
Array.from(VALUE);

View File

@@ -0,0 +1,3 @@
(function (obj) {
return obj && (obj["default"] || obj);
})

View File

@@ -1 +1 @@
var self = typeof global === "undefined" ? window : global;
typeof global === "undefined" ? self : global

View File

@@ -0,0 +1,3 @@
(function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
});

View File

@@ -29,10 +29,13 @@ AMDFormatter.prototype.transform = function (ast) {
var params = _.values(this.ids);
params.unshift(t.identifier("exports"));
var moduleName = this.getModuleName();
var container = t.functionExpression(null, params, t.blockStatement(body));
var call = t.callExpression(t.identifier("define"), [t.literal(moduleName), names, container]);
var defineArgs = [names, container];
var moduleName = this.getModuleName();
if (moduleName) defineArgs.unshift(t.literal(moduleName));
var call = t.callExpression(t.identifier("define"), defineArgs);
program.body = [t.expressionStatement(call)];
};
@@ -42,6 +45,10 @@ AMDFormatter.prototype.getModuleName = function () {
var filenameRelative = opts.filenameRelative;
var moduleName = "";
if (!opts.amdModuleIds) {
return null;
}
if (opts.moduleRoot) {
moduleName = opts.moduleRoot + "/";
}
@@ -71,7 +78,7 @@ AMDFormatter.prototype._push = function (node) {
if (ids[id]) {
return ids[id];
} else {
return this.ids[id] = t.identifier(this.file.generateUid(id));
return this.ids[id] = this.file.generateUidIdentifier(id);
}
};

View File

@@ -0,0 +1,28 @@
module.exports = CommonJSInteropFormatter;
var CommonJSFormatter = require("./common");
var util = require("../../util");
var t = require("../../types");
function CommonJSInteropFormatter(file) {
this.file = file;
}
util.inherits(CommonJSInteropFormatter, CommonJSFormatter);
CommonJSInteropFormatter.prototype.importSpecifier = function (specifier, node, nodes) {
var variableName = t.getSpecifierName(specifier);
// import foo from "foo";
if (specifier.default) {
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(variableName,
t.callExpression(this.file.addDeclaration("interop-require"), [util.template("require", {
MODULE_NAME: node.source.raw
})])
)
]));
} else {
CommonJSFormatter.prototype.importSpecifier.apply(this, arguments);
}
};

View File

@@ -5,9 +5,8 @@ var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
function UMDFormatter(file) {
this.file = file;
this.ids = {};
function UMDFormatter() {
AMDFormatter.apply(this, arguments);
}
util.inherits(UMDFormatter, AMDFormatter);
@@ -32,10 +31,12 @@ UMDFormatter.prototype.transform = function (ast) {
// runner
var defineArgs = [t.arrayExpression([t.literal("exports")].concat(names))];
var moduleName = this.getModuleName();
if (moduleName) defineArgs.unshift(t.literal(moduleName));
var runner = util.template("umd-runner-body", {
AMD_ARGUMENTS: [t.literal(moduleName), t.arrayExpression([t.literal("exports")].concat(names))],
AMD_ARGUMENTS: defineArgs,
COMMON_ARGUMENTS: names.map(function (name) {
return t.callExpression(t.identifier("require"), [name]);

View File

@@ -20,10 +20,11 @@ transform._ensureTransformerNames = function (type, keys) {
transform.transformers = {};
transform.moduleFormatters = {
common: require("./modules/common"),
ignore: require("./modules/ignore"),
amd: require("./modules/amd"),
umd: require("./modules/umd")
common: require("./modules/common"),
commonInterop: require("./modules/common-interop"),
ignore: require("./modules/ignore"),
amd: require("./modules/amd"),
umd: require("./modules/umd")
};
_.each({

View File

@@ -6,11 +6,11 @@ var go = function (getBody, node, file, scope) {
var thisId;
var getArgumentsId = function () {
return argumentsId = argumentsId || t.identifier(file.generateUid("arguments", scope));
return argumentsId = argumentsId || file.generateUidIdentifier("arguments", scope);
};
var getThisId = function () {
return thisId = thisId || t.identifier(file.generateUid("this", scope));
return thisId = thisId || file.generateUidIdentifier("this", scope);
};
// traverse the function and find all alias functions so we can alias

View File

@@ -1,12 +1,12 @@
var t = require("../../types");
var _ = require("lodash");
module.exports = function (ast, file) {
var body = ast.program.body;
_.each(file.declarations, function (declar) {
for (var i in file.declarations) {
var declar = file.declarations[i];
body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(declar.uid, declar.node)
]));
});
}
};

View File

@@ -2,7 +2,7 @@ var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
var singleArrayExpression = function (node) {
var single = function (node, file) {
var block = node.blocks[0];
var templateName = "array-expression-comprehension-map";
@@ -11,7 +11,7 @@ var singleArrayExpression = function (node) {
var result = util.template(templateName, {
STATEMENT: node.body,
FILTER: node.filter,
ARRAY: block.right,
ARRAY: file.toArray(block.right),
KEY: block.left
});
@@ -25,7 +25,7 @@ var singleArrayExpression = function (node) {
};
var multiple = function (node, file) {
var uid = file.generateUid("arr");
var uid = file.generateUidIdentifier("arr");
var container = util.template("array-comprehension-container", {
KEY: uid
@@ -73,8 +73,8 @@ exports._build = function (node, buildBody) {
exports.ComprehensionExpression = function (node, parent, file) {
if (node.generator) return;
if (node.blocks.length === 1 && t.isArrayExpression(node.blocks[0].right)) {
return singleArrayExpression(node);
if (node.blocks.length === 1) {
return single(node, file);
} else {
return multiple(node, file);
}

View File

@@ -36,7 +36,7 @@ function Class(node, file, scope) {
this.instanceMutatorMap = {};
this.staticMutatorMap = {};
this.hasConstructor = false;
this.className = node.id || t.identifier(file.generateUid("class", scope));
this.className = node.id || file.generateUidIdentifier("class", scope);
this.superName = node.superClass;
}
@@ -58,7 +58,7 @@ Class.prototype.run = function () {
superClassArgument = superClassCallee = getMemberExpressionObject(superName);
} else if (!t.isIdentifier(superName)) {
superClassArgument = superName;
superClassCallee = superName = t.identifier(file.generateUid("ref", this.scope));
superClassCallee = superName = file.generateUidIdentifier("ref", this.scope);
}
}

View File

@@ -11,50 +11,60 @@ var buildVariableAssign = function (kind, id, init) {
}
};
var push = function (kind, nodes, elem, parentId) {
var push = function (opts, nodes, elem, parentId) {
if (t.isObjectPattern(elem)) {
pushObjectPattern(kind, nodes, elem, parentId);
pushObjectPattern(opts, nodes, elem, parentId);
} else if (t.isArrayPattern(elem)) {
pushArrayPattern(kind, nodes, elem, parentId);
pushArrayPattern(opts, nodes, elem, parentId);
} else if (t.isMemberExpression(elem)) {
nodes.push(buildVariableAssign(false, elem, parentId));
} else {
nodes.push(buildVariableAssign(kind, elem, parentId));
nodes.push(buildVariableAssign(opts.kind, elem, parentId));
}
};
var pushObjectPattern = function (kind, nodes, pattern, parentId) {
var pushObjectPattern = function (opts, nodes, pattern, parentId) {
_.each(pattern.properties, function (prop) {
var pattern2 = prop.value;
var patternId2 = t.memberExpression(parentId, prop.key);
var patternId2 = t.memberExpression(parentId, prop.key, prop.computed);
if (t.isPattern(pattern2)) {
push(kind, nodes, pattern2, patternId2);
push(opts, nodes, pattern2, patternId2);
} else {
nodes.push(buildVariableAssign(kind, pattern2, patternId2));
nodes.push(buildVariableAssign(opts.kind, pattern2, patternId2));
}
});
};
var pushArrayPattern = function (kind, nodes, pattern, parentId) {
var pushArrayPattern = function (opts, nodes, pattern, parentId) {
var _parentId = opts.file.generateUidIdentifier("ref", opts.scope);
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(_parentId, opts.file.toArray(parentId))
]));
parentId = _parentId;
_.each(pattern.elements, function (elem, i) {
if (!elem) return;
var newPatternId;
if (t.isSpreadElement(elem)) {
newPatternId = t.callExpression(t.memberExpression(parentId, t.identifier("slice")), [t.literal(i)]);
newPatternId = opts.file.toArray(parentId);
if (+i > 0) {
newPatternId = t.callExpression(t.memberExpression(newPatternId, t.identifier("slice")), [t.literal(i)]);
}
elem = elem.argument;
} else {
newPatternId = t.memberExpression(parentId, t.literal(i), true);
}
push(kind, nodes, elem, newPatternId);
push(opts, nodes, elem, newPatternId);
});
};
var pushPattern = function (opts) {
var kind = opts.kind;
var nodes = opts.nodes;
var pattern = opts.pattern;
var parentId = opts.id;
@@ -62,7 +72,7 @@ var pushPattern = function (opts) {
var scope = opts.scope;
if (!t.isMemberExpression(parentId) && !t.isIdentifier(parentId)) {
var key = t.identifier(file.generateUid("ref", scope));
var key = file.generateUidIdentifier("ref", scope);
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(key, parentId)
@@ -71,7 +81,7 @@ var pushPattern = function (opts) {
parentId = key;
}
push(kind, nodes, pattern, parentId);
push(opts, nodes, pattern, parentId);
};
exports.ForInStatement =
@@ -82,14 +92,18 @@ exports.ForOfStatement = function (node, parent, file, scope) {
var pattern = declar.declarations[0].id;
if (!t.isPattern(pattern)) return;
var key = t.identifier(file.generateUid("ref", scope));
var key = file.generateUidIdentifier("ref", scope);
node.left = t.variableDeclaration(declar.kind, [
t.variableDeclarator(key, null)
]);
var nodes = [];
push(declar.kind, nodes, pattern, key);
push({
kind: declar.kind,
file: file,
scope: scope
}, nodes, pattern, key);
t.ensureBlock(node);
@@ -106,7 +120,7 @@ exports.Function = function (node, parent, file, scope) {
if (!t.isPattern(pattern)) return pattern;
hasDestructuring = true;
var parentId = t.identifier(file.generateUid("ref", scope));
var parentId = file.generateUidIdentifier("ref", scope);
pushPattern({
kind: "var",
@@ -136,12 +150,16 @@ exports.ExpressionStatement = function (node, parent, file, scope) {
var nodes = [];
var ref = t.identifier(file.generateUid("ref", scope));
var ref = file.generateUidIdentifier("ref", scope);
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(ref, expr.right)
]));
push(false, nodes, expr.left, ref);
push({
kind: false,
file: file,
scope: scope
}, nodes, expr.left, ref);
return nodes;
};

View File

@@ -5,7 +5,7 @@ exports.ForOfStatement = function (node, parent, file, scope) {
var left = node.left;
var declar;
var stepKey = t.identifier(file.generateUid("step", scope));
var stepKey = file.generateUidIdentifier("step", scope);
var stepValue = t.memberExpression(stepKey, t.identifier("value"));
if (t.isIdentifier(left)) {
@@ -19,7 +19,7 @@ exports.ForOfStatement = function (node, parent, file, scope) {
}
var node2 = util.template("for-of", {
ITERATOR_KEY: file.generateUid("iterator", scope),
ITERATOR_KEY: file.generateUidIdentifier("iterator", scope),
STEP_KEY: stepKey,
OBJECT: node.right
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var loc = require("../util").loc;
var t = require("../../../../types");
exports.ParenthesizedExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(this.explodeExpression(path.get("expression")));
};
exports.MemberExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.memberExpression(
this.explodeExpression(path.get("object")),
expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property,
expr.computed
));
};
exports.CallExpression = function (expr, path, explodeViaTempVar, finish) {
var oldCalleePath = path.get("callee");
var newCallee = this.explodeExpression(oldCalleePath);
// If the callee was not previously a MemberExpression, then the
// CallExpression was "unqualified," meaning its `this` object should
// be the global object. If the exploded expression has become a
// MemberExpression, then we need to force it to be unqualified by
// using the (0, object.property)(...) trick; otherwise, it will
// receive the object of the MemberExpression as its `this` object.
if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) {
newCallee = t.sequenceExpression([
t.literal(0),
newCallee
]);
}
return finish(t.callExpression(
newCallee,
path.get("arguments").map(function (argPath) {
return explodeViaTempVar(null, argPath);
})
));
};
exports.NewExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.newExpression(
explodeViaTempVar(null, path.get("callee")),
path.get("arguments").map(function (argPath) {
return explodeViaTempVar(null, argPath);
})
));
};
exports.ObjectExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.objectExpression(
path.get("properties").map(function (propPath) {
return t.property(
propPath.value.kind,
propPath.value.key,
explodeViaTempVar(null, propPath.get("value"))
);
})
));
};
exports.ArrayExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.arrayExpression(
path.get("elements").map(function (elemPath) {
return explodeViaTempVar(null, elemPath);
})
));
};
exports.SequenceExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var lastIndex = expr.expressions.length - 1;
var self = this;
var result;
path.get("expressions").each(function (exprPath) {
if (exprPath.name === lastIndex) {
result = self.explodeExpression(exprPath, ignoreResult);
} else {
self.explodeExpression(exprPath, true);
}
});
return result;
};
exports.LogicalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var after = loc();
var result;
if (!ignoreResult) {
result = this.makeTempVar();
}
var left = explodeViaTempVar(result, path.get("left"));
if (expr.operator === "&&") {
this.jumpIfNot(left, after);
} else {
assert.strictEqual(expr.operator, "||");
this.jumpIf(left, after);
}
explodeViaTempVar(result, path.get("right"), ignoreResult);
this.mark(after);
return result;
};
exports.ConditionalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) {
var elseLoc = loc();
var after = loc();
var test = this.explodeExpression(path.get("test"));
var result;
this.jumpIfNot(test, elseLoc);
if (!ignoreResult) {
result = this.makeTempVar();
}
explodeViaTempVar(result, path.get("consequent"), ignoreResult);
this.jump(after);
this.mark(elseLoc);
explodeViaTempVar(result, path.get("alternate"), ignoreResult);
this.mark(after);
return result;
};
exports.UnaryExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.unaryExpression(
expr.operator,
// Can't (and don't need to) break up the syntax of the argument.
// Think about delete a[b].
this.explodeExpression(path.get("argument")),
!!expr.prefix
));
};
exports.BinaryExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.binaryExpression(
expr.operator,
explodeViaTempVar(null, path.get("left")),
explodeViaTempVar(null, path.get("right"))
));
};
exports.AssignmentExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.assignmentExpression(
expr.operator,
this.explodeExpression(path.get("left")),
this.explodeExpression(path.get("right"))
));
};
exports.UpdateExpression = function (expr, path, explodeViaTempVar, finish) {
return finish(t.updateExpression(
expr.operator,
this.explodeExpression(path.get("argument")),
expr.prefix
));
};
exports.YieldExpression = function (expr, path) {
var after = loc();
var arg = expr.argument && this.explodeExpression(path.get("argument"));
var result;
if (arg && expr.delegate) {
result = this.makeTempVar();
this.emit(t.returnStatement(t.callExpression(
this.contextProperty("delegateYield"), [
arg,
t.literal(result.property.name),
after
]
)));
this.mark(after);
return result;
}
this.emitAssign(this.contextProperty("next"), after);
this.emit(t.returnStatement(arg || null));
this.mark(after);
return this.contextProperty("sent");
};

View File

@@ -0,0 +1,334 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var types = require("ast-types");
var leap = require("../leap");
var util = require("../util");
var t = require("../../../../types");
var runtimeKeysMethod = util.runtimeProperty("keys");
var loc = util.loc;
exports.ExpressionStatement = function (path) {
this.explodeExpression(path.get("expression"), true);
};
exports.LabeledStatement = function (path, stmt) {
this.explodeStatement(path.get("body"), stmt.label);
};
exports.WhileStatement = function (path, stmt, labelId) {
var before = loc();
var after = loc();
this.mark(before);
this.jumpIfNot(this.explodeExpression(path.get("test")), after);
this.leapManager.withEntry(
new leap.LoopEntry(after, before, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.jump(before);
this.mark(after);
};
exports.DoWhileStatement = function (path, stmt, labelId) {
var first = loc();
var test = loc();
var after = loc();
this.mark(first);
this.leapManager.withEntry(
new leap.LoopEntry(after, test, labelId),
function () { this.explode(path.get("body")); }
);
this.mark(test);
this.jumpIf(this.explodeExpression(path.get("test")), first);
this.mark(after);
};
exports.ForStatement = function (path, stmt, labelId) {
var head = loc();
var update = loc();
var after = loc();
if (stmt.init) {
// We pass true here to indicate that if stmt.init is an expression
// then we do not care about its result.
this.explode(path.get("init"), true);
}
this.mark(head);
if (stmt.test) {
this.jumpIfNot(this.explodeExpression(path.get("test")), after);
} else {
// No test means continue unconditionally.
}
this.leapManager.withEntry(
new leap.LoopEntry(after, update, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.mark(update);
if (stmt.update) {
// We pass true here to indicate that if stmt.update is an
// expression then we do not care about its result.
this.explode(path.get("update"), true);
}
this.jump(head);
this.mark(after);
};
exports.ForInStatement = function (path, stmt, labelId) {
t.assertIdentifier(stmt.left);
var head = loc();
var after = loc();
var keyIterNextFn = this.makeTempVar();
this.emitAssign(
keyIterNextFn,
t.callExpression(
runtimeKeysMethod,
[this.explodeExpression(path.get("right"))]
)
);
this.mark(head);
var keyInfoTmpVar = this.makeTempVar();
this.jumpIf(
t.memberExpression(
t.assignmentExpression(
"=",
keyInfoTmpVar,
t.callExpression(keyIterNextFn, [])
),
t.identifier("done"),
false
),
after
);
this.emitAssign(
stmt.left,
t.memberExpression(
keyInfoTmpVar,
t.identifier("value"),
false
)
);
this.leapManager.withEntry(
new leap.LoopEntry(after, head, labelId),
function () { this.explodeStatement(path.get("body")); }
);
this.jump(head);
this.mark(after);
};
exports.BreakStatement = function (path, stmt) {
this.emitAbruptCompletion({
type: "break",
target: this.leapManager.getBreakLoc(stmt.label)
});
};
exports.ContinueStatement = function (path, stmt) {
this.emitAbruptCompletion({
type: "continue",
target: this.leapManager.getContinueLoc(stmt.label)
});
};
exports.SwitchStatement = function (path, stmt) {
// Always save the discriminant into a temporary variable in case the
// test expressions overwrite values like context.sent.
var disc = this.emitAssign(
this.makeTempVar(),
this.explodeExpression(path.get("discriminant"))
);
var after = loc();
var defaultLoc = loc();
var condition = defaultLoc;
var caseLocs = [];
var self = this;
// If there are no cases, .cases might be undefined.
var cases = stmt.cases || [];
for (var i = cases.length - 1; i >= 0; --i) {
var c = cases[i];
t.assertSwitchCase(c);
if (c.test) {
condition = t.conditionalExpression(
t.binaryExpression("===", disc, c.test),
caseLocs[i] = loc(),
condition
);
} else {
caseLocs[i] = defaultLoc;
}
}
this.jump(this.explodeExpression(
new types.NodePath(condition, path, "discriminant")
));
this.leapManager.withEntry(
new leap.SwitchEntry(after),
function () {
path.get("cases").each(function (casePath) {
var i = casePath.name;
self.mark(caseLocs[i]);
casePath.get("consequent").each(
self.explodeStatement,
self
);
});
}
);
this.mark(after);
if (defaultLoc.value === -1) {
this.mark(defaultLoc);
assert.strictEqual(after.value, defaultLoc.value);
}
};
exports.IfStatement = function (path, stmt) {
var elseLoc = stmt.alternate && loc();
var after = loc();
this.jumpIfNot(
this.explodeExpression(path.get("test")),
elseLoc || after
);
this.explodeStatement(path.get("consequent"));
if (elseLoc) {
this.jump(after);
this.mark(elseLoc);
this.explodeStatement(path.get("alternate"));
}
this.mark(after);
};
exports.ReturnStatement = function (path) {
this.emitAbruptCompletion({
type: "return",
value: this.explodeExpression(path.get("argument"))
});
};
exports.TryStatement = function (path, stmt) {
var after = loc();
var self = this;
var handler = stmt.handler;
if (!handler && stmt.handlers) {
handler = stmt.handlers[0] || null;
}
var catchLoc = handler && loc();
var catchEntry = catchLoc && new leap.CatchEntry(
catchLoc,
handler.param
);
var finallyLoc = stmt.finalizer && loc();
var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc);
var tryEntry = new leap.TryEntry(
this.getUnmarkedCurrentLoc(),
catchEntry,
finallyEntry
);
this.tryEntries.push(tryEntry);
this.updateContextPrevLoc(tryEntry.firstLoc);
this.leapManager.withEntry(tryEntry, function () {
this.explodeStatement(path.get("block"));
if (catchLoc) {
if (finallyLoc) {
// If we have both a catch block and a finally block, then
// because we emit the catch block first, we need to jump over
// it to the finally block.
this.jump(finallyLoc);
} else {
// If there is no finally block, then we need to jump over the
// catch block to the fall-through location.
this.jump(after);
}
this.updateContextPrevLoc(self.mark(catchLoc));
var bodyPath = path.get("handler", "body");
var safeParam = this.makeTempVar();
this.clearPendingException(tryEntry.firstLoc, safeParam);
var catchScope = bodyPath.scope;
var catchParamName = handler.param.name;
t.assertCatchClause(catchScope.node);
assert.strictEqual(catchScope.lookup(catchParamName), catchScope);
types.visit(bodyPath, {
visitIdentifier: function (path) {
if (path.value.name === catchParamName &&
path.scope.lookup(catchParamName) === catchScope) {
return safeParam;
}
this.traverse(path);
}
});
this.leapManager.withEntry(catchEntry, function () {
this.explodeStatement(bodyPath);
});
}
if (finallyLoc) {
this.updateContextPrevLoc(this.mark(finallyLoc));
this.leapManager.withEntry(finallyEntry, function () {
this.explodeStatement(path.get("finalizer"));
});
this.emit(t.callExpression(
this.contextProperty("finish"),
[finallyEntry.firstLoc]
));
}
});
this.mark(after);
};
exports.ThrowStatement = function (path) {
this.emit(t.throwStatement(
this.explodeExpression(path.get("argument"))
));
};

View File

@@ -0,0 +1,611 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
exports.Emitter = Emitter;
var explodeExpressions = require("./explode-expressions");
var explodeStatements = require("./explode-statements");
var assert = require("assert");
var types = require("ast-types");
var leap = require("../leap");
var meta = require("../meta");
var util = require("../util");
var t = require("../../../../types");
var _ = require("lodash");
var loc = util.loc;
var n = types.namedTypes;
function Emitter(contextId) {
assert.ok(this instanceof Emitter);
t.assertIdentifier(contextId);
// In order to make sure the context object does not collide with
// anything in the local scope, we might have to rename it, so we
// refer to it symbolically instead of just assuming that it will be
// called "context".
this.contextId = contextId;
// An append-only list of Statements that grows each time this.emit is
// called.
this.listing = [];
// A sparse array whose keys correspond to locations in this.listing
// that have been marked as branch/jump targets.
this.marked = [true];
// The last location will be marked when this.getDispatchLoop is
// called.
this.finalLoc = loc();
// A list of all leap.TryEntry statements emitted.
this.tryEntries = [];
// Each time we evaluate the body of a loop, we tell this.leapManager
// to enter a nested loop context that determines the meaning of break
// and continue statements therein.
this.leapManager = new leap.LeapManager(this);
}
// Sets the exact value of the given location to the offset of the next
// Statement emitted.
Emitter.prototype.mark = function (loc) {
t.assertLiteral(loc);
var index = this.listing.length;
if (loc.value === -1) {
loc.value = index;
} else {
// Locations can be marked redundantly, but their values cannot change
// once set the first time.
assert.strictEqual(loc.value, index);
}
this.marked[index] = true;
return loc;
};
Emitter.prototype.emit = function (node) {
if (t.isExpression(node)) node = t.expressionStatement(node);
t.assertStatement(node);
this.listing.push(node);
};
// Shorthand for emitting assignment statements. This will come in handy
// for assignments to temporary variables.
Emitter.prototype.emitAssign = function (lhs, rhs) {
this.emit(this.assign(lhs, rhs));
return lhs;
};
// Shorthand for an assignment statement.
Emitter.prototype.assign = function (lhs, rhs) {
return t.expressionStatement(
t.assignmentExpression("=", lhs, rhs));
};
// Convenience function for generating expressions like context.next,
// context.sent, and context.rval.
Emitter.prototype.contextProperty = function (name, computed) {
return t.memberExpression(
this.contextId,
computed ? t.literal(name) : t.identifier(name),
!!computed
);
};
var volatileContextPropertyNames = {
prev: true,
next: true,
sent: true,
rval: true
};
// A "volatile" context property is a MemberExpression like context.sent
// that should probably be stored in a temporary variable when there's a
// possibility the property will get overwritten.
Emitter.prototype.isVolatileContextProperty = function (expr) {
if (t.isMemberExpression(expr)) {
if (expr.computed) {
// If it's a computed property such as context[couldBeAnything],
// assume the worst in terms of volatility.
return true;
}
if (t.isIdentifier(expr.object) &&
t.isIdentifier(expr.property) &&
expr.object.name === this.contextId.name &&
_.has(volatileContextPropertyNames, expr.property.name)) {
return true;
}
}
return false;
};
// Shorthand for setting context.rval and jumping to `context.stop()`.
Emitter.prototype.stop = function (rval) {
if (rval) {
this.setReturnValue(rval);
}
this.jump(this.finalLoc);
};
Emitter.prototype.setReturnValue = function (valuePath) {
t.assertExpression(valuePath.value);
this.emitAssign(
this.contextProperty("rval"),
this.explodeExpression(valuePath)
);
};
Emitter.prototype.clearPendingException = function (tryLoc, assignee) {
t.assertLiteral(tryLoc);
var catchCall = t.callExpression(
this.contextProperty("catch", true),
[tryLoc]
);
if (assignee) {
this.emitAssign(assignee, catchCall);
} else {
this.emit(catchCall);
}
};
// Emits code for an unconditional jump to the given location, even if the
// exact value of the location is not yet known.
Emitter.prototype.jump = function (toLoc) {
this.emitAssign(this.contextProperty("next"), toLoc);
this.emit(t.breakStatement());
};
// Conditional jump.
Emitter.prototype.jumpIf = function (test, toLoc) {
t.assertExpression(test);
t.assertLiteral(toLoc);
this.emit(t.ifStatement(
test,
t.blockStatement([
this.assign(this.contextProperty("next"), toLoc),
t.breakStatement()
])
));
};
// Conditional jump, with the condition negated.
Emitter.prototype.jumpIfNot = function (test, toLoc) {
t.assertExpression(test);
t.assertLiteral(toLoc);
var negatedTest;
if (t.isUnaryExpression(test) && test.operator === "!") {
// Avoid double negation.
negatedTest = test.argument;
} else {
negatedTest = t.unaryExpression("!", test);
}
this.emit(t.ifStatement(
negatedTest,
t.blockStatement([
this.assign(this.contextProperty("next"), toLoc),
t.breakStatement()
])
));
};
// Returns a unique MemberExpression that can be used to store and
// retrieve temporary values. Since the object of the member expression is
// the context object, which is presumed to coexist peacefully with all
// other local variables, and since we just increment `nextTempId`
// monotonically, uniqueness is assured.
var nextTempId = 0;
Emitter.prototype.makeTempVar = function () {
return this.contextProperty("t" + nextTempId++);
};
Emitter.prototype.getContextFunction = function (id) {
var node = t.functionExpression(
id || null,
[this.contextId],
t.blockStatement([this.getDispatchLoop()]),
false, // Not a generator anymore!
false // Nor an expression.
);
node._aliasFunction = true;
return node;
};
// Turns this.listing into a loop of the form
//
// while (1) switch (context.next) {
// case 0:
// ...
// case n:
// return context.stop();
// }
//
// Each marked location in this.listing will correspond to one generated
// case statement.
Emitter.prototype.getDispatchLoop = function () {
var self = this;
var cases = [];
var current;
// If we encounter a break, continue, or return statement in a switch
// case, we can skip the rest of the statements until the next case.
var alreadyEnded = false;
self.listing.forEach(function (stmt, i) {
if (self.marked.hasOwnProperty(i)) {
cases.push(t.switchCase(t.literal(i), current = []));
alreadyEnded = false;
}
if (!alreadyEnded) {
current.push(stmt);
if (isSwitchCaseEnder(stmt))
alreadyEnded = true;
}
});
// Now that we know how many statements there will be in this.listing,
// we can finally resolve this.finalLoc.value.
this.finalLoc.value = this.listing.length;
cases.push(
t.switchCase(this.finalLoc, [
// Intentionally fall through to the "end" case...
]),
// So that the runtime can jump to the final location without having
// to know its offset, we provide the "end" case as a synonym.
t.switchCase(t.literal("end"), [
// This will check/clear both context.thrown and context.rval.
t.returnStatement(
t.callExpression(this.contextProperty("stop"), [])
)
])
);
return t.whileStatement(
t.literal(true),
t.switchStatement(
t.assignmentExpression(
"=",
this.contextProperty("prev"),
this.contextProperty("next")
),
cases
)
);
};
// See comment above re: alreadyEnded.
function isSwitchCaseEnder(stmt) {
return t.isBreakStatement(stmt) ||
t.isContinueStatement(stmt) ||
t.isReturnStatement(stmt) ||
t.isThrowStatement(stmt);
}
Emitter.prototype.getTryEntryList = function () {
if (this.tryEntries.length === 0) {
// To avoid adding a needless [] to the majority of runtime.wrap
// argument lists, force the caller to handle this case specially.
return null;
}
var lastLocValue = 0;
return t.arrayExpression(
this.tryEntries.map(function (tryEntry) {
var thisLocValue = tryEntry.firstLoc.value;
assert.ok(thisLocValue >= lastLocValue, "try entries out of order");
lastLocValue = thisLocValue;
var ce = tryEntry.catchEntry;
var fe = tryEntry.finallyEntry;
var triple = [
tryEntry.firstLoc,
// The null here makes a hole in the array.
ce ? ce.firstLoc : null
];
if (fe) {
triple[2] = fe.firstLoc;
}
return t.arrayExpression(triple);
})
);
};
// All side effects must be realized in order.
// If any subexpression harbors a leap, all subexpressions must be
// neutered of side effects.
// No destructive modification of AST nodes.
Emitter.prototype.explode = function (path, ignoreResult) {
assert.ok(path instanceof types.NodePath);
var node = path.value;
var self = this;
n.Node.check(node);
if (t.isStatement(node))
return self.explodeStatement(path);
if (t.isExpression(node))
return self.explodeExpression(path, ignoreResult);
if (t.isDeclaration(node))
throw getDeclError(node);
switch (node.type) {
case "Program":
return path.get("body").map(self.explodeStatement, self);
case "VariableDeclarator":
throw getDeclError(node);
// These node types should be handled by their parent nodes
// (ObjectExpression, SwitchStatement, and TryStatement, respectively).
case "Property":
case "SwitchCase":
case "CatchClause":
throw new Error(node.type + " nodes should be handled by their parents");
default:
throw new Error("unknown Node of type " + JSON.stringify(node.type));
}
};
function getDeclError(node) {
return new Error(
"all declarations should have been transformed into " +
"assignments before the Exploder began its work: " +
JSON.stringify(node));
}
Emitter.prototype.explodeStatement = function (path, labelId) {
assert.ok(path instanceof types.NodePath);
var stmt = path.value;
var self = this;
t.assertStatement(stmt);
if (labelId) {
t.assertIdentifier(labelId);
} else {
labelId = null;
}
// Explode BlockStatement nodes even if they do not contain a yield,
// because we don't want or need the curly braces.
if (t.isBlockStatement(stmt)) {
return path.get("body").each(
self.explodeStatement,
self
);
}
if (!meta.containsLeap(stmt)) {
// Technically we should be able to avoid emitting the statement
// altogether if !meta.hasSideEffects(stmt), but that leads to
// confusing generated code (for instance, `while (true) {}` just
// disappears) and is probably a more appropriate job for a dedicated
// dead code elimination pass.
self.emit(stmt);
return;
}
var fn = explodeStatements[stmt.type];
if (fn) {
fn.call(this, path, stmt, labelId);
} else {
throw new Error("unknown Statement of type " + JSON.stringify(stmt.type));
}
};
Emitter.prototype.emitAbruptCompletion = function (record) {
if (!isValidCompletion(record)) {
assert.ok(
false,
"invalid completion record: " + JSON.stringify(record)
);
}
assert.notStrictEqual(
record.type, "normal",
"normal completions are not abrupt"
);
var abruptArgs = [t.literal(record.type)];
if (record.type === "break" || record.type === "continue") {
t.assertLiteral(record.target);
abruptArgs[1] = record.target;
} else if (record.type === "return" || record.type === "throw") {
if (record.value) {
t.assertExpression(record.value);
abruptArgs[1] = record.value;
}
}
this.emit(
t.returnStatement(
t.callExpression(
this.contextProperty("abrupt"),
abruptArgs
)
)
);
};
function isValidCompletion(record) {
var type = record.type;
if (type === "normal") {
return !_.has(record, "target");
}
if (type === "break" || type === "continue") {
return !_.has(record, "value") && t.isLiteral(record.target);
}
if (type === "return" || type === "throw") {
return _.has(record, "value") && !_.has(record, "target");
}
return false;
}
// Not all offsets into emitter.listing are potential jump targets. For
// example, execution typically falls into the beginning of a try block
// without jumping directly there. This method returns the current offset
// without marking it, so that a switch case will not necessarily be
// generated for this offset (I say "not necessarily" because the same
// location might end up being marked in the process of emitting other
// statements). There's no logical harm in marking such locations as jump
// targets, but minimizing the number of switch cases keeps the generated
// code shorter.
Emitter.prototype.getUnmarkedCurrentLoc = function () {
return t.literal(this.listing.length);
};
// The context.prev property takes the value of context.next whenever we
// evaluate the switch statement discriminant, which is generally good
// enough for tracking the last location we jumped to, but sometimes
// context.prev needs to be more precise, such as when we fall
// successfully out of a try block and into a finally block without
// jumping. This method exists to update context.prev to the freshest
// available location. If we were implementing a full interpreter, we
// would know the location of the current instruction with complete
// precision at all times, but we don't have that luxury here, as it would
// be costly and verbose to set context.prev before every statement.
Emitter.prototype.updateContextPrevLoc = function (loc) {
if (loc) {
t.assertLiteral(loc);
if (loc.value === -1) {
// If an uninitialized location literal was passed in, set its value
// to the current this.listing.length.
loc.value = this.listing.length;
} else {
// Otherwise assert that the location matches the current offset.
assert.strictEqual(loc.value, this.listing.length);
}
} else {
loc = this.getUnmarkedCurrentLoc();
}
// Make sure context.prev is up to date in case we fell into this try
// statement without jumping to it. TODO Consider avoiding this
// assignment when we know control must have jumped here.
this.emitAssign(this.contextProperty("prev"), loc);
};
Emitter.prototype.explodeExpression = function (path, ignoreResult) {
assert.ok(path instanceof types.NodePath);
var expr = path.value;
if (expr) {
t.assertExpression(expr);
} else {
return expr;
}
var self = this;
function finish(expr) {
t.assertExpression(expr);
if (ignoreResult) {
self.emit(expr);
} else {
return expr;
}
}
// If the expression does not contain a leap, then we either emit the
// expression as a standalone statement or return it whole.
if (!meta.containsLeap(expr)) {
return finish(expr);
}
// If any child contains a leap (such as a yield or labeled continue or
// break statement), then any sibling subexpressions will almost
// certainly have to be exploded in order to maintain the order of their
// side effects relative to the leaping child(ren).
var hasLeapingChildren = meta.containsLeap.onlyChildren(expr);
// In order to save the rest of explodeExpression from a combinatorial
// trainwreck of special cases, explodeViaTempVar is responsible for
// deciding when a subexpression needs to be "exploded," which is my
// very technical term for emitting the subexpression as an assignment
// to a temporary variable and the substituting the temporary variable
// for the original subexpression. Think of exploded view diagrams, not
// Michael Bay movies. The point of exploding subexpressions is to
// control the precise order in which the generated code realizes the
// side effects of those subexpressions.
function explodeViaTempVar(tempVar, childPath, ignoreChildResult) {
assert.ok(childPath instanceof types.NodePath);
assert.ok(
!ignoreChildResult || !tempVar,
"Ignoring the result of a child expression but forcing it to " +
"be assigned to a temporary variable?"
);
var result = self.explodeExpression(childPath, ignoreChildResult);
if (ignoreChildResult) {
// Side effects already emitted above.
} else if (tempVar || (hasLeapingChildren &&
(self.isVolatileContextProperty(result) ||
meta.hasSideEffects(result)))) {
// If tempVar was provided, then the result will always be assigned
// to it, even if the result does not otherwise need to be assigned
// to a temporary variable. When no tempVar is provided, we have
// the flexibility to decide whether a temporary variable is really
// necessary. In general, temporary assignment is required only
// when some other child contains a leap and the child in question
// is a context property like $ctx.sent that might get overwritten
// or an expression with side effects that need to occur in proper
// sequence relative to the leap.
result = self.emitAssign(
tempVar || self.makeTempVar(),
result
);
}
return result;
}
// If ignoreResult is true, then we must take full responsibility for
// emitting the expression with all its side effects, and we should not
// return a result.
var fn = explodeExpressions[expr.type];
if (fn) {
return fn.call(this, expr, path, explodeViaTempVar, finish, ignoreResult);
} else {
throw new Error("unknown Expression of type " + JSON.stringify(expr.type));
}
};

View File

@@ -3,36 +3,35 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* https://raw.githut.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var types = require("ast-types");
var n = types.namedTypes;
var b = types.builders;
var hasOwn = Object.prototype.hasOwnProperty;
var types = require("ast-types");
var t = require("../../../types");
var _ = require("lodash");
// The hoist function takes a FunctionExpression or FunctionDeclaration
// and replaces any Declaration nodes in its body with assignments, then
// returns a VariableDeclaration containing just the names of the removed
// declarations.
exports.hoist = function(funPath) {
exports.hoist = function (funPath) {
assert.ok(funPath instanceof types.NodePath);
n.Function.assert(funPath.value);
t.assertFunction(funPath.value);
var vars = {};
function varDeclToExpr(vdec, includeIdentifiers) {
n.VariableDeclaration.assert(vdec);
t.assertVariableDeclaration(vdec);
var exprs = [];
vdec.declarations.forEach(function(dec) {
vdec.declarations.forEach(function (dec) {
vars[dec.id.name] = dec.id;
if (dec.init) {
exprs.push(b.assignmentExpression(
exprs.push(t.assignmentExpression(
"=", dec.id, dec.init
));
} else if (includeIdentifiers) {
@@ -46,18 +45,18 @@ exports.hoist = function(funPath) {
if (exprs.length === 1)
return exprs[0];
return b.sequenceExpression(exprs);
return t.sequenceExpression(exprs);
}
types.visit(funPath.get("body"), {
visitVariableDeclaration: function(path) {
visitVariableDeclaration: function (path) {
var expr = varDeclToExpr(path.value, false);
if (expr === null) {
path.replace();
} else {
// We don't need to traverse this expression any further because
// there can't be any new declarations inside an expression.
return b.expressionStatement(expr);
return t.expressionStatement(expr);
}
// Since the original node has been either removed or replaced,
@@ -65,31 +64,31 @@ exports.hoist = function(funPath) {
return false;
},
visitForStatement: function(path) {
visitForStatement: function (path) {
var init = path.value.init;
if (n.VariableDeclaration.check(init)) {
if (t.isVariableDeclaration(init)) {
path.get("init").replace(varDeclToExpr(init, false));
}
this.traverse(path);
},
visitForInStatement: function(path) {
visitForInStatement: function (path) {
var left = path.value.left;
if (n.VariableDeclaration.check(left)) {
if (t.isVariableDeclaration(left)) {
path.get("left").replace(varDeclToExpr(left, true));
}
this.traverse(path);
},
visitFunctionDeclaration: function(path) {
visitFunctionDeclaration: function (path) {
var node = path.value;
vars[node.id.name] = node.id;
var assignment = b.expressionStatement(
b.assignmentExpression(
var assignment = t.expressionStatement(
t.assignmentExpression(
"=",
node.id,
b.functionExpression(
t.functionExpression(
node.id,
node.params,
node.body,
@@ -99,7 +98,7 @@ exports.hoist = function(funPath) {
)
);
if (n.BlockStatement.check(path.parent.node)) {
if (t.isBlockStatement(path.parent.node)) {
// Insert the assignment form before the first statement in the
// enclosing block.
path.parent.get("body").unshift(assignment);
@@ -119,16 +118,16 @@ exports.hoist = function(funPath) {
return false;
},
visitFunctionExpression: function() {
visitFunctionExpression: function () {
// Don't descend into nested function expressions.
return false;
}
});
var paramNames = {};
funPath.get("params").each(function(paramPath) {
funPath.get("params").each(function (paramPath) {
var param = paramPath.value;
if (n.Identifier.check(param)) {
if (t.isIdentifier(param)) {
paramNames[param.name] = param;
} else {
// Variables declared by destructuring parameter patterns will be
@@ -138,9 +137,9 @@ exports.hoist = function(funPath) {
var declarations = [];
Object.keys(vars).forEach(function(name) {
if (!hasOwn.call(paramNames, name)) {
declarations.push(b.variableDeclarator(vars[name], null));
Object.keys(vars).forEach(function (name) {
if (!_.has(paramNames, name)) {
declarations.push(t.variableDeclarator(vars[name], null));
}
});
@@ -148,5 +147,5 @@ exports.hoist = function(funPath) {
return null; // Be sure to handle this case!
}
return b.variableDeclaration("var", declarations);
return t.variableDeclaration("var", declarations);
};

View File

@@ -8,10 +8,19 @@
* the same directory.
*/
exports.FunctionEntry = FunctionEntry;
exports.FinallyEntry = FinallyEntry;
exports.SwitchEntry = SwitchEntry;
exports.LeapManager = LeapManager;
exports.CatchEntry = CatchEntry;
exports.LoopEntry = LoopEntry;
exports.TryEntry = TryEntry;
var assert = require("assert");
var types = require("ast-types");
var n = types.namedTypes;
var inherits = require("util").inherits;
var util = require("util");
var t = require("../../../types");
var inherits = util.inherits;
function Entry() {
assert.ok(this instanceof Entry);
@@ -20,55 +29,46 @@ function Entry() {
function FunctionEntry(returnLoc) {
Entry.call(this);
n.Literal.assert(returnLoc);
t.assertLiteral(returnLoc);
Object.defineProperties(this, {
returnLoc: { value: returnLoc }
});
this.returnLoc = returnLoc;
}
inherits(FunctionEntry, Entry);
exports.FunctionEntry = FunctionEntry;
function LoopEntry(breakLoc, continueLoc, label) {
Entry.call(this);
n.Literal.assert(breakLoc);
n.Literal.assert(continueLoc);
t.assertLiteral(breakLoc);
t.assertLiteral(continueLoc);
if (label) {
n.Identifier.assert(label);
t.assertIdentifier(label);
} else {
label = null;
}
Object.defineProperties(this, {
breakLoc: { value: breakLoc },
continueLoc: { value: continueLoc },
label: { value: label }
});
this.breakLoc = breakLoc;
this.continueLoc = continueLoc;
this.label = label;
}
inherits(LoopEntry, Entry);
exports.LoopEntry = LoopEntry;
function SwitchEntry(breakLoc) {
Entry.call(this);
n.Literal.assert(breakLoc);
t.assertLiteral(breakLoc);
Object.defineProperties(this, {
breakLoc: { value: breakLoc }
});
this.breakLoc = breakLoc;
}
inherits(SwitchEntry, Entry);
exports.SwitchEntry = SwitchEntry;
function TryEntry(firstLoc, catchEntry, finallyEntry) {
Entry.call(this);
n.Literal.assert(firstLoc);
t.assertLiteral(firstLoc);
if (catchEntry) {
assert.ok(catchEntry instanceof CatchEntry);
@@ -85,43 +85,34 @@ function TryEntry(firstLoc, catchEntry, finallyEntry) {
// Have to have one or the other (or both).
assert.ok(catchEntry || finallyEntry);
Object.defineProperties(this, {
firstLoc: { value: firstLoc },
catchEntry: { value: catchEntry },
finallyEntry: { value: finallyEntry }
});
this.firstLoc = firstLoc;
this.catchEntry = catchEntry;
this.finallyEntry = finallyEntry;
}
inherits(TryEntry, Entry);
exports.TryEntry = TryEntry;
function CatchEntry(firstLoc, paramId) {
Entry.call(this);
n.Literal.assert(firstLoc);
n.Identifier.assert(paramId);
t.assertLiteral(firstLoc);
t.assertIdentifier(paramId);
Object.defineProperties(this, {
firstLoc: { value: firstLoc },
paramId: { value: paramId }
});
this.firstLoc = firstLoc;
this.paramId = paramId;
}
inherits(CatchEntry, Entry);
exports.CatchEntry = CatchEntry;
function FinallyEntry(firstLoc) {
Entry.call(this);
n.Literal.assert(firstLoc);
t.assertLiteral(firstLoc);
Object.defineProperties(this, {
firstLoc: { value: firstLoc }
});
this.firstLoc = firstLoc;
}
inherits(FinallyEntry, Entry);
exports.FinallyEntry = FinallyEntry;
function LeapManager(emitter) {
assert.ok(this instanceof LeapManager);
@@ -129,18 +120,11 @@ function LeapManager(emitter) {
var Emitter = require("./emit").Emitter;
assert.ok(emitter instanceof Emitter);
Object.defineProperties(this, {
emitter: { value: emitter },
entryStack: {
value: [new FunctionEntry(emitter.finalLoc)]
}
});
this.emitter = emitter;
this.entryStack = [new FunctionEntry(emitter.finalLoc)];
}
var LMp = LeapManager.prototype;
exports.LeapManager = LeapManager;
LMp.withEntry = function(entry, callback) {
LeapManager.prototype.withEntry = function (entry, callback) {
assert.ok(entry instanceof Entry);
this.entryStack.push(entry);
try {
@@ -151,7 +135,7 @@ LMp.withEntry = function(entry, callback) {
}
};
LMp._findLeapLocation = function(property, label) {
LeapManager.prototype._findLeapLocation = function (property, label) {
for (var i = this.entryStack.length - 1; i >= 0; --i) {
var entry = this.entryStack[i];
var loc = entry[property];
@@ -170,10 +154,10 @@ LMp._findLeapLocation = function(property, label) {
return null;
};
LMp.getBreakLoc = function(label) {
LeapManager.prototype.getBreakLoc = function (label) {
return this._findLeapLocation("breakLoc", label);
};
LMp.getContinueLoc = function(label) {
LeapManager.prototype.getContinueLoc = function (label) {
return this._findLeapLocation("continueLoc", label);
};

View File

@@ -9,15 +9,16 @@
*/
var assert = require("assert");
var types = require("ast-types");
var m = require("private").makeAccessor();
var types = require("ast-types");
var m = require("private").makeAccessor();
var _ = require("lodash");
var isArray = types.builtInTypes.array;
var n = types.namedTypes;
var hasOwn = Object.prototype.hasOwnProperty;
var n = types.namedTypes;
function makePredicate(propertyName, knownTypes) {
function onlyChildren(node) {
n.Node.assert(node);
n.Node.check(node);
// Assume no side effects until we find out otherwise.
var result = false;
@@ -34,7 +35,7 @@ function makePredicate(propertyName, knownTypes) {
return result;
}
types.eachField(node, function(name, child) {
types.eachField(node, function (name, child) {
check(child);
});
@@ -42,19 +43,16 @@ function makePredicate(propertyName, knownTypes) {
}
function predicate(node) {
n.Node.assert(node);
n.Node.check(node);
var meta = m(node);
if (hasOwn.call(meta, propertyName))
return meta[propertyName];
if (_.has(meta, propertyName)) return meta[propertyName];
// Certain types are "opaque," which means they have no side
// effects or leaps and we don't care about their subexpressions.
if (hasOwn.call(opaqueTypes, node.type))
return meta[propertyName] = false;
if (_.has(opaqueTypes, node.type)) return meta[propertyName] = false;
if (hasOwn.call(knownTypes, node.type))
return meta[propertyName] = true;
if (_.has(knownTypes, node.type)) return meta[propertyName] = true;
return meta[propertyName] = onlyChildren(node);
}
@@ -91,7 +89,7 @@ var leapTypes = {
// All leap types are also side effect types.
for (var type in leapTypes) {
if (hasOwn.call(leapTypes, type)) {
if (_.has(leapTypes, type)) {
sideEffectTypes[type] = leapTypes[type];
}
}

View File

@@ -8,13 +8,9 @@
* the same directory.
*/
if (typeof global.regeneratorRuntime === "object") {
return;
}
var hasOwn = Object.prototype.hasOwnProperty;
var iteratorSymbol = typeof Symbol === "function" && Symbol.iterator || "@@iterator";
var runtime = global.regeneratorRuntime = exports;
var hasOwn = Object.prototype.hasOwnProperty;
var wrap = runtime.wrap = function wrap(innerFn, outerFn, self, tryList) {
return new Generator(innerFn, outerFn, self || null, tryList || []);
@@ -42,19 +38,19 @@ var GFName = "GeneratorFunction";
if (GF.name !== GFName) GF.name = GFName;
if (GF.name !== GFName) throw new Error(GFName + " renamed?");
runtime.isGeneratorFunction = function(genFun) {
runtime.isGeneratorFunction = function (genFun) {
var ctor = genFun && genFun.constructor;
return ctor ? GF.name === ctor.name : false;
};
runtime.mark = function(genFun) {
runtime.mark = function (genFun) {
genFun.__proto__ = GFp;
genFun.prototype = Object.create(Gp);
return genFun;
};
runtime.async = function(innerFn, outerFn, self, tryList) {
return new Promise(function(resolve, reject) {
runtime.async = function (innerFn, outerFn, self, tryList) {
return new Promise(function (resolve, reject) {
var generator = wrap(innerFn, outerFn, self, tryList);
var callNext = step.bind(generator.next);
var callThrow = step.bind(generator["throw"]);
@@ -206,11 +202,11 @@ function Generator(innerFn, outerFn, self, tryList) {
return generator;
}
Gp[iteratorSymbol] = function() {
Gp[iteratorSymbol] = function () {
return this;
};
Gp.toString = function() {
Gp.toString = function () {
return "[object Generator]";
};
@@ -244,7 +240,7 @@ function Context(tryList) {
this.reset();
}
runtime.keys = function(object) {
runtime.keys = function (object) {
var keys = [];
for (var key in object) {
keys.push(key);
@@ -297,7 +293,7 @@ runtime.values = values;
Context.prototype = {
constructor: Context,
reset: function() {
reset: function () {
this.prev = 0;
this.next = 0;
this.sent = undefined;
@@ -315,7 +311,7 @@ Context.prototype = {
}
},
stop: function() {
stop: function () {
this.done = true;
var rootEntry = this.tryEntries[0];
@@ -327,7 +323,7 @@ Context.prototype = {
return this.rval;
},
dispatchException: function(exception) {
dispatchException: function (exception) {
if (this.done) {
throw exception;
}
@@ -379,7 +375,7 @@ Context.prototype = {
}
},
_findFinallyEntry: function(finallyLoc) {
_findFinallyEntry: function (finallyLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc <= this.prev &&
@@ -391,7 +387,7 @@ Context.prototype = {
}
},
abrupt: function(type, arg) {
abrupt: function (type, arg) {
var entry = this._findFinallyEntry();
var record = entry ? entry.completion : {};
@@ -407,13 +403,12 @@ Context.prototype = {
return ContinueSentinel;
},
complete: function(record) {
complete: function (record) {
if (record.type === "throw") {
throw record.arg;
}
if (record.type === "break" ||
record.type === "continue") {
if (record.type === "break" || record.type === "continue") {
this.next = record.arg;
} else if (record.type === "return") {
this.rval = record.arg;
@@ -423,12 +418,12 @@ Context.prototype = {
return ContinueSentinel;
},
finish: function(finallyLoc) {
finish: function (finallyLoc) {
var entry = this._findFinallyEntry(finallyLoc);
return this.complete(entry.completion);
},
"catch": function(tryLoc) {
"catch": function (tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc === tryLoc) {
@@ -447,7 +442,7 @@ Context.prototype = {
throw new Error("illegal catch attempt");
},
delegateYield: function(iterable, resultName, nextLoc) {
delegateYield: function (iterable, resultName, nextLoc) {
this.delegate = {
iterator: values(iterable),
resultName: resultName,

View File

@@ -8,30 +8,21 @@
* the same directory.
*/
var b = require("ast-types").builders;
var hasOwn = Object.prototype.hasOwnProperty;
var t = require("../../../types");
exports.defaults = function(obj) {
var len = arguments.length;
var extension;
for (var i = 1; i < len; ++i) {
if ((extension = arguments[i])) {
for (var key in extension) {
if (hasOwn.call(extension, key) && !hasOwn.call(obj, key)) {
obj[key] = extension[key];
}
}
}
}
return obj;
};
exports.runtimeProperty = function(name) {
return b.memberExpression(
b.identifier("regeneratorRuntime"),
b.identifier(name),
false
exports.runtimeProperty = function (name) {
return t.memberExpression(
t.identifier("regeneratorRuntime"),
t.identifier(name)
);
};
// Offsets into this.listing that could be used as targets for branches or
// jumps are represented as numeric Literal nodes. This representation has
// the amazingly convenient benefit of allowing the exact value of the
// location to be determined at any time, even after generating code that
// refers to the location.
exports.loc = function () {
return t.literal(-1);
};

View File

@@ -3,205 +3,204 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* https://raw.githut.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var types = require("ast-types");
var n = types.namedTypes;
var b = types.builders;
var hoist = require("./hoist").hoist;
var Emitter = require("./emit").Emitter;
var runtimeProperty = require("./util").runtimeProperty;
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
var runtimeAsyncMethod = runtimeProperty("async");
var Emitter = require("./emit").Emitter;
var hoist = require("./hoist").hoist;
var types = require("ast-types");
var t = require("../../../types");
exports.transform = function transform(node) {
return types.visit(node, visitor);
var runtimeAsyncMethod = runtimeProperty("async");
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
exports.transform = function transform(node, file) {
return types.visit(node, {
visitFunction: function (path) {
return visitor.call(this, path, file);
}
});
};
var visitor = types.PathVisitor.fromMethodsObject({
visitFunction: function(path) {
// Calling this.traverse(path) first makes for a post-order traversal.
this.traverse(path);
var visitor = function (path, file) {
// Calling this.traverse(path) first makes for a post-order traversal.
this.traverse(path);
var node = path.value;
var node = path.value;
var scope; // we need to actually get the current scope
if (!node.generator && !node.async) {
if (!node.generator && !node.async) {
return;
}
node.generator = false;
if (node.expression) {
// Transform expression lambdas into normal functions.
node.expression = false;
node.body = t.blockStatement([
t.returnStatement(node.body)
]);
}
if (node.async) {
awaitVisitor.visit(path.get("body"));
}
var outerFnId = node.id || (
node.id = file.generateUidIdentifier("callee", scope)
);
var innerFnId = t.identifier(node.id.name + "$");
var contextId = file.generateUidIdentifier("context$", scope);
var vars = hoist(path);
var emitter = new Emitter(contextId);
emitter.explode(path.get("body"));
var outerBody = [];
if (vars && vars.declarations.length > 0) {
outerBody.push(vars);
}
var wrapArgs = [
emitter.getContextFunction(innerFnId),
// Async functions don't care about the outer function because they
// don't need it to be marked and don't inherit from its .prototype.
node.async ? t.literal(null) : outerFnId,
t.thisExpression()
];
var tryEntryList = emitter.getTryEntryList();
if (tryEntryList) {
wrapArgs.push(tryEntryList);
}
var wrapCall = t.callExpression(
node.async ? runtimeAsyncMethod : runtimeWrapMethod,
wrapArgs
);
outerBody.push(t.returnStatement(wrapCall));
node.body = t.blockStatement(outerBody);
if (node.async) {
node.async = false;
return;
}
if (t.isFunctionDeclaration(node)) {
var pp = path.parent;
while (pp && !(t.isBlockStatement(pp.value) || t.isProgram(pp.value))) {
pp = pp.parent;
}
if (!pp) {
return;
}
node.generator = false;
// Here we turn the FunctionDeclaration into a named
// FunctionExpression that will be assigned to a variable of the
// same name at the top of the enclosing block. This is important
// for a very subtle reason: named function expressions can refer to
// themselves by name without fear that the binding may change due
// to code executing outside the function, whereas function
// declarations are vulnerable to the following rebinding:
//
// function f() { return f }
// var g = f;
// f = "asdf";
// g(); // "asdf"
//
// One way to prevent the problem illustrated above is to transform
// the function declaration thus:
//
// var f = function f() { return f };
// var g = f;
// f = "asdf";
// g(); // f
// g()()()()(); // f
//
// In the code below, we transform generator function declarations
// in the following way:
//
// gen().next(); // { value: gen, done: true }
// function *gen() {
// return gen;
// }
//
// becomes something like
//
// var gen = runtime.mark(function *gen() {
// return gen;
// });
// gen().next(); // { value: gen, done: true }
//
// which ensures that the generator body can always reliably refer
// to gen by name.
if (node.expression) {
// Transform expression lambdas into normal functions.
node.expression = false;
node.body = b.blockStatement([
b.returnStatement(node.body)
]);
}
// Remove the FunctionDeclaration so that we can add it back as a
// FunctionExpression passed to runtime.mark.
path.replace();
if (node.async) {
awaitVisitor.visit(path.get("body"));
}
// Change the type of the function to be an expression instead of a
// declaration. Note that all the other fields are the same.
node.type = "FunctionExpression";
var outerFnId = node.id || (
node.id = path.scope.parent.declareTemporary("callee$")
);
var varDecl = t.variableDeclaration("var", [
t.variableDeclarator(
node.id,
t.callExpression(runtimeMarkMethod, [node])
)
]);
var innerFnId = b.identifier(node.id.name + "$");
var contextId = path.scope.declareTemporary("context$");
var vars = hoist(path);
// Copy any comments preceding the function declaration to the
// variable declaration, to avoid weird formatting consequences.
t.inheritsComments(varDecl, node);
t.removeComments(node);
var emitter = new Emitter(contextId);
emitter.explode(path.get("body"));
varDecl._blockHoist = true;
var outerBody = [];
var bodyPath = pp.get("body");
var bodyLen = bodyPath.value.length;
if (vars && vars.declarations.length > 0) {
outerBody.push(vars);
}
var wrapArgs = [
emitter.getContextFunction(innerFnId),
// Async functions don't care about the outer function because they
// don't need it to be marked and don't inherit from its .prototype.
node.async ? b.literal(null) : outerFnId,
b.thisExpression()
];
var tryEntryList = emitter.getTryEntryList();
if (tryEntryList) {
wrapArgs.push(tryEntryList);
}
var wrapCall = b.callExpression(
node.async ? runtimeAsyncMethod : runtimeWrapMethod,
wrapArgs
);
outerBody.push(b.returnStatement(wrapCall));
node.body = b.blockStatement(outerBody);
if (node.async) {
node.async = false;
return;
}
if (n.FunctionDeclaration.check(node)) {
var pp = path.parent;
while (pp && !(n.BlockStatement.check(pp.value) ||
n.Program.check(pp.value))) {
pp = pp.parent;
}
if (!pp) {
for (var i = 0; i < bodyLen; ++i) {
var firstStmtPath = bodyPath.get(i);
if (!shouldNotHoistAbove(firstStmtPath)) {
firstStmtPath.insertBefore(varDecl);
return;
}
// Here we turn the FunctionDeclaration into a named
// FunctionExpression that will be assigned to a variable of the
// same name at the top of the enclosing block. This is important
// for a very subtle reason: named function expressions can refer to
// themselves by name without fear that the binding may change due
// to code executing outside the function, whereas function
// declarations are vulnerable to the following rebinding:
//
// function f() { return f }
// var g = f;
// f = "asdf";
// g(); // "asdf"
//
// One way to prevent the problem illustrated above is to transform
// the function declaration thus:
//
// var f = function f() { return f };
// var g = f;
// f = "asdf";
// g(); // f
// g()()()()(); // f
//
// In the code below, we transform generator function declarations
// in the following way:
//
// gen().next(); // { value: gen, done: true }
// function *gen() {
// return gen;
// }
//
// becomes something like
//
// var gen = runtime.mark(function *gen() {
// return gen;
// });
// gen().next(); // { value: gen, done: true }
//
// which ensures that the generator body can always reliably refer
// to gen by name.
// Remove the FunctionDeclaration so that we can add it back as a
// FunctionExpression passed to runtime.mark.
path.replace();
// Change the type of the function to be an expression instead of a
// declaration. Note that all the other fields are the same.
node.type = "FunctionExpression";
var varDecl = b.variableDeclaration("var", [
b.variableDeclarator(
node.id,
b.callExpression(runtimeMarkMethod, [node])
)
]);
if (node.comments) {
// Copy any comments preceding the function declaration to the
// variable declaration, to avoid weird formatting consequences.
varDecl.comments = node.comments;
node.comments = null;
}
var bodyPath = pp.get("body");
var bodyLen = bodyPath.value.length;
for (var i = 0; i < bodyLen; ++i) {
var firstStmtPath = bodyPath.get(i);
if (!shouldNotHoistAbove(firstStmtPath)) {
firstStmtPath.insertBefore(varDecl);
return;
}
}
bodyPath.push(varDecl);
} else {
n.FunctionExpression.assert(node);
return b.callExpression(runtimeMarkMethod, [node]);
}
bodyPath.push(varDecl);
} else {
t.assertFunctionExpression(node);
return t.callExpression(runtimeMarkMethod, [node]);
}
});
};
function shouldNotHoistAbove(stmtPath) {
var value = stmtPath.value;
n.Statement.assert(value);
t.assertStatement(value);
// If the first statement is a "use strict" declaration, make sure to
// insert hoisted declarations afterwards.
if (n.ExpressionStatement.check(value) &&
n.Literal.check(value.expression) &&
if (t.isExpressionStatement(value) &&
t.isLiteral(value.expression) &&
value.expression.value === "use strict") {
return true;
}
if (n.VariableDeclaration.check(value)) {
if (t.isVariableDeclaration(value)) {
for (var i = 0; i < value.declarations.length; ++i) {
var decl = value.declarations[i];
if (n.CallExpression.check(decl.init) &&
types.astNodesAreEquivalent(decl.init.callee,
runtimeMarkMethod)) {
if (t.isCallExpression(decl.init) && types.astNodesAreEquivalent(decl.init.callee, runtimeMarkMethod)) {
return true;
}
}
@@ -211,12 +210,12 @@ function shouldNotHoistAbove(stmtPath) {
}
var awaitVisitor = types.PathVisitor.fromMethodsObject({
visitFunction: function() {
visitFunction: function () {
return false; // Don't descend into nested function scopes.
},
visitAwaitExpression: function(path) {
visitAwaitExpression: function (path) {
// Convert await expressions to yield expressions.
return b.yieldExpression(path.value.argument, false);
return t.yieldExpression(path.value.argument, false);
}
});

View File

@@ -88,6 +88,9 @@ LetScoping.prototype.run = function () {
this.info = this.getInfo();
// remap all let references that exist in upper scopes to their uid
this.remap();
// this is a block within a `Function` so we can safely leave it be
if (t.isFunction(this.parent)) return this.noClosure();
@@ -126,7 +129,7 @@ LetScoping.prototype.run = function () {
// build a call and a unique id that we can assign the return value to
var call = t.callExpression(fn, params);
var ret = t.identifier(this.file.generateUid("ret", this.scope));
var ret = this.file.generateUidIdentifier("ret", this.scope);
var hasYield = traverse.hasType(fn.body, "YieldExpression", t.FUNCTION_TYPES);
if (hasYield) {
@@ -138,23 +141,29 @@ LetScoping.prototype.run = function () {
};
/**
* There are no let references accessed within a closure so we can just traverse
* through this block and replace all references that exist in a higher scope to
* their uids.
* There are no let references accessed within a closure so we can just turn the
* lets into vars.
*/
LetScoping.prototype.noClosure = function () {
var replacements = this.info.duplicates;
var declarators = this.info.declarators;
var block = this.block;
standardiseLets(this.info.declarators);
};
standardiseLets(declarators);
/**
* Traverse through block and replace all references that exist in a higher
* scope to their uids.
*/
LetScoping.prototype.remap = function () {
var replacements = this.info.duplicates;
var block = this.block;
if (_.isEmpty(replacements)) return;
var replace = function (node, parent) {
var replace = function (node, parent, scope) {
if (!t.isIdentifier(node)) return;
if (!t.isReferenced(node, parent)) return;
if (scope && scope.hasOwn(node.name)) return;
node.name = replacements[node.name] || node.name;
};
@@ -260,7 +269,7 @@ LetScoping.prototype.checkFor = function () {
return false;
}
if (forParent && !node.label) {
if (forParent && node && !node.label) {
if (t.isBreakStatement(node)) {
has.hasBreak = true;
replace = t.returnStatement(t.literal("break"));
@@ -436,7 +445,7 @@ LetScoping.prototype.buildHas = function (ret, call) {
if (has.hasBreak || has.hasContinue) {
// ensure that the parent has a label as we're building a switch and we
// need to be able to access it
var label = forParent.label = forParent.label || t.identifier(this.file.generateUid("loop", this.scope));
var label = forParent.label = forParent.label || this.file.generateUidIdentifier("loop", this.scope);
if (has.hasBreak) {
cases.push(t.switchCase(t.literal("break"), [t.breakStatement(label)]));

View File

@@ -1,15 +1,8 @@
var t = require("../../types");
var _ = require("lodash");
var getSpreadLiteral = function (spread) {
var literal = spread.argument;
if (!t.isArrayExpression(literal)) {
literal = t.callExpression(
t.memberExpression(t.identifier("Array"), t.identifier("from")),
[literal]
);
}
return literal;
var getSpreadLiteral = function (spread, file) {
return file.toArray(spread.argument);
};
var hasSpread = function (nodes) {
@@ -23,7 +16,7 @@ var hasSpread = function (nodes) {
return has;
};
var build = function (props) {
var build = function (props, file) {
var nodes = [];
var _props = [];
@@ -37,7 +30,7 @@ var build = function (props) {
_.each(props, function (prop) {
if (t.isSpreadElement(prop)) {
push();
nodes.push(getSpreadLiteral(prop));
nodes.push(getSpreadLiteral(prop, file));
} else {
_props.push(prop);
}
@@ -48,11 +41,11 @@ var build = function (props) {
return nodes;
};
exports.ArrayExpression = function (node) {
exports.ArrayExpression = function (node, parent, file) {
var elements = node.elements;
if (!hasSpread(elements)) return;
var nodes = build(elements);
var nodes = build(elements, file);
var first = nodes.shift();
if (!nodes.length) return first;
@@ -60,7 +53,7 @@ exports.ArrayExpression = function (node) {
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
};
exports.CallExpression = function (node) {
exports.CallExpression = function (node, parent, file) {
var args = node.arguments;
if (!hasSpread(args)) return;
@@ -68,7 +61,7 @@ exports.CallExpression = function (node) {
node.arguments = [];
var nodes = build(args);
var nodes = build(args, file);
var first = nodes.shift();
if (nodes.length) {
@@ -100,7 +93,7 @@ exports.NewExpression = function (node, parent, file) {
var args = node.arguments;
if (!hasSpread(args)) return;
var nodes = build(args);
var nodes = build(args, file);
var first = nodes.shift();
if (nodes.length) {

View File

@@ -22,9 +22,7 @@ exports.TaggedTemplateExpression = function (node, parent, file) {
t.arrayExpression(raw)
]));
_.each(quasi.expressions, function (expr) {
args.push(expr);
});
args = args.concat(quasi.expressions);
return t.callExpression(node.tag, args);
};

View File

@@ -55,7 +55,7 @@ function traverse(parent, callbacks, opts) {
//
var opts2 = { scope: opts.scope, blacklist: opts.blacklist };
if (t.isScope(node)) opts2.scope = new Scope(opts.scope, node);
if (t.isScope(node)) opts2.scope = new Scope(node, opts.scope);
// enter
if (callbacks.enter) {
@@ -89,9 +89,10 @@ function traverse(parent, callbacks, opts) {
traverse.removeProperties = function (tree) {
var clear = function (node) {
delete node._scopeReferences;
delete node.extendedRange;
delete node._scopeIds;
delete node._parent;
delete node._scope;
delete node.tokens;
delete node.range;
delete node.start;

View File

@@ -6,25 +6,30 @@ var _ = require("lodash");
var FOR_KEYS = ["left", "init"];
function Scope(parent, block) {
/**
* This searches the current "scope" and collects all references/declarations
* within.
*
* @param {Node} block
* @param {Scope} [parent]
*/
function Scope(block, parent) {
this.parent = parent;
this.block = block;
this.info = this.getInfo();
this.declarations = this.info.declarations;
this.references = this.getReferences();
}
Scope.prototype.getInfo = function () {
Scope.prototype.getReferences = function () {
var block = this.block;
if (block._scope) return block._scope;
if (block._scopeReferences) return block._scopeReferences;
var self = this;
var info = block._scope = {
declarations: {}
};
var self = this;
var references = block._scopeReferences = {};
var add = function (node) {
self.addDeclaration(node, info.declarations);
self.add(node, references);
};
// ForStatement - left, init
@@ -56,7 +61,7 @@ Scope.prototype.getInfo = function () {
// Program, Function - var variables
if (t.isProgram(block) || t.isFunction(block)) {
traverse(block, function (node) {
traverse(block, function (node, parent, scope) {
if (t.isFor(node)) {
_.each(FOR_KEYS, function (key) {
var declar = node[key];
@@ -68,12 +73,16 @@ Scope.prototype.getInfo = function () {
// declared within are accessible
if (t.isFunction(node)) return false;
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
add(node);
}
// we've ran into a declaration!
// we'll let the BlockStatement scope deal with `let` declarations
if (t.isDeclaration(node) && !t.isLet(node)) {
add(node);
}
});
}, { scope: this });
}
// Function - params, rest
@@ -85,12 +94,12 @@ Scope.prototype.getInfo = function () {
});
}
return info;
return references;
};
Scope.prototype.addDeclaration = function (node, declarations) {
Scope.prototype.add = function (node, references) {
if (!node) return;
_.merge(declarations || this.declarations, t.getIds(node, true));
_.merge(references || this.references, t.getIds(node, true));
};
Scope.prototype.get = function (id) {
@@ -98,7 +107,7 @@ Scope.prototype.get = function (id) {
};
Scope.prototype.getOwn = function (id) {
return _.has(this.declarations, id) && this.declarations[id];
return _.has(this.references, id) && this.references[id];
};
Scope.prototype.parentGet = function (id) {

View File

@@ -19,6 +19,7 @@
"Property": ["kind", "key", "value", "computed"],
"ReturnStatement": ["argument"],
"SequenceExpression": ["expressions"],
"ThrowExpression": ["argument"],
"UnaryExpression": ["operator", "argument", "prefix"],
"VariableDeclaration": ["kind", "declarations"],
"VariableDeclarator": ["id", "init"],

View File

@@ -2,14 +2,25 @@ var _ = require("lodash");
var t = exports;
var addAssert = function (type, is) {
t["assert" + type] = function (node, opts) {
opts = opts || {};
if (!is(node, opts)) {
throw new Error("Expected type " + JSON.stringify(type) + " with option " + JSON.stringify(opts));
}
};
};
//
t.VISITOR_KEYS = require("./visitor-keys");
_.each(t.VISITOR_KEYS, function (keys, type) {
t["is" + type] = function (node, opts) {
var is = t["is" + type] = function (node, opts) {
return node && node.type === type && t.shallowEqual(node, opts);
};
addAssert(type, is);
});
//
@@ -43,13 +54,23 @@ _.each(t.ALIAS_KEYS, function (aliases, type) {
_.each(_aliases, function (types, type) {
t[type.toUpperCase() + "_TYPES"] = types;
t["is" + type] = function (node, opts) {
var is = t["is" + type] = function (node, opts) {
return node && _.contains(types, node.type) && t.shallowEqual(node, opts);
};
addAssert(type, is);
});
//
t.isExpression = function (node) {
return !t.isStatement(node);
};
addAssert("Expression", t.isExpression);
//
t.shallowEqual = function (actual, expected) {
var same = true;
@@ -229,6 +250,11 @@ t.inheritsComments = function (child, parent) {
return child;
};
t.removeComments = function (node) {
delete node.leadingComments;
delete node.trailingComments;
};
t.inherits = function (child, parent) {
child.loc = parent.loc;
child.end = parent.end;

View File

@@ -37,6 +37,21 @@ exports.list = function (val) {
return val ? val.split(",") : [];
};
exports.regexify = function (val) {
if (!val) return new RegExp;
if (_.isArray(val)) val = val.join("|");
if (_.isString(val)) return new RegExp(val || "");
if (_.isRegExp(val)) return val;
throw new TypeError("illegal type for regexify");
};
exports.arrayify = function (val) {
if (!val) return [];
if (_.isString(val)) return exports.list(val);
if (_.isArray(val)) return val;
throw new TypeError("illegal type for arrayify");
};
exports.getUid = function (parent, file) {
var node;
@@ -50,7 +65,7 @@ exports.getUid = function (parent, file) {
if (t.isIdentifier(node)) id = node.name;
return t.identifier(file.generateUid(id));
return file.generateUidIdentifier(id);
};
exports.isAbsolute = function (loc) {
@@ -203,7 +218,7 @@ exports.parse = function (opts, code, callback) {
var ast = acorn.parse(code, {
allowReturnOutsideFunction: true,
preserveParens: true,
ecmaVersion: Infinity,
ecmaVersion: opts.experimental ? 7 : 6,
strictMode: true,
onComment: comments,
locations: true,

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.12.19",
"version": "1.13.2",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/6to5/6to5",
"repository": {
@@ -35,21 +35,21 @@
"test": "make test"
},
"dependencies": {
"ast-types": "~0.6.0",
"ast-types": "0.6.5",
"commander": "2.5.0",
"fs-readdir-recursive": "0.0.2",
"fs-readdir-recursive": "0.1.0",
"lodash": "2.4.1",
"mkdirp": "0.5.0",
"es6-shim": "0.20.2",
"es6-shim": "0.20.3",
"es6-symbol": "0.1.1",
"regexpu": "0.3.0",
"source-map": "0.1.40",
"chokidar": "0.10.5",
"chokidar": "0.11.1",
"source-map-support": "0.2.8",
"esutils": "1.1.4",
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/74d8e9bed20ba302d3504f53d0b1c649968959e1.tar.gz",
"estraverse": "^1.7.0",
"private": "^0.1.6"
"acorn-6to5": "0.9.1-4",
"estraverse": "1.8.0",
"private": "0.1.6"
},
"devDependencies": {
"istanbul": "0.3.2",

View File

@@ -1,3 +1,4 @@
"use strict";
var Test = function Test() {};
//# sourceMappingURL=bar.js.map

View File

@@ -3,3 +3,4 @@
arr.map(function (x) {
return x * MULTIPLIER;
});
//# sourceMappingURL=foo.js.map

View File

@@ -6,3 +6,5 @@ var Test = function Test() {};
arr.map(function (x) {
return x * MULTIPLIER;
});
//# sourceMappingURL=script3.js.map

View File

@@ -3,3 +3,5 @@
arr.map(function (x) {
return x * x;
});
//# sourceMappingURL=test.js.map

View File

@@ -2,4 +2,4 @@
var Test = function Test() {
arr.map(x => x * x);
};
};

View File

@@ -2,4 +2,4 @@
var arr = [1, 2, 3].map(function (i) {
return i * i;
});
});

View File

@@ -0,0 +1,3 @@
{
"experimental": true
}

View File

@@ -0,0 +1 @@
var arr = [for (i of nums) if (i > 1) i * i];

View File

@@ -0,0 +1,11 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var arr = _toArray(nums).filter(function (i) {
return i > 1;
}).map(function (i) {
return i * i;
});

View File

@@ -0,0 +1 @@
var arr = [for (i of nums) i * i];

View File

@@ -0,0 +1,9 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var arr = _toArray(nums).map(function (i) {
return i * i;
});

View File

@@ -4,4 +4,4 @@ var a = function (_ref) {
var target = _ref.target;
return console.log(target);
};
a({ target: "I am a target" });
a({ target: "I am a target" });

View File

@@ -2,4 +2,4 @@
var t = function () {
return 5 + 5;
};
};

View File

@@ -1,3 +1,3 @@
"use strict";
var t = function () {};
var t = function () {};

View File

@@ -2,4 +2,4 @@
arr.map(function (x) {
return x * x;
});
});

View File

@@ -2,4 +2,4 @@
arr.map(function (i) {
return i + 1;
});
});

View File

@@ -2,4 +2,4 @@
var t = function (i, x) {
return i * x;
};
};

View File

@@ -2,4 +2,4 @@
var t = function (i) {
return i * 5;
};
};

View File

@@ -2,4 +2,4 @@
var t = function (i) {
return i * 5;
};
};

View File

@@ -4,4 +4,4 @@ nums.forEach(function (v) {
if (v % 5 === 0) {
fives.push(v);
}
});
});

View File

@@ -3,4 +3,4 @@
var _this = this;
var t = function (x) {
return _this.x + x;
};
};

View File

@@ -1,3 +1,4 @@
{
"asyncExec": true
"asyncExec": true,
"experimental": true
}

View File

@@ -1,5 +1,9 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _classProps = function (child, staticProps, instanceProps) {
if (staticProps) Object.defineProperties(child, staticProps);
if (instanceProps) Object.defineProperties(child.prototype, instanceProps);
@@ -24,11 +28,11 @@ var Test = (function (Foo) {
Foo.prototype.test.call(this);
foob(Foo);
Foo.call.apply(Foo, [this].concat(Array.from(arguments)));
Foo.call.apply(Foo, [this, "test"].concat(Array.from(arguments)));
Foo.call.apply(Foo, [this].concat(_toArray(arguments)));
Foo.call.apply(Foo, [this, "test"].concat(_toArray(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this, "test"].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this].concat(_toArray(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this, "test"].concat(_toArray(arguments)));
};
_extends(Test, Foo);
@@ -38,8 +42,8 @@ var Test = (function (Foo) {
writable: true,
value: function () {
Foo.foo.call(this);
Foo.foo.call.apply(Foo.foo, [this].concat(Array.from(arguments)));
Foo.foo.call.apply(Foo.foo, [this, "test"].concat(Array.from(arguments)));
Foo.foo.call.apply(Foo.foo, [this].concat(_toArray(arguments)));
Foo.foo.call.apply(Foo.foo, [this, "test"].concat(_toArray(arguments)));
}
}
}, {
@@ -47,8 +51,8 @@ var Test = (function (Foo) {
writable: true,
value: function () {
Foo.prototype.test.call(this);
Foo.prototype.test.call.apply(Foo.prototype.test, [this].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this, "test"].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this].concat(_toArray(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this, "test"].concat(_toArray(arguments)));
}
}
});

View File

@@ -1,3 +1,3 @@
"use strict";
var Test = function Test() {};
var Test = function Test() {};

View File

@@ -2,4 +2,4 @@
var Test = function Test() {
Function.prototype.hasOwnProperty.call(this, "test");
};
};

View File

@@ -3,4 +3,4 @@
foo((function (_ref) {
_ref[bar] = "foobar";
return _ref;
})({}));
})({}));

View File

@@ -3,4 +3,4 @@
foo = (function (_foo) {
_foo[bar] = "foobar";
return _foo;
})({});
})({});

View File

@@ -5,4 +5,4 @@ var obj = (function (_obj) {
return "foobar";
};
return _obj;
})({});
})({});

View File

@@ -7,4 +7,4 @@ var obj = (function (_obj) {
})({
foo: "foo",
bar: "bar"
});
});

View File

@@ -4,4 +4,4 @@ var obj = (function (_obj) {
_obj["x" + foo] = "heh";
_obj["y" + bar] = "noo";
return _obj;
})({});
})({});

View File

@@ -3,4 +3,4 @@
var obj = (function (_obj) {
_obj["x" + foo] = "heh";
return _obj;
})({});
})({});

View File

@@ -4,4 +4,4 @@ var _this = this;
var obj = (function (_obj) {
_obj["x" + _this.foo] = "heh";
return _obj;
})({});
})({});

View File

@@ -3,4 +3,4 @@
var foo = (function (_foo) {
_foo[bar] = "foobar";
return _foo;
})({});
})({});

View File

@@ -1,16 +1,24 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = [1, 2];
var a = _ref[0];
var b = _ref[1];
var _ref2 = [3, 4];
var _ref2 = _toArray(_ref);
var c = _ref2[0];
var d = _ref2[1];
var _ref3 = { e: 5, f: 6 };
var e = _ref3.e;
var f = _ref3.f;
var _ref4 = { a: 7, b: 8 };
var g = _ref4.a;
var h = _ref4.b;
var a = _ref2[0];
var b = _ref2[1];
var _ref3 = [3, 4];
var _ref4 = _toArray(_ref3);
var c = _ref4[0];
var d = _ref4[1];
var _ref5 = { e: 5, f: 6 };
var e = _ref5.e;
var f = _ref5.f;
var _ref6 = { a: 7, b: 8 };
var g = _ref6.a;
var h = _ref6.b;

View File

@@ -1,8 +1,18 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = ["hello", [", ", "junk"], ["world"]];
var a = _ref[0];
var b = _ref[1][0];
var c = _ref[2][0];
var d = _ref[3];
var _ref2 = _toArray(_ref);
var a = _ref2[0];
var _ref3 = _toArray(_ref2[1]);
var b = _ref3[0];
var _ref4 = _toArray(_ref2[2]);
var c = _ref4[0];
var d = _ref2[3];

View File

@@ -0,0 +1 @@
console.log([x] = [1]);

View File

@@ -0,0 +1,3 @@
{
"throws": "AssignmentExpression destructuring outside of a ExpressionStatement is forbidden due to current 6to5 limitations"
}

View File

@@ -1,6 +1,12 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = f();
a = _ref[0];
b = _ref[1];
var _ref2 = _toArray(_ref);
a = _ref2[0];
b = _ref2[1];

View File

@@ -1,8 +1,18 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = ["foo", "hello", [", ", "junk"], ["world"]];
var a = _ref[1];
var b = _ref[2][0];
var c = _ref[3][0];
var d = _ref[4];
var _ref2 = _toArray(_ref);
var a = _ref2[1];
var _ref3 = _toArray(_ref2[2]);
var b = _ref3[0];
var _ref4 = _toArray(_ref2[3]);
var c = _ref4[0];
var d = _ref2[4];

View File

@@ -1,7 +1,13 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
for (var _ref in obj) {
var name = _ref[0];
var value = _ref[1];
var _ref2 = _toArray(_ref);
var name = _ref2[0];
var value = _ref2[1];
print("Name: " + name + ", Value: " + value);
}

View File

@@ -1,8 +1,14 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
for (var _iterator = this.test.expectation.registers[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
var _ref = _step.value;
var name = _ref[0];
var before = _ref[1];
var after = _ref[2];
}
var _ref2 = _toArray(_ref);
var name = _ref2[0];
var before = _ref2[1];
var after = _ref2[2];
}

View File

@@ -1,6 +1,12 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = [1, 2];
this.foo = _ref[0];
this.bar = _ref[1];
var _ref2 = _toArray(_ref);
this.foo = _ref2[0];
this.bar = _ref2[1];

View File

@@ -1,6 +1,14 @@
"use strict";
var x1 = rect.topLeft[0];
var y1 = rect.topLeft[1];
var x2 = rect.bottomRight[0];
var y2 = rect.bottomRight[1];
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var _ref = _toArray(rect.topLeft);
var x1 = _ref[0];
var y1 = _ref[1];
var _ref2 = _toArray(rect.bottomRight);
var x2 = _ref2[0];
var y2 = _ref2[1];

View File

@@ -2,4 +2,4 @@
var x = coords.x;
var y = coords.y;
var foo = "bar";
var foo = "bar";

View File

@@ -3,4 +3,4 @@
var x1 = rect.topLeft.x;
var y1 = rect.topLeft.y;
var x2 = rect.bottomRight.x;
var y2 = rect.bottomRight.y;
var y2 = rect.bottomRight.y;

View File

@@ -1,4 +1,4 @@
"use strict";
var x = coords.x;
var y = coords.y;
var y = coords.y;

View File

@@ -1,5 +1,9 @@
"use strict";
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
function somethingAdvanced(_ref) {
var x1 = _ref.topLeft.x;
var y1 = _ref.topLeft.y;
@@ -15,13 +19,17 @@ function unpackObject(_ref2) {
console.log(unpackObject({ title: "title", author: "author" }));
var unpackArray = function (_ref3, _ref4) {
var a = _ref3[0];
var b = _ref3[1];
var c = _ref3[2];
var x = _ref4[0];
var y = _ref4[1];
var z = _ref4[2];
var unpackArray = function (_ref3, _ref5) {
var _ref4 = _toArray(_ref3);
var a = _ref4[0];
var b = _ref4[1];
var c = _ref4[2];
var _ref6 = _toArray(_ref5);
var x = _ref6[0];
var y = _ref6[1];
var z = _ref6[2];
return a + b + c;
};

Some files were not shown because too many files have changed in this diff Show More