Compare commits

...

75 Commits

Author SHA1 Message Date
Sebastian McKenzie
02cb397873 v5.2.2 2015-05-01 00:43:39 +01:00
Sebastian McKenzie
d9169a87ad allow util.arrayify to take arbitrary types and coerce it into an array - #1398 2015-05-01 00:41:47 +01:00
Sebastian McKenzie
f3b6f2fc61 5.2.1 2015-05-01 00:41:24 +01:00
Sebastian McKenzie
04cc24ee82 v5.2.1 2015-05-01 00:30:42 +01:00
Sebastian McKenzie
f32079ef42 fix regression in node/register that caused node_modules to not be ignored - fixes #1398 2015-05-01 00:29:57 +01:00
Sebastian McKenzie
d1b69656ae update 5.2.0 changelog 2015-04-30 23:28:39 +01:00
Sebastian McKenzie
09453a490b 5.2.0 2015-04-30 23:27:37 +01:00
Sebastian McKenzie
e2e7627f0f v5.2.0 2015-04-30 23:15:06 +01:00
Sebastian McKenzie
4fe24a9a3b Merge pull request #1392 from jden/jden-patch-1
process glob matching in babel-cli (windows compat)
2015-04-30 23:10:24 +01:00
Sebastian McKenzie
d26e7ad577 fix no RHS in class properties causing undefined to be used instead of a noop - fixes #1396 2015-04-30 23:09:17 +01:00
Sebastian McKenzie
571cb4928f add register-without-polyfill option 2015-04-30 22:27:52 +01:00
Sebastian McKenzie
c12e8122f8 fix browser tests 2015-04-30 20:11:32 +01:00
Sebastian McKenzie
92e7a01d14 remove regenerator and test262 git submodule and tests - closes #1393 2015-04-30 20:03:34 +01:00
jden
b9ca9d42dc fix formatting per feedback from @sebmck
https://github.com/babel/babel/pull/1392#discussion-diff-29454022
2015-04-30 11:06:51 -07:00
jden
479c3e477a process glob matching in babel-cli (windows compat) 2015-04-30 10:57:48 -07:00
Sebastian McKenzie
2c3d3d8105 DRY up plugin manager position definition 2015-04-30 18:13:33 +01:00
Sebastian McKenzie
ea03f67505 use a strict regex when splitting string plugins - fixes #1361 2015-04-30 18:13:17 +01:00
Sebastian McKenzie
ee0c88a070 clean up plugin manager constructor and add some basic plugin manager tests 2015-04-30 18:06:15 +01:00
Sebastian McKenzie
98206df864 fix retainLines for comments and block statements - fixes #1388 2015-04-30 17:43:31 +01:00
Sebastian McKenzie
1066a42fb2 fix weird path context state by clearing the context before we visit it 2015-04-30 17:19:27 +01:00
Sebastian McKenzie
062175586c add parens around LHS object patterns 2015-04-30 17:18:36 +01:00
Sebastian McKenzie
0dc6b582a6 Merge pull request #1385 from monsanto/fix-var-checker
fix reference check for shorthand properties
2015-04-30 16:43:36 +01:00
Sebastian McKenzie
d8d70ba137 Merge pull request #1388 from amasad/master
Add failing test for printing block line comments with retainLines option
2015-04-30 16:42:55 +01:00
Sebastian McKenzie
f23c916520 make function name inferrence smarter - fixes #1367 2015-04-30 16:41:25 +01:00
Sebastian McKenzie
8ae4601177 rename insertOntoContainerStart to unshiftContainer 2015-04-30 14:33:54 +01:00
Sebastian McKenzie
9a466d3ef9 add optimisation.flow.forOf internal usage 2015-04-30 14:31:52 +01:00
Sebastian McKenzie
713845d14c add Terminatorless alias key for node expression wrappers that don't accept new lines 2015-04-30 13:56:42 +01:00
Sebastian McKenzie
471d60e5cd Merge branch 'master' of github.com:babel/babel 2015-04-30 13:53:58 +01:00
Sebastian McKenzie
43864e0686 Merge pull request #1390 from amasad/retainLines-return
Parenthesize statement argument when on a different line
2015-04-30 13:53:52 +01:00
Amjad Masad
4c2ae5dd19 Parenthesize statement argument when on a different line 2015-04-30 05:43:08 -07:00
Amjad Masad
a540cbe801 Failing test with return not on the same line as it's expression
Note that this is not a parenthesis issue but this was the easiest way
to reproduce it. I ran into it when testing generators with `retainLines`
and the generated `return` statement (replacing yeild) was printed on
the line preceding the expression being yielded.
2015-04-30 05:06:56 -07:00
Amjad Masad
34cc577fa2 Add failing test for printing block line comments with retainLines option 2015-04-30 04:37:45 -07:00
Sebastian McKenzie
c855b55133 add additional comment test to comment statement with retainlines option generation test 2015-04-29 23:58:36 +01:00
Sebastian McKenzie
16c86c25b7 properly catch up to comments position - fixes #1384 2015-04-29 23:57:43 +01:00
Sebastian McKenzie
4345f7945b Merge pull request #1377 from Mark-Simulacrum/issue-1376
Allow passing an array of globs to "only" option.
2015-04-29 23:39:17 +01:00
Christopher Monsanto
f44c93add2 fix reference check for shorthand properties 2015-04-29 17:56:36 -04:00
Sebastian McKenzie
09e45c51a4 Merge pull request #1384 from amasad/master
Add failing test for printing comments with retainLines option
2015-04-29 22:44:03 +01:00
Amjad Masad
1a42b72b15 Add failing test for printing comments with retainLines option 2015-04-29 14:40:23 -07:00
Sebastian McKenzie
d30415d74a update es6.spec.symbols instanceof test to reflect Function.prototype[@@hasInstance] being nonwritable #1364 2015-04-29 21:20:35 +01:00
Sebastian McKenzie
616ef8d840 make jscript transformer more trigger happy - #1382 2015-04-29 12:03:15 +01:00
Sebastian McKenzie
56437f94bc Merge pull request #1382 from kondi/jscript
add optional jscript transformer for basic IE8 compatibility (fixes #1369)
2015-04-29 11:59:32 +01:00
Pusztai Tibor
881fa6430b add optional jscript transformer for basic IE8 compatibility (fixes #1369) 2015-04-29 12:36:12 +02:00
Sebastian McKenzie
b7971690f3 add additional comments to path class, really need to go and fill in all the dummy jsdoc descriptions... 2015-04-29 01:19:56 +01:00
Sebastian McKenzie
c01d0abbd3 add insertOntoContainerStart and insertOntoContainerEnd methods 2015-04-29 01:13:35 +01:00
Sebastian McKenzie
7043119346 fix PluginManager 2015-04-29 01:13:23 +01:00
Mark-Simulacrum
b5325df57f Allow passing an array of globs to "only" option. 2015-04-28 17:59:20 -06:00
Sebastian McKenzie
0fc958e0fc remove useless force parameter in Buffer#_newline 2015-04-29 00:22:10 +01:00
Sebastian McKenzie
9cb16711dd abstract plugin initialisation to a plugin manager 2015-04-29 00:20:49 +01:00
Sebastian McKenzie
04766b13f5 add retainLines code generator option 2015-04-29 00:20:35 +01:00
Sebastian McKenzie
433d704739 add null check to interop-require-wildcard helper 2015-04-28 16:56:57 +01:00
Sebastian McKenzie
30204d2ee6 disable sudo travis config option, it breaks the build since it's using a cached node_modules which has old major versions of dependencies, ugh 2015-04-28 16:31:00 +01:00
Sebastian McKenzie
374b7cca2c update interop-require-wildcard helper 2015-04-28 15:58:37 +01:00
Sebastian McKenzie
152ae388f0 remove excessive newline 2015-04-28 15:32:16 +01:00
Sebastian McKenzie
04344026bb remove typeof object check for interop-require-wildcard helper 2015-04-28 15:32:09 +01:00
Sebastian McKenzie
cfffaf6cdb upgrade to babel 5 2015-04-28 14:55:28 +01:00
Sebastian McKenzie
2952d94e60 wrap instanceof to support @@hasInstance - fixes #1364 2015-04-28 14:27:30 +01:00
Sebastian McKenzie
0276c3ae81 visit decorators key for ClassProperty nodes 2015-04-28 00:05:10 +01:00
Sebastian McKenzie
c00f8dce3f add make build to makefile and elaborate on build steps in CONTRIBUTING - #1357. 2015-04-27 03:16:39 +01:00
Sebastian McKenzie
4e24ae39cf Merge branch 'master' of github.com:babel/babel 2015-04-27 03:06:23 +01:00
Sebastian McKenzie
12bd6494b7 use class ref instead of class name when adding class super native constructor call - fixes #1358 2015-04-27 03:06:13 +01:00
Sebastian McKenzie
e35c7550fe Merge pull request #1356 from monsanto/clean-build
remove lib/ before building
2015-04-27 02:32:53 +01:00
Christopher Monsanto
e7046abe72 remove lib/ before building 2015-04-26 21:12:50 -04:00
Sebastian McKenzie
affa7f0c6f Merge pull request #1352 from monsanto/descriptor-initalizer
call descriptor.initializer with `target` as `this`
2015-04-26 21:17:50 +01:00
Sebastian McKenzie
be650ffc61 call decorator initializers with the proper context - #1350 - thanks @monsanto 2015-04-26 21:17:15 +01:00
Sebastian McKenzie
3078d48178 don't rely on sequence expressions for <= 1 sequence expressions in blockScoping transformer 2015-04-26 21:15:30 +01:00
Sebastian McKenzie
0be93563dd fix spec.blockScopedFunctions shouldVisit method 2015-04-26 21:15:08 +01:00
Christopher Monsanto
3e55980145 call descriptor.initializer with target as this 2015-04-26 16:11:11 -04:00
Sebastian McKenzie
470ebf3a46 various random optimisations 2015-04-26 21:04:06 +01:00
Sebastian McKenzie
b695369126 add babel brand to code gen deopt message 2015-04-26 21:03:54 +01:00
Sebastian McKenzie
f4611469b4 remove declarations transformer and instead do it whenever we push a generated declaration, better for perf and removes shitty bugs - fixes #1268 2015-04-26 15:46:06 +01:00
Sebastian McKenzie
68bfafe745 add missing ast-types definitions 2015-04-26 05:26:29 +01:00
Sebastian McKenzie
f72782b71c remove transformer prepass and various other optimisations 2015-04-26 05:26:21 +01:00
Sebastian McKenzie
0f1f5e3565 implement path-specific transformer skipping via the starting prepass 2015-04-26 02:42:15 +01:00
Sebastian McKenzie
dfe126f3d4 verify traversal visitors 2015-04-25 22:49:54 +01:00
Sebastian McKenzie
4c9cb957a9 5.1.13 2015-04-25 22:46:01 +01:00
180 changed files with 1368 additions and 761 deletions

View File

@@ -1,6 +1,6 @@
{
"experimental": true,
"playground": true,
"loose": true,
"blacklist": ["es6.tailCall"]
"stage": 0,
"loose": ["all"],
"blacklist": ["es6.tailCall"],
"optional": ["optimisation.flow.forOf"]
}

6
.gitmodules vendored
View File

@@ -1,12 +1,6 @@
[submodule "vendor/traceur"]
path = vendor/traceur
url = https://github.com/google/traceur-compiler
[submodule "vendor/regenerator"]
path = vendor/regenerator
url = https://github.com/babel/regenerator-babel
[submodule "vendor/test262"]
path = vendor/test262
url = https://github.com/tc39/test262
[submodule "vendor/compat-table"]
path = vendor/compat-table
url = https://github.com/kangax/compat-table

View File

@@ -1,4 +1,4 @@
sudo: false
#sudo: false
language: node_js
cache:
directories:

View File

@@ -13,6 +13,38 @@ _Note: Gaps between patch versions are faulty/broken releases._
See [CHANGELOG - 6to5](CHANGELOG-6to5.md) for the pre-4.0.0 version changelog.
## 5.2.2
* **Internal**
* Allow `util.arrayify` to take arbitrary types and coerce it into an array.
## 5.2.1
* **Bug Fix**
* Fix regression in `node/register` that caused `node_modules` to not be ignored.
## 5.2.0
* **Bug Fix**
* Fix plugin strings splitting arbitrarily on `:` which caused full paths on Windows to fail as they include `:` after the drive letter.
* Call class property `initializer`s with their target instead of their descriptor.
* Fix `ignore` and `only` not properly working on Windows path separators. Thanks [@stagas](https://github.com/stagas)!
* Fix `resolveRc` running on files twice causing issues. Thanks [@lukescott](https://github.com/lukescott)!
* Fix shorthand properties not correctly being target for `isReferenced` checks. Thanks [@monsanto](https://github.com/monsanto)!
* **Polish**
* Allow passing an array of globs to `babel/register` `only` and `ignore` options. Thanks [@Mark-Simulacrum](https://github.com/Mark-Simulacrum)!
* When inferring function names that collide with upper bindings, instead of doing the wrapper, instead rename them.
* Consider constant-like variable declaration functions to always refer to themselves so TOC can be performed.
* Process globs manually when using `$ babel` as some shells such as Windows don't explode them. Thanks [@jden](https://github.com/jden)!
* Add alternative way to execute plugins via a closure that's called with the current Babel instance.
* **Internal**
* Remove multiple internal transformers in favor of directly doing things when we need to. Previously, declarations such as `_ref` that we needed to create in specific scopes were done at the very end via the `_declarations` transformer. Now, they're done and added to the scope **right** when they're needed. This gets rid of the crappy `_declarations` property on scope nodes and fixes the crappy regenerator bug where it was creating a new `BlockStatement` so the declarations were being lost.
* Rework transformer traversal optimisation. Turns out that calling a `check` function for **every single node** in the AST is ridiculously expensive. 300,000 nodes timesed by ~30 transformers meant that it took tens of seconds to perform while it's quicker to just do the unnecessary traversal. Seems obvious in hindsight.
* **New Feature**
* Add `jscript` transformer that turns named function expressions into function declarations to get around [JScript's horribly broken function expression semantics](https://kangax.github.io/nfe/#jscript-bugs). Thanks [@kondi](https://github.com/kondi)!
* Add `@@hasInstance` support to objects when using the `es6.spec.symbols` transformer.
* Add `retainLines` option that retains the line (but not the columns!) of the input code.
## 5.1.13
* **Polish**

View File

@@ -29,16 +29,19 @@ $ cd babel
$ make bootstrap
```
Then you need to run:
Then you can either run:
```sh
$ make build-core
```
to build Babel **once** or:
```sh
$ make watch-core
```
This will compile Babel and then sit in the background and on file modification
recompile the necessary files. Babel itself is written in ES6. The source files
reside in `src/` and transpile to `lib/`
to have Babel build itself then incrementally build files on change.
#### Running tests

View File

@@ -9,17 +9,20 @@ BABEL_CMD = node_modules/babel/bin/babel
export NODE_ENV = test
.PHONY: clean test test-cov test-clean test-travis test-simple test-all test-browser test-parser publish build bootstrap publish-core publish-runtime build-core watch-core build-core-test
.PHONY: clean test test-cov test-clean test-travis test-simple test-all test-browser test-parser publish build bootstrap publish-core publish-runtime build-core watch-core build-core-test clean-core
build-core:
build-core: clean-core
node $(BABEL_CMD) src --out-dir lib --copy-files
build-core-test:
build-core-test: clean-core
node $(BABEL_CMD) src --out-dir lib --copy-files --auxiliary-comment "istanbul ignore next"
watch-core:
watch-core: clean-core
node $(BABEL_CMD) src --out-dir lib --watch --copy-files
clean-core:
rm -rf lib
build:
mkdir -p dist
make build-core
@@ -115,3 +118,4 @@ bootstrap:
cd packages/babel-cli && npm install && npm link && npm link babel-core
git submodule update --init
cd vendor/compat-table && npm install object-assign
make build

View File

@@ -1,7 +1,7 @@
{
"name": "babel-core",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "5.1.13",
"version": "5.2.2",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
"repository": "babel/babel",
@@ -59,7 +59,7 @@
"user-home": "^1.1.1"
},
"devDependencies": {
"babel": "4.7.13",
"babel": "5.1.13",
"browserify": "^9.0.8",
"chai": "^2.2.0",
"eslint": "^0.18.0",

View File

@@ -8,6 +8,7 @@ var util = require("babel-core").util;
var each = require("lodash/collection/each");
var keys = require("lodash/object/keys");
var fs = require("fs");
var glob = require("glob");
each(options, function (option, key) {
if (option.hidden) return;
@@ -69,7 +70,9 @@ commander.parse(process.argv);
var errors = [];
var filenames = commander.args;
var filenames = commander.args.reduce(function (globbed, input) {
return globbed.concat(glob.sync(input));
}, []);
each(filenames, function (filename) {
if (!fs.existsSync(filename)) {

View File

@@ -1,21 +1,22 @@
{
"name": "babel",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "5.1.12",
"version": "5.2.1",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
"repository": "babel/babel",
"preferGlobal": true,
"dependencies": {
"babel-core": "^5.1.12",
"babel-core": "^5.2.1",
"chokidar": "^1.0.0",
"commander": "^2.6.0",
"fs-readdir-recursive": "^0.1.0",
"output-file-sync": "^1.1.0",
"lodash": "^3.2.0",
"convert-source-map": "^1.1.0",
"source-map": "^0.4.0",
"path-is-absolute": "^1.0.0"
"fs-readdir-recursive": "^0.1.0",
"glob": "^5.0.5",
"lodash": "^3.2.0",
"output-file-sync": "^1.1.0",
"path-is-absolute": "^1.0.0",
"source-map": "^0.4.0"
},
"bin": {
"babel": "./bin/babel/index.js",

View File

@@ -0,0 +1 @@
module.exports = require("babel-core/register-without-polyfill");

View File

@@ -1,7 +1,7 @@
{
"name": "babel-runtime",
"description": "babel selfContained runtime",
"version": "5.1.12",
"version": "5.2.1",
"repository": "babel/babel",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"dependencies": {

View File

@@ -0,0 +1 @@
module.exports = require("./lib/babel/api/register/node");

View File

@@ -1 +1 @@
module.exports = require("./lib/babel/api/register/node");
module.exports = require("./lib/babel/api/register/node-polyfill");

3
src/acorn/index.js Normal file
View File

@@ -0,0 +1,3 @@
export * from "./src/index";
import "./plugins/flow";
import "./plugins/jsx";

View File

@@ -2,7 +2,7 @@
"name": "acorn",
"description": "ECMAScript parser",
"homepage": "https://github.com/marijnh/acorn",
"main": "src/index.js",
"main": "index.js",
"version": "1.0.0",
"engines": {
"node": ">=0.4.0"

View File

@@ -1,4 +1,4 @@
var acorn = require("..")
var acorn = require("../src/index")
var pp = acorn.Parser.prototype
var tt = acorn.tokTypes

View File

@@ -1,4 +1,4 @@
var acorn = require("..")
var acorn = require("../src/index")
var tt = acorn.tokTypes;
var tc = acorn.tokContexts;

View File

@@ -38,9 +38,6 @@ export {isIdentifierChar, isIdentifierStart} from "./identifier"
export {Token} from "./tokenize"
export {isNewLine, lineBreak, lineBreakG} from "./whitespace"
import "../plugins/flow";
import "../plugins/jsx";
export const version = "1.0.0"
// The main exported interface (under `self.acorn` when in the

View File

@@ -11,7 +11,7 @@ transform.run = function (code, opts = {}) {
};
transform.load = function (url, callback, opts = {}, hold) {
opts.filename ||= url;
opts.filename = opts.filename || url;
var xhr = global.ActiveXObject ? new global.ActiveXObject("Microsoft.XMLHTTP") : new global.XMLHttpRequest();
xhr.open("GET", url, true);

View File

@@ -17,7 +17,7 @@ import * as t from "../types";
export { t as types };
export function register(opts?: Object) {
var callback = require("./register/node");
var callback = require("./register/node-polyfill");
if (opts != null) callback(opts);
return callback;
}

View File

@@ -0,0 +1,2 @@
import "../../polyfill";
export { default } from "./node";

View File

@@ -1,4 +1,3 @@
import "../../polyfill";
import sourceMapSupport from "source-map-support";
import * as registerCache from "./cache";
import resolveRc from "../../tools/resolve-rc";
@@ -32,8 +31,10 @@ var cache = registerCache.get();
//
var transformOpts = {};
var ignoreRegex = /node_modules/;
var onlyRegex;
var ignore;
var only;
var oldHandlers = {};
var maps = {};
@@ -77,8 +78,11 @@ var compile = function (filename) {
};
var shouldIgnore = function (filename) {
filename = slash(filename);
return (ignoreRegex && ignoreRegex.test(filename)) || (onlyRegex && !onlyRegex.test(filename));
if (!ignore && !only) {
return /node_modules/.test(filename);
} else {
return util.shouldIgnore(filename, ignore || [], only || []);
}
};
var istanbulMonkey = {};
@@ -144,8 +148,8 @@ var hookExtensions = function (_exts) {
hookExtensions(util.canCompile.EXTENSIONS);
export default function (opts = {}) {
if (opts.only != null) onlyRegex = util.regexify(opts.only);
if (opts.ignore != null) ignoreRegex = util.regexify(opts.ignore);
if (opts.only != null) only = util.arrayify(opts.only, util.regexify);
if (opts.ignore != null) ignore = util.arrayify(opts.ignore, util.regexify);
if (opts.extensions) hookExtensions(util.arrayify(opts.extensions));

View File

@@ -70,14 +70,14 @@ export default class Buffer {
}
newline(i, removeLast) {
if (this.format.compact) return;
if (this.format.compact || this.format.retainLines) return;
if (this.format.concise) {
this.space();
return;
}
removeLast ||= false;
removeLast = removeLast || false;
if (isNumber(i)) {
i = Math.min(2, i);

View File

@@ -13,7 +13,7 @@ export function BlockStatement(node, print) {
this.push("{");
this.newline();
print.sequence(node.body, { indent: true });
this.removeLast("\n");
if (!this.format.retainLines) this.removeLast("\n");
this.rightBrace();
}
}

View File

@@ -12,7 +12,7 @@ import * as t from "../types";
class CodeGenerator {
constructor(ast, opts, code) {
opts ||= {};
opts = opts || {};
this.comments = ast.comments || [];
this.tokens = ast.tokens || [];
@@ -34,6 +34,7 @@ class CodeGenerator {
}
var format = {
retainLines: opts.retainLines,
comments: opts.comments == null || opts.comments,
compact: opts.compact,
quotes: CodeGenerator.findCommonStringDelimeter(code, tokens),
@@ -48,7 +49,7 @@ class CodeGenerator {
format.compact = code.length > 100000; // 100KB
if (format.compact) {
console.error(messages.get("codeGeneratorDeopt", opts.filename, "100KB"));
console.error("[BABEL] " + messages.get("codeGeneratorDeopt", opts.filename, "100KB"));
}
}
@@ -146,6 +147,22 @@ class CodeGenerator {
return print;
}
catchUp(node, parent) {
// catch up to this nodes newline if we're behind
if (node.loc && this.format.retainLines && this.buffer.buf) {
var needsParens = false;
if (parent && this.position.line < node.loc.start.line && t.isTerminatorless(parent)) {
needsParens = true;
this._push("(");
}
while (this.position.line < node.loc.start.line) {
this._push("\n");
}
return needsParens;
}
return false;
}
print(node, parent, opts = {}) {
if (!node) return;
@@ -197,6 +214,8 @@ class CodeGenerator {
this.printLeadingComments(node, parent);
var needsParensFromCatchup = this.catchUp(node, parent);
newline(true);
if (opts.before) opts.before();
@@ -208,7 +227,7 @@ class CodeGenerator {
this.newline();
this.dedent();
}
if (needsParens) this.push(")");
if (needsParens || needsParensFromCatchup) this.push(")");
this.map.mark(node, "end");
if (opts.after) opts.after();
@@ -328,6 +347,8 @@ class CodeGenerator {
if (skip) return;
this.catchUp(comment);
// whitespace before
this.newline(this.whitespace.getNewlinesBefore(comment));
@@ -340,7 +361,6 @@ class CodeGenerator {
}
//
if (comment.type === "Block" && this.format.indent.adjustMultilineComment) {
var offset = comment.loc.start.column;
if (offset) {
@@ -356,8 +376,13 @@ class CodeGenerator {
val = this.getIndent() + val;
}
//
// force a newline for line comments when retainLines is set in case the next printed node
// doesn't catch up
if (this.format.retainLines && comment.type === "Line") {
val += "\n";
}
//
this._push(val);
// whitespace after

View File

@@ -85,16 +85,7 @@ export default class Node {
return false;
}
if (t.isYieldExpression(parent) || t.isAwaitExpression(parent)) {
return true;
}
if (t.isContinueStatement(parent) || t.isBreakStatement(parent) ||
t.isReturnStatement(parent) || t.isThrowStatement(parent)) {
return true;
}
return false;
return t.isTerminatorless(parent);
}
}

View File

@@ -171,4 +171,10 @@ export function ConditionalExpression(node, parent) {
return false;
}
export { ConditionalExpression as AssignmentExpression };
export function AssignmentExpression(node) {
if (t.isObjectPattern(node.left)) {
return true;
} else {
return ConditionalExpression(...arguments);
}
}

View File

@@ -16,7 +16,7 @@ function crawl(node, state = {}) {
} else if (t.isFunction(node)) {
state.hasFunction = true;
} else if (t.isIdentifier(node)) {
state.hasHelper ||= isHelper(node.callee);
state.hasHelper = state.hasHelper || isHelper(node.callee);
}
return state;

View File

@@ -22,7 +22,19 @@ export const MESSAGES = {
codeGeneratorDeopt: "Note: The code generator has deoptimised the styling of $1 as it exceeds the max of $2.",
missingTemplatesDirectory: "no templates directory - this is most likely the result of a broken `npm publish`. Please report to https://github.com/babel/babel/issues",
unsupportedOutputType: "Unsupported output type $1",
illegalMethodName: "Illegal method name $1"
illegalMethodName: "Illegal method name $1",
traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node",
traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
traverseVerifyVisitorFunction: "Hey! You passed \`traverse()\` a visitor object with the key $1 that's a straight up `Function` instead of `{ enter: Function }`. You need to normalise it with `traverse.explode(visitor)`.",
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",
pluginIllegalKind: "Illegal kind $1 for plugin $2",
pluginIllegalPosition: "Illegal position $1 for plugin $2",
pluginKeyCollision: "The plugin $1 collides with another of the same name",
pluginNotTransformer: "The plugin $1 didn't export a Transformer instance",
pluginUnknown: "Unknown plugin $1",
transformerNotFile: "Transformer $1 is resolving to a different Babel version to what is doing the actual transformation..."
};
export function get(key: String, ...args) {

View File

@@ -55,4 +55,18 @@ def("ExportNamedDeclaration")
)])
.field("source", or(def("ModuleSpecifier"), null));
def("ExportNamespaceSpecifier")
.bases("Specifier")
.field("exported", def("Identifier"));
def("ExportDefaultSpecifier")
.bases("Specifier")
.field("exported", def("Identifier"));
def("ExportAllDeclaration")
.bases("Declaration")
.build("exported", "source")
.field("exported", def("Identifier"))
.field("source", def("Literal"));
types.finalize();

View File

@@ -33,7 +33,7 @@ export default function (loc, opts = {}) {
var json;
try {
json = jsons[content] ||= JSON.parse(stripJsonComments(content));
json = jsons[content] = jsons[content] || JSON.parse(stripJsonComments(content));
} catch (err) {
err.message = `${file}: ${err.message}`;
throw err;
@@ -47,7 +47,7 @@ export default function (loc, opts = {}) {
var c = a.slice(0);
for (var v of b) {
if (a.indexOf(v) < 0) {
c.push(v);
c.push(v);
}
}
return c;

View File

@@ -1,5 +1,6 @@
import convertSourceMap from "convert-source-map";
import * as optionParsers from "./option-parsers";
import PluginManager from "./plugin-manager";
import shebangRegex from "shebang-regex";
import TraversalPath from "../../traversal/path";
import isFunction from "lodash/lang/isFunction";
@@ -18,20 +19,21 @@ import Scope from "../../traversal/scope";
import slash from "slash";
import clone from "lodash/lang/clone";
import * as util from "../../util";
import * as api from "../../api/node";
import path from "path";
import each from "lodash/collection/each";
import * as t from "../../types";
var checkTransformerVisitor = {
enter(node, parent, scope, state) {
checkNode(state.stack, node, scope);
exit(node, parent, scope, state) {
checkPath(state.stack, this);
}
};
function checkNode(stack, node, scope) {
function checkPath(stack, path) {
each(stack, function (pass) {
if (pass.shouldRun || pass.ran) return;
pass.checkNode(node, scope);
pass.checkPath(path);
});
}
@@ -41,15 +43,15 @@ export default class File {
this.dynamicImportIds = {};
this.dynamicImports = [];
this.usedHelpers = {};
this.dynamicData = {};
this.data = {};
this.uids = {};
this.declarations = {};
this.usedHelpers = {};
this.dynamicData = {};
this.data = {};
this.uids = {};
this.lastStatements = [];
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.ast = {};
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.ast = {};
this.buildTransformers();
}
@@ -85,6 +87,7 @@ export default class File {
"temporal-assert-defined",
"self-global",
"default-props",
"instanceof",
// legacy
"interop-require",
@@ -133,7 +136,7 @@ export default class File {
if (optionParser) val = optionParser(key, val);
if (option.alias) {
opts[option.alias] ||= val;
opts[option.alias] = opts[option.alias] || val;
} else {
opts[key] = val;
}
@@ -216,8 +219,14 @@ export default class File {
// init plugins!
var beforePlugins = [];
var afterPlugins = [];
var pluginManager = new PluginManager({
file: this,
transformers: this.transformers,
before: beforePlugins,
after: afterPlugins
});
for (var i = 0; i < file.opts.plugins.length; i++) {
this.addPlugin(file.opts.plugins[i], beforePlugins, afterPlugins);
pluginManager.add(file.opts.plugins[i]);
}
stack = beforePlugins.concat(stack, afterPlugins);
@@ -240,60 +249,6 @@ export default class File {
return new ModuleFormatter(this);
}
addPlugin(name, before, after) {
var position = "before";
var plugin;
if (name) {
if (typeof name === "object" && name.transformer) {
plugin = name.transformer;
position = name.position || position;
} else if (typeof name === "string") {
// this is a plugin in the form of "foobar" or "foobar:after"
// where the optional colon is the delimiter for plugin position in the transformer stack
[name, position = "before"] = name.split(":");
var loc = util.resolveRelative(name) || util.resolveRelative(`babel-plugin-${name}`);
if (loc) {
plugin = require(loc)
} else {
throw new ReferenceError(`Unknown plugin ${JSON.stringify(name)}`);
}
} else {
// not a string so we'll just assume that it's a direct Transformer instance, if not then
// the checks later on will complain
plugin = name;
}
} else {
throw new TypeError(`Ilegal kind ${typeof name} for plugin name ${JSON.stringify(name)}`);
}
// validate position
if (position !== "before" && position !== "after") {
throw new TypeError(`Plugin ${JSON.stringify(name)} has an illegal position of ${JSON.stringify(position)}`);
}
// validate transformer key
var key = plugin.key;
if (this.transformers[key]) {
throw new ReferenceError(`The key for plugin ${JSON.stringify(name)} of ${key} collides with an existing plugin`);
}
// validate Transformer instance
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
throw new TypeError(`Plugin ${JSON.stringify(name)} didn't export a default Transformer instance`);
}
// build!
var pass = this.transformers[key] = plugin.buildPass(this);
if (pass.canTransform()) {
var stack = before;
if (position === "after") stack = after;
stack.push(pass);
}
}
parseInputSourceMap(code: string) {
var opts = this.opts;
@@ -348,7 +303,7 @@ export default class File {
}
addImport(source: string, name?: string, type?: string): Object {
name ||= source;
name = name || source;
var id = this.dynamicImportIds[name];
if (!id) {
@@ -360,7 +315,7 @@ export default class File {
declar._blockHoist = 3;
if (type) {
var modules = this.dynamicImportTypes[type] ||= [];
var modules = this.dynamicImportTypes[type] = this.dynamicImportTypes[type] || [];
modules.push(declar);
}
@@ -375,14 +330,10 @@ export default class File {
return id;
}
isConsequenceExpressionStatement(node: Object): boolean {
return t.isExpressionStatement(node) && this.lastStatements.indexOf(node) >= 0;
}
attachAuxiliaryComment(node: Object): Object {
var comment = this.opts.auxiliaryComment;
if (comment) {
node.leadingComments ||= [];
node.leadingComments = node.leadingComments || [];
node.leadingComments.push({
type: "Line",
value: " " + comment
@@ -400,8 +351,8 @@ export default class File {
var program = this.ast.program;
var declar = program._declarations && program._declarations[name];
if (declar) return declar.id;
var declar = this.declarations[name];
if (declar) return declar;
this.usedHelpers[name] = true;
@@ -418,11 +369,11 @@ export default class File {
var ref = util.template("helper-" + name);
ref._compact = true;
var uid = this.scope.generateUidIdentifier(name);
var uid = this.declarations[name] = this.scope.generateUidIdentifier(name);
this.scope.push({
key: name,
id: uid,
init: ref
init: ref,
unique: true
});
return uid;
}
@@ -479,9 +430,12 @@ export default class File {
parseOpts.strictMode = features.strict;
parseOpts.sourceType = "module";
this.log.debug("Parse start");
//
return parse(parseOpts, code, (tree) => {
this.log.debug("Parse stop");
this.transform(tree);
return this.generate();
});
@@ -504,25 +458,25 @@ export default class File {
}
transform(ast) {
this.log.debug();
this.log.debug("Start set AST");
this.setAst(ast);
this.log.debug("End set AST");
this.lastStatements = t.getLastStatements(ast.program);
this.log.debug("Start prepass");
this.checkPath(this.path);
this.log.debug("End prepass");
this.log.debug("Start module formatter init");
var modFormatter = this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
if (modFormatter.init && this.transformers["es6.modules"].canTransform()) {
modFormatter.init();
}
this.checkNode(ast);
this.log.debug("End module formatter init");
this.call("pre");
each(this.transformerStack, function (pass) {
pass.transform();
});
this.call("post");
}
@@ -535,20 +489,19 @@ export default class File {
}
}
checkNode(node, scope) {
if (Array.isArray(node)) {
for (var i = 0; i < node.length; i++) {
this.checkNode(node[i], scope);
checkPath(path) {
if (Array.isArray(path)) {
for (var i = 0; i < path.length; i++) {
this.checkPath(path[i]);
}
return;
}
var stack = this.transformerStack;
scope ||= this.scope;
checkNode(stack, node, scope);
checkPath(stack, path);
scope.traverse(node, checkTransformerVisitor, {
path.traverse(checkTransformerVisitor, {
stack: stack
});
}
@@ -598,10 +551,14 @@ export default class File {
if (opts.ast) result.ast = ast;
if (!opts.code) return result;
this.log.debug("Generation start");
var _result = generate(ast, opts, this.code);
result.code = _result.code;
result.map = _result.map;
this.log.debug("Generation end");
if (this.shebang) {
// add back shebang
result.code = `${this.shebang}\n${result.code}`;

View File

@@ -25,6 +25,13 @@
"type": "string"
},
"retainLines": {
"hidden": true,
"type": "boolean",
"default": false,
"description": "retain line numbers - will result in really ugly code"
},
"nonStandard": {
"type": "boolean",
"default": true,
@@ -212,5 +219,4 @@
"hidden": true,
"description": "do not load the same .babelrc file twice"
}
}

View File

@@ -0,0 +1,104 @@
import * as messages from "../../messages";
import * as util from "../../util";
export default class PluginManager {
static memoisedPlugins = [];
static memoisePluginContainer(fn) {
for (var i = 0; i < PluginManager.memoisedPlugins.length; i++) {
var plugin = PluginManager.memoisedPlugins[i];
if (plugin.container === fn) return plugin.transformer;
}
var transformer = fn(node);
PluginManager.memoisedPlugins.push({
container: fn,
transformer: transformer
});
return transformer;
}
static positions = ["before", "after"];
constructor({ file, transformers, before, after } = { transformers: {}, before: [], after: [] }) {
this.transformers = transformers;
this.file = file;
this.before = before;
this.after = after;
}
subnormaliseString(name, position) {
// this is a plugin in the form of "foobar" or "foobar:after"
// where the optional colon is the delimiter for plugin position in the transformer stack
var match = name.match(/^(.*?):(after|before)$/);
if (match) [, name, position] = match;
var loc = util.resolveRelative(name) || util.resolveRelative(`babel-plugin-${name}`);
if (loc) {
return {
position: position,
plugin: require(loc)
};
} else {
throw new ReferenceError(messages.get("pluginUnknown", name));
}
}
validate(name, plugin) {
// validate transformer key
var key = plugin.key;
if (this.transformers[key]) {
throw new ReferenceError(messages.get("pluginKeyCollision", key));
}
// validate Transformer instance
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
throw new TypeError(messages.get("pluginNotTransformer", name));
}
}
add(name) {
var position;
var plugin;
if (name) {
if (typeof name === "object" && name.transformer) {
({ plugin: name, position } = name);
} else if (typeof name !== "string") {
// not a string so we'll just assume that it's a direct Transformer instance, if not then
// the checks later on will complain
plugin = name;
}
if (typeof name === "string") {
({ plugin, position } = this.subnormaliseString(name, position));
}
} else {
throw new TypeError(messages.get("pluginIllegalKind", typeof name, name));
}
// default position
position = position || "before";
// validate position
if (PluginManager.positions.indexOf(position) < 0) {
throw new TypeError(messages.get("pluginIllegalPosition", position, name));
}
// allow plugin containers to be specified so they don't have to manually require
if (typeof plugin === "function") {
plugin = PluginManager.memoisePluginContainer(plugin);
}
//
this.validate(name, plugin);
// build!
var pass = this.transformers[plugin.key] = plugin.buildPass(this.file);
if (pass.canTransform()) {
var stack = position === "before" ? this.before : this.after;
stack.push(pass);
}
}
}

View File

@@ -10,9 +10,13 @@ export default function (exports, opts) {
return t.assignmentExpression("=", left, right);
};
exports.shouldVisit = function (node) {
return node.operator && (node.operator === opts.operator || node.operator === opts.operator + "=");
};
exports.ExpressionStatement = function (node, parent, scope, file) {
// hit the `AssignmentExpression` one below
if (file.isConsequenceExpressionStatement(node)) return;
if (this.isCompletionRecord()) return;
var expr = node.expression;
if (!isAssignment(expr)) return;

View File

@@ -8,7 +8,7 @@ export default function (exports, opts) {
exports.ExpressionStatement = function (node, parent, scope, file) {
// hit the `AssignmentExpression` one below
if (file.isConsequenceExpressionStatement(node)) return;
if (this.isCompletionRecord()) return;
var expr = node.expression;
if (!opts.is(expr, file)) return;

View File

@@ -15,7 +15,7 @@ export function push(mutatorMap, node, kind, file) {
//
map._inherits ||= [];
map._inherits = map._inherits || [];
map._inherits.push(node);
map._key = node.key;
@@ -25,7 +25,7 @@ export function push(mutatorMap, node, kind, file) {
}
if (node.decorators) {
var decorators = map.decorators ||= t.arrayExpression([]);
var decorators = map.decorators = map.decorators || t.arrayExpression([]);
decorators.elements = decorators.elements.concat(node.decorators.map(dec => dec.expression));
}

View File

@@ -26,7 +26,11 @@ export default function (decorators, scope) {
[ref]
));
decorator.expression = t.sequenceExpression(nodes);
if (nodes.length === 1) {
decorator.expression = nodes[0];
} else {
decorator.expression = t.sequenceExpression(nodes);
}
}
return decorators;

View File

@@ -20,27 +20,32 @@ var visitor = {
var wrap = function (state, method, id, scope) {
if (state.selfReference) {
var templateName = "property-method-assignment-wrapper";
if (method.generator) templateName += "-generator";
var template = util.template(templateName, {
FUNCTION: method,
FUNCTION_ID: id,
FUNCTION_KEY: scope.generateUidIdentifier(id.name)
});
template.callee._skipModulesRemap = true;
if (scope.hasBinding(id.name)) {
// we can just munge the local binding
scope.rename(id.name);
} else {
// need to add a wrapper since we can't change the references
var templateName = "property-method-assignment-wrapper";
if (method.generator) templateName += "-generator";
var template = util.template(templateName, {
FUNCTION: method,
FUNCTION_ID: id,
FUNCTION_KEY: scope.generateUidIdentifier(id.name)
});
template.callee._skipModulesRemap = true;
// shim in dummy params to retain function arity, if you try to read the
// source then you'll get the original since it's proxied so it's all good
var params = template.callee.body.body[0].params;
for (var i = 0, len = getFunctionArity(method); i < len; i++) {
params.push(scope.generateUidIdentifier("x"));
// shim in dummy params to retain function arity, if you try to read the
// source then you'll get the original since it's proxied so it's all good
var params = template.callee.body.body[0].params;
for (var i = 0, len = getFunctionArity(method); i < len; i++) {
params.push(scope.generateUidIdentifier("x"));
}
return template;
}
return template;
} else {
method.id = id;
return method;
}
method.id = id;
};
var visit = function (node, name, scope) {
@@ -82,7 +87,7 @@ var visit = function (node, name, scope) {
// so we can safely just set the id and move along as it shadows the
// bound function id
}
} else {
} else if (state.outerDeclar || scope.hasGlobal(name)) {
scope.traverse(node, visitor, state);
}
@@ -96,7 +101,7 @@ export function custom(node, id, scope) {
export function property(node, file, scope) {
var key = t.toComputedKey(node, node.key);
if (!t.isLiteral(key)) return node; // we can't set a function id with this
if (!t.isLiteral(key)) return; // we can't set a function id with this
var name = t.toIdentifier(key.value);
if (name === "eval" || name === "arguments") name = "_" + name;
@@ -104,12 +109,12 @@ export function property(node, file, scope) {
var method = node.value;
var state = visit(method, name, scope);
node.value = wrap(state, method, id, scope);
node.value = wrap(state, method, id, scope) || method;
}
export function bare(node, parent, scope) {
// has an `id` so we don't need to infer one
if (node.id) return node;
if (node.id) return;
var id;
if (t.isProperty(parent) && parent.kind === "init" && (!parent.computed || t.isLiteral(parent.key))) {
@@ -118,8 +123,17 @@ export function bare(node, parent, scope) {
} else if (t.isVariableDeclarator(parent)) {
// var foo = function () {};
id = parent.id;
if (t.isIdentifier(id)) {
var bindingInfo = scope.parent.getBinding(id.name);
if (bindingInfo && bindingInfo.constant && scope.getBinding(id.name) === bindingInfo) {
// always going to reference this method
node.id = id;
return;
}
}
} else {
return node;
return;
}
var name;

View File

@@ -20,7 +20,7 @@ var referenceVisitor = {
enter(node, parent, scope, state) {
var name = state.id.name;
if (t.isReferencedIdentifier(node, parent, { name: name }) && scope.bindingIdentifierEquals(name, state.id)) {
return state.ref ||= scope.generateUidIdentifier(name);
return state.ref = state.ref || scope.generateUidIdentifier(name);
}
}
};

View File

@@ -218,7 +218,7 @@ export default class ReplaceSupers {
return this.setSuperProperty(node.left.property, node.right, node.left.computed, getThisReference());
} else {
// super.age += 2; -> var _ref = super.age; super.age = _ref + 2;
ref ||= path.scope.generateUidIdentifier("ref");
ref = ref || path.scope.generateUidIdentifier("ref");
return [
t.variableDeclaration("var", [
t.variableDeclarator(ref, node.left)

View File

@@ -60,7 +60,7 @@ import rawTransformers from "./transformers";
each(rawTransformers, function (transformer, key) {
var namespace = key.split(".")[0];
transform.namespaces[namespace] ||= [];
transform.namespaces[namespace] = transform.namespaces[namespace] || [];
transform.namespaces[namespace].push(key);
transform.transformerNamespaces[key] = namespace;

View File

@@ -166,7 +166,7 @@ export default class DefaultFormatter {
}
_addExport(name, exported) {
var info = this.localExports[name] ||= {
var info = this.localExports[name] = this.localExports[name] || {
binding: this.scope.getBindingIdentifier(name),
exported: []
};

View File

@@ -20,7 +20,7 @@ export default class CommonJSFormatter extends DefaultFormatter {
if (this.file.isLoose("es6.modules")) templateName += "-loose";
var declar = util.template(templateName, true);
declar._blockHoist = 3;
file.ast.program.body.unshift(declar);
file.path.unshiftContainer("body", [declar]);
}
}
@@ -114,7 +114,7 @@ export default class CommonJSFormatter extends DefaultFormatter {
uid = this.scope.generateUidBasedOnNode(node, "import");
}
uid ||= node.specifiers[0].local;
uid = uid || node.specifiers[0].local;
var declar = t.variableDeclaration("var", [
t.variableDeclarator(uid, call)

View File

@@ -77,11 +77,11 @@ var runnerSettersVisitor = {
export default class SystemFormatter extends AMDFormatter {
constructor(file) {
super(file);
this.exportIdentifier = file.scope.generateUidIdentifier("export");
this.noInteropRequireExport = true;
this.noInteropRequireImport = true;
DefaultFormatter.apply(this, arguments);
}
_addImportSource(node, exportNode) {

View File

@@ -24,7 +24,7 @@
}
}
if (descriptor.initializer) {
if (descriptor.initializer !== undefined) {
initializers[key] = descriptor;
continue;
}

View File

@@ -26,9 +26,10 @@
}
}
descriptor.value = descriptor.initializer();
Object.defineProperty(target, key, descriptor);
if (descriptor.initializer) {
descriptor.value = descriptor.initializer.call(target);
Object.defineProperty(target, key, descriptor);
}
}
return target;

View File

@@ -6,7 +6,8 @@
for (var _key in _descriptor) descriptor[_key] = _descriptor[_key];
// initialize it
descriptor.value = descriptor.initializer();
if (!descriptor.initializer) return;
descriptor.value = descriptor.initializer.call(target);
Object.defineProperty(target, key, descriptor);
})

View File

@@ -0,0 +1,7 @@
(function (left, right) {
if (right != null && right[Symbol.hasInstance]) {
return right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
});

View File

@@ -3,7 +3,7 @@
return obj;
} else {
var newObj = {};
if (typeof obj === "object" && obj !== null) {
if (obj != null) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
}

View File

@@ -8,11 +8,12 @@ import traverse from "../traversal";
export default class TransformerPass {
constructor(file: File, transformer: Transformer) {
this.transformer = transformer;
this.shouldRun = !transformer.check;
this.handlers = transformer.handlers;
this.file = file;
this.ran = false;
this.shouldTransform = !transformer.shouldVisit;
this.transformer = transformer;
this.handlers = transformer.handlers;
this.skipKey = transformer.skipKey;
this.file = file;
this.ran = false;
}
canTransform(): boolean {
@@ -42,24 +43,23 @@ export default class TransformerPass {
return true;
}
checkNode(node: Object): boolean {
var check = this.transformer.check;
if (check) {
return this.shouldRun = check(node);
} else {
return true;
}
checkPath(path: TraversalPath): boolean {
if (this.shouldTransform || this.ran) return;
this.shouldTransform = this.transformer.shouldVisit(path.node);
}
transform() {
if (!this.shouldRun) return;
if (!this.shouldTransform) return;
var file = this.file;
file.log.debug(`Running transformer ${this.transformer.key}`);
file.log.debug(`Start transformer ${this.transformer.key}`);
traverse(file.ast, this.handlers, file.scope, file);
file.log.debug(`Finish transformer ${this.transformer.key}`);
this.ran = true;
}
}

View File

@@ -1,4 +1,5 @@
import TransformerPass from "./transformer-pass";
import * as messages from "../messages";
import isFunction from "lodash/lang/isFunction";
import traverse from "../traversal";
import isObject from "lodash/lang/isObject";
@@ -14,7 +15,7 @@ import each from "lodash/collection/each";
*/
export default class Transformer {
constructor(transformerKey: key, transformer: Object, opts: Object) {
constructor(transformerKey: string, transformer: Object, opts: Object) {
transformer = assign({}, transformer);
var take = function (key) {
@@ -24,19 +25,35 @@ export default class Transformer {
};
this.manipulateOptions = take("manipulateOptions");
this.shouldVisit = take("shouldVisit");
this.metadata = take("metadata") || {};
this.parser = take("parser");
this.check = take("check");
this.post = take("post");
this.pre = take("pre");
//
if (this.metadata.stage != null) {
this.metadata.optional = true;
}
//
this.handlers = this.normalize(transformer);
this.opts ||= {};
this.opts = this.opts || {};
this.key = transformerKey;
//
if (!this.shouldVisit) {
var types = Object.keys(this.handlers);
this.shouldVisit = function (node) {
for (var i = 0; i < types.length; i++) {
if (node.type === types[i]) return true;
}
return false;
};
}
}
normalize(transformer: Object): Object {
@@ -71,7 +88,7 @@ export default class Transformer {
buildPass(file: File): TransformerPass {
// validate Transformer instance
if (!(file instanceof File)) {
throw new TypeError(`Transformer ${this.key} is resolving to a different Babel version to what is doing the actual transformation...`);
throw new TypeError(messages.get("transformerNotFile", this.key));
}
return new TransformerPass(file, this);

View File

@@ -1,7 +1,7 @@
import * as defineMap from "../../helpers/define-map";
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isProperty(node) && (node.kind === "get" || node.kind === "set");
}

View File

@@ -1,6 +1,6 @@
import * as t from "../../../types";
export var check = t.isArrowFunctionExpression;
export var shouldVisit = t.isArrowFunctionExpression;
export function ArrowFunctionExpression(node) {
t.ensureBlock(node);

View File

@@ -14,7 +14,7 @@ function isLet(node, parent) {
if (isLetInitable(node, parent)) {
for (var i = 0; i < node.declarations.length; i++) {
var declar = node.declarations[i];
declar.init ||= t.identifier("undefined");
declar.init = declar.init || t.identifier("undefined");
}
}
@@ -37,7 +37,7 @@ function standardizeLets(declars) {
}
}
export function check(node) {
export function shouldVisit(node) {
return t.isVariableDeclaration(node) && (node.kind === "let" || node.kind === "const");
}
@@ -139,7 +139,12 @@ var hoistVarDeclarationsVisitor = {
enter(node, parent, scope, self) {
if (this.isForStatement()) {
if (isVar(node.init, node)) {
node.init = t.sequenceExpression(self.pushDeclar(node.init));
var nodes = self.pushDeclar(node.init);
if (nodes.length === 1) {
node.init = nodes[0];
} else {
node.init = t.sequenceExpression(nodes);
}
}
} else if (this.isFor()) {
if (isVar(node.left, node)) {
@@ -606,7 +611,7 @@ class BlockScoping {
for (var i = 0; i < cases.length; i++) {
var caseConsequent = cases[i].consequent[0];
if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) {
caseConsequent.label = this.loopLabel ||= this.file.scope.generateUidIdentifier("loop");
caseConsequent.label = this.loopLabel = this.loopLabel || this.file.scope.generateUidIdentifier("loop");
}
}

View File

@@ -11,7 +11,7 @@ import * as t from "../../../types";
const PROPERTY_COLLISION_METHOD_NAME = "__initializeProperties";
export var check = t.isClass;
export var shouldVisit = t.isClass;
export function ClassDeclaration(node, parent, scope, file) {
return t.variableDeclaration("let", [
@@ -245,7 +245,7 @@ class ClassTransformer {
if (body.length === 1) return t.toExpression(body[0]);
} else {
// infer class name if this is a nameless class expression
constructor = nameMethod.bare(constructor, this.parent, this.scope);
constructor = nameMethod.bare(constructor, this.parent, this.scope) || constructor;
body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(classRef, constructor)
@@ -347,7 +347,7 @@ class ClassTransformer {
if (this.isNativeSuper) helperName = "class-super-native-constructor-call";
constructorBody.body.push(util.template(helperName, {
NATIVE_REF: this.nativeSuperRef,
CLASS_NAME: className,
CLASS_NAME: this.classRef,
SUPER_NAME: this.superName
}, true));
}
@@ -550,19 +550,23 @@ class ClassTransformer {
if (node.decorators) {
var body = [];
if (node.value) body.push(t.returnStatement(node.value));
node.value = t.functionExpression(null, [], t.blockStatement(body));
if (node.value) {
body.push(t.returnStatement(node.value));
node.value = t.functionExpression(null, [], t.blockStatement(body));
} else {
node.value = t.literal(null);
}
this.pushToMap(node, true, "initializer");
var initializers;
var body;
var target;
if (node.static) {
initializers = this.staticInitializersId ||= this.scope.generateUidIdentifier("staticInitializers");
initializers = this.staticInitializersId = this.staticInitializersId || this.scope.generateUidIdentifier("staticInitializers");
body = this.staticPropBody;
target = this.classRef;
} else {
initializers = this.instanceInitializersId ||= this.scope.generateUidIdentifier("instanceInitializers");
initializers = this.instanceInitializersId = this.instanceInitializersId || this.scope.generateUidIdentifier("instanceInitializers");
body = this.instancePropBody;
target = t.thisExpression();
}
@@ -575,7 +579,7 @@ class ClassTransformer {
])
));
} else {
node.value ||= t.identifier("undefined");
if (!node.value && !node.decorators) return;
if (node.static) {
// can just be added to the static map

View File

@@ -1,7 +1,7 @@
import * as messages from "../../../messages";
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isVariableDeclaration(node, { kind: "const" }) || t.isImportDeclaration(node);
}

View File

@@ -1,7 +1,7 @@
import * as messages from "../../../messages";
import * as t from "../../../types";
export var check = t.isPattern;
export var shouldVisit = t.isPattern;
export function ForOfStatement(node, parent, scope, file) {
var left = node.left;
@@ -78,11 +78,11 @@ exports.Function = function (node, parent, scope, file) {
if (!hasDestructuring) return;
file.checkNode(nodes);
t.ensureBlock(node);
var block = node.body;
block.body = nodes.concat(block.body);
return node;
};
export function CatchClause(node, parent, scope, file) {
@@ -111,7 +111,7 @@ export function ExpressionStatement(node, parent, scope, file) {
var expr = node.expression;
if (expr.type !== "AssignmentExpression") return;
if (!t.isPattern(expr.left)) return;
if (file.isConsequenceExpressionStatement(node)) return;
if (this.isCompletionRecord()) return;
var destructuring = new DestructuringTransformer({
operator: expr.operator,
@@ -200,7 +200,7 @@ export function VariableDeclaration(node, parent, scope, file) {
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
declar ||= t.variableDeclaration(node.kind, []);
declar = declar || t.variableDeclaration(node.kind, []);
if (!t.isVariableDeclaration(node) && declar.kind !== node.kind) {
throw file.errorWithNode(node, messages.get("invalidParentForThisNode"));

View File

@@ -2,7 +2,7 @@ import * as messages from "../../../messages";
import * as util from "../../../util";
import * as t from "../../../types";
export var check = t.isForOfStatement;
export var shouldVisit = t.isForOfStatement;
export function ForOfStatement(node, parent, scope, file) {
if (this.get("right").isArrayExpression()) {

View File

@@ -1,7 +1,7 @@
import ReplaceSupers from "../../helpers/replace-supers";
import * as t from "../../../types";
export var check = t.isSuper;
export var shouldVisit = t.isSuper;
function Property(path, node, scope, getObjectRef, file) {
if (!node.method) return;
@@ -32,7 +32,7 @@ function Property(path, node, scope, getObjectRef, file) {
export function ObjectExpression(node, parent, scope, file) {
var objectRef;
var getObjectRef = () => objectRef ||= scope.generateUidIdentifier("obj");
var getObjectRef = () => objectRef = objectRef || scope.generateUidIdentifier("obj");
var propPaths = this.get("properties");
for (var i = 0; i < node.properties.length; i++) {

View File

@@ -2,7 +2,7 @@ import callDelegate from "../../helpers/call-delegate";
import * as util from "../../../util";
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isFunction(node) && hasDefaults(node);
}
@@ -45,7 +45,6 @@ exports.Function = function (node, parent, scope, file) {
ARGUMENT_KEY: t.literal(i),
ARGUMENTS: argsIdentifier
}, true);
file.checkNode(defNode);
defNode._blockHoist = node.params.length - i;
body.push(defNode);
};
@@ -97,4 +96,6 @@ exports.Function = function (node, parent, scope, file) {
} else {
node.body.body = body.concat(node.body.body);
}
return node;
};

View File

@@ -2,7 +2,7 @@ import isNumber from "lodash/lang/isNumber";
import * as util from "../../../util";
import * as t from "../../../types";
export var check = t.isRestElement;
export var shouldVisit = t.isRestElement;
var memberExpressionOptimisationVisitor = {
enter(node, parent, scope, state) {
@@ -74,7 +74,6 @@ exports.Function = function (node, parent, scope, file) {
var accessExpr = t.memberExpression(rest, t.literal(index), true);
return t.variableDeclarator(elem, accessExpr);
}));
file.checkNode(declar);
node.body.body.unshift(declar);
}
@@ -97,7 +96,7 @@ exports.Function = function (node, parent, scope, file) {
candidate.replaceWith(argsId);
optimizeMemberExpression(candidate.parent, node.params.length);
}
return;
return node;
}
//
@@ -138,4 +137,5 @@ exports.Function = function (node, parent, scope, file) {
});
loop._blockHoist = node.params.length + 1;
node.body.body.unshift(loop);
return node;
};

View File

@@ -84,7 +84,7 @@ function spec(node, body, objId, initProps, file) {
}
}
export function check(node) {
export function shouldVisit(node) {
return t.isProperty(node) && node.computed;
}

View File

@@ -1,6 +1,6 @@
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isProperty(node) && (node.method || node.shorthand);
}

View File

@@ -1,7 +1,7 @@
import * as regex from "../../helpers/regex";
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return regex.is(node, "y");
}

View File

@@ -1,7 +1,7 @@
import rewritePattern from "regexpu/rewrite-pattern";
import * as regex from "../../helpers/regex";
export function check(node) {
export function shouldVisit(node) {
return regex.is(node, "u");
}

View File

@@ -5,14 +5,16 @@ export var metadata = {
};
export function UnaryExpression(node, parent, scope, file) {
this.skip();
if (node._ignoreSpecSymbols) return;
if (node.operator === "typeof") {
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
if (this.get("argument").isIdentifier()) {
var undefLiteral = t.literal("undefined");
var unary = t.unaryExpression("typeof", node.argument);
unary._ignoreSpecSymbols = true;
return t.conditionalExpression(
t.binaryExpression("===", t.unaryExpression("typeof", node.argument), undefLiteral),
t.binaryExpression("===", unary, undefLiteral),
undefLiteral,
call
);
@@ -21,3 +23,13 @@ export function UnaryExpression(node, parent, scope, file) {
}
}
}
export function BinaryExpression(node, parent, scope, file) {
if (node.operator === "instanceof") {
return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]);
}
}
export function VariableDeclaration(node) {
if (node._generated) this.skip();
}

View File

@@ -44,7 +44,7 @@ function build(props, scope) {
return nodes;
}
export var check = t.isSpreadElement;
export var shouldVisit = t.isSpreadElement;
export function ArrayExpression(node, parent, scope) {
var elements = node.elements;

View File

@@ -101,23 +101,23 @@ class TailCallTransformer {
}
getArgumentsId() {
return this.argumentsId ||= this.scope.generateUidIdentifier("arguments");
return this.argumentsId = this.argumentsId || this.scope.generateUidIdentifier("arguments");
}
getThisId() {
return this.thisId ||= this.scope.generateUidIdentifier("this");
return this.thisId = this.thisId || this.scope.generateUidIdentifier("this");
}
getLeftId() {
return this.leftId ||= this.scope.generateUidIdentifier("left");
return this.leftId = this.leftId || this.scope.generateUidIdentifier("left");
}
getFunctionId() {
return this.functionId ||= this.scope.generateUidIdentifier("function");
return this.functionId = this.functionId || this.scope.generateUidIdentifier("function");
}
getAgainId() {
return this.againId ||= this.scope.generateUidIdentifier("again");
return this.againId = this.againId || this.scope.generateUidIdentifier("again");
}
getParams() {

View File

@@ -4,7 +4,7 @@ var buildBinaryExpression = function (left, right) {
return t.binaryExpression("+", left, right);
};
export function check(node) {
export function shouldVisit(node) {
return t.isTemplateLiteral(node) || t.isTaggedTemplateExpression(node);
}

View File

@@ -2,6 +2,6 @@ export var metadata = {
stage: 1
};
export function check() {
export function shouldVisit() {
return false;
}

View File

@@ -2,6 +2,6 @@ export var metadata = {
stage: 0
};
export function check() {
export function shouldVisit() {
return false;
}

View File

@@ -7,7 +7,7 @@ export var metadata = {
stage: 1
};
export function check(node) {
export function shouldVisit(node) {
return !!node.decorators;
}

View File

@@ -5,7 +5,7 @@ export var metadata = {
stage: 0
};
export var check = t.isDoExpression;
export var shouldVisit = t.isDoExpression;
export function DoExpression(node) {
var body = node.body.body;

View File

@@ -6,7 +6,7 @@ export var metadata = {
stage: 1
};
export function check(node) {
export function shouldVisit(node) {
return t.isExportDefaultSpecifier(node) || t.isExportNamespaceSpecifier(node);
}

View File

@@ -2,6 +2,6 @@ export var metadata = {
stage: 1
};
export function check() {
export function shouldVisit() {
return false;
}

View File

@@ -1,4 +1,6 @@
export default {
_modules: require("./internal/modules"),
"es7.classProperties": require("./es7/class-properties"),
"es7.trailingFunctionCommas": require("./es7/trailing-function-commas"),
"es7.asyncFunctions": require("./es7/async-functions"),
@@ -24,8 +26,6 @@ export default {
reactCompat: require("./other/react-compat"),
react: require("./other/react"),
_modules: require("./internal/modules"),
// needs to be before `regenerator` due to generator comprehensions
// needs to be before `_shadowFunctions`
"es7.comprehensions": require("./es7/comprehensions"),
@@ -94,8 +94,6 @@ export default {
"spec.protoToAssign": require("./spec/proto-to-assign"),
_declarations: require("./internal/declarations"),
_shadowFunctions: require("./internal/shadow-functions"),
"es7.doExpressions": require("./es7/do-expressions"),
@@ -117,6 +115,6 @@ export default {
"utility.inlineExpressions": require("./utility/inline-expressions"),
"utility.deadCodeElimination": require("./utility/dead-code-elimination"),
flow: require("./other/flow"),
_cleanUp: require("./internal/cleanup")
jscript: require("./other/jscript"),
flow: require("./other/flow")
};

View File

@@ -1,30 +0,0 @@
export var SequenceExpression = {
exit(node) {
if (node.expressions.length === 1) {
return node.expressions[0];
} else if (!node.expressions.length) {
this.remove();
}
}
};
export var ExpressionStatement = {
exit(node) {
if (!node.expression) this.remove();
}
};
export var Binary = {
exit(node) {
var right = node.right;
var left = node.left;
if (!left && !right) {
this.remove();
} else if (!left) {
return right;
} else if (!right) {
return left;
}
}
};

View File

@@ -1,37 +0,0 @@
import * as strict from "../../helpers/strict";
import * as t from "../../../types";
export var metadata = {
secondPass: true
};
export function BlockStatement(node, parent, scope, file) {
if (!node._declarations) return;
strict.wrap(node, function () {
var kinds = {};
var kind;
for (var i in node._declarations) {
var declar = node._declarations[i];
kind = declar.kind || "var";
var declarNode = t.variableDeclarator(declar.id, declar.init);
if (declar.init) {
node.body.unshift(file.attachAuxiliaryComment(t.variableDeclaration(kind, [declarNode])));
} else {
kinds[kind] ||= [];
kinds[kind].push(declarNode);
}
}
for (kind in kinds) {
node.body.unshift(file.attachAuxiliaryComment(t.variableDeclaration(kind, kinds[kind])));
}
node._declarations = null;
});
}
export { BlockStatement as Program };

View File

@@ -1,6 +1,8 @@
import * as strict from "../../helpers/strict";
export function Program(program, parent, scope, file) {
this.stop();
strict.wrap(program, function () {
program.body = file.dynamicImports.concat(program.body);
});

View File

@@ -6,7 +6,7 @@
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isImportDeclaration(node) || t.isExportDeclaration(node);
}

View File

@@ -52,11 +52,11 @@ function aliasFunction(getBody, path, scope) {
var state = {
getArgumentsId() {
return argumentsId ||= scope.generateUidIdentifier("arguments");
return argumentsId = argumentsId || scope.generateUidIdentifier("arguments");
},
getThisId() {
return thisId ||= scope.generateUidIdentifier("this");
return thisId = thisId || scope.generateUidIdentifier("this");
}
};
@@ -67,7 +67,7 @@ function aliasFunction(getBody, path, scope) {
var body;
var pushDeclaration = function (id, init) {
body ||= getBody();
body = body || getBody();
body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(id, init)
]));
@@ -82,6 +82,10 @@ function aliasFunction(getBody, path, scope) {
}
};
export function shouldVisit(node) {
return true;
}
export function Program(node, parent, scope) {
aliasFunction(function () {
return node.body;

View File

@@ -13,6 +13,6 @@ export function Program(program, parent, scope, file) {
}
}
program.body.unshift(directive);
this.unshiftContainer("body", [directive]);
}
}

View File

@@ -21,7 +21,7 @@ export function MethodDefinition(node) {
var isConstructor = !node.computed && t.isIdentifier(node.key, { name: "constructor" });
// get ["constructor"]() {}
isConstructor ||= t.isLiteral(node.key, { value: "constructor" });
isConstructor = isConstructor || t.isLiteral(node.key, { value: "constructor" });
if (isConstructor) {
throw this.errorWithNode(messages.get("classesIllegalConstructorKind"));

View File

@@ -1,7 +1,7 @@
import { _ForOfStatementArray } from "../es6/for-of";
import * as t from "../../../types";
export var check = t.isForOfStatement;
export var shouldVisit = t.isForOfStatement;
export var optional = true;
export function ForOfStatement(node, parent, scope, file) {

View File

@@ -1,5 +1,9 @@
import * as t from "../../../types";
export function shouldVisit(node) {
return node.isType || node.optional || node.implements || node.typeAnnotation || t.isFlow(node);
}
export function Flow(node) {
this.remove();
}

View File

@@ -0,0 +1,18 @@
import * as t from "../../../types";
export var metadata = {
optional: true
};
export function FunctionExpression(node, print) {
if (!node.id) return;
node._ignoreUserWhitespace = true;
return t.callExpression(
t.functionExpression(null, [], t.blockStatement([
t.toStatement(node),
t.returnStatement(node.id)
])),
[]
);
}

View File

@@ -1,7 +1,7 @@
import regenerator from "regenerator";
import * as t from "../../../types";
export function check(node) {
export function shouldVisit(node) {
return t.isFunction(node) && (node.async || node.generator);
}
@@ -9,5 +9,6 @@ export var Program = {
enter(ast) {
regenerator.transform(ast);
this.stop();
return ast; // force a checkPath, this really needs to be optimised
}
};

View File

@@ -1,8 +1,12 @@
import * as t from "../../../types";
function statementList(key, node, file) {
for (var i = 0; i < node[key].length; i++) {
var func = node[key][i];
function statementList(key, path, file) {
var paths = path.get(key);
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
var func = path.node;
if (!t.isFunctionDeclaration(func)) continue;
var declar = t.variableDeclaration("let", [
@@ -15,20 +19,33 @@ function statementList(key, node, file) {
// todo: name this
func.id = null;
node[key][i] = declar;
file.checkNode(declar);
path.replaceWith(declar);
}
}
export function shouldVisit(node) {
var body;
if (node.type === "SwitchCase") {
body = node.consequent;
} else if (node.type === "BlockStatement") {
body = node.body;
}
if (body) {
for (var i = 0; i < body.length; i++) {
if (body[i].type === "FunctionDeclaration") return true;
}
}
return false;
}
export function BlockStatement(node, parent, scope, file) {
if ((t.isFunction(parent) && parent.body === node) || t.isExportDeclaration(parent)) {
return;
}
statementList("body", node, file);
statementList("body", this, file);
}
export function SwitchCase(node, parent, scope, file) {
statementList("consequent", node, file);
statementList("consequent", this, file);
}

View File

@@ -1,2 +1 @@
export { bare as FunctionExpression } from "../../helpers/name-method";
export { bare as ArrowFunctionExpression } from "../../helpers/name-method";
export { bare as FunctionExpression, bare as ArrowFunctionExpression } from "../../helpers/name-method";

View File

@@ -1,6 +1,14 @@
import * as messages from "../../../messages";
import * as t from "../../../types";
export var metadata = {
readOnly: true
};
export function shouldVisit(node) {
return t.isModuleDeclaration(node) || (t.isCallExpression(node) && t.isIdentifier(node.callee, { name: "require" }));
}
// check if the input Literal `source` is an alternate casing of "react"
function check(source, file) {
if (t.isLiteral(source)) {

View File

@@ -2,7 +2,8 @@ import levenshtein from "leven";
import * as messages from "../../../messages";
export var metadata = {
optional: true
optional: true,
readOnly: true
};
export function Identifier(node, parent, scope, file) {

View File

@@ -32,9 +32,10 @@ export default class TraversalContext {
for (let i = 0; i < queue.length; i++) {
var path = queue[i];
if (visited.indexOf(path.node) >= 0) continue;
visited.push(path.node);
path.setContext(this.parentPath, this, path.key);
if (path.visit()) {
stop = true;
break;

View File

@@ -0,0 +1,19 @@
import * as t from "../types";
export default function (obj) {
for (var type in obj) {
var fns = obj[type];
if (typeof fns === "function") {
obj[type] = fns = { enter: fns };
}
var aliases = t.FLIPPED_ALIAS_KEYS[type];
if (aliases) {
for (var i = 0; i < aliases.length; i++) {
var alias = aliases[i];
obj[alias] = obj[alias] || fns;
}
}
}
return obj;
}

View File

@@ -1,4 +1,6 @@
import TraversalContext from "./context";
import explode from "./explode";
import * as messages from "../messages";
import includes from "lodash/collection/includes";
import * as t from "../types";
@@ -7,13 +9,12 @@ export default function traverse(parent, opts, scope, state, parentPath) {
if (!opts.noScope && !scope) {
if (parent.type !== "Program" && parent.type !== "File") {
throw new Error(`Must pass a scope and parentPath unless traversing a Program/File got a ${parent.type} node`);
throw new Error(messages.get("traverseNeedsParent", parent.type));
}
}
if (!opts) opts = {};
if (!opts.enter) opts.enter = function () { };
if (!opts.exit) opts.exit = function () { };
traverse.verify(opts);
// array of nodes
if (Array.isArray(parent)) {
@@ -25,6 +26,43 @@ export default function traverse(parent, opts, scope, state, parentPath) {
}
}
/**
* Quickly iterate over some traversal options and validate them.
*/
traverse.verify = function (opts) {
if (opts._verified) return;
if (typeof opts === "function") {
throw new Error(messages.get("traverseVerifyRootFunction"));
}
if (!opts.enter) opts.enter = function () { };
if (!opts.exit) opts.exit = function () { };
if (!opts.shouldSkip) opts.shouldSkip = function () { return false; };
for (var key in opts) {
// it's all good
if (key === "blacklist") continue;
var opt = opts[key];
if (typeof opt === "function") {
// it's all good, it's fine for this key to be a function
if (key === "enter" || key === "exit" || key === "shouldSkip") continue;
throw new Error(messages.get("traverseVerifyVisitorFunction", key));
} else if (typeof opt === "object") {
for (var key2 in opt) {
if (key2 === "enter" || key2 === "exit") continue;
throw new Error(messages.get("traverseVerifyVisitorProperty", key, key2));
}
}
}
opts._verified = true;
};
traverse.node = function (node, opts, scope, state, parentPath) {
var keys = t.VISITOR_KEYS[node.type];
if (!keys) return;
@@ -39,7 +77,7 @@ traverse.node = function (node, opts, scope, state, parentPath) {
const CLEAR_KEYS = [
"trailingComments", "leadingComments", "extendedRange",
"_declarations", "_scopeInfo" ,"_paths",
"_scopeInfo" ,"_paths",
"tokens", "range", "start", "end", "loc", "raw"
];
@@ -75,22 +113,7 @@ traverse.removeProperties = function (tree) {
return tree;
};
traverse.explode = function (obj) {
for (var type in obj) {
var fns = obj[type];
if (typeof fns === "function") {
obj[type] = fns = { enter: fns };
}
var aliases = t.FLIPPED_ALIAS_KEYS[type];
if (aliases) {
for (var i = 0; i < aliases.length; i++) {
obj[aliases[i]] ||= fns;
}
}
}
return obj;
};
traverse.explode = explode;
function hasBlacklistedType(node, parent, scope, state) {
if (node.type === state.type) {

View File

@@ -45,9 +45,13 @@ export default class TraversalPath {
this.data = {};
}
/**
* Description
*/
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
var targetNode = container[key];
var paths = container._paths ||= [];
var paths = container._paths = container._paths || [];
var path;
for (var i = 0; i < paths.length; i++) {
@@ -68,6 +72,10 @@ export default class TraversalPath {
return path;
}
/**
* Description
*/
static getScope(path: TraversalPath, scope: Scope, file?: File) {
var ourScope = scope;
@@ -79,28 +87,36 @@ export default class TraversalPath {
return ourScope;
}
/**
* Description
*/
queueNode(path) {
if (this.context) {
this.context.queue.push(path);
}
}
/**
* Description
*/
insertBefore(nodes) {
nodes = this._verifyNodeList(nodes);
this.checkNodes(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
return this.parentPath.insertBefore(nodes);
} else if (this.isPreviousType("Expression") || (this.parentPath.isForStatement() && this.key === "init")) {
if (this.node) nodes.push(this.node);
this.replaceExpressionWithStatements(nodes);
} else if (this.isPreviousType("Statement")) {
} else if (this.isPreviousType("Statement") || !this.type) {
this._maybePopFromStatements(nodes);
if (Array.isArray(this.container)) {
this._containerInsertBefore(nodes);
} else if (this.isStatementOrBlock()) {
if (this.node) nodes.push(this.node);
this.container[this.key] = t.blockStatement(nodes);
this.checkPaths(this);
} else {
throw new Error("We don't know what to do with this node type. We were previously a Statement but we can't fit in here?");
}
@@ -112,14 +128,23 @@ export default class TraversalPath {
_containerInsert(from, nodes) {
this.updateSiblingKeys(from, nodes.length);
var paths = [];
for (var i = 0; i < nodes.length; i++) {
var to = from + i;
this.container.splice(to, 0, nodes[i]);
var node = nodes[i];
this.container.splice(to, 0, node);
if (this.context) {
this.queueNode(this.context.create(this.parent, this.container, to));
var path = this.context.create(this.parent, this.container, to);
paths.push(path);
this.queueNode(path);
} else {
paths.push(TraversalPath.get(this, null, node, this.container, to));
}
}
this.checkPaths(paths);
}
_containerInsertBefore(nodes) {
@@ -137,6 +162,10 @@ export default class TraversalPath {
}
}
/**
* Description
*/
isCompletionRecord() {
var path = this;
@@ -150,6 +179,10 @@ export default class TraversalPath {
return true;
}
/**
* Description
*/
isStatementOrBlock() {
if (t.isLabeledStatement(this.parent) || t.isBlockStatement(this.container)) {
return false;
@@ -158,9 +191,12 @@ export default class TraversalPath {
}
}
/**
* Description
*/
insertAfter(nodes) {
nodes = this._verifyNodeList(nodes);
this.checkNodes(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
return this.parentPath.insertAfter(nodes);
@@ -171,13 +207,14 @@ export default class TraversalPath {
nodes.push(t.expressionStatement(temp));
}
this.replaceExpressionWithStatements(nodes);
} else if (this.isPreviousType("Statement")) {
} else if (this.isPreviousType("Statement") || !this.type) {
this._maybePopFromStatements(nodes);
if (Array.isArray(this.container)) {
this._containerInsertAfter(nodes);
} else if (this.isStatementOrBlock()) {
if (this.node) nodes.unshift(this.node);
this.container[this.key] = t.blockStatement(nodes);
this.checkPaths(this);
} else {
throw new Error("We don't know what to do with this node type. We were previously a Statement but we can't fit in here?");
}
@@ -186,6 +223,10 @@ export default class TraversalPath {
}
}
/**
* Description
*/
updateSiblingKeys(fromIndex, incrementBy) {
var paths = this.container._paths;
for (var i = 0; i < paths.length; i++) {
@@ -196,24 +237,45 @@ export default class TraversalPath {
}
}
/**
* Description
*/
setData(key, val) {
return this.data[key] = val;
}
/**
* Description
*/
getData(key, def) {
var val = this.data[key];
if (!val && def) val = this.data[key] = def;
return val;
}
/**
* Description
*/
setScope(file?) {
this.scope = TraversalPath.getScope(this, this.context && this.context.scope, file);
var target = this.context || this.parentPath;
this.scope = TraversalPath.getScope(this, target && target.scope, file);
}
/**
* Description
*/
clearContext() {
this.context = null;
}
/**
* Description
*/
setContext(parentPath, context, key, file?) {
this.shouldSkip = false;
this.shouldStop = false;
@@ -230,7 +292,10 @@ export default class TraversalPath {
this.type = this.node && this.node.type;
var log = file && this.type === "Program";
if (log) file.log.debug("Start scope building");
this.setScope(file);
if (log) file.log.debug("End scope building");
}
_remove() {
@@ -242,27 +307,60 @@ export default class TraversalPath {
}
}
remove() {
var removeParent = false;
if (this.parentPath) {
removeParent ||= this.parentPath.isExpressionStatement();
removeParent ||= this.parentPath.isSequenceExpression() && this.parent.expressions.length === 1
if (removeParent) return this.parentPath.remove();
}
/**
* Description
*/
remove() {
this._remove();
this.removed = true;
var parentPath = this.parentPath;
var parent = this.parent;
if (!parentPath) return;
// we're the child of an expression statement so we should remove the parent
if (parentPath.isExpressionStatement()) {
return parentPath.remove();
}
// we've just removed the second element of a sequence expression so let's turn that sequence
// expression into a regular expression
if (parentPath.isSequenceExpression() && parent.expressions.length === 1) {
parentPath.replaceWith(parent.expressions[0]);
}
// we're in a binary expression, better remove it and replace it with the last expression
if (parentPath.isBinary()) {
if (this.key === "left") {
parentPath.replaceWith(parent.right);
} else { // key === "right"
parentPath.replaceWith(parent.left);
}
}
}
/**
* Description
*/
skip() {
this.shouldSkip = true;
}
/**
* Description
*/
stop() {
this.shouldStop = true;
this.shouldSkip = true;
}
/**
* Description
*/
errorWithNode(msg, Error = SyntaxError) {
var loc = this.node.loc.start;
var err = new Error(`Line ${loc.line}: ${msg}`);
@@ -282,6 +380,10 @@ export default class TraversalPath {
throw new Error("Don't use `path.node = newNode;`, use `path.replaceWith(newNode)` or `path.replaceWithMultiple([newNode])`");
}
/**
* Description
*/
replaceInline(nodes) {
if (Array.isArray(nodes)) {
if (Array.isArray(this.container)) {
@@ -296,6 +398,10 @@ export default class TraversalPath {
}
}
/**
* Description
*/
_verifyNodeList(nodes) {
if (nodes.constructor !== Array) {
nodes = [nodes];
@@ -315,6 +421,43 @@ export default class TraversalPath {
return nodes;
}
/**
* Description
*/
unshiftContainer(containerKey, nodes) {
nodes = this._verifyNodeList(nodes);
// get the first path and insert our nodes before it, if it doesn't exist then it
// doesn't matter, our nodes will be inserted anyway
var container = this.node[containerKey];
var path = TraversalPath.get(this, null, this.node, container, 0);
return path.insertBefore(nodes);
}
/**
* Description
*/
pushContainer(containerKey, nodes) {
nodes = this._verifyNodeList(nodes);
// get an invisible path that represents the last node + 1 and replace it with our
// nodes, effectively inlining it
var container = this.node[containerKey];
var i = container.length;
var path = TraversalPath.get(this, null, this.node, container, i);
return path.replaceWith(nodes, true);
}
/**
* Description
*/
replaceWithMultiple(nodes: Array<Object>) {
nodes = this._verifyNodeList(nodes);
t.inheritsComments(nodes[0], this.node);
@@ -323,6 +466,10 @@ export default class TraversalPath {
if (!this.node) this.remove();
}
/**
* Description
*/
replaceWith(replacement, arraysAllowed) {
if (this.removed) {
throw new Error("You can't replace this node, we've already removed it");
@@ -354,19 +501,23 @@ export default class TraversalPath {
// potentially create new scope
this.setScope();
this.checkNodes([replacement]);
this.checkPaths(this);
}
checkNodes(nodes) {
/**
* Description
*/
checkPaths(paths) {
var scope = this.scope;
var file = scope && scope.file;
if (!file) return;
for (var i = 0; i < nodes.length; i++) {
file.checkNode(nodes[i], scope);
}
if (file) file.checkPath(paths);
}
/**
* Description
*/
getStatementParent(): ?TraversalPath {
var path = this;
@@ -385,6 +536,10 @@ export default class TraversalPath {
return path;
}
/**
* Description
*/
getLastStatements(): Array<TraversalPath> {
var paths = [];
@@ -406,6 +561,10 @@ export default class TraversalPath {
return paths;
}
/**
* Description
*/
replaceExpressionWithStatements(nodes: Array) {
var toSequenceExpression = t.toSequenceExpression(nodes, this.scope);
@@ -432,6 +591,10 @@ export default class TraversalPath {
}
}
/**
* Description
*/
call(key) {
var node = this.node;
if (!node) return;
@@ -440,17 +603,27 @@ export default class TraversalPath {
var fn = opts[key] || opts;
if (opts[node.type]) fn = opts[node.type][key] || fn;
// call the function with the params (node, parent, scope, state)
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
if (replacement) this.replaceWith(replacement, true);
}
/**
* Description
*/
isBlacklisted(): boolean {
var blacklist = this.opts.blacklist;
return blacklist && blacklist.indexOf(this.node.type) > -1;
}
/**
* Description
*/
visit(): boolean {
if (this.isBlacklisted()) return false;
if (this.opts.shouldSkip(this)) return false;
this.call("enter");
@@ -481,44 +654,91 @@ export default class TraversalPath {
return TraversalPath.get(this.parentPath, null, this.parent, this.container, key, this.file);
}
/**
* Description
*/
get(key: string): TraversalPath {
var parts = key.split(".");
if (parts.length === 1) { // "foo.bar"
var node = this.node;
var container = node[key];
if (Array.isArray(container)) {
return container.map((_, i) => {
return TraversalPath.get(this, null, node, container, i);
});
} else {
return TraversalPath.get(this, null, node, node, key);
}
} else { // "foo"
var path = this;
for (var i = 0; i > parts.length; i++) {
var part = parts[i];
if (part === ".") {
path = path.parentPath;
} else {
path = path.get(parts[i]);
}
}
return path;
if (parts.length === 1) { // "foo"
return this._getKey(key);
} else { // "foo.bar"
return this._getPattern(parts);
}
}
has(key): boolean {
return !!this.node[key];
/**
* Description
*/
_getKey(key) {
var node = this.node;
var container = node[key];
if (Array.isArray(container)) {
// requested a container so give them all the paths
return container.map((_, i) => {
return TraversalPath.get(this, null, node, container, i);
});
} else {
return TraversalPath.get(this, null, node, node, key);
}
}
/**
* Description
*/
_getPattern(parts) {
var path = this;
for (var i = 0; i > parts.length; i++) {
var part = parts[i];
if (part === ".") {
path = path.parentPath;
} else {
if (Array.isArray(path)) {
path = path[part];
} else {
path = path.get(part);
}
}
}
return path;
}
/**
* Description
*/
has(key): boolean {
var val = this.node[key];
if (val && Array.isArray(val)) {
return !!val.length;
} else {
return !!val;
}
}
/**
* Description
*/
is(key): boolean {
return this.has(key);
}
/**
* Description
*/
isnt(key): boolean {
return !this.has(key);
}
/**
* Description
*/
getTypeAnnotation(): {
inferred: boolean;
annotation: ?Object;
@@ -547,6 +767,10 @@ export default class TraversalPath {
return info;
}
/**
* Description
*/
resolve(): ?TraversalPath {
if (this.isVariableDeclarator()) {
if (this.get("id").isIdentifier()) {
@@ -589,7 +813,7 @@ export default class TraversalPath {
var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });
// { "foo": "obj" } or { ["foo"]: "obj" }
match ||= key.isLiteral({ value: targetName });
match = match || key.isLiteral({ value: targetName });
if (match) return prop.get("value");
}
@@ -598,6 +822,10 @@ export default class TraversalPath {
}
}
/**
* Description
*/
inferType(path: TraversalPath): ?Object {
path = path.resolve();
if (!path) return;
@@ -635,30 +863,58 @@ export default class TraversalPath {
}
}
/**
* Description
*/
isScope(): boolean {
return t.isScope(this.node, this.parent);
}
/**
* Description
*/
isReferencedIdentifier(opts): boolean {
return t.isReferencedIdentifier(this.node, this.parent, opts);
}
/**
* Description
*/
isReferenced(): boolean {
return t.isReferenced(this.node, this.parent);
}
/**
* Description
*/
isBlockScoped(): boolean {
return t.isBlockScoped(this.node);
}
/**
* Description
*/
isVar(): boolean {
return t.isVar(this.node);
}
/**
* Description
*/
isPreviousType(type: string): boolean {
return t.isType(this.type, type);
}
/**
* Description
*/
isTypeGeneric(genericName: string, opts = {}): boolean {
var typeInfo = this.getTypeAnnotation();
var type = typeInfo.annotation;
@@ -679,10 +935,18 @@ export default class TraversalPath {
return true;
}
/**
* Description
*/
getBindingIdentifiers() {
return t.getBindingIdentifiers(this.node);
}
/**
* Description
*/
traverse(visitor, state) {
traverse(this.node, visitor, this.scope, state, this);
}

View File

@@ -1,4 +1,5 @@
import includes from "lodash/collection/includes";
import explode from "./explode";
import traverse from "./index";
import defaults from "lodash/object/defaults";
import * as messages from "../messages";
@@ -64,6 +65,60 @@ var blockVariableVisitor = {
}
};
var renameVisitor = explode({
Identifier(node, parent, scope, state) {
if (this.isReferenced() && node.name === state.oldName) {
if (this.parentPath.isProperty() && this.key === "key" && parent.shorthand) {
parent.shorthand = false;
parent.value = t.identifier(state.newName);
} else {
node.name = state.newName;
}
}
},
Declaration(node, parent, scope, state) {
var ids = {};
var matchesLocal = (node, key) => {
return node.local === node[key] && (node.local.name === state.oldName || node.local.name === state.newName);
};
if (this.isExportDeclaration() && this.has("specifiers")) {
var specifiers = this.get("specifiers");
for (var specifier of (specifiers: Array)) {
if (specifier.isExportSpecifier() && matchesLocal(specifier.node, "exported")) {
specifier.get("exported").replaceWith(t.identifier(state.oldName));
}
}
} else if (this.isImportDeclaration() && this.has("specifiers")) {
var specifiers = this.get("specifiers");
for (var specifier of (specifiers: Array)) {
if (specifier.isImportSpecifier() && matchesLocal(specifier.node, "imported")) {
state.binding = state.info.identifier = t.identifier(state.newName);
specifier.get("local").replaceWith(state.binding);
} else {
extend(ids, specifier.getBindingIdentifiers());
}
}
} else {
ids = this.getBindingIdentifiers();
}
for (var name in ids) {
if (name === state.oldName) ids[name].name = state.newName;
}
},
Scopable(node, parent, scope, state) {
if (this.isScope()) {
if (!scope.bindingIdentifierEquals(state.oldName, state.binding)) {
this.skip();
}
}
}
});
export default class Scope {
/**
@@ -242,8 +297,8 @@ export default class Scope {
if (kind === "hoisted" && local.kind === "let") return;
var duplicate = false;
duplicate ||= kind === "let" || kind === "const" || local.kind === "let" || local.kind === "const" || local.kind === "module";
duplicate ||= local.kind === "param" && (kind === "let" || kind === "const");
if (!duplicate) duplicate = kind === "let" || kind === "const" || local.kind === "let" || local.kind === "const" || local.kind === "module";
if (!duplicate) duplicate = local.kind === "param" && (kind === "let" || kind === "const");
if (duplicate) {
throw this.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
@@ -255,36 +310,38 @@ export default class Scope {
*/
rename(oldName: string, newName: string, block?) {
newName ||= this.generateUidIdentifier(oldName).name;
newName = newName || this.generateUidIdentifier(oldName).name;
var info = this.getBinding(oldName);
if (!info) return;
var binding = info.identifier;
var scope = info.scope;
var state = {
newName: newName,
oldName: oldName,
binding: info.identifier,
info: info
};
scope.traverse(block || scope.block, {
enter(node, parent, scope) {
if (t.isReferencedIdentifier(node, parent) && node.name === oldName) {
node.name = newName;
} else if (t.isDeclaration(node)) {
var ids = this.getBindingIdentifiers();
for (var name in ids) {
if (name === oldName) ids[name].name = newName;
}
} else if (this.isScope()) {
if (!scope.bindingIdentifierEquals(oldName, binding)) {
this.skip();
}
}
}
});
var scope = info.scope;
scope.traverse(block || scope.block, renameVisitor, state);
if (!block) {
scope.removeOwnBinding(oldName);
scope.bindings[newName] = info;
state.binding.name = newName;
}
binding.name = newName;
var file = this.file;
if (file) {
this._renameFromMap(file.moduleFormatter.localImports, oldName, newName, state.binding);
//this._renameFromMap(file.moduleFormatter.localExports, oldName, newName);
}
}
_renameFromMap(map, oldName, newName, value) {
if (map[oldName]) {
map[newName] = value;
map[oldName] = null;
}
}
@@ -516,23 +573,35 @@ export default class Scope {
*/
push(opts: Object) {
var block = this.block;
var path = this.path;
if (t.isLoop(block) || t.isCatchClause(block) || t.isFunction(block)) {
t.ensureBlock(block);
block = block.body;
if (path.isLoop() || path.isCatchClause() || path.isFunction()) {
t.ensureBlock(path.node);
path = path.get("body");
}
if (!t.isBlockStatement(block) && !t.isProgram(block)) {
block = this.getBlockParent().block;
if (!path.isBlockStatement() && !path.isProgram()) {
path = this.getBlockParent().path;
}
block._declarations ||= {};
block._declarations[opts.key || opts.id.name] = {
kind: opts.kind || "var",
id: opts.id,
init: opts.init
};
var unique = opts.unique;
var kind = opts.kind || "var";
var dataKey = `declaration:${kind}`;
var declar = !unique && path.getData(dataKey);
if (!declar) {
declar = t.variableDeclaration(opts.kind || "var", []);
declar._generated = true;
declar._blockHoist = 2;
this.file.attachAuxiliaryComment(declar);
path.get("body")[0]._containerInsertBefore([declar]);
if (!unique) path.setData(dataKey, declar);
}
declar.declarations.push(t.variableDeclarator(opts.id, opts.init));
}
/**
@@ -681,7 +750,7 @@ export default class Scope {
*/
removeOwnBinding(name: string) {
this.bindings[name] = null;
delete this.bindings[name];
}
/**

View File

@@ -1,13 +1,13 @@
{
"ExpressionStatement": ["Statement"],
"BreakStatement": ["Statement"],
"ContinueStatement": ["Statement"],
"BreakStatement": ["Statement", "Terminatorless"],
"ContinueStatement": ["Statement", "Terminatorless"],
"DebuggerStatement": ["Statement"],
"DoWhileStatement": ["Statement", "Loop", "While", "Scopable"],
"IfStatement": ["Statement"],
"ReturnStatement": ["Statement"],
"ReturnStatement": ["Statement", "Terminatorless"],
"SwitchStatement": ["Statement", "Scopable"],
"ThrowStatement": ["Statement"],
"ThrowStatement": ["Statement", "Terminatorless"],
"TryStatement": ["Statement"],
"WhileStatement": ["Statement", "Loop", "While", "Scopable"],
"WithStatement": ["Statement"],
@@ -56,7 +56,7 @@
"ArrayExpression": ["Expression"],
"AssignmentExpression": ["Expression"],
"AwaitExpression": ["Expression"],
"AwaitExpression": ["Expression", "Terminatorless"],
"CallExpression": ["Expression"],
"ComprehensionExpression": ["Expression", "Scopable"],
"ConditionalExpression": ["Expression"],
@@ -74,7 +74,7 @@
"UpdateExpression": ["Expression"],
"JSXEmptyExpression": ["Expression"],
"JSXMemberExpression": ["Expression"],
"YieldExpression": ["Expression"],
"YieldExpression": ["Expression", "Terminatorless"],
"AnyTypeAnnotation": ["Flow"],
"ArrayTypeAnnotation": ["Flow"],

View File

@@ -43,8 +43,7 @@ export function toSequenceExpression(nodes: Array<Object>, scope: Scope): Object
var ensureLastUndefined = false;
var exprs = [];
for (let i = 0; i < nodes.length; i++) {
var node = nodes[i];
for (let node of (nodes: Array)) {
if (t.isExpression(node)) {
exprs.push(node);
} else if (t.isExpressionStatement(node)) {

View File

@@ -17,7 +17,7 @@ function registerType(type: string, skipAliasCheck?: boolean) {
};
t[`assert${type}`] = function (node, opts) {
opts ||= {};
opts = opts || {};
if (!is(node, opts)) {
throw new Error(`Expected type ${JSON.stringify(type)} with option ${JSON.stringify(opts)}`);
}
@@ -42,7 +42,7 @@ each(t.VISITOR_KEYS, function (keys, type) {
each(t.ALIAS_KEYS, function (aliases, type) {
each(aliases, function (alias) {
var types = t.FLIPPED_ALIAS_KEYS[alias] ||= [];
var types = t.FLIPPED_ALIAS_KEYS[alias] = t.FLIPPED_ALIAS_KEYS[alias] || [];
types.push(type);
});
});
@@ -78,7 +78,11 @@ export function isType(nodeType, targetType) {
if (nodeType === targetType) return true;
var aliases = t.FLIPPED_ALIAS_KEYS[targetType];
if (aliases) return aliases.indexOf(nodeType) > -1;
if (aliases) {
for (var alias of (aliases: Array)) {
if (nodeType === alias) return true;
}
}
return false;
}
@@ -118,9 +122,7 @@ each(t.BUILDER_KEYS, function (keys, type) {
export function shallowEqual(actual: Object, expected: Object): boolean {
var keys = Object.keys(expected);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
for (var key of (keys: Array)) {
if (actual[key] !== expected[key]) {
return false;
}
@@ -282,12 +284,11 @@ export function inheritsComments(child: Object, parent: Object): Object {
export function inherits(child: Object, parent: Object): Object {
if (!child || !parent) return child;
child._declarations = parent._declarations;
child._scopeInfo = parent._scopeInfo;
child.range = parent.range;
child.start = parent.start;
child.loc = parent.loc;
child.end = parent.end;
child._scopeInfo = parent._scopeInfo;
child.range = parent.range;
child.start = parent.start;
child.loc = parent.loc;
child.end = parent.end;
child.typeAnnotation = parent.typeAnnotation;
child.returnType = parent.returnType;

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