Compare commits

...

103 Commits

Author SHA1 Message Date
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
Sebastian McKenzie
a3a4a7645c v1.12.19 2014-11-17 14:10:10 +11:00
Sebastian McKenzie
7bd1337ee8 clean up weird regenerator formatting, only one instance, heaps more to go! 2014-11-17 13:56:42 +11:00
Sebastian McKenzie
c54f530b10 fix up duplicate variables in regenerator 2014-11-17 12:48:35 +11:00
Sebastian McKenzie
9d3a3a57f2 fix up generator normaliseOptions 2014-11-17 12:39:01 +11:00
Sebastian McKenzie
e1474c2f5f add 1.12.19 changelog 2014-11-17 12:00:05 +11:00
Sebastian McKenzie
8a9a205122 fix up comments option 2014-11-17 11:59:52 +11:00
Sebastian McKenzie
885d65f9de Merge pull request #179 from webpro/remove-comments
Remove comments
2014-11-17 11:54:41 +11:00
Sebastian McKenzie
43d1435c97 Merge pull request #180 from SimonDegraeve/add-jsxhint-plugin
Add JSXHint in the plugins list.
2014-11-17 11:47:47 +11:00
Simon Degraeve
247c14c5ab Add JSXHint in the plugins list. 2014-11-17 08:19:49 +08:00
Lars Kappert
0e2b12c134 Separate comments and comments setting 2014-11-16 21:11:43 +01:00
Lars Kappert
59c5abe188 Exclude comments from generated code 2014-11-16 20:33:50 +01:00
Lars Kappert
e1cc1dcb4b Introduce --remove-comments (-c) option 2014-11-16 20:33:50 +01:00
Sebastian McKenzie
d091793077 add generator support let scoping - fixes #178 2014-11-17 04:09:48 +11:00
Sebastian McKenzie
e6baac1003 move regenerator into main repo so we can iterate on it faster and make a bunch of additional changes 2014-11-17 04:09:29 +11:00
Sebastian McKenzie
c41608edc3 add gobble to plugins 2014-11-17 04:04:02 +11:00
Sebastian McKenzie
3815913537 v1.12.18 2014-11-16 21:01:12 +11:00
Sebastian McKenzie
e5c18749f0 add changelog for 1.12.18 2014-11-16 21:00:00 +11:00
Sebastian McKenzie
b7458f949c Merge pull request #177 from josh/browser-global
Prefer module provided `global` rather than `window` reference
2014-11-16 20:58:12 +11:00
Sebastian McKenzie
69302b314f add sprockets-es6 to plugins 2014-11-16 20:55:56 +11:00
Joshua Peek
0c57a00fdb Check if attachEvent is defined 2014-11-16 01:41:56 -08:00
Joshua Peek
3bec8b0311 Prefer module global reference rather than window 2014-11-16 01:41:16 -08:00
Sebastian McKenzie
6a88e05362 v1.12.17 2014-11-16 19:29:25 +11:00
Sebastian McKenzie
e3bd2dff8d remove unused path variable 2014-11-16 19:27:49 +11:00
Sebastian McKenzie
ef82171254 update amd/umd modules documentation 2014-11-16 19:27:15 +11:00
Sebastian McKenzie
00d94fd810 update changelog with additional new options 2014-11-16 19:26:03 +11:00
Sebastian McKenzie
d929d3c5eb remove duplicate i variable from traverse 2014-11-16 19:24:58 +11:00
Sebastian McKenzie
5c1ee86b97 remove filenameRelative from bin/6to5* since it's unneccesary 2014-11-16 19:24:47 +11:00
Sebastian McKenzie
5409691a3a update umd and amd tests with new moduleName option 2014-11-16 19:22:37 +11:00
Sebastian McKenzie
24964ac454 add filenameRelative to bin/6to5* 2014-11-16 19:20:08 +11:00
Sebastian McKenzie
faa81ab85b add 1.12.17 changelog 2014-11-16 19:19:57 +11:00
Sebastian McKenzie
d4bc082bb9 add new filenameRelative, sourceRoot and moduleRoot option documentation 2014-11-16 19:19:46 +11:00
Sebastian McKenzie
3777af6bbd add filenameRelative default and make sourceFileName and sourceMapName inherit form it 2014-11-16 19:19:25 +11:00
Sebastian McKenzie
1f258e9e9c add sourceRoot to source map 2014-11-16 19:19:07 +11:00
Sebastian McKenzie
50333c879c add comments and change single quotes in amd formatter getModuleName 2014-11-16 19:18:56 +11:00
Sebastian McKenzie
105e6ac379 add filenameRelative to tests 2014-11-16 19:18:30 +11:00
Sebastian McKenzie
dadab64e39 Merge pull request #176 from darvelo/master
Generate moduleNames for AMD/UMD
2014-11-16 19:00:56 +11:00
Sebastian McKenzie
2b82f2bcc2 ignore unknown nodes in traversal 2014-11-16 18:52:54 +11:00
Sebastian McKenzie
f1183505b1 optimise traverse, improves traversal speed by 50% 2014-11-16 18:50:07 +11:00
Sebastian McKenzie
fa3b24e5b4 don't lazy set templates, can't even remember why i did this 2014-11-16 18:49:29 +11:00
Sebastian McKenzie
5789447068 add loc option to exec test 2014-11-16 18:48:32 +11:00
David Arvelo
f1f7321590 Generate moduleNames for AMD/UMD 2014-11-16 02:38:00 -05:00
211 changed files with 4747 additions and 311 deletions

View File

@@ -1,3 +1,42 @@
# 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).
* Embed `regenerator`.
# 1.12.18
* Use `global` reference instead of `window`.
# 1.12.17
* Add `moduleName`, `sourceRoot` and `filenameRelative` options. Thanks [@darvelo](https://github.com/darvelo).
* Traversal optimisations.
# 1.12.16
* Fix comments not being retained from `MethodDefinition` in classes.

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

@@ -17,6 +17,8 @@ commander.option("-w, --whitelist [whitelist]", "Whitelist of transformers to ON
commander.option("-b, --blacklist [blacklist]", "Blacklist of transformers to NOT use", util.list);
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) {
@@ -88,6 +90,8 @@ exports.opts = {
blacklist: commander.blacklist,
whitelist: commander.whitelist,
sourceMap: commander.sourceMaps || commander.sourceMapsInline,
comments: !commander.removeComments,
amdModuleIds: commander.amdModuleIds,
runtime: commander.runtime,
modules: commander.modules
};

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

@@ -37,7 +37,7 @@ 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
### Array destructuring / Spread
An [ES6 polyfill](polyfill.md) is required in order for spread to work. More
specifically a polyfill for `Array.from`.
An [ES6 polyfill](polyfill.md) is required for spread and array destructuring.
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

@@ -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
```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

@@ -77,6 +77,12 @@ define(["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**
@@ -111,7 +117,6 @@ export function bar() {
### Ignore
**In**
```javascript

View File

@@ -5,11 +5,13 @@
- [Brunch](https://github.com/es128/6to5-brunch)
- [Duo](https://github.com/bdo-labs/duo6to5)
- [Connect](https://github.com/6to5/6to5-connect)
- [Gobble](https://github.com/gobblejs/gobble-6to5)
- [Gulp](https://github.com/sindresorhus/gulp-6to5)
- [Grunt](https://github.com/sindresorhus/grunt-6to5)
- [Jade](https://github.com/Apoxx/jade-6to5)
- [Jest](https://github.com/6to5/6to5-jest)
- [JSXHint](https://github.com/STRML/JSXHint) (A wrapper around JSHint to allow linting of JSX files)
- [Karma](https://github.com/shuhei/karma-6to5-preprocessor)
- [Mocha](https://github.com/6to5/6to5-mocha)
- [Rails](https://github.com/6to5/6to5-rails)
- [Rails](https://github.com/josh/sprockets-es6) or via [browserify-rails](https://github.com/6to5/6to5-rails)
- [webpack](https://github.com/Couto/6to5-loader)

View File

@@ -83,6 +83,10 @@ to5.transformFile("filename.js", options, function (err, result) {
// Default: "unknown"
filename: "filename",
// Filename relative to `sourceRoot`
// Default: `filename` option.
filenameRelative: "",
// List of transformers to EXCLUDE.
// Run `6to5 --help` to see a full list of transformers.
blacklist: [],
@@ -103,17 +107,35 @@ to5.transformFile("filename.js", options, function (err, result) {
sourceMap: true,
// Set `file` on returned source map.
// Default: `filename` option.
// Default: `filenameRelative` option.
sourceMapName: "filename",
// Set `sources[0]` on returned source map.
// Default: `filename` option.
// Default: `filenameRelative` option.
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
runtime: true
runtime: true,
// Output comments in generated output
// Default: true
comments: false
}
```

View File

@@ -12,7 +12,7 @@ transform.load = function (url, callback, opts, hold) {
opts = opts || {};
opts.filename = opts.filename || url;
var xhr = window.ActiveXObject ? new window.ActiveXObject("Microsoft.XMLHTTP") : new window.XMLHttpRequest();
var xhr = global.ActiveXObject ? new global.ActiveXObject("Microsoft.XMLHTTP") : new global.XMLHttpRequest();
xhr.open("GET", url, true);
if ("overrideMimeType" in xhr) xhr.overrideMimeType("text/plain");
@@ -60,7 +60,7 @@ var runScripts = function () {
}
};
var _scripts = window.document.getElementsByTagName("script");
var _scripts = global.document.getElementsByTagName("script");
for (var i in _scripts) {
var _script = _scripts[i];
if (types.indexOf(_script.type) >= 0) scripts.push(_script);
@@ -73,8 +73,8 @@ var runScripts = function () {
exec();
};
if (window.addEventListener) {
window.addEventListener("DOMContentLoaded", runScripts, false);
} else {
window.attachEvent("onload", runScripts);
if (global.addEventListener) {
global.addEventListener("DOMContentLoaded", runScripts, false);
} else if (global.attachEvent) {
global.attachEvent("onload", runScripts);
}

View File

@@ -19,7 +19,7 @@ function File(opts) {
}
File.declarations = ["extends", "class-props", "slice", "apply-constructor",
"tagged-template-literal"];
"tagged-template-literal", "interop-require"];
File.normaliseOptions = function (opts) {
opts = _.cloneDeep(opts || {});
@@ -29,6 +29,7 @@ File.normaliseOptions = function (opts) {
blacklist: [],
whitelist: [],
sourceMap: false,
comments: true,
filename: "unknown",
modules: "common",
runtime: false,
@@ -38,9 +39,24 @@ File.normaliseOptions = function (opts) {
// 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, {
sourceFileName: opts.filename,
sourceMapName: opts.filename
moduleRoot: opts.sourceRoot
});
_.defaults(opts, {
sourceRoot: opts.moduleRoot
});
_.defaults(opts, {
filenameRelative: opts.filename
});
_.defaults(opts, {
sourceFileName: opts.filenameRelative,
sourceMapName: opts.filenameRelative
});
if (opts.runtime === true) {
@@ -54,7 +70,7 @@ File.normaliseOptions = function (opts) {
};
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);

View File

@@ -35,21 +35,17 @@ _.each(Buffer.prototype, function (fn, key) {
});
CodeGenerator.normaliseOptions = function (opts) {
opts = opts.format || {};
opts = _.merge({
return _.merge({
parentheses: true,
semicolons: true,
comments: true,
comments: opts.comments == null || opts.comments,
compact: false,
indent: {
adjustMultilineComment: true,
style: " ",
base: 0
}
}, opts);
return opts;
}, opts.format || {});
};
CodeGenerator.generators = {
@@ -169,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

@@ -9,7 +9,8 @@ function SourceMap(position, opts, code) {
if (opts.sourceMap) {
this.map = new sourceMap.SourceMapGenerator({
file: opts.sourceMapName
file: opts.sourceMapName,
sourceRoot: opts.sourceRoot
});
this.map.setSourceContent(opts.sourceFileName, code);

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

@@ -3,4 +3,4 @@ if (typeof Symbol === "undefined") {
}
require("es6-shim");
require("regenerator-6to5/runtime");
require("./transformation/transformers/generators/runtime");

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");
@@ -71,7 +72,8 @@ var loader = function (m, filename) {
var result = to5.transformFileSync(filename, {
whitelist: whitelist,
blacklist: blacklist,
sourceMap: true
sourceMap: true,
modules: "commonInterop"
});
maps[filename] = result.map;
@@ -100,11 +102,11 @@ 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;
if (opts.blacklist) blacklist = util.arrayify(opts.blacklist);
if (opts.whitelist) whitelist = util.arrayify(opts.whitelist);
};

View File

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

View File

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

View File

@@ -30,11 +30,47 @@ AMDFormatter.prototype.transform = function (ast) {
params.unshift(t.identifier("exports"));
var container = t.functionExpression(null, params, t.blockStatement(body));
var call = t.callExpression(t.identifier("define"), [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)];
};
AMDFormatter.prototype.getModuleName = function () {
var opts = this.file.opts;
var filenameRelative = opts.filenameRelative;
var moduleName = "";
if (!opts.amdModuleIds) {
return null;
}
if (opts.moduleRoot) {
moduleName = opts.moduleRoot + "/";
}
if (!opts.filenameRelative) {
return moduleName + opts.filename.replace(/^\//, "");
}
if (opts.sourceRoot) {
// remove sourceRoot from filename
var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
}
// remove extension
filenameRelative = filenameRelative.replace(/\.(.*?)$/, "");
moduleName += filenameRelative;
return moduleName;
};
AMDFormatter.prototype._push = function (node) {
var id = node.source.value;
var ids = this.ids;

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,8 +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.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({
@@ -45,17 +46,17 @@ _.each({
destructuring: require("./transformers/destructuring"),
forOf: require("./transformers/for-of"),
unicodeRegex: require("./transformers/unicode-regex"),
react: require("./transformers/react"),
constants: require("./transformers/constants"),
letScoping: require("./transformers/let-scoping"),
react: require("./transformers/react"),
generators: require("./transformers/generators"),
_aliasFunctions: require("./transformers/_alias-functions"),
_blockHoist: require("./transformers/_block-hoist"),
_declarations: require("./transformers/_declarations"),
_aliasFunctions: require("./transformers/_alias-functions"),
generators: require("./transformers/generators"),
useStrict: require("./transformers/use-strict"),
_memberExpressionKeywords: require("./transformers/_member-expression-keywords"),

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

@@ -1,5 +1,6 @@
var t = require("../../types");
var _ = require("lodash");
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
var buildVariableAssign = function (kind, id, init) {
if (kind === false) {
@@ -11,50 +12,64 @@ 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);
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 = t.identifier(opts.file.generateUid("ref", opts.scope));
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(_parentId, util.template("array-from", {
VALUE: 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 = util.template("array-from", {
VALUE: 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;
@@ -71,7 +86,7 @@ var pushPattern = function (opts) {
parentId = key;
}
push(kind, nodes, pattern, parentId);
push(opts, nodes, pattern, parentId);
};
exports.ForInStatement =
@@ -89,7 +104,11 @@ exports.ForOfStatement = function (node, parent, file, scope) {
var nodes = [];
push(declar.kind, nodes, pattern, key);
push({
kind: declar.kind,
file: file,
scope: scope
}, nodes, pattern, key);
t.ensureBlock(node);
@@ -141,7 +160,11 @@ exports.ExpressionStatement = function (node, parent, file, scope) {
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

@@ -1,3 +0,0 @@
var regenerator = require("regenerator-6to5");
module.exports = regenerator.transform;

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

@@ -0,0 +1,151 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* 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 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) {
assert.ok(funPath instanceof types.NodePath);
t.assertFunction(funPath.value);
var vars = {};
function varDeclToExpr(vdec, includeIdentifiers) {
t.assertVariableDeclaration(vdec);
var exprs = [];
vdec.declarations.forEach(function (dec) {
vars[dec.id.name] = dec.id;
if (dec.init) {
exprs.push(t.assignmentExpression(
"=", dec.id, dec.init
));
} else if (includeIdentifiers) {
exprs.push(dec.id);
}
});
if (exprs.length === 0)
return null;
if (exprs.length === 1)
return exprs[0];
return t.sequenceExpression(exprs);
}
types.visit(funPath.get("body"), {
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 t.expressionStatement(expr);
}
// Since the original node has been either removed or replaced,
// avoid traversing it any further.
return false;
},
visitForStatement: function (path) {
var init = path.value.init;
if (t.isVariableDeclaration(init)) {
path.get("init").replace(varDeclToExpr(init, false));
}
this.traverse(path);
},
visitForInStatement: function (path) {
var left = path.value.left;
if (t.isVariableDeclaration(left)) {
path.get("left").replace(varDeclToExpr(left, true));
}
this.traverse(path);
},
visitFunctionDeclaration: function (path) {
var node = path.value;
vars[node.id.name] = node.id;
var assignment = t.expressionStatement(
t.assignmentExpression(
"=",
node.id,
t.functionExpression(
node.id,
node.params,
node.body,
node.generator,
node.expression
)
)
);
if (t.isBlockStatement(path.parent.node)) {
// Insert the assignment form before the first statement in the
// enclosing block.
path.parent.get("body").unshift(assignment);
// Remove the function declaration now that we've inserted the
// equivalent assignment form at the beginning of the block.
path.replace();
} else {
// If the parent node is not a block statement, then we can just
// replace the declaration with the equivalent assignment form
// without worrying about hoisting it.
path.replace(assignment);
}
// Don't hoist variables out of inner functions.
return false;
},
visitFunctionExpression: function () {
// Don't descend into nested function expressions.
return false;
}
});
var paramNames = {};
funPath.get("params").each(function (paramPath) {
var param = paramPath.value;
if (t.isIdentifier(param)) {
paramNames[param.name] = param;
} else {
// Variables declared by destructuring parameter patterns will be
// harmlessly re-declared.
}
});
var declarations = [];
Object.keys(vars).forEach(function (name) {
if (!_.has(paramNames, name)) {
declarations.push(t.variableDeclarator(vars[name], null));
}
});
if (declarations.length === 0) {
return null; // Be sure to handle this case!
}
return t.variableDeclaration("var", declarations);
};

View File

@@ -0,0 +1 @@
module.exports = require("./visit").transform;

View File

@@ -0,0 +1,163 @@
/**
* 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.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 util = require("util");
var t = require("../../../types");
var inherits = util.inherits;
function Entry() {
assert.ok(this instanceof Entry);
}
function FunctionEntry(returnLoc) {
Entry.call(this);
t.assertLiteral(returnLoc);
this.returnLoc = returnLoc;
}
inherits(FunctionEntry, Entry);
function LoopEntry(breakLoc, continueLoc, label) {
Entry.call(this);
t.assertLiteral(breakLoc);
t.assertLiteral(continueLoc);
if (label) {
t.assertIdentifier(label);
} else {
label = null;
}
this.breakLoc = breakLoc;
this.continueLoc = continueLoc;
this.label = label;
}
inherits(LoopEntry, Entry);
function SwitchEntry(breakLoc) {
Entry.call(this);
t.assertLiteral(breakLoc);
this.breakLoc = breakLoc;
}
inherits(SwitchEntry, Entry);
function TryEntry(firstLoc, catchEntry, finallyEntry) {
Entry.call(this);
t.assertLiteral(firstLoc);
if (catchEntry) {
assert.ok(catchEntry instanceof CatchEntry);
} else {
catchEntry = null;
}
if (finallyEntry) {
assert.ok(finallyEntry instanceof FinallyEntry);
} else {
finallyEntry = null;
}
// Have to have one or the other (or both).
assert.ok(catchEntry || finallyEntry);
this.firstLoc = firstLoc;
this.catchEntry = catchEntry;
this.finallyEntry = finallyEntry;
}
inherits(TryEntry, Entry);
function CatchEntry(firstLoc, paramId) {
Entry.call(this);
t.assertLiteral(firstLoc);
t.assertIdentifier(paramId);
this.firstLoc = firstLoc;
this.paramId = paramId;
}
inherits(CatchEntry, Entry);
function FinallyEntry(firstLoc) {
Entry.call(this);
t.assertLiteral(firstLoc);
this.firstLoc = firstLoc;
}
inherits(FinallyEntry, Entry);
function LeapManager(emitter) {
assert.ok(this instanceof LeapManager);
var Emitter = require("./emit").Emitter;
assert.ok(emitter instanceof Emitter);
this.emitter = emitter;
this.entryStack = [new FunctionEntry(emitter.finalLoc)];
}
LeapManager.prototype.withEntry = function (entry, callback) {
assert.ok(entry instanceof Entry);
this.entryStack.push(entry);
try {
callback.call(this.emitter);
} finally {
var popped = this.entryStack.pop();
assert.strictEqual(popped, entry);
}
};
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];
if (loc) {
if (label) {
if (entry.label &&
entry.label.name === label.name) {
return loc;
}
} else {
return loc;
}
}
}
return null;
};
LeapManager.prototype.getBreakLoc = function (label) {
return this._findLeapLocation("breakLoc", label);
};
LeapManager.prototype.getContinueLoc = function (label) {
return this._findLeapLocation("continueLoc", label);
};

View File

@@ -0,0 +1,98 @@
/**
* 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 m = require("private").makeAccessor();
var _ = require("lodash");
var isArray = types.builtInTypes.array;
var n = types.namedTypes;
function makePredicate(propertyName, knownTypes) {
function onlyChildren(node) {
n.Node.check(node);
// Assume no side effects until we find out otherwise.
var result = false;
function check(child) {
if (result) {
// Do nothing.
} else if (isArray.check(child)) {
child.some(check);
} else if (n.Node.check(child)) {
assert.strictEqual(result, false);
result = predicate(child);
}
return result;
}
types.eachField(node, function (name, child) {
check(child);
});
return result;
}
function predicate(node) {
n.Node.check(node);
var meta = m(node);
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 (_.has(opaqueTypes, node.type)) return meta[propertyName] = false;
if (_.has(knownTypes, node.type)) return meta[propertyName] = true;
return meta[propertyName] = onlyChildren(node);
}
predicate.onlyChildren = onlyChildren;
return predicate;
}
var opaqueTypes = {
FunctionExpression: true
};
// These types potentially have side effects regardless of what side
// effects their subexpressions have.
var sideEffectTypes = {
CallExpression: true, // Anything could happen!
ForInStatement: true, // Modifies the key variable.
UnaryExpression: true, // Think delete.
BinaryExpression: true, // Might invoke .toString() or .valueOf().
AssignmentExpression: true, // Side-effecting by definition.
UpdateExpression: true, // Updates are essentially assignments.
NewExpression: true // Similar to CallExpression.
};
// These types are the direct cause of all leaps in control flow.
var leapTypes = {
YieldExpression: true,
BreakStatement: true,
ContinueStatement: true,
ReturnStatement: true,
ThrowStatement: true
};
// All leap types are also side effect types.
for (var type in leapTypes) {
if (_.has(leapTypes, type)) {
sideEffectTypes[type] = leapTypes[type];
}
}
exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes);
exports.containsLeap = makePredicate("containsLeap", leapTypes);

View File

@@ -0,0 +1,454 @@
/**
* 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 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 || []);
};
var GenStateSuspendedStart = "suspendedStart";
var GenStateSuspendedYield = "suspendedYield";
var GenStateExecuting = "executing";
var GenStateCompleted = "completed";
// Returning this object from the innerFn has the same effect as
// breaking out of the dispatch switch statement.
var ContinueSentinel = {};
// Dummy constructor that we use as the .constructor property for
// functions that return Generator objects.
var GF = function GeneratorFunction() {};
var GFp = function GeneratorFunctionPrototype() {};
var Gp = GFp.prototype = Generator.prototype;
(GFp.constructor = GF).prototype =
Gp.constructor = GFp;
// Ensure isGeneratorFunction works when Function#name not supported.
var GFName = "GeneratorFunction";
if (GF.name !== GFName) GF.name = GFName;
if (GF.name !== GFName) throw new Error(GFName + " renamed?");
runtime.isGeneratorFunction = function (genFun) {
var ctor = genFun && genFun.constructor;
return ctor ? GF.name === ctor.name : false;
};
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) {
var generator = wrap(innerFn, outerFn, self, tryList);
var callNext = step.bind(generator.next);
var callThrow = step.bind(generator["throw"]);
function step(arg) {
var info;
var value;
try {
info = this(arg);
value = info.value;
} catch (error) {
return reject(error);
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(callNext, callThrow);
}
}
callNext();
});
};
function Generator(innerFn, outerFn, self, tryList) {
var generator = outerFn ? Object.create(outerFn.prototype) : this;
var context = new Context(tryList);
var state = GenStateSuspendedStart;
function invoke(method, arg) {
if (state === GenStateExecuting) {
throw new Error("Generator is already running");
}
if (state === GenStateCompleted) {
throw new Error("Generator has already finished");
}
while (true) {
var delegate = context.delegate;
var info;
if (delegate) {
try {
info = delegate.iterator[method](arg);
// Delegate generator ran and handled its own exceptions so
// regardless of what the method was, we continue as if it is
// "next" with an undefined arg.
method = "next";
arg = undefined;
} catch (uncaught) {
context.delegate = null;
// Like returning generator.throw(uncaught), but without the
// overhead of an extra function call.
method = "throw";
arg = uncaught;
continue;
}
if (info.done) {
context[delegate.resultName] = info.value;
context.next = delegate.nextLoc;
} else {
state = GenStateSuspendedYield;
return info;
}
context.delegate = null;
}
if (method === "next") {
if (state === GenStateSuspendedStart &&
typeof arg !== "undefined") {
// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
throw new TypeError(
"attempt to send " + JSON.stringify(arg) + " to newborn generator"
);
}
if (state === GenStateSuspendedYield) {
context.sent = arg;
} else {
delete context.sent;
}
} else if (method === "throw") {
if (state === GenStateSuspendedStart) {
state = GenStateCompleted;
throw arg;
}
if (context.dispatchException(arg)) {
// If the dispatched exception was caught by a catch block,
// then let that catch block handle the exception normally.
method = "next";
arg = undefined;
}
} else if (method === "return") {
context.abrupt("return", arg);
}
state = GenStateExecuting;
try {
var value = innerFn.call(self, context);
// If an exception is thrown from innerFn, we leave state ===
// GenStateExecuting and loop back for another invocation.
state = context.done ? GenStateCompleted : GenStateSuspendedYield;
info = {
value: value,
done: context.done
};
if (value === ContinueSentinel) {
if (context.delegate && method === "next") {
// Deliberately forget the last sent value so that we don't
// accidentally pass it on to the delegate.
arg = undefined;
}
} else {
return info;
}
} catch (thrown) {
state = GenStateCompleted;
if (method === "next") {
context.dispatchException(thrown);
} else {
arg = thrown;
}
}
}
}
generator.next = invoke.bind(generator, "next");
generator["throw"] = invoke.bind(generator, "throw");
generator["return"] = invoke.bind(generator, "return");
return generator;
}
Gp[iteratorSymbol] = function () {
return this;
};
Gp.toString = function () {
return "[object Generator]";
};
function pushTryEntry(triple) {
var entry = { tryLoc: triple[0] };
if (1 in triple) {
entry.catchLoc = triple[1];
}
if (2 in triple) {
entry.finallyLoc = triple[2];
}
this.tryEntries.push(entry);
}
function resetTryEntry(entry, i) {
var record = entry.completion || {};
record.type = i === 0 ? "normal" : "return";
delete record.arg;
entry.completion = record;
}
function Context(tryList) {
// The root entry object (effectively a try statement without a catch
// or a finally block) gives us a place to store values thrown from
// locations where there is no enclosing try statement.
this.tryEntries = [{ tryLoc: "root" }];
tryList.forEach(pushTryEntry, this);
this.reset();
}
runtime.keys = function (object) {
var keys = [];
for (var key in object) {
keys.push(key);
}
keys.reverse();
// Rather than returning an object with a next method, we keep
// things simple and return the next function itself.
return function next() {
while (keys.length) {
var key = keys.pop();
if (key in object) {
next.value = key;
next.done = false;
return next;
}
}
// To avoid creating an additional object, we just hang the .value
// and .done properties off the next function object itself. This
// also ensures that the minifier will not anonymize the function.
next.done = true;
return next;
};
};
function values(iterable) {
var iterator = iterable;
if (iteratorSymbol in iterable) {
iterator = iterable[iteratorSymbol]();
} else if (!isNaN(iterable.length)) {
var i = -1;
iterator = function next() {
while (++i < iterable.length) {
if (i in iterable) {
next.value = iterable[i];
next.done = false;
return next;
}
}
next.done = true;
return next;
};
iterator.next = iterator;
}
return iterator;
}
runtime.values = values;
Context.prototype = {
constructor: Context,
reset: function () {
this.prev = 0;
this.next = 0;
this.sent = undefined;
this.done = false;
this.delegate = null;
this.tryEntries.forEach(resetTryEntry);
// Pre-initialize at least 20 temporary variables to enable hidden
// class optimizations for simple generators.
for (var tempIndex = 0, tempName;
hasOwn.call(this, tempName = "t" + tempIndex) || tempIndex < 20;
++tempIndex) {
this[tempName] = null;
}
},
stop: function () {
this.done = true;
var rootEntry = this.tryEntries[0];
var rootRecord = rootEntry.completion;
if (rootRecord.type === "throw") {
throw rootRecord.arg;
}
return this.rval;
},
dispatchException: function (exception) {
if (this.done) {
throw exception;
}
var context = this;
function handle(loc, caught) {
record.type = "throw";
record.arg = exception;
context.next = loc;
return !!caught;
}
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
var record = entry.completion;
if (entry.tryLoc === "root") {
// Exception thrown outside of any try block that could handle
// it, so set the completion value of the entire function to
// throw the exception.
return handle("end");
}
if (entry.tryLoc <= this.prev) {
var hasCatch = hasOwn.call(entry, "catchLoc");
var hasFinally = hasOwn.call(entry, "finallyLoc");
if (hasCatch && hasFinally) {
if (this.prev < entry.catchLoc) {
return handle(entry.catchLoc, true);
} else if (this.prev < entry.finallyLoc) {
return handle(entry.finallyLoc);
}
} else if (hasCatch) {
if (this.prev < entry.catchLoc) {
return handle(entry.catchLoc, true);
}
} else if (hasFinally) {
if (this.prev < entry.finallyLoc) {
return handle(entry.finallyLoc);
}
} else {
throw new Error("try statement without catch or finally");
}
}
}
},
_findFinallyEntry: function (finallyLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc <= this.prev &&
hasOwn.call(entry, "finallyLoc") && (
entry.finallyLoc === finallyLoc ||
this.prev < entry.finallyLoc)) {
return entry;
}
}
},
abrupt: function (type, arg) {
var entry = this._findFinallyEntry();
var record = entry ? entry.completion : {};
record.type = type;
record.arg = arg;
if (entry) {
this.next = entry.finallyLoc;
} else {
this.complete(record);
}
return ContinueSentinel;
},
complete: function (record) {
if (record.type === "throw") {
throw record.arg;
}
if (record.type === "break" || record.type === "continue") {
this.next = record.arg;
} else if (record.type === "return") {
this.rval = record.arg;
this.next = "end";
}
return ContinueSentinel;
},
finish: function (finallyLoc) {
var entry = this._findFinallyEntry(finallyLoc);
return this.complete(entry.completion);
},
"catch": function (tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc === tryLoc) {
var record = entry.completion;
var thrown;
if (record.type === "throw") {
thrown = record.arg;
resetTryEntry(entry, i);
}
return thrown;
}
}
// The context.catch method must only be called with a location
// argument that corresponds to a known catch block.
throw new Error("illegal catch attempt");
},
delegateYield: function (iterable, resultName, nextLoc) {
this.delegate = {
iterator: values(iterable),
resultName: resultName,
nextLoc: nextLoc
};
return ContinueSentinel;
}
};

View File

@@ -0,0 +1,28 @@
/**
* 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 t = require("../../../types");
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

@@ -0,0 +1,218 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* 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 runtimeProperty = require("./util").runtimeProperty;
var Emitter = require("./emit").Emitter;
var hoist = require("./hoist").hoist;
var types = require("ast-types");
var t = require("../../../types");
var runtimeAsyncMethod = runtimeProperty("async");
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
exports.transform = function transform(node) {
return types.visit(node, visitor);
};
var visitor = types.PathVisitor.fromMethodsObject({
visitFunction: function (path) {
// Calling this.traverse(path) first makes for a post-order traversal.
this.traverse(path);
var node = path.value;
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 = path.scope.parent.declareTemporary("callee$")
);
var innerFnId = t.identifier(node.id.name + "$");
var contextId = path.scope.declareTemporary("context$");
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;
}
// 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 = t.variableDeclaration("var", [
t.variableDeclarator(
node.id,
t.callExpression(runtimeMarkMethod, [node])
)
]);
// Copy any comments preceding the function declaration to the
// variable declaration, to avoid weird formatting consequences.
t.inheritsComments(varDecl, node);
t.removeComments(node);
varDecl._blockHoist = true;
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 {
t.assertFunctionExpression(node);
return t.callExpression(runtimeMarkMethod, [node]);
}
}
});
function shouldNotHoistAbove(stmtPath) {
var value = stmtPath.value;
t.assertStatement(value);
// If the first statement is a "use strict" declaration, make sure to
// insert hoisted declarations afterwards.
if (t.isExpressionStatement(value) &&
t.isLiteral(value.expression) &&
value.expression.value === "use strict") {
return true;
}
if (t.isVariableDeclaration(value)) {
for (var i = 0; i < value.declarations.length; ++i) {
var decl = value.declarations[i];
if (t.isCallExpression(decl.init) && types.astNodesAreEquivalent(decl.init.callee, runtimeMarkMethod)) {
return true;
}
}
}
return false;
}
var awaitVisitor = types.PathVisitor.fromMethodsObject({
visitFunction: function () {
return false; // Don't descend into nested function scopes.
},
visitAwaitExpression: function (path) {
// Convert await expressions to yield expressions.
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();
@@ -128,27 +131,39 @@ LetScoping.prototype.run = function () {
var call = t.callExpression(fn, params);
var ret = t.identifier(this.file.generateUid("ret", this.scope));
var hasYield = traverse.hasType(fn.body, "YieldExpression", t.FUNCTION_TYPES);
if (hasYield) {
fn.generator = true;
call = t.yieldExpression(call, true);
}
this.build(ret, call);
};
/**
* 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;
};
@@ -245,28 +260,34 @@ LetScoping.prototype.checkFor = function () {
hasBreak: false,
};
if (this.forParent) {
traverse(this.block, function (node) {
var replace;
var forParent = this.forParent;
if (t.isFunction(node) || t.isFor(node)) {
return false;
} else if (t.isBreakStatement(node) && !node.label) {
traverse(this.block, function (node) {
var replace;
if (t.isFunction(node) || t.isFor(node)) {
return false;
}
if (forParent && node && !node.label) {
if (t.isBreakStatement(node)) {
has.hasBreak = true;
replace = t.returnStatement(t.literal("break"));
} else if (t.isContinueStatement(node) && !node.label) {
} else if (t.isContinueStatement(node)) {
has.hasContinue = true;
replace = t.returnStatement(t.literal("continue"));
} else if (t.isReturnStatement(node)) {
has.hasReturn = true;
replace = t.returnStatement(t.objectExpression([
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
]));
}
}
if (replace) return t.inherits(replace, node);
});
}
if (t.isReturnStatement(node)) {
has.hasReturn = true;
replace = t.returnStatement(t.objectExpression([
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
]));
}
if (replace) return t.inherits(replace, node);
});
return has;
};

View File

@@ -1,13 +1,13 @@
var t = require("../../types");
var _ = require("lodash");
var util = require("../../util");
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]
);
literal = util.template("array-from", {
VALUE: literal
});
}
return literal;
};

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

@@ -29,25 +29,32 @@ function traverse(parent, callbacks, opts) {
// normalise callbacks
if (_.isFunction(callbacks)) callbacks = { enter: callbacks };
_.each(keys, function (key) {
for (var i in keys) {
var key = keys[i];
var nodes = parent[key];
if (!nodes) return;
if (!nodes) continue;
var updated = false;
var handle = function (obj, key) {
var node = obj[key];
if (!node) return;
// type is blacklisted
if (_.contains(blacklistTypes, node.type)) return;
if (blacklistTypes.indexOf(node.type) > -1) return;
// replace node
var maybeReplace = function (result) {
if (result === false) return;
if (result != null) node = obj[key] = result;
if (result != null) {
updated = true;
node = obj[key] = result;
}
};
//
var opts2 = _.clone(opts);
var opts2 = { scope: opts.scope, blacklist: opts.blacklist };
if (t.isScope(node)) opts2.scope = new Scope(opts.scope, node);
// enter
@@ -69,15 +76,15 @@ function traverse(parent, callbacks, opts) {
};
if (_.isArray(nodes)) {
_.each(nodes, function (node, i) {
for (i in nodes) {
handle(nodes, i);
});
}
parent[key] = _.flatten(parent[key]);
if (updated) parent[key] = _.flatten(parent[key]);
} else {
handle(parent, key);
}
});
}
}
traverse.removeProperties = function (tree) {

View File

@@ -6,25 +6,30 @@ var _ = require("lodash");
var FOR_KEYS = ["left", "init"];
/**
* This searches the current "scope" and collects all references/declarations
* within.
*
* @param {Scope} [parent]
* @param {Node} block
*/
function Scope(parent, block) {
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;
var self = this;
var info = block._scope = {
declarations: {}
};
var self = this;
var references = block._scope = {};
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,7 +19,9 @@
"Property": ["kind", "key", "value", "computed"],
"ReturnStatement": ["argument"],
"SequenceExpression": ["expressions"],
"ThrowExpression": ["argument"],
"UnaryExpression": ["operator", "argument", "prefix"],
"VariableDeclaration": ["kind", "declarations"],
"VariableDeclarator": ["id", "init"]
"VariableDeclarator": ["id", "init"],
"YieldExpression": ["argument", "delegate"]
}

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;
@@ -276,9 +291,5 @@ try {
} catch (err) {
if (err.code !== "MODULE_NOT_FOUND") throw err;
Object.defineProperty(exports, "templates", {
get: function () {
return exports.templates = loadTemplates();
}
});
exports.templates = loadTemplates();
}

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.12.16",
"version": "1.12.24",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/6to5/6to5",
"repository": {
@@ -37,19 +37,19 @@
"dependencies": {
"ast-types": "~0.6.0",
"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-symbol": "0.1.1",
"regexpu": "0.3.0",
"source-map": "0.1.40",
"regenerator-6to5": "https://github.com/6to5/regenerator-6to5/archive/a9c53518af063ffef410f826225f8ee250131932.tar.gz",
"chokidar": "0.10.5",
"chokidar": "0.11.0",
"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"
"acorn-6to5": "0.9.1-2",
"estraverse": "^1.7.0",
"private": "^0.1.6"
},
"devDependencies": {
"istanbul": "0.3.2",

View File

@@ -0,0 +1,33 @@
var assert = require("assert");
exports.check = function check(g, yields, returnValue) {
for (var i = 0; i < yields.length; ++i) {
var info = i > 0 ? g.next(i) : g.next();
assert.deepEqual(info.value, yields[i]);
assert.strictEqual(info.done, false);
}
assert.deepEqual(
i > 0 ? g.next(i) : g.next(),
{ value: returnValue, done: true }
);
};
// A version of `throw` whose behavior can't be statically analyzed.
// Useful for testing dynamic exception dispatching.
exports.raise = function raise(argument) {
throw argument;
};
exports.assertAlreadyFinished = function assertAlreadyFinished(generator) {
try {
generator.next();
assert.ok(false, "should have thrown an exception");
} catch (err) {
assert.ok(err instanceof Error);
assert.strictEqual(
err.message,
"Generator has already finished"
);
}
};

View File

@@ -48,8 +48,9 @@ exports.get = function (entryName) {
var execLoc = taskDir + "/exec.js";
var taskOpts = _.merge({
sourceFileName: actualLocAlias,
sourceMapName: expectLocAlias
filenameRelative: expectLocAlias,
sourceFileName: actualLocAlias,
sourceMapName: expectLocAlias
}, _.cloneDeep(suite.options));
var taskOptsLoc = taskDir + "/options.json";
@@ -60,6 +61,7 @@ exports.get = function (entryName) {
disabled: taskName[0] === ".",
options: taskOpts,
exec: {
loc: execLoc,
code: readFile(execLoc),
filename: execLocAlias,
},

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

@@ -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

@@ -0,0 +1,7 @@
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.

View File

@@ -0,0 +1,26 @@
async function outer(value) {
var resolved = false;
var p1 = new Promise(function(resolve) {
setTimeout(function() {
resolve(value + 1);
resolved = true;
}, 0);
});
assert.strictEqual(resolved, false);
var v2 = await p1.then(function(value) {
return value + 1;
});
assert.strictEqual(resolved, true);
var v1 = await p1;
return [v1, v2];
}
outer(1).then(function(pair) {
assert.deepEqual(pair, [2, 3]);
done();
}).catch(done);

View File

@@ -0,0 +1,40 @@
var markers = [];
async function innerMost(marker) {
markers.push(marker);
return await marker;
}
async function inner(marker) {
markers.push(marker);
assert.strictEqual(
await innerMost(marker + 1),
marker + 1
);
markers.push(marker + 2);
assert.strictEqual(
await innerMost(marker + 3),
marker + 3
);
markers.push(marker + 4);
}
async function outer() {
markers.push(0);
await inner(1);
markers.push(6);
await inner(7);
markers.push(12);
}
outer().then(function() {
var expected = [];
for (var i = 0; i <= 12; ++i)
expected.push(i);
assert.deepEqual(markers, expected);
done();
}).catch(done);

View File

@@ -0,0 +1,15 @@
var called = false;
async function noAwait(value) {
called = true;
return value;
}
var promise = noAwait("asdf");
assert.strictEqual(called, true);
promise.then(function(value) {
assert.strictEqual(called, true);
assert.strictEqual(value, "asdf");
done();
}).catch(done);

View File

@@ -0,0 +1,19 @@
var flag1 = false;
var flag2 = false;
async function oneAwait(value) {
flag1 = true;
var result = await value;
flag2 = true;
return result;
}
var promise = oneAwait("asdf");
assert.strictEqual(flag1, true);
assert.strictEqual(flag2, false);
promise.then(function(value) {
assert.strictEqual(flag2, true);
assert.strictEqual(value, "asdf");
done();
}).catch(done);

View File

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

View File

@@ -0,0 +1,42 @@
var error = new Error("rejected");
async function e(arg) {
if (arg) {
throw arg;
}
return "did not throw";
}
async function f(arg) {
return await e(arg);
}
async function g(arg) {
return await f(arg);
}
async function h(arg) {
return await Promise.all([
g(arg),
Promise.resolve("dummy")
]);
}
Promise.all([
h(error).then(function() {
done(new Error("should not have resolved"));
}, function(e) {
assert.strictEqual(e, error);
return "ok1";
}),
h(null).then(function(result) {
assert.deepEqual(result, [
"did not throw",
"dummy"
]);
return "ok2";
})
]).then(function(results) {
assert.deepEqual(results, ["ok1", "ok2"]);
done();
}).catch(done);

View File

@@ -0,0 +1,21 @@
var error = new Error("rejected");
async function f(arg) {
try {
return await arg;
} catch (e) {
assert.strictEqual(e, error);
return "did throw";
}
}
Promise.all([
f(Promise.reject(error)),
f(Promise.resolve("did not throw"))
]).then(function(results) {
assert.deepEqual(results, [
"did throw",
"did not throw"
]);
done();
}).catch(done);

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

@@ -2,15 +2,19 @@
var _ref = [1, 2];
var a = _ref[0];
var b = _ref[1];
var _ref2 = [3, 4];
var _ref2 = Array.from(_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 = Array.from(_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

@@ -2,7 +2,13 @@
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 = Array.from(_ref);
var a = _ref2[0];
var _ref3 = Array.from(_ref2[1]);
var b = _ref3[0];
var _ref4 = Array.from(_ref2[2]);
var c = _ref4[0];
var d = _ref2[3];

View File

@@ -2,5 +2,7 @@
var _ref = f();
a = _ref[0];
b = _ref[1];
var _ref2 = Array.from(_ref);
a = _ref2[0];
b = _ref2[1];

View File

@@ -2,7 +2,13 @@
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 = Array.from(_ref);
var a = _ref2[1];
var _ref3 = Array.from(_ref2[2]);
var b = _ref3[0];
var _ref4 = Array.from(_ref2[3]);
var c = _ref4[0];
var d = _ref2[4];

View File

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

View File

@@ -2,7 +2,9 @@
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 = Array.from(_ref);
var name = _ref2[0];
var before = _ref2[1];
var after = _ref2[2];
}

View File

@@ -2,5 +2,7 @@
var _ref = [1, 2];
this.foo = _ref[0];
this.bar = _ref[1];
var _ref2 = Array.from(_ref);
this.foo = _ref2[0];
this.bar = _ref2[1];

View File

@@ -1,6 +1,10 @@
"use strict";
var x1 = rect.topLeft[0];
var y1 = rect.topLeft[1];
var x2 = rect.bottomRight[0];
var y2 = rect.bottomRight[1];
var _ref = Array.from(rect.topLeft);
var x1 = _ref[0];
var y1 = _ref[1];
var _ref2 = Array.from(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

@@ -15,13 +15,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 = Array.from(_ref3);
var a = _ref4[0];
var b = _ref4[1];
var c = _ref4[2];
var _ref6 = Array.from(_ref5);
var x = _ref6[0];
var y = _ref6[1];
var z = _ref6[2];
return a + b + c;
};

View File

@@ -0,0 +1,7 @@
function* f() {
for (var i = 0; i < 3; i++) {
yield i;
}
}
var [...xs] = f();
assert.deepEqual(xs, [0, 1, 2]);

View File

@@ -1,9 +1,11 @@
"use strict";
var isSorted = function (_ref) {
var x = _ref[0];
var y = _ref[1];
var wow = _ref.slice(2);
var _ref2 = Array.from(_ref);
var x = _ref2[0];
var y = _ref2[1];
var wow = Array.from(_ref2).slice(2);
if (!zs.length) return true;
if (y > x) return isSorted(zs);

View File

@@ -2,4 +2,4 @@
for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
i = _step.value;
}
}

View File

@@ -2,4 +2,4 @@
for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
var i = _step.value;
}
}

View File

@@ -0,0 +1,7 @@
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.

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