[Pkg-javascript-commits] [node-recast] 01/03: New upstream version 0.14.4

Julien Puydt julien.puydt at laposte.net
Wed Feb 28 22:41:03 UTC 2018


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to branch master
in repository node-recast.

commit 7e6cff7f5772ef13afa2b7c40f64059478523827
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Wed Feb 28 22:50:47 2018 +0100

    New upstream version 0.14.4
---
 .gitignore                  |    2 +
 README.md                   |   39 ++
 lib/fast-path.js            |   16 +-
 lib/options.js              |    2 +-
 lib/parser.js               |   89 +--
 lib/printer.js              |  833 +++++++++++++++++++++----
 lib/util.js                 |   25 +-
 package-lock.json           | 1315 +++++++++++++++++++++++-----------------
 package.json                |   15 +-
 parsers/_babylon_options.js |   39 ++
 parsers/acorn.js            |   35 ++
 parsers/babylon.js          |   14 +
 parsers/esprima.js          |   28 +
 parsers/flow.js             |   14 +
 parsers/typescript.js       |   14 +
 test/babylon.js             |   22 +-
 test/comments.js            | 1405 ++++++++++++++++++++++---------------------
 test/jsx.js                 |    2 +-
 test/parser.js              |  128 +++-
 test/printer.js             |   15 +-
 test/run.js                 |   16 +
 test/run.sh                 |   28 +
 test/syntax.js              |   77 +--
 test/type-syntax.js         |    4 +
 test/typescript.js          |  350 +++++++++++
 yarn.lock                   |   48 +-
 26 files changed, 3051 insertions(+), 1524 deletions(-)

diff --git a/.gitignore b/.gitignore
index 07e6e47..c104045 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 /node_modules
+/test/data/babylon-typescript-fixtures
+/test/data/graphql-tools-src
diff --git a/README.md b/README.md
index 6d2d91b..98ec53f 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,45 @@ var add = function(b, a) {
 ```
 Note that the weird formatting was discarded, yet the behavior and abstract structure of the code remain the same.
 
+Using a different parser
+---
+
+By default, Recast uses the [Esprima JavaScript parser](https://www.npmjs.com/package/esprima) when you call `recast.parse(code)`. While Esprima supports almost all modern ECMAScript syntax, you may want to use a different parser to enable TypeScript or Flow syntax, or just because you want to match other compilation tools you might be using.
+
+In order to get any benefits from Recast's conservative pretty-printing, **it is very important that you continue to call `recast.parse`** (rather than parsing the AST yourself using a different parser), and simply instruct `recast.parse` to use a different parser:
+
+```js
+const acornAst = recast.parse(source, {
+  parser: require("acorn")
+});
+```
+
+Why is this so important? When you call `recast.parse`, it makes a shadow copy of the AST before returning it to you, giving every copied AST node a reference back to the original through a special `.original` property. This information is what enables `recast.print` to detect where the AST has been modified, so that it can preserve formatting for parts of the AST that were not modified.
+
+Any `parser` object that supports a `parser.parse(source)` method will work here; however, if your parser requires additional options, you can always implement your own `parse` method that invokes your parser with custom options:
+
+```js
+const acornAst = recast.parse(source, {
+  parser: {
+    parse(source) {
+      return require("acorn").parse(source, {
+        // additional options
+      });
+    }
+  }
+});
+```
+
+To take some of the guesswork out of configuring common parsers, Recast provides [several preconfigured parsers](https://github.com/benjamn/recast/tree/master/parsers), so you can parse TypeScript (for example) without worrying about the configuration details:
+
+```js
+const tsAst = recast.parse(source, {
+  parser: require("recast/parsers/typescript")
+});
+```
+
+**Note:** Some of these parsers import npm packages that Recast does not directly depend upon, so please be aware you may have to run `npm install babylon at next` to use the `typescript`, `flow`, or `babylon` parsers, or `npm install acorn` to use the `acorn` parser. Only Esprima is installed by default when Recast is installed.
+
 Source maps
 ---
 
diff --git a/lib/fast-path.js b/lib/fast-path.js
index 94e280a..8defc7f 100644
--- a/lib/fast-path.js
+++ b/lib/fast-path.js
@@ -426,8 +426,20 @@ function containsCallExpression(node) {
 
 FPp.canBeFirstInStatement = function() {
   var node = this.getNode();
-  return !n.FunctionExpression.check(node)
-    && !n.ObjectExpression.check(node);
+
+  if (n.FunctionExpression.check(node)) {
+    return false;
+  }
+
+  if (n.ObjectExpression.check(node)) {
+    return false;
+  }
+
+  if (n.ClassExpression.check(node)) {
+    return false;
+  }
+
+  return true;
 };
 
 FPp.firstInStatement = function() {
diff --git a/lib/options.js b/lib/options.js
index 82e46b2..74e9210 100644
--- a/lib/options.js
+++ b/lib/options.js
@@ -2,7 +2,7 @@ var defaults = {
     // If you want to use a different branch of esprima, or any other
     // module that supports a .parse function, pass that module object to
     // recast.parse as options.parser (legacy synonym: options.esprima).
-    parser: require("esprima"),
+    parser: require("../parsers/esprima"),
 
     // Number of spaces the pretty-printer should use per tab for
     // indentation. If you do not pass this option explicitly, it will be
diff --git a/lib/parser.js b/lib/parser.js
index e6157cb..98dc861 100644
--- a/lib/parser.js
+++ b/lib/parser.js
@@ -1,3 +1,5 @@
+"use strict";
+
 var assert = require("assert");
 var types = require("./types");
 var n = types.namedTypes;
@@ -14,67 +16,80 @@ var util = require("./util");
 exports.parse = function parse(source, options) {
   options = normalizeOptions(options);
 
-  var lines = fromString(source, options);
+  const lines = fromString(source, options);
 
-  var sourceWithoutTabs = lines.toString({
+  const sourceWithoutTabs = lines.toString({
     tabWidth: options.tabWidth,
     reuseWhitespace: false,
     useTabs: false
   });
 
-  var comments = [];
-  var program = options.parser.parse(sourceWithoutTabs, {
+  let comments = [];
+  const ast = options.parser.parse(sourceWithoutTabs, {
     jsx: true,
     loc: true,
     locations: true,
     range: options.range,
     comment: true,
     onComment: comments,
-    tolerant: options.tolerant,
+    tolerant: util.getOption(options, "tolerant", true),
     ecmaVersion: 6,
-    sourceType: 'module'
+    sourceType: util.getOption(options, "sourceType", "module")
   });
 
-  // If the source was empty, some parsers give loc.{start,end}.line
-  // values of 0, instead of the minimum of 1.
-  util.fixFaultyLocations(program, lines);
-
-  program.loc = program.loc || {
-    start: lines.firstPos(),
-    end: lines.lastPos()
-  };
-
-  program.loc.lines = lines;
-  program.loc.indent = 0;
-
-  // Expand the Program node's .loc to include all comments, since
-  // typically its .loc.start and .loc.end will coincide with those of the
-  // first and last statements, respectively, excluding any comments that
-  // fall outside that region.
-  var trueProgramLoc = util.getTrueLoc(program, lines);
-  program.loc.start = trueProgramLoc.start;
-  program.loc.end = trueProgramLoc.end;
+  if (Array.isArray(ast.comments)) {
+    comments = ast.comments;
+    delete ast.comments;
+  }
 
-  if (program.comments) {
-    comments = program.comments;
-    delete program.comments;
+  if (ast.loc) {
+    // If the source was empty, some parsers give loc.{start,end}.line
+    // values of 0, instead of the minimum of 1.
+    util.fixFaultyLocations(ast, lines);
+  } else {
+    ast.loc = {
+      start: lines.firstPos(),
+      end: lines.lastPos()
+    };
   }
 
-  // In order to ensure we reprint leading and trailing program comments,
-  // wrap the original Program node with a File node.
-  var file = program;
-  if (file.type === "Program") {
-    var file = b.file(program, options.sourceFileName || null);
+  ast.loc.lines = lines;
+  ast.loc.indent = 0;
+
+  let file;
+  let program;
+  if (ast.type === "Program") {
+    program = ast;
+    // In order to ensure we reprint leading and trailing program
+    // comments, wrap the original Program node with a File node. Only
+    // ESTree parsers (Acorn and Esprima) return a Program as the root AST
+    // node. Most other (Babylon-like) parsers return a File.
+    file = b.file(ast, options.sourceFileName || null);
     file.loc = {
-      lines: lines,
-      indent: 0,
       start: lines.firstPos(),
-      end: lines.lastPos()
+      end: lines.lastPos(),
+      lines: lines,
+      indent: 0
     };
-  } else if (file.type === "File") {
+  } else if (ast.type === "File") {
+    file = ast;
     program = file.program;
   }
 
+  // Expand the Program's .loc to include all comments (not just those
+  // attached to the Program node, as its children may have comments as
+  // well), since sometimes program.loc.{start,end} will coincide with the
+  // .loc.{start,end} of the first and last *statements*, mistakenly
+  // excluding comments that fall outside that region.
+  var trueProgramLoc = util.getTrueLoc({
+    type: program.type,
+    loc: program.loc,
+    body: [],
+    comments
+  }, lines);
+  program.loc.start = trueProgramLoc.start;
+  program.loc.end = trueProgramLoc.end;
+
   // Passing file.program here instead of just file means that initial
   // comments will be attached to program.body[0] instead of program.
   attachComments(
diff --git a/lib/printer.js b/lib/printer.js
index 9bc2a58..818c4b7 100644
--- a/lib/printer.js
+++ b/lib/printer.js
@@ -1,3 +1,5 @@
+"use strict";
+
 var assert = require("assert");
 var sourceMap = require("source-map");
 var printComments = require("./comments").printComments;
@@ -298,6 +300,7 @@ function genericPrintNoParens(path, options, print) {
     case "Identifier":
         return concat([
             fromString(n.name, options),
+            n.optional ? "?" : "",
             path.call(print, "typeAnnotation")
         ]);
 
@@ -308,12 +311,22 @@ function genericPrintNoParens(path, options, print) {
     case "SpreadPropertyPattern":
     case "ObjectTypeSpreadProperty":
     case "RestElement":
-        return concat(["...", path.call(print, "argument")]);
+        return concat([
+            "...",
+            path.call(print, "argument"),
+            path.call(print, "typeAnnotation")
+        ]);
 
     case "FunctionDeclaration":
     case "FunctionExpression":
-        if (n.async)
+    case "TSDeclareFunction":
+        if (n.declare) {
+            parts.push("declare ");
+        }
+
+        if (n.async) {
             parts.push("async ");
+        }
 
         parts.push("function");
 
@@ -332,29 +345,30 @@ function genericPrintNoParens(path, options, print) {
             "(",
             printFunctionParams(path, options, print),
             ")",
-            path.call(print, "returnType"),
-            " ",
-            path.call(print, "body")
+            path.call(print, "returnType")
         );
 
+        if (n.body) {
+            parts.push(" ", path.call(print, "body"));
+        }
+
         return concat(parts);
 
     case "ArrowFunctionExpression":
-        if (n.async)
+        if (n.async) {
             parts.push("async ");
+        }
 
         if (n.typeParameters) {
             parts.push(path.call(print, "typeParameters"));
         }
 
-        if (
-            !options.arrowParensAlways &&
+        if (! options.arrowParensAlways &&
             n.params.length === 1 &&
-            !n.rest &&
+            ! n.rest &&
             n.params[0].type === 'Identifier' &&
-            !n.params[0].typeAnnotation &&
-            !n.returnType
-        ) {
+            ! n.params[0].typeAnnotation &&
+            ! n.returnType) {
             parts.push(path.call(print, "params", 0));
         } else {
             parts.push(
@@ -370,13 +384,7 @@ function genericPrintNoParens(path, options, print) {
         return concat(parts);
 
     case "MethodDefinition":
-        if (n.static) {
-            parts.push("static ");
-        }
-
-        parts.push(printMethod(path, options, print));
-
-        return concat(parts);
+        return printMethod(path, options, print);
 
     case "YieldExpression":
         parts.push("yield");
@@ -413,6 +421,9 @@ function genericPrintNoParens(path, options, print) {
         return fromString(" ").join(parts);
 
     case "ImportSpecifier":
+        if (n.importKind && n.importKind !== "value") {
+            parts.push(n.importKind + " ");
+        }
         if (n.imported) {
             parts.push(path.call(print, "imported"));
             if (n.local &&
@@ -462,6 +473,9 @@ function genericPrintNoParens(path, options, print) {
         }
         return path.call(print, "id");
 
+    case "TSExportAssignment":
+        return concat(["export = ", path.call(print, "expression")]);
+
     case "ExportDeclaration":
     case "ExportDefaultDeclaration":
     case "ExportNamedDeclaration":
@@ -481,6 +495,10 @@ function genericPrintNoParens(path, options, print) {
 
         return concat(parts);
 
+    case "TSNamespaceExportDeclaration":
+        parts.push("export as namespace ", path.call(print, "id"));
+        return maybeAddSemicolon(concat(parts));
+
     case "ExportNamespaceSpecifier":
         return concat(["* as ", path.call(print, "exported")]);
 
@@ -490,7 +508,7 @@ function genericPrintNoParens(path, options, print) {
     case "Import":
         return fromString("import", options);
 
-    case "ImportDeclaration":
+    case "ImportDeclaration": {
         parts.push("import ");
 
         if (n.importKind && n.importKind !== "value") {
@@ -500,36 +518,48 @@ function genericPrintNoParens(path, options, print) {
         if (n.specifiers &&
             n.specifiers.length > 0) {
 
-            var foundImportSpecifier = false;
+            const unbracedSpecifiers = [];
+            const bracedSpecifiers = [];
+
+            path.each(function (specifierPath) {
+                const spec = specifierPath.getValue();
+                if (spec.type === "ImportSpecifier") {
+                    bracedSpecifiers.push(print(specifierPath));
+                } else if (spec.type === "ImportDefaultSpecifier" ||
+                           spec.type === "ImportNamespaceSpecifier") {
+                    unbracedSpecifiers.push(print(specifierPath));
+                }
+            }, "specifiers");
 
-            path.each(function(specifierPath) {
-                var i = specifierPath.getName();
+            unbracedSpecifiers.forEach((lines, i) => {
                 if (i > 0) {
                     parts.push(", ");
                 }
+                parts.push(lines);
+            });
 
-                var value = specifierPath.getValue();
-
-                if (namedTypes.ImportDefaultSpecifier.check(value) ||
-                    namedTypes.ImportNamespaceSpecifier.check(value)) {
-                    assert.strictEqual(foundImportSpecifier, false);
-                } else {
-                    namedTypes.ImportSpecifier.assert(value);
-                    if (!foundImportSpecifier) {
-                        foundImportSpecifier = true;
-                        parts.push(
-                          options.objectCurlySpacing ? "{ " : "{"
-                        );
-                    }
+            if (bracedSpecifiers.length > 0) {
+                let lines = fromString(", ").join(bracedSpecifiers);
+                if (lines.getLineLength(1) > options.wrapColumn) {
+                    lines = concat([
+                        fromString(",\n").join(
+                            bracedSpecifiers
+                        ).indent(options.tabWidth),
+                        ","
+                    ]);
                 }
 
-                parts.push(print(specifierPath));
-            }, "specifiers");
+                if (unbracedSpecifiers.length > 0) {
+                    parts.push(", ");
+                }
 
-            if (foundImportSpecifier) {
-                parts.push(
-                  options.objectCurlySpacing ? " }" : "}"
-                );
+                if (lines.length > 1) {
+                    parts.push("{\n", lines, "\n}");
+                } else if (options.objectCurlySpacing) {
+                    parts.push("{ ", lines, " }");
+                } else {
+                    parts.push("{", lines, "}");
+                }
             }
 
             parts.push(" from ");
@@ -538,6 +568,7 @@ function genericPrintNoParens(path, options, print) {
         parts.push(path.call(print, "source"), ";");
 
         return concat(parts);
+    }
 
     case "BlockStatement":
         var naked = path.call(function(bodyPath) {
@@ -689,14 +720,9 @@ function genericPrintNoParens(path, options, print) {
         return concat(parts);
 
     case "ClassMethod": // Babel 6
-        if (n.static) {
-            parts.push("static ");
-        }
-
-        return concat([parts, printObjectMethod(path, options, print)]);
-
     case "ObjectMethod": // Babel 6
-        return printObjectMethod(path, options, print);
+    case "TSDeclareMethod":
+        return printMethod(path, options, print);
 
     case "Decorator":
         return concat(["@", path.call(print, "expression")]);
@@ -851,7 +877,12 @@ function genericPrintNoParens(path, options, print) {
         return concat(parts);
 
     case "VariableDeclaration":
+        if (n.declare) {
+            parts.push("declare ");
+        }
+
         parts.push(n.kind, " ");
+
         var maxLen = 0;
         var printed = path.map(function(childPath) {
             var lines = print(childPath);
@@ -1232,10 +1263,22 @@ function genericPrintNoParens(path, options, print) {
         return concat(parts);
 
     case "ClassProperty":
+        if (typeof n.accessibility === "string") {
+            parts.push(n.accessibility, " ");
+        }
+
         if (n.static) {
             parts.push("static ");
         }
 
+        if (n.abstract) {
+            parts.push("abstract ");
+        }
+
+        if (n.readonly) {
+            parts.push("readonly ");
+        }
+
         var key = path.call(print, "key");
 
         if (n.computed) {
@@ -1248,6 +1291,10 @@ function genericPrintNoParens(path, options, print) {
 
         parts.push(key);
 
+        if (n.optional) {
+            parts.push("?");
+        }
+
         if (n.typeAnnotation) {
             parts.push(path.call(print, "typeAnnotation"));
         }
@@ -1261,16 +1308,27 @@ function genericPrintNoParens(path, options, print) {
 
     case "ClassDeclaration":
     case "ClassExpression":
+        if (n.declare) {
+            parts.push("declare ");
+        }
+
+        if (n.abstract) {
+            parts.push("abstract ");
+        }
+
         parts.push("class");
 
         if (n.id) {
             parts.push(
                 " ",
-                path.call(print, "id"),
-                path.call(print, "typeParameters")
+                path.call(print, "id")
             );
         }
 
+        if (n.typeParameters) {
+            parts.push(path.call(print, "typeParameters"));
+        }
+
         if (n.superClass) {
             parts.push(
                 " extends ",
@@ -1332,6 +1390,8 @@ function genericPrintNoParens(path, options, print) {
     case "MemberTypeAnnotation": // Flow
     case "TupleTypeAnnotation": // Flow
     case "Type": // Flow
+    case "TSHasOptionalTypeParameters":
+    case "TSHasOptionalTypeAnnotation":
         throw new Error("unprintable type: " + JSON.stringify(n.type));
 
     case "CommentBlock": // Babel block comment.
@@ -1478,21 +1538,29 @@ function genericPrintNoParens(path, options, print) {
         // Fall through to InterfaceDeclaration...
 
     case "InterfaceDeclaration":
+    case "TSInterfaceDeclaration":
+        if (n.declare) {
+            parts.push("declare ");
+        }
+
         parts.push(
-            fromString("interface ", options),
+            "interface ",
             path.call(print, "id"),
             path.call(print, "typeParameters"),
             " "
         );
 
-        if (n["extends"]) {
+        if (n["extends"] && n["extends"].length > 0) {
             parts.push(
                 "extends ",
-                fromString(", ").join(path.map(print, "extends"))
+                fromString(", ").join(path.map(print, "extends")),
+                " "
             );
         }
 
-        parts.push(" ", path.call(print, "body"));
+        if (n.body) {
+            parts.push(path.call(print, "body"));
+        }
 
         return concat(parts);
 
@@ -1658,6 +1726,519 @@ function genericPrintNoParens(path, options, print) {
     case "NullTypeAnnotation":
         return fromString("null", options);
 
+    // Type Annotations for TypeScript (when using Babylon as parser)
+    case "TSType":
+        throw new Error("unprintable type: " + JSON.stringify(n.type));
+
+    case "TSNumberKeyword":
+        return fromString("number", options);
+
+    case "TSObjectKeyword":
+        return fromString("object", options);
+
+    case "TSBooleanKeyword":
+        return fromString("boolean", options);
+
+    case "TSStringKeyword":
+        return fromString("string", options);
+
+    case "TSSymbolKeyword":
+        return fromString("symbol", options);
+
+    case "TSAnyKeyword":
+        return fromString("any", options);
+
+    case "TSVoidKeyword":
+        return fromString("void", options);
+
+    case "TSThisType":
+        return fromString("this", options);
+
+    case "TSNullKeyword":
+        return fromString("null", options);
+
+    case "TSUndefinedKeyword":
+        return fromString("undefined", options);
+
+    case "TSNeverKeyword":
+        return fromString("never", options);
+
+    case "TSArrayType":
+        return concat([
+            path.call(print, "elementType"),
+            "[]"
+        ]);
+
+    case "TSLiteralType":
+        return path.call(print, "literal")
+
+    case "TSUnionType":
+        return fromString(" | ").join(path.map(print, "types"));
+
+    case "TSIntersectionType":
+        return fromString(" & ").join(path.map(print, "types"));
+
+    case "TSConditionalType":
+        parts.push(
+            path.call(print, "checkType"),
+            " extends ",
+            path.call(print, "extendsType"),
+            " ? ",
+            path.call(print, "trueType"),
+            " : ",
+            path.call(print, "falseType")
+        );
+
+        return concat(parts);
+
+    case "TSInferType":
+        parts.push(
+            "infer ",
+            path.call(print, "typeParameter")
+        );
+
+        return concat(parts);
+
+    case "TSParenthesizedType":
+        return concat([
+            "(",
+            path.call(print, "typeAnnotation"),
+            ")"
+        ]);
+
+    case "TSFunctionType":
+    case "TSConstructorType":
+        return concat([
+            path.call(print, "typeParameters"),
+            "(",
+            printFunctionParams(path, options, print),
+            ")",
+            path.call(print, "typeAnnotation")
+        ]);
+
+    case "TSMappedType": {
+        parts.push(
+            n.readonly ? "readonly " : "",
+            "[",
+            path.call(print, "typeParameter"),
+            "]",
+            n.optional ? "?" : ""
+        );
+
+        if (n.typeAnnotation) {
+            parts.push(": ", path.call(print, "typeAnnotation"), ";");
+        }
+
+        return concat([
+            "{\n",
+            concat(parts).indent(options.tabWidth),
+            "\n}",
+        ]);
+    }
+
+    case "TSTupleType":
+        return concat([
+            "[",
+            fromString(", ").join(path.map(print, "elementTypes")),
+            "]"
+        ]);
+
+    case "TSIndexedAccessType":
+        return concat([
+            path.call(print, "objectType"),
+            "[",
+            path.call(print, "indexType"),
+            "]"
+        ]);
+
+    case "TSTypeOperator":
+        return concat([
+            path.call(print, "operator"),
+            " ",
+            path.call(print, "typeAnnotation")
+        ]);
+
+    case "TSTypeLiteral": {
+        const memberLines =
+            fromString(",\n").join(path.map(print, "members"));
+
+        if (memberLines.isEmpty()) {
+            return fromString("{}", options);
+        }
+
+        parts.push(
+            "{\n",
+            memberLines.indent(options.tabWidth),
+            "\n}"
+        );
+
+        return concat(parts);
+    }
+
+    case "TSEnumMember":
+        parts.push(path.call(print, "id"));
+        if (n.initializer) {
+            parts.push(
+                " = ",
+                path.call(print, "initializer")
+            );
+        }
+        return concat(parts);
+
+    case "TSTypeQuery":
+        return concat([
+            "typeof ",
+            path.call(print, "exprName"),
+        ]);
+
+    case "TSParameterProperty":
+        if (n.accessibility) {
+            parts.push(n.accessibility, " ");
+        }
+
+        if (n.export) {
+            parts.push("export ");
+        }
+
+        if (n.static) {
+            parts.push("static ");
+        }
+
+        if (n.readonly) {
+            parts.push("readonly ");
+        }
+
+        parts.push(path.call(print, "parameter"));
+
+        return concat(parts);
+
+    case "TSTypeReference":
+        return concat([
+            path.call(print, "typeName"),
+            path.call(print, "typeParameters")
+        ]);
+
+    case "TSQualifiedName":
+        return concat([
+            path.call(print, "left"),
+            ".",
+            path.call(print, "right")
+        ]);
+
+    case "TSAsExpression": {
+        var withParens = n.extra && n.extra.parenthesized === true;
+        parts = [];
+        if (withParens) parts.push("(");
+        parts.push(
+            path.call(print, "expression"),
+            fromString(" as "),
+            path.call(print, "typeAnnotation")
+        );
+        if (withParens) parts.push(")");
+
+        return concat(parts);
+    }
+
+    case "TSNonNullExpression":
+        return concat([
+            path.call(print, "expression"),
+            "!"
+        ]);
+
+    case "TSTypeAnnotation": {
+        // similar to flow's FunctionTypeAnnotation, this can be
+        // ambiguous: it can be prefixed by => or :
+        // in a type predicate, it takes the for u is U
+        var parent = path.getParentNode(0);
+        var prefix = ": ";
+        var isFunctionType = namedTypes.TSFunctionType.check(parent);
+        if (namedTypes.TSFunctionType.check(parent)) {
+            prefix = " => ";
+        }
+
+        if (namedTypes.TSTypePredicate.check(parent)) {
+            prefix = " is ";
+        }
+
+        return concat([
+            prefix,
+            path.call(print, "typeAnnotation")
+        ]);
+    }
+
+    case "TSIndexSignature":
+        return concat([
+            n.readonly ? "readonly " : "",
+            "[",
+            path.map(print, "parameters"),
+            "]",
+            path.call(print, "typeAnnotation")
+        ]);
+
+    case "TSPropertySignature":
+        parts.push(
+            printVariance(path, print),
+            n.readonly ? "readonly " : ""
+        );
+
+        if (n.computed) {
+            parts.push(
+                "[",
+                path.call(print, "key"),
+                "]"
+            );
+        } else {
+            parts.push(path.call(print, "key"));
+        }
+
+        parts.push(
+            n.optional ? "?" : "",
+            path.call(print, "typeAnnotation")
+        );
+
+        return concat(parts);
+
+    case "TSMethodSignature":
+        if (n.computed) {
+            parts.push(
+                "[",
+                path.call(print, "key"),
+                "]"
+            );
+        } else {
+            parts.push(path.call(print, "key"));
+        }
+
+        if (n.optional) {
+            parts.push("?");
+        }
+
+        parts.push(
+            path.call(print, "typeParameters"),
+            "(",
+            printFunctionParams(path, options, print),
+            ")",
+            path.call(print, "typeAnnotation")
+        );
+
+        return concat(parts);
+
+    case "TSTypePredicate":
+        return concat([
+            path.call(print, "parameterName"),
+            path.call(print, "typeAnnotation")
+        ]);
+
+    case "TSCallSignatureDeclaration":
+        return concat([
+            path.call(print, "typeParameters"),
+            "(",
+            printFunctionParams(path, options, print),
+            ")",
+            path.call(print, "typeAnnotation")
+        ]);
+
+    case "TSConstructSignatureDeclaration":
+        if (n.typeParameters) {
+            parts.push(
+                "new",
+                path.call(print, "typeParameters")
+            );
+        } else {
+            parts.push("new ");
+        }
+
+        parts.push(
+            "(",
+            printFunctionParams(path, options, print),
+            ")",
+            path.call(print, "typeAnnotation")
+        );
+
+        return concat(parts);
+
+    case "TSTypeAliasDeclaration":
+        return concat([
+            "type ",
+            path.call(print, "id"),
+            path.call(print, "typeParameters"),
+            " = ",
+            path.call(print, "typeAnnotation"),
+            ";"
+        ]);
+
+    case "TSTypeParameter":
+        parts.push(path.call(print, "name"));
+
+        // ambiguous because of TSMappedType
+        var parent = path.getParentNode(0);
+        var isInMappedType = namedTypes.TSMappedType.check(parent);
+
+        if (n.constraint) {
+            parts.push(
+                isInMappedType ? " in " : " extends ",
+                path.call(print, "constraint")
+            );
+        }
+
+        if (n["default"]) {
+            parts.push(" = ", path.call(print, "default"));
+        }
+
+        return concat(parts);
+
+    case "TSTypeAssertion":
+        var withParens = n.extra && n.extra.parenthesized === true;
+        if (withParens) {
+            parts.push("(");
+        }
+
+        parts.push(
+            "<",
+            path.call(print, "typeAnnotation"),
+            "> ",
+            path.call(print, "expression")
+        );
+
+        if (withParens) {
+            parts.push(")");
+        }
+
+        return concat(parts);
+
+    case "TSTypeParameterDeclaration":
+    case "TSTypeParameterInstantiation":
+        return concat([
+            "<",
+            fromString(", ").join(path.map(print, "params")),
+            ">"
+        ]);
+
+    case "TSEnumDeclaration":
+        parts.push(
+            n.declare ? "declare " : "",
+            n.const ? "const " : "",
+            "enum ",
+            path.call(print, "id")
+        );
+
+        const memberLines =
+            fromString(",\n").join(path.map(print, "members"));
+
+        if (memberLines.isEmpty()) {
+            parts.push(" {}");
+        } else {
+            parts.push(
+                " {\n",
+                memberLines.indent(options.tabWidth),
+                "\n}"
+            );
+        }
+
+        return concat(parts);
+
+    case "TSExpressionWithTypeArguments":
+        return concat([
+            path.call(print, "expression"),
+            path.call(print, "typeParameters")
+        ]);
+
+    case "TSInterfaceBody":
+        var lines = fromString(";\n").join(path.map(print, "body"));
+        if (lines.isEmpty()) {
+            return fromString("{}", options);
+        }
+
+        return concat([
+            "{\n",
+            lines.indent(options.tabWidth), ";",
+            "\n}",
+        ]);
+
+    case "TSImportEqualsDeclaration":
+        if (n.isExport) {
+            parts.push("export ");
+        }
+
+        parts.push(
+            "import ",
+            path.call(print, "id"),
+            " = ",
+            path.call(print, "moduleReference")
+        );
+
+        return maybeAddSemicolon(concat(parts));
+
+    case "TSExternalModuleReference":
+      return concat(["require(", path.call(print, "expression"), ")"]);
+
+    case "TSModuleDeclaration": {
+        const parent = path.getParentNode();
+
+        if (parent.type === "TSModuleDeclaration") {
+            parts.push(".");
+        } else {
+            if (n.declare) {
+                parts.push("declare ");
+            }
+
+            if (! n.global) {
+                const isExternal = n.id.type === "StringLiteral" ||
+                    (n.id.type === "Literal" &&
+                     typeof n.id.value === "string");
+
+                if (isExternal) {
+                    parts.push("module ");
+
+                } else if (n.loc &&
+                           n.loc.lines &&
+                           n.id.loc) {
+                    const prefix = n.loc.lines.sliceString(
+                        n.loc.start,
+                        n.id.loc.start
+                    );
+
+                    // These keywords are fundamentally ambiguous in the
+                    // Babylon parser, and not reflected in the AST, so
+                    // the best we can do is to match the original code,
+                    // when possible.
+                    if (prefix.indexOf("module") >= 0) {
+                        parts.push("module ");
+                    } else {
+                        parts.push("namespace ");
+                    }
+
+                } else {
+                    parts.push("namespace ");
+                }
+            }
+        }
+
+        parts.push(path.call(print, "id"));
+
+        if (n.body && n.body.type === "TSModuleDeclaration") {
+            parts.push(path.call(print, "body"));
+        } else if (n.body) {
+            const bodyLines = path.call(print, "body");
+            if (bodyLines.isEmpty()) {
+                parts.push(" {}");
+            } else {
+                parts.push(
+                    " {\n",
+                    bodyLines.indent(options.tabWidth),
+                    "\n}"
+                );
+            }
+        }
+
+        return concat(parts);
+    }
+
+    case "TSModuleBlock":
+        return path.call(function (bodyPath) {
+            return printStatementSequence(bodyPath, options, print);
+        }, "body");
+
     // Unhandled types below. If encountered, nodes of these types should
     // be either left alone or desugared into AST types that are fully
     // supported by the pretty-printer.
@@ -1841,22 +2422,37 @@ function printMethod(path, options, print) {
     var kind = node.kind;
     var parts = [];
 
-    if (node.type === "ObjectMethod" || node.type === "ClassMethod") {
-        node.value = node;
-    } else {
-        namedTypes.FunctionExpression.assert(node.value);
+    var nodeValue = node.value;
+    if (! namedTypes.FunctionExpression.check(nodeValue)) {
+        nodeValue = node;
+    }
+
+    var access = node.accessibility || node.access;
+    if (typeof access === "string") {
+        parts.push(access, " ");
+    }
+
+    if (node.static) {
+        parts.push("static ");
+    }
+
+    if (node.abstract) {
+        parts.push("abstract ");
     }
 
-    if (node.value.async) {
+    if (node.readonly) {
+        parts.push("readonly ");
+    }
+
+    if (nodeValue.async) {
         parts.push("async ");
     }
 
-    if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
-        if (node.value.generator) {
-            parts.push("*");
-        }
-    } else {
-        assert.ok(kind === "get" || kind === "set");
+    if (nodeValue.generator) {
+        parts.push("*");
+    }
+
+    if (kind === "get" || kind === "set") {
         parts.push(kind, " ");
     }
 
@@ -1865,18 +2461,44 @@ function printMethod(path, options, print) {
         key = concat(["[", key, "]"]);
     }
 
-    parts.push(
-        key,
-        path.call(print, "value", "typeParameters"),
-        "(",
-        path.call(function(valuePath) {
-            return printFunctionParams(valuePath, options, print);
-        }, "value"),
-        ")",
-        path.call(print, "value", "returnType"),
-        " ",
-        path.call(print, "value", "body")
-    );
+    parts.push(key);
+
+    if (node.optional) {
+        parts.push("?");
+    }
+
+    if (node === nodeValue) {
+        parts.push(
+            path.call(print, "typeParameters"),
+            "(",
+            printFunctionParams(path, options, print),
+            ")",
+            path.call(print, "returnType")
+        );
+
+        if (node.body) {
+            parts.push(" ", path.call(print, "body"));
+        } else {
+            parts.push(";");
+        }
+
+    } else {
+        parts.push(
+            path.call(print, "value", "typeParameters"),
+            "(",
+            path.call(function(valuePath) {
+                return printFunctionParams(valuePath, options, print);
+            }, "value"),
+            ")",
+            path.call(print, "value", "returnType")
+        );
+
+        if (nodeValue.body) {
+            parts.push(" ", path.call(print, "value", "body"));
+        } else {
+            parts.push(";");
+        }
+    }
 
     return concat(parts);
 }
@@ -1901,9 +2523,13 @@ function printArgumentsList(path, options, print) {
 function printFunctionParams(path, options, print) {
     var fun = path.getValue();
 
-    namedTypes.Function.assert(fun);
-
-    var printed = path.map(print, "params");
+    if (fun.params) {
+        var params = fun.params;
+        var printed = path.map(print, "params");
+    } else if (fun.parameters) {
+        params = fun.parameters;
+        printed = path.map(print, "parameters");
+    }
 
     if (fun.defaults) {
         path.each(function(defExprPath) {
@@ -1925,7 +2551,7 @@ function printFunctionParams(path, options, print) {
         joined = fromString(",\n").join(printed);
         if (util.isTrailingCommaEnabled(options, "parameters") &&
             !fun.rest &&
-            fun.params[fun.params.length - 1].type !== 'RestElement') {
+            params[params.length - 1].type !== 'RestElement') {
             joined = concat([joined, ",\n"]);
         } else {
             joined = concat([joined, "\n"]);
@@ -1936,42 +2562,12 @@ function printFunctionParams(path, options, print) {
     return joined;
 }
 
-function printObjectMethod(path, options, print) {
-    var objMethod = path.getValue();
-    var parts = [];
-
-    if (objMethod.async)
-        parts.push("async ");
-
-    if (objMethod.generator)
-        parts.push("*");
-
-    if (objMethod.method || objMethod.kind === "get" || objMethod.kind === "set") {
-        return printMethod(path, options, print);
-    }
-
-    var key = path.call(print, "key");
-    if (objMethod.computed) {
-        parts.push("[", key, "]");
-    } else {
-        parts.push(key);
-    }
-
-    parts.push(
-        "(",
-        printFunctionParams(path, options, print),
-        ")",
-        path.call(print, "returnType"),
-        " ",
-        path.call(print, "body")
-    );
-
-    return concat(parts);
-}
-
 function printExportDeclaration(path, options, print) {
     var decl = path.getValue();
     var parts = ["export "];
+    if (decl.exportKind && decl.exportKind !== "value") {
+        parts.push(decl.exportKind + " ");
+    }
     var shouldPrintSpaces = options.objectCurlySpacing;
 
     namedTypes.Declaration.assert(decl);
@@ -2004,14 +2600,15 @@ function printExportDeclaration(path, options, print) {
     }
 
     var lines = concat(parts);
-
     if (lastNonSpaceCharacter(lines) !== ";" &&
         ! (decl.declaration &&
            (decl.declaration.type === "FunctionDeclaration" ||
-            decl.declaration.type === "ClassDeclaration"))) {
+            decl.declaration.type === "ClassDeclaration" ||
+            decl.declaration.type === "TSModuleDeclaration" ||
+            decl.declaration.type === "TSInterfaceDeclaration" ||
+            decl.declaration.type === "TSEnumDeclaration"))) {
         lines = concat([lines, ";"]);
     }
-
     return lines;
 }
 
diff --git a/lib/util.js b/lib/util.js
index 81895de..1f6e96a 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -8,6 +8,14 @@ var SourceMapGenerator = sourceMap.SourceMapGenerator;
 var hasOwn = Object.prototype.hasOwnProperty;
 var util = exports;
 
+function getOption(options, key, defaultValue) {
+  if (options && hasOwn.call(options, key)) {
+    return options[key];
+  }
+  return defaultValue;
+}
+util.getOption = getOption;
+
 function getUnionOfKeys() {
   var result = {};
   var argc = arguments.length;
@@ -102,17 +110,12 @@ util.getTrueLoc = function(node, lines) {
     expandLoc(result, node.loc);
   }
 
-  // If the node has any comments, their locations might contribute to
-  // the true start/end positions of the node.
-  if (node.comments) {
-    node.comments.forEach(include);
-  }
-
   // If the node is an export declaration and its .declaration has any
   // decorators, their locations might contribute to the true start/end
   // positions of the export declaration node.
-  if (node.declaration && util.isExportDeclaration(node) &&
-      node.declaration.decorators) {
+  if (node.declaration &&
+      node.declaration.decorators &&
+      util.isExportDeclaration(node)) {
     node.declaration.decorators.forEach(include);
   }
 
@@ -129,6 +132,12 @@ util.getTrueLoc = function(node, lines) {
     }
   }
 
+  // If the node has any comments, their locations might contribute to
+  // the true start/end positions of the node.
+  if (node.comments) {
+    node.comments.forEach(include);
+  }
+
   return result;
 };
 
diff --git a/package-lock.json b/package-lock.json
index 495abc6..52a33cc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,76 +1,40 @@
 {
   "name": "recast",
-  "version": "0.13.2",
+  "version": "0.14.4",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
-    "acorn": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",
-      "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==",
-      "dev": true
-    },
-    "ansi-regex": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-      "dev": true
-    },
-    "ansi-styles": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
-      "dev": true
-    },
-    "ast-types": {
-      "version": "0.10.2",
-      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.2.tgz",
-      "integrity": "sha512-ufWX953VU1eIuWqxS0nRDMYlGyFH+yxln5CsmIHlpzEt3fdYqUnRtsFt0XAsQot8OaVCwFqxT1RiwvtzYjeYeg=="
-    },
-    "babel-code-frame": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
-      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+    "@babel/code-frame": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz",
+      "integrity": "sha512-eVXQSbu/RimU6OKcK2/gDJVTFcxXJI4sHbIqw2mhwMZeQ2as/8AhS9DGkEDoHMBBNJZ5B0US63lF56x+KDcxiA==",
       "dev": true,
       "requires": {
-        "chalk": "1.1.3",
-        "esutils": "2.0.2",
-        "js-tokens": "3.0.2"
+        "@babel/highlight": "7.0.0-beta.40"
       }
     },
-    "babel-core": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
-      "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+    "@babel/core": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.0.0-beta.40.tgz",
+      "integrity": "sha512-jJMjn/EMg89xDGv7uq4BoFg+fHEchSeqNc9YUMnGuAi/FWKBkSsDbhh2y5euw4qaGOFD2jw1le0rvCu5gPUc6Q==",
       "dev": true,
       "requires": {
-        "babel-code-frame": "6.26.0",
-        "babel-generator": "6.26.1",
-        "babel-helpers": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-register": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "babylon": "6.18.0",
+        "@babel/code-frame": "7.0.0-beta.40",
+        "@babel/generator": "7.0.0-beta.40",
+        "@babel/helpers": "7.0.0-beta.40",
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/traverse": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "babylon": "7.0.0-beta.40",
         "convert-source-map": "1.5.1",
-        "debug": "2.6.9",
+        "debug": "3.1.0",
         "json5": "0.5.1",
         "lodash": "4.17.5",
-        "minimatch": "3.0.4",
-        "path-is-absolute": "1.0.1",
-        "private": "0.1.8",
-        "slash": "1.0.0",
+        "micromatch": "2.3.11",
+        "resolve": "1.5.0",
         "source-map": "0.5.7"
       },
       "dependencies": {
-        "babylon": {
-          "version": "6.18.0",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-          "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
-          "dev": true
-        },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -79,17 +43,14 @@
         }
       }
     },
-    "babel-generator": {
-      "version": "6.26.1",
-      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
-      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+    "@babel/generator": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.40.tgz",
+      "integrity": "sha512-c91BQcXyTq/5aFV4afgOionxZS1dxWt8OghEx5Q52SKssdGRFSiMKnk9tGkev1pYULPJBqjSDZU2Pcuc58ffZw==",
       "dev": true,
       "requires": {
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "detect-indent": "4.0.0",
-        "jsesc": "1.3.0",
+        "@babel/types": "7.0.0-beta.40",
+        "jsesc": "2.5.1",
         "lodash": "4.17.5",
         "source-map": "0.5.7",
         "trim-right": "1.0.1"
@@ -103,493 +64,455 @@
         }
       }
     },
-    "babel-helper-call-delegate": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
-      "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+    "@babel/helper-annotate-as-pure": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.40.tgz",
+      "integrity": "sha512-bJd92d70QTlcqCO9WiE8C94r7NwVzJx1V6Yz7rYi4IQ53P0jbh9jjKL2zl8YoU2S8M/KX1jpu+yIgXbx+LOruQ==",
       "dev": true,
       "requires": {
-        "babel-helper-hoist-variables": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-helper-define-map": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
-      "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+    "@babel/helper-call-delegate": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.40.tgz",
+      "integrity": "sha512-kfLlTpTayyCwj3/Rq4zDaK85GVPzRIR433QLhuNb0qjJfMQgLit2UEfBHUPPMRvKlb0FelrlXGTxXfsHLmfgzw==",
       "dev": true,
       "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "lodash": "4.17.5"
+        "@babel/helper-hoist-variables": "7.0.0-beta.40",
+        "@babel/traverse": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-helper-function-name": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
-      "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+    "@babel/helper-define-map": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.40.tgz",
+      "integrity": "sha512-hDg3sFSAxYQ/CSXzIBzGeNRD4yp89MkC3wkwvGBH80LXobL6csEdQpzCPhwpL0K8RNB07awRnck1OtPqjeCpgA==",
       "dev": true,
       "requires": {
-        "babel-helper-get-function-arity": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-function-name": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "lodash": "4.17.5"
       }
     },
-    "babel-helper-get-function-arity": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
-      "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+    "@babel/helper-function-name": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz",
+      "integrity": "sha512-cK9BVLtOfisSISTTHXKGvBc2OBh65tjEk4PgXhsSnnH0i8RP2v+5RCxoSlh2y/i+l2fxQqKqv++Qo5RMiwmRCA==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-get-function-arity": "7.0.0-beta.40",
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-helper-hoist-variables": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
-      "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+    "@babel/helper-get-function-arity": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz",
+      "integrity": "sha512-MwquaPznI4cUoZEgHC/XGkddOXtqKqD4DvZDOyJK2LR9Qi6TbMbAhc6IaFoRX7CRTFCmtGeu8gdXW2dBotBBTA==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-helper-optimise-call-expression": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
-      "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+    "@babel/helper-hoist-variables": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.40.tgz",
+      "integrity": "sha512-ghnJxUUEmqK8mssF7Y7R5jNzF5xDu4hmWQ1aZghZtLNJSymmj3HrXCLl5m1dBYpq9gGk7TlZK8stIvIJsCGmTQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-helper-regex": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
-      "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+    "@babel/helper-module-imports": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.40.tgz",
+      "integrity": "sha512-QFOskAKWbqJSBbGIl/Y1igJI4mW0A+wD5NFqsgDJj85KSvj/dHM4wNGIeqCi85nN9aMa4DgTBBrzUK4zSMsN2Q==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
+        "@babel/types": "7.0.0-beta.40",
         "lodash": "4.17.5"
       }
     },
-    "babel-helper-replace-supers": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
-      "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+    "@babel/helper-module-transforms": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.40.tgz",
+      "integrity": "sha512-1H7cBk7kUWJpTepPH77TIRGwKILRGpu1yXmz1OjOruR6y2z0qfbp7ZzzZ3/xg6NlLDENLArEyO2+J0mO+VyQsg==",
       "dev": true,
       "requires": {
-        "babel-helper-optimise-call-expression": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-module-imports": "7.0.0-beta.40",
+        "@babel/helper-simple-access": "7.0.0-beta.40",
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "lodash": "4.17.5"
       }
     },
-    "babel-helpers": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
-      "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+    "@babel/helper-optimise-call-expression": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.40.tgz",
+      "integrity": "sha512-2f4ZKEkvdnKiTUA/Nhju+oEoRcyHcpf6lFuQI5cxbo1Toxqa8E9HBO5tiOWwlIwuak7RZPYSnxnrJQy/0d4YUw==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-messages": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
-      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+    "@babel/helper-regex": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0-beta.40.tgz",
+      "integrity": "sha512-75zi8hZSdWLT7upmEyAemfN0hJ7522svItPGbIj4Pi2T/C5vbgNFXLy8o/iOCX4FzB+yVKhz0zWC3SzN9hyigA==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "lodash": "4.17.5"
       }
     },
-    "babel-plugin-check-es2015-constants": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
-      "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+    "@babel/helper-replace-supers": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.40.tgz",
+      "integrity": "sha512-Nu/5wpUV3rG35RzOq/upZlm61cP0lSAtmNkJLFfO5k2zOGCiHRczD1Y/xKqYOMl5f2iZmYw9fANi1jE4odMIIQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "@babel/helper-optimise-call-expression": "7.0.0-beta.40",
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/traverse": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-arrow-functions": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
-      "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+    "@babel/helper-simple-access": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.40.tgz",
+      "integrity": "sha512-hEKOIXUZFOiyqUPiGydGc+Jr0s8mVCFrD1OtAw2BDkXf1BaR+PxVEVcBAWcJVLOjqrr7oVZL9SENjR4B/Y+yEw==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "lodash": "4.17.5"
       }
     },
-    "babel-plugin-transform-es2015-block-scoped-functions": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
-      "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+    "@babel/helpers": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.0.0-beta.40.tgz",
+      "integrity": "sha512-NK/mM/I16inThgXmKPxoqrg+N6OCLt+e9Zsmy8TJ93/zMx4Eddd679I231YwDP2J1Z12UgkfWCLbbvauU5TLlQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "@babel/template": "7.0.0-beta.40",
+        "@babel/traverse": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-block-scoping": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
-      "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+    "@babel/highlight": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.40.tgz",
+      "integrity": "sha512-mOhhTrzieV6VO7odgzFGFapiwRK0ei8RZRhfzHhb6cpX3QM8XXuCLXWjN8qBB7JReDdUR80V3LFfFrGUYevhNg==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "lodash": "4.17.5"
+        "chalk": "2.3.1",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.2"
       }
     },
-    "babel-plugin-transform-es2015-classes": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
-      "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
-      "dev": true,
-      "requires": {
-        "babel-helper-define-map": "6.26.0",
-        "babel-helper-function-name": "6.24.1",
-        "babel-helper-optimise-call-expression": "6.24.1",
-        "babel-helper-replace-supers": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
-      }
+    "@babel/plugin-transform-arrow-functions": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.40.tgz",
+      "integrity": "sha512-B6wh62BErLWS3XInOUHhLcqBSK1QGdBph8E2K82EEFgJdQvphy30QXb0vwLUr8YU1efYyZXTsRA0JZ12jcm30Q==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-computed-properties": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
-      "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
-      }
+    "@babel/plugin-transform-block-scoped-functions": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0-beta.40.tgz",
+      "integrity": "sha512-GC64FqQfGJ5Wt3i0zSMcwRxmnZwgrx8fVLCeONNNm3BlK7Ui5Usuc7WubygM3bDq47UiHfeKo8ih54pr/POsFw==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-destructuring": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
-      "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+    "@babel/plugin-transform-block-scoping": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.40.tgz",
+      "integrity": "sha512-8QpOK9lXdzrq1QIrP3Hfx/BmGPaCKjBORd2QSjdghPNNRlQFZmO2l3kb0I6yC7w75U1M5q26KvUbAcPrE68E4w==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "lodash": "4.17.5"
       }
     },
-    "babel-plugin-transform-es2015-duplicate-keys": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
-      "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+    "@babel/plugin-transform-classes": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.40.tgz",
+      "integrity": "sha512-yjViyoOYJtt2vLDai8jluxl9quOtq/Xq4GTjT9uzy+mOfUTE77dcJySMGkWHE52Mu3n0TSI09ENBFYykpvXXDw==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-annotate-as-pure": "7.0.0-beta.40",
+        "@babel/helper-define-map": "7.0.0-beta.40",
+        "@babel/helper-function-name": "7.0.0-beta.40",
+        "@babel/helper-optimise-call-expression": "7.0.0-beta.40",
+        "@babel/helper-replace-supers": "7.0.0-beta.40",
+        "globals": "11.3.0"
       }
     },
-    "babel-plugin-transform-es2015-for-of": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
-      "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "6.26.0"
-      }
+    "@babel/plugin-transform-computed-properties": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.40.tgz",
+      "integrity": "sha512-1VBpE+6YN4bj72MtbQoIwXZxoI5VfPLutQ5uhOx/tIrjf1KbLKsFR0epPPGx4nZ13u++lUR8CjUFUHGJ6RJirA==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-function-name": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
-      "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
-      "dev": true,
-      "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
-      }
+    "@babel/plugin-transform-destructuring": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.40.tgz",
+      "integrity": "sha512-/FJq+WUAw4R5kg+2XWkmk0rDJqVs76rNNSIPpxeE0SiJvp8tvou7y8u0D1IhoO29ZgC+53jbdL+MkVN7mrH/iQ==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-literals": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
-      "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "6.26.0"
-      }
+    "@babel/plugin-transform-duplicate-keys": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0-beta.40.tgz",
+      "integrity": "sha512-rxEyRbU/iEGR99oBMoer5QeGWLMhT3Kq4a8B03DFLCBpGLv3XirpSGC/Ys1YhUKAmEio4jIcVVI8dRBbcVeyDw==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-modules-amd": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
-      "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
-      "dev": true,
-      "requires": {
-        "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
-      }
+    "@babel/plugin-transform-for-of": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.40.tgz",
+      "integrity": "sha512-ArDbLAGMzI++G5Ut8HIbLvnAxZNOC5tFzMXiud51JJTHRaeFB7AwX+duY9x/Hu/KypISXjels3BYVYCV/EH+ow==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-modules-commonjs": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
-      "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
+    "@babel/plugin-transform-function-name": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.40.tgz",
+      "integrity": "sha512-wvpswFciLQ2eAnHAs6/NSWymPg88LhHH87BljjXDxNnyGBzckip/iEa051Dz6lDumVUUjXLukw3D2fv5NBitVA==",
       "dev": true,
       "requires": {
-        "babel-plugin-transform-strict-mode": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-function-name": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-modules-systemjs": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
-      "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
-      "dev": true,
-      "requires": {
-        "babel-helper-hoist-variables": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
-      }
+    "@babel/plugin-transform-instanceof": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.0.0-beta.40.tgz",
+      "integrity": "sha512-ORqBkINVkU09q/K2ALP1H6sSFkoipyFN+LX5cR81FKEFvyP4q74MLdGfDFi3wATExms9qFECnaIPz10XhzyRdw==",
+      "dev": true
     },
-    "babel-plugin-transform-es2015-modules-umd": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
-      "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+    "@babel/plugin-transform-literals": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.40.tgz",
+      "integrity": "sha512-p7VlTod2r7srx0uKVrKqMJR1f6iyvDAnlLdTEDGrLHpP9pXXvIc/bP8xZTxVPn+IziSFh6FvOzHXXLMtnRKnow==",
+      "dev": true
+    },
+    "@babel/plugin-transform-modules-amd": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.0.0-beta.40.tgz",
+      "integrity": "sha512-o/XTve9C+M9203MVxGRBOXNx4f9DZGiPLbwPPeDobdtw3NKHUCymFNbh9xxMJy0MPMEe8JldxbVwGy2f8DY/3w==",
       "dev": true,
       "requires": {
-        "babel-plugin-transform-es2015-modules-amd": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
+        "@babel/helper-module-transforms": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-object-super": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
-      "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+    "@babel/plugin-transform-modules-commonjs": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.40.tgz",
+      "integrity": "sha512-1kRhaQP3K9kRiJhhLpP7J5NsMV+SiKWSsli6TUR6uxbuHHNAleRtlsZ76JgCRMaufBgPMLxq5pp7yibUhwTn8w==",
       "dev": true,
       "requires": {
-        "babel-helper-replace-supers": "6.24.1",
-        "babel-runtime": "6.26.0"
+        "@babel/helper-module-transforms": "7.0.0-beta.40",
+        "@babel/helper-simple-access": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-parameters": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
-      "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+    "@babel/plugin-transform-modules-systemjs": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0-beta.40.tgz",
+      "integrity": "sha512-q5IpFXNlzrK2ObpHkH5jzTCqRVzoNzmH8RoE8ZHQvLLiaIT346u8ynNv/BH1ltA49SPUPWyYpA+Z7OqCM4d3NA==",
       "dev": true,
       "requires": {
-        "babel-helper-call-delegate": "6.24.1",
-        "babel-helper-get-function-arity": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-hoist-variables": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-shorthand-properties": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
-      "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+    "@babel/plugin-transform-modules-umd": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.0.0-beta.40.tgz",
+      "integrity": "sha512-LHKqJFwo7x/CeEwjLyUE99SlG/kbTl8LS1DQ26fWctVnW5JuPt3hwYrggnmo1L/g/dal7EP2IL56+UezDMpJUQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-module-transforms": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-spread": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
-      "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+    "@babel/plugin-transform-object-super": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.0.0-beta.40.tgz",
+      "integrity": "sha512-a9kXy4amuvAz7eFuntXiyjg0eKXej1FH++xQg37ugh24zozD0cmfr3pvRbYOGlmbmOeZWJnlq+O6X8BSfLSycw==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "@babel/helper-replace-supers": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-sticky-regex": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
-      "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+    "@babel/plugin-transform-parameters": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.40.tgz",
+      "integrity": "sha512-JShFDeKEzwwTB+pHcUuLdX9zPi98sRekvtdCEOt8UoF5pzW02k1XdsVOckp/PzcEdoGAgZiiI1PFkJZ+xanfPg==",
       "dev": true,
       "requires": {
-        "babel-helper-regex": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/helper-call-delegate": "7.0.0-beta.40",
+        "@babel/helper-get-function-arity": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-template-literals": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
-      "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+    "@babel/plugin-transform-regenerator": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.40.tgz",
+      "integrity": "sha512-hFj52wAXbEpXwwfKsMol5Y967D3L8tz46Jin9n/gYPgcNWugvsw6d7g+HknBJ8FzaUESrDruFRkGPXgD+FyjvQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "regenerator-transform": "0.12.3"
       }
     },
-    "babel-plugin-transform-es2015-typeof-symbol": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
-      "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+    "@babel/plugin-transform-shorthand-properties": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.40.tgz",
+      "integrity": "sha512-1leHn9ST0PKFHwH7klJqGA76YPoqs3cR5zeJK6YGZETeX89YiAVtR+5JTSGhfI/1RR0Vcg9Tl1LnPpf7LmYlng==",
+      "dev": true
+    },
+    "@babel/plugin-transform-spread": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.40.tgz",
+      "integrity": "sha512-RPrIpV+h8OqoqyMic7CNeM8TdSDk7ec+T6jM97vMb9XQQrRInAUWlwWvG6d36v72xobFtHoPA28VN/0aVsbQDg==",
+      "dev": true
+    },
+    "@babel/plugin-transform-sticky-regex": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0-beta.40.tgz",
+      "integrity": "sha512-dJPUaV2D5SwSXypaDFRJd+LIhabeaWhZ3McmNo0COn+lBINJ9iL7mYuPxnqwhM/KoBNv+vYIoFFZzT/I27K6AQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0"
+        "@babel/helper-regex": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-es2015-unicode-regex": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
-      "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+    "@babel/plugin-transform-template-literals": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.40.tgz",
+      "integrity": "sha512-ScGHntym1y5FweT751OJxGW4rydxdLA9BwkHfJ5o6RcCoq+LRubDeGu2HeuX4SMEvAw0MnZeSk8vw5TwIOzEIQ==",
       "dev": true,
       "requires": {
-        "babel-helper-regex": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "regexpu-core": "2.0.0"
+        "@babel/helper-annotate-as-pure": "7.0.0-beta.40"
       }
     },
-    "babel-plugin-transform-regenerator": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
-      "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+    "@babel/plugin-transform-typeof-symbol": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0-beta.40.tgz",
+      "integrity": "sha512-y+mXC0tIlTZj04ZD9326grEIvFjI/IeLSIVVKMIf8nSodLDCgipuM6zXhxqXVvjcTrvvUKuxPrvPeSuht0eeMg==",
+      "dev": true
+    },
+    "@babel/plugin-transform-unicode-regex": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.40.tgz",
+      "integrity": "sha512-+eProDq93qiYnXOy+LDSMoKF2lEQVQ+r6DF3ZZXJV5QJ3f2+vwpSqGIQy61sSkVMEaoNtYL/Jy+G8HrWFw9p3w==",
       "dev": true,
       "requires": {
-        "regenerator-transform": "0.10.1"
+        "@babel/helper-regex": "7.0.0-beta.40",
+        "regexpu-core": "4.1.3"
       }
     },
-    "babel-plugin-transform-strict-mode": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
-      "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+    "@babel/preset-es2015": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/preset-es2015/-/preset-es2015-7.0.0-beta.40.tgz",
+      "integrity": "sha512-qt3UcEUbN2IwyN2RzMlOYnup98CpaXkd/6sQh3I0k1ezEQXYQDnTdc44fpWP+JTY07kDGT1VTePIy1GUpMQKHw==",
+      "dev": true,
+      "requires": {
+        "@babel/plugin-transform-arrow-functions": "7.0.0-beta.40",
+        "@babel/plugin-transform-block-scoped-functions": "7.0.0-beta.40",
+        "@babel/plugin-transform-block-scoping": "7.0.0-beta.40",
+        "@babel/plugin-transform-classes": "7.0.0-beta.40",
+        "@babel/plugin-transform-computed-properties": "7.0.0-beta.40",
+        "@babel/plugin-transform-destructuring": "7.0.0-beta.40",
+        "@babel/plugin-transform-duplicate-keys": "7.0.0-beta.40",
+        "@babel/plugin-transform-for-of": "7.0.0-beta.40",
+        "@babel/plugin-transform-function-name": "7.0.0-beta.40",
+        "@babel/plugin-transform-instanceof": "7.0.0-beta.40",
+        "@babel/plugin-transform-literals": "7.0.0-beta.40",
+        "@babel/plugin-transform-modules-amd": "7.0.0-beta.40",
+        "@babel/plugin-transform-modules-commonjs": "7.0.0-beta.40",
+        "@babel/plugin-transform-modules-systemjs": "7.0.0-beta.40",
+        "@babel/plugin-transform-modules-umd": "7.0.0-beta.40",
+        "@babel/plugin-transform-object-super": "7.0.0-beta.40",
+        "@babel/plugin-transform-parameters": "7.0.0-beta.40",
+        "@babel/plugin-transform-regenerator": "7.0.0-beta.40",
+        "@babel/plugin-transform-shorthand-properties": "7.0.0-beta.40",
+        "@babel/plugin-transform-spread": "7.0.0-beta.40",
+        "@babel/plugin-transform-sticky-regex": "7.0.0-beta.40",
+        "@babel/plugin-transform-template-literals": "7.0.0-beta.40",
+        "@babel/plugin-transform-typeof-symbol": "7.0.0-beta.40",
+        "@babel/plugin-transform-unicode-regex": "7.0.0-beta.40"
+      }
+    },
+    "@babel/template": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.40.tgz",
+      "integrity": "sha512-RlQiVB7eL7fxsKN6JvnCCwEwEL28CBYalXSgWWULuFlEHjtMoXBqQanSie3bNyhrANJx67sb+Sd/vuGivoMwLQ==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "@babel/code-frame": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "babylon": "7.0.0-beta.40",
+        "lodash": "4.17.5"
       }
     },
-    "babel-preset-es2015": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
-      "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
+    "@babel/traverse": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.40.tgz",
+      "integrity": "sha512-h96SQorjvdSuxQ6hHFIuAa3oxnad1TA5bU1Zz88+XqzwmM5QM0/k2D+heXGGy/76gT5ajl7xYLKGiPA/KTyVhQ==",
       "dev": true,
       "requires": {
-        "babel-plugin-check-es2015-constants": "6.22.0",
-        "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
-        "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0",
-        "babel-plugin-transform-es2015-block-scoping": "6.26.0",
-        "babel-plugin-transform-es2015-classes": "6.24.1",
-        "babel-plugin-transform-es2015-computed-properties": "6.24.1",
-        "babel-plugin-transform-es2015-destructuring": "6.23.0",
-        "babel-plugin-transform-es2015-duplicate-keys": "6.24.1",
-        "babel-plugin-transform-es2015-for-of": "6.23.0",
-        "babel-plugin-transform-es2015-function-name": "6.24.1",
-        "babel-plugin-transform-es2015-literals": "6.22.0",
-        "babel-plugin-transform-es2015-modules-amd": "6.24.1",
-        "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
-        "babel-plugin-transform-es2015-modules-systemjs": "6.24.1",
-        "babel-plugin-transform-es2015-modules-umd": "6.24.1",
-        "babel-plugin-transform-es2015-object-super": "6.24.1",
-        "babel-plugin-transform-es2015-parameters": "6.24.1",
-        "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
-        "babel-plugin-transform-es2015-spread": "6.22.0",
-        "babel-plugin-transform-es2015-sticky-regex": "6.24.1",
-        "babel-plugin-transform-es2015-template-literals": "6.22.0",
-        "babel-plugin-transform-es2015-typeof-symbol": "6.23.0",
-        "babel-plugin-transform-es2015-unicode-regex": "6.24.1",
-        "babel-plugin-transform-regenerator": "6.26.0"
+        "@babel/code-frame": "7.0.0-beta.40",
+        "@babel/generator": "7.0.0-beta.40",
+        "@babel/helper-function-name": "7.0.0-beta.40",
+        "@babel/types": "7.0.0-beta.40",
+        "babylon": "7.0.0-beta.40",
+        "debug": "3.1.0",
+        "globals": "11.3.0",
+        "invariant": "2.2.3",
+        "lodash": "4.17.5"
       }
     },
-    "babel-register": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
-      "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+    "@babel/types": {
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.40.tgz",
+      "integrity": "sha512-uXCGCzTgMZxcSUzutCPtZmXbVC+cvENgS2e0tRuhn+Y1hZnMb8IHP0Trq7Q2MB/eFmG5pKrAeTIUfQIe5kA4Tg==",
       "dev": true,
       "requires": {
-        "babel-core": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "core-js": "2.5.3",
-        "home-or-tmp": "2.0.0",
+        "esutils": "2.0.2",
         "lodash": "4.17.5",
-        "mkdirp": "0.5.1",
-        "source-map-support": "0.4.18"
+        "to-fast-properties": "2.0.0"
       }
     },
-    "babel-runtime": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
-      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
-      "dev": true,
-      "requires": {
-        "core-js": "2.5.3",
-        "regenerator-runtime": "0.11.1"
-      }
+    "acorn": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",
+      "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==",
+      "dev": true
     },
-    "babel-template": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
-      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+    "ansi-styles": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+      "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "babylon": "6.18.0",
-        "lodash": "4.17.5"
-      },
-      "dependencies": {
-        "babylon": {
-          "version": "6.18.0",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-          "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
-          "dev": true
-        }
+        "color-convert": "1.9.1"
       }
     },
-    "babel-traverse": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
-      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+    "arr-diff": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
       "dev": true,
       "requires": {
-        "babel-code-frame": "6.26.0",
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "babylon": "6.18.0",
-        "debug": "2.6.9",
-        "globals": "9.18.0",
-        "invariant": "2.2.2",
-        "lodash": "4.17.5"
-      },
-      "dependencies": {
-        "babylon": {
-          "version": "6.18.0",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-          "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
-          "dev": true
-        }
+        "arr-flatten": "1.1.0"
       }
     },
-    "babel-types": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
-      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "6.26.0",
-        "esutils": "2.0.2",
-        "lodash": "4.17.5",
-        "to-fast-properties": "1.0.3"
-      }
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+      "dev": true
+    },
+    "ast-types": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.2.tgz",
+      "integrity": "sha512-aL+pcOQ+6dpWd0xrUe+Obo2CgdkFvsntkXEmzZKqEN4cR0PStF+1MBuc4V+YZsv4Q36luvyjG7F4lc+wH2bmag=="
     },
     "babylon": {
       "version": "7.0.0-beta.40",
@@ -613,6 +536,17 @@
         "concat-map": "0.0.1"
       }
     },
+    "braces": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+      "dev": true,
+      "requires": {
+        "expand-range": "1.8.2",
+        "preserve": "0.2.0",
+        "repeat-element": "1.1.2"
+      }
+    },
     "browser-stdout": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
@@ -620,18 +554,31 @@
       "dev": true
     },
     "chalk": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz",
+      "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==",
       "dev": true,
       "requires": {
-        "ansi-styles": "2.2.1",
+        "ansi-styles": "3.2.0",
         "escape-string-regexp": "1.0.5",
-        "has-ansi": "2.0.0",
-        "strip-ansi": "3.0.1",
-        "supports-color": "2.0.0"
+        "supports-color": "5.2.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
+      "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
       }
     },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
     "commander": {
       "version": "2.11.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
@@ -650,30 +597,15 @@
       "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
       "dev": true
     },
-    "core-js": {
-      "version": "2.5.3",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",
-      "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=",
-      "dev": true
-    },
     "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
       "dev": true,
       "requires": {
         "ms": "2.0.0"
       }
     },
-    "detect-indent": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
-      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
-      "dev": true,
-      "requires": {
-        "repeating": "2.0.1"
-      }
-    },
     "diff": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
@@ -703,12 +635,73 @@
       "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
       "dev": true
     },
+    "expand-brackets": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+      "dev": true,
+      "requires": {
+        "is-posix-bracket": "0.1.1"
+      }
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "dev": true,
+      "requires": {
+        "fill-range": "2.2.3"
+      }
+    },
+    "extglob": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+      "dev": true,
+      "requires": {
+        "is-extglob": "1.0.0"
+      }
+    },
+    "filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
+      "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
+      "dev": true,
+      "requires": {
+        "is-number": "2.1.0",
+        "isobject": "2.1.0",
+        "randomatic": "1.1.7",
+        "repeat-element": "1.1.2",
+        "repeat-string": "1.6.1"
+      }
+    },
     "flow-parser": {
       "version": "0.66.0",
       "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.66.0.tgz",
       "integrity": "sha1-vlg/77ARkqpRZEFdMaYkGzVxiYM=",
       "dev": true
     },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "for-own": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+      "dev": true,
+      "requires": {
+        "for-in": "1.0.2"
+      }
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -729,10 +722,29 @@
         "path-is-absolute": "1.0.1"
       }
     },
+    "glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "dev": true,
+      "requires": {
+        "glob-parent": "2.0.0",
+        "is-glob": "2.0.1"
+      }
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "dev": true,
+      "requires": {
+        "is-glob": "2.0.1"
+      }
+    },
     "globals": {
-      "version": "9.18.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
-      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.3.0.tgz",
+      "integrity": "sha512-kkpcKNlmQan9Z5ZmgqKH/SMbSmjxQ7QjyNqfXVc8VJcoBV2UEg+sxQD15GQofGRh2hfpwUb70VC31DR7Rq5Hdw==",
       "dev": true
     },
     "growl": {
@@ -741,19 +753,10 @@
       "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
       "dev": true
     },
-    "has-ansi": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
-      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "2.1.1"
-      }
-    },
     "has-flag": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
-      "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
       "dev": true
     },
     "he": {
@@ -762,16 +765,6 @@
       "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
       "dev": true
     },
-    "home-or-tmp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
-      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
-      "dev": true,
-      "requires": {
-        "os-homedir": "1.0.2",
-        "os-tmpdir": "1.0.2"
-      }
-    },
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -789,21 +782,90 @@
       "dev": true
     },
     "invariant": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
-      "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz",
+      "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==",
       "dev": true,
       "requires": {
         "loose-envify": "1.3.1"
       }
     },
-    "is-finite": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
-      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+      "dev": true
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
       "dev": true,
       "requires": {
-        "number-is-nan": "1.0.1"
+        "is-primitive": "2.0.0"
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true
+    },
+    "is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true,
+      "requires": {
+        "is-extglob": "1.0.0"
+      }
+    },
+    "is-number": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+      "dev": true,
+      "requires": {
+        "kind-of": "3.2.2"
+      }
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+      "dev": true
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "dev": true,
+      "requires": {
+        "isarray": "1.0.0"
       }
     },
     "js-tokens": {
@@ -813,9 +875,9 @@
       "dev": true
     },
     "jsesc": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
-      "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz",
+      "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=",
       "dev": true
     },
     "json5": {
@@ -824,6 +886,15 @@
       "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
       "dev": true
     },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "requires": {
+        "is-buffer": "1.1.6"
+      }
+    },
     "lodash": {
       "version": "4.17.5",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
@@ -839,6 +910,27 @@
         "js-tokens": "3.0.2"
       }
     },
+    "micromatch": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+      "dev": true,
+      "requires": {
+        "arr-diff": "2.0.0",
+        "array-unique": "0.2.1",
+        "braces": "1.8.5",
+        "expand-brackets": "0.1.5",
+        "extglob": "0.3.2",
+        "filename-regex": "2.0.1",
+        "is-extglob": "1.0.0",
+        "is-glob": "2.0.1",
+        "kind-of": "3.2.2",
+        "normalize-path": "2.1.1",
+        "object.omit": "2.0.1",
+        "parse-glob": "3.0.4",
+        "regex-cache": "0.4.4"
+      }
+    },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -899,14 +991,11 @@
         "supports-color": "4.4.0"
       },
       "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
+        "has-flag": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+          "dev": true
         },
         "supports-color": {
           "version": "4.4.0",
@@ -925,11 +1014,24 @@
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
       "dev": true
     },
-    "number-is-nan": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-      "dev": true
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "requires": {
+        "remove-trailing-separator": "1.1.0"
+      }
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "dev": true,
+      "requires": {
+        "for-own": "0.1.5",
+        "is-extendable": "0.1.1"
+      }
     },
     "once": {
       "version": "1.4.0",
@@ -940,17 +1042,17 @@
         "wrappy": "1.0.2"
       }
     },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-      "dev": true
-    },
-    "os-tmpdir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-      "dev": true
+    "parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "dev": true,
+      "requires": {
+        "glob-base": "0.3.0",
+        "is-dotfile": "1.0.3",
+        "is-extglob": "1.0.0",
+        "is-glob": "2.0.1"
+      }
     },
     "path-is-absolute": {
       "version": "1.0.1",
@@ -958,55 +1060,121 @@
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },
+    "path-parse": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+      "dev": true
+    },
+    "preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+      "dev": true
+    },
     "private": {
       "version": "0.1.8",
       "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
       "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
     },
+    "randomatic": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
+      "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
+      "dev": true,
+      "requires": {
+        "is-number": "3.0.0",
+        "kind-of": "4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "1.1.6"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "1.1.6"
+          }
+        }
+      }
+    },
     "regenerate": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
       "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==",
       "dev": true
     },
-    "regenerator-runtime": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
-      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
-      "dev": true
+    "regenerate-unicode-properties": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-5.1.3.tgz",
+      "integrity": "sha512-Yjy6t7jFQczDhYE+WVm7pg6gWYE258q4sUkk9qDErwXJIqx7jU9jGrMFHutJK/SRfcg7MEkXjGaYiVlOZyev/A==",
+      "dev": true,
+      "requires": {
+        "regenerate": "1.3.3"
+      }
     },
     "regenerator-transform": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
-      "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+      "version": "0.12.3",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.12.3.tgz",
+      "integrity": "sha512-y2uxO/6u+tVmtEDIKo+tLCtI0GcbQr0OreosKgCd7HP4VypGjtTrw79DezuwT+W5QX0YWuvpeBOgumrepwM1kA==",
       "dev": true,
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
         "private": "0.1.8"
       }
     },
+    "regex-cache": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+      "dev": true,
+      "requires": {
+        "is-equal-shallow": "0.1.3"
+      }
+    },
     "regexpu-core": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
-      "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.1.3.tgz",
+      "integrity": "sha512-mB+njEzO7oezA57IbQxxd6fVPOeWKDmnGvJ485CwmfNchjHe5jWwqKepapmzUEj41yxIAqOg+C4LbXuJlkiO8A==",
       "dev": true,
       "requires": {
         "regenerate": "1.3.3",
-        "regjsgen": "0.2.0",
-        "regjsparser": "0.1.5"
+        "regenerate-unicode-properties": "5.1.3",
+        "regjsgen": "0.3.0",
+        "regjsparser": "0.2.1",
+        "unicode-match-property-ecmascript": "1.0.3",
+        "unicode-match-property-value-ecmascript": "1.0.1"
       }
     },
     "regjsgen": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
-      "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.3.0.tgz",
+      "integrity": "sha1-DuSj6SdkMM2iXx54nqbBW4ewy0M=",
       "dev": true
     },
     "regjsparser": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
-      "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.2.1.tgz",
+      "integrity": "sha1-w3h1U/rwTndcMCEC7zRtmVAA7Bw=",
       "dev": true,
       "requires": {
         "jsesc": "0.5.0"
@@ -1021,9 +1189,9 @@
       }
     },
     "reify": {
-      "version": "0.14.1",
-      "resolved": "https://registry.npmjs.org/reify/-/reify-0.14.1.tgz",
-      "integrity": "sha512-HAKYzqlCCWsfAcOTm8gsJZ6FE5I06kvjzHRQTCDD6xqUJaY8Mh4ve9oiCDe8yiYXOqZqpt03gn8yS4+bokRmhQ==",
+      "version": "0.14.2",
+      "resolved": "https://registry.npmjs.org/reify/-/reify-0.14.2.tgz",
+      "integrity": "sha512-gJA67pCidAROSmr4/8SQuMQXtZwtSvoVIDR6KjoWxnO4LSD8iYNjMcRrHuQQ/c8cXYaoCpEQh0rO9CNNu1z5lA==",
       "dev": true,
       "requires": {
         "acorn": "5.4.1",
@@ -1031,13 +1199,31 @@
         "semver": "5.5.0"
       }
     },
-    "repeating": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
-      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+      "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
+      "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
       "dev": true,
       "requires": {
-        "is-finite": "1.0.2"
+        "path-parse": "1.0.5"
       }
     },
     "semver": {
@@ -1046,53 +1232,24 @@
       "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
       "dev": true
     },
-    "slash": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
-      "dev": true
-    },
     "source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
       "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
     },
-    "source-map-support": {
-      "version": "0.4.18",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
-      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
-      "dev": true,
-      "requires": {
-        "source-map": "0.5.7"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "strip-ansi": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+    "supports-color": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz",
+      "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==",
       "dev": true,
       "requires": {
-        "ansi-regex": "2.1.1"
+        "has-flag": "3.0.0"
       }
     },
-    "supports-color": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
-      "dev": true
-    },
     "to-fast-properties": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
-      "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
       "dev": true
     },
     "trim-right": {
@@ -1101,6 +1258,34 @@
       "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
       "dev": true
     },
+    "unicode-canonical-property-names-ecmascript": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.3.tgz",
+      "integrity": "sha512-iG/2t0F2LAU8aZYPkX5gi7ebukHnr3sWFESpb+zPQeeaQwOkfoO6ZW17YX7MdRPNG9pCy+tjzGill+Ah0Em0HA==",
+      "dev": true
+    },
+    "unicode-match-property-ecmascript": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.3.tgz",
+      "integrity": "sha512-nFcaBFcr08UQNF15ZgI5ISh3yUnQm7SJRRxwYrL5VYX46pS+6Q7TCTv4zbK+j6/l7rQt0mMiTL2zpmeygny6rA==",
+      "dev": true,
+      "requires": {
+        "unicode-canonical-property-names-ecmascript": "1.0.3",
+        "unicode-property-aliases-ecmascript": "1.0.3"
+      }
+    },
+    "unicode-match-property-value-ecmascript": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.1.tgz",
+      "integrity": "sha512-lM8B0FDZQh9yYGgiabRQcyWicB27VLOolSBRIxsO7FeQPtg+79Oe7sC8Mzr8BObDs+G9CeYmC/shHo6OggNEog==",
+      "dev": true
+    },
+    "unicode-property-aliases-ecmascript": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.3.tgz",
+      "integrity": "sha512-TdDmDOTxEf2ad1g3ZBpM6cqKIb2nJpVlz1Q++casDryKz18tpeMBhSng9hjC1CTQCkOV9Rw2knlSB6iRo7ad1w==",
+      "dev": true
+    },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
diff --git a/package.json b/package.json
index 37c0dfa..75f2192 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
     "parsing",
     "pretty-printing"
   ],
-  "version": "0.13.2",
+  "version": "0.14.4",
   "homepage": "http://github.com/benjamn/recast",
   "repository": {
     "type": "git",
@@ -21,24 +21,25 @@
   "license": "MIT",
   "main": "main.js",
   "scripts": {
-    "test": "node ./node_modules/mocha/bin/mocha --reporter spec --full-trace",
-    "debug": "node ./node_modules/mocha/bin/mocha --inspect-brk --reporter spec --full-trace"
+    "test": "test/run.sh",
+    "debug": "test/run.sh --inspect-brk"
   },
   "browser": {
     "fs": false
   },
   "dependencies": {
-    "ast-types": "0.10.2",
+    "ast-types": "0.11.2",
     "esprima": "~4.0.0",
     "private": "~0.1.5",
     "source-map": "~0.6.1"
   },
   "devDependencies": {
-    "babel-core": "^6.23.1",
-    "babel-preset-es2015": "^6.22.0",
-    "babylon": "~7.0.0-beta.31",
+    "@babel/core": "^7.0.0-beta.40",
+    "@babel/preset-es2015": "^7.0.0-beta.40",
+    "babylon": "^7.0.0-beta.40",
     "esprima-fb": "^15001.1001.0-dev-harmony-fb",
     "flow-parser": "^0.66.0",
+    "glob": "^7.1.2",
     "mocha": "~5.0.0",
     "reify": "^0.14.1",
     "semver": "^5.3.0"
diff --git a/parsers/_babylon_options.js b/parsers/_babylon_options.js
new file mode 100644
index 0000000..64587b7
--- /dev/null
+++ b/parsers/_babylon_options.js
@@ -0,0 +1,39 @@
+const getOption = require("../lib/util.js").getOption;
+
+module.exports = function (options) {
+  // The goal here is to tolerate as much syntax as possible, since Recast
+  // is not in the business of forbidding anything. If you want your
+  // parser to be more restrictive for some reason, you can always pass
+  // your own parser object to recast.parse.
+  return {
+    sourceType: getOption(options, "sourceType", "module"),
+    strictMode: getOption(options, "strictMode", false),
+    allowImportExportEverywhere: true,
+    allowReturnOutsideFunction: true,
+    startLine: 1,
+    tokens: getOption(options, "tokens", true),
+    plugins: [
+      "asyncGenerators",
+      "bigInt",
+      "classPrivateMethods",
+      "classPrivateProperties",
+      "classProperties",
+      "decorators",
+      "doExpressions",
+      "dynamicImport",
+      "exportDefaultFrom",
+      "exportExtensions",
+      "exportNamespaceFrom",
+      "functionBind",
+      "functionSent",
+      "importMeta",
+      "nullishCoalescingOperator",
+      "numericSeparator",
+      "objectRestSpread",
+      "optionalCatchBinding",
+      "optionalChaining",
+      "pipelineOperator",
+      "throwExpressions",
+    ]
+  };
+};
diff --git a/parsers/acorn.js b/parsers/acorn.js
new file mode 100644
index 0000000..b24018f
--- /dev/null
+++ b/parsers/acorn.js
@@ -0,0 +1,35 @@
+"use strict";
+
+// This module is suitable for passing as options.parser when calling
+// recast.parse to process JavaScript code with Acorn:
+//
+//   const ast = recast.parse(source, {
+//     parser: require("recast/parsers/acorn")
+//   });
+//
+const getOption = require("../lib/util.js").getOption;
+
+exports.parse = function parse(source, options) {
+  const comments = [];
+  const tokens = [];
+  const ast = require("acorn").parse(source, {
+    allowHashBang: true,
+    allowImportExportEverywhere: true,
+    allowReturnOutsideFunction: true,
+    ecmaVersion: getOption(options, "ecmaVersion", 8),
+    sourceType: getOption(options, "sourceType", "module"),
+    locations: true,
+    onComment: comments,
+    onToken: tokens,
+  });
+
+  if (! ast.comments) {
+    ast.comments = comments;
+  }
+
+  if (! ast.tokens) {
+    ast.tokens = tokens;
+  }
+
+  return ast;
+};
diff --git a/parsers/babylon.js b/parsers/babylon.js
new file mode 100644
index 0000000..c630f02
--- /dev/null
+++ b/parsers/babylon.js
@@ -0,0 +1,14 @@
+"use strict";
+
+// This module is suitable for passing as options.parser when calling
+// recast.parse to process JavaScript code with Babel:
+//
+//   const ast = recast.parse(source, {
+//     parser: require("recast/parsers/babylon")
+//   });
+//
+exports.parse = function (source, options) {
+  options = require("./_babylon_options.js")(options);
+  options.plugins.push("jsx", "flow");
+  return require("babylon").parse(source, options);
+};
diff --git a/parsers/esprima.js b/parsers/esprima.js
new file mode 100644
index 0000000..e9ac53c
--- /dev/null
+++ b/parsers/esprima.js
@@ -0,0 +1,28 @@
+"use strict";
+
+// This module is suitable for passing as options.parser when calling
+// recast.parse to process ECMAScript code with Esprima:
+//
+//   const ast = recast.parse(source, {
+//     parser: require("recast/parsers/esprima")
+//   });
+//
+const getOption = require("../lib/util.js").getOption;
+
+exports.parse = function (source, options) {
+  const comments = [];
+  const ast = require("esprima").parse(source, {
+    loc: true,
+    locations: true,
+    comment: true,
+    onComment: comments,
+    tolerant: getOption(options, "tolerant", true),
+    tokens: getOption(options, "tokens", true)
+  });
+
+  if (! Array.isArray(ast.comments)) {
+    ast.comments = comments;
+  }
+
+  return ast;
+};
diff --git a/parsers/flow.js b/parsers/flow.js
new file mode 100644
index 0000000..1a10092
--- /dev/null
+++ b/parsers/flow.js
@@ -0,0 +1,14 @@
+"use strict";
+
+// This module is suitable for passing as options.parser when calling
+// recast.parse to process Flow code:
+//
+//   const ast = recast.parse(source, {
+//     parser: require("recast/parsers/flow")
+//   });
+//
+exports.parse = function parse(source, options) {
+  options = require("./_babylon_options.js")(options);
+  options.plugins.push("jsx", "flow");
+  return require("babylon").parse(source, options);
+};
diff --git a/parsers/typescript.js b/parsers/typescript.js
new file mode 100644
index 0000000..60a0771
--- /dev/null
+++ b/parsers/typescript.js
@@ -0,0 +1,14 @@
+"use strict";
+
+// This module is suitable for passing as options.parser when calling
+// recast.parse to process TypeScript code:
+//
+//   const ast = recast.parse(source, {
+//     parser: require("recast/parsers/typescript")
+//   });
+//
+exports.parse = function parse(source, options) {
+  options = require("./_babylon_options.js")(options);
+  options.plugins.push("typescript");
+  return require("babylon").parse(source, options);
+};
diff --git a/test/babylon.js b/test/babylon.js
index 157827a..b6ac699 100644
--- a/test/babylon.js
+++ b/test/babylon.js
@@ -5,12 +5,12 @@ var b = recast.types.builders;
 var eol = require("os").EOL;
 
 describe("Babel", function () {
-  var babelTransform = require("babel-core").transform;
-  var babelPresetES2015 = require("babel-preset-es2015");
+  var babelTransform = require("@babel/core").transform;
+  var babelPresetES2015 = require("@babel/preset-es2015");
   var parseOptions = {};
 
   try {
-    parseOptions.parser = require("reify/lib/parsers/babylon.js");
+    parseOptions.parser = require("../parsers/babylon");
   } catch (e) {
     if (require("semver").gte(process.version, "4.0.0")) {
       throw e;
@@ -369,6 +369,13 @@ describe("Babel", function () {
       )
     );
 
+    ast.program.body[0] = replacement;
+
+    assert.strictEqual(
+      recast.print(ast).code,
+      '\nfn(test, true);'
+    );
+
     recast.types.visit(ast, {
       visitIfStatement: function(path) {
         path.replace(replacement);
@@ -376,20 +383,15 @@ describe("Babel", function () {
       }
     });
 
-    // This also doesn't work:
-    // ast.program.body[0] = replacement;
-
-    // The `ast` contains the correct replacement nodes but the printed code
-    // is still the same as the original.
     assert.strictEqual(
       recast.print(ast).code,
-      'fn(test, true);'
+      '\nfn(test, true);'
     );
   });
 
   it("should parse and print dynamic import(...)", function () {
     var code = 'wait(import("oyez"));';
-    var ast = recast.parse(code, parseOptions);
+  var ast = recast.parse(code, parseOptions);
     assert.strictEqual(
       recast.prettyPrint(ast).code,
       code
diff --git a/test/comments.js b/test/comments.js
index 7952866..3337939 100644
--- a/test/comments.js
+++ b/test/comments.js
@@ -1,3 +1,5 @@
+"use strict";
+
 var recast = require("../main");
 var n = recast.types.namedTypes;
 var b = recast.types.builders;
@@ -8,688 +10,745 @@ var printer = new Printer;
 var eol = require("os").EOL;
 
 var annotated = [
-    "function dup(/* string */ s,",
-    "             /* int */ n) /* string */",
-    "{",
-    "  // Use an array full of holes.",
-    "  return Array(n + /*",
-    "                    * off-by-*/ 1).join(s);",
-    "}"
+  "function dup(/* string */ s,",
+  "             /* int */ n) /* string */",
+  "{",
+  "  // Use an array full of holes.",
+  "  return Array(n + /*",
+  "                    * off-by-*/ 1).join(s);",
+  "}"
 ];
 
 describe("comments", function() {
-    it("attachment and reprinting", function() {
-        var code = annotated.join(eol);
-        var ast = recast.parse(code);
-
-        var dup = ast.program.body[0];
-        n.FunctionDeclaration.assert(dup);
-        assert.strictEqual(dup.id.name, "dup");
-
-        // More of a basic sanity test than a comment test.
-        assert.strictEqual(recast.print(ast).code, code);
-        assert.strictEqual(recast.print(ast.program).code, code);
-        assert.strictEqual(recast.print(dup).code, code);
-
-        assert.strictEqual(
-            recast.print(dup.params[0]).code,
-            "/* string */ s"
-        );
-
-        assert.strictEqual(
-            recast.print(dup.params[1]).code,
-            "/* int */ n"
-        );
-
-        assert.strictEqual(
-            recast.print(dup.body).code,
-            ["/* string */"].concat(annotated.slice(2)).join(eol)
-        );
-
-        var retStmt = dup.body.body[0];
-        n.ReturnStatement.assert(retStmt);
-
-        var indented = annotated.slice(3, 6).join(eol);
-        var flush = fromString(indented).indent(-2);
-
-        assert.strictEqual(
-            recast.print(retStmt).code,
-            flush.toString()
-        );
-
-        var join = retStmt.argument;
-        n.CallExpression.assert(join);
-
-        var one = join.callee.object.arguments[0].right;
-        n.Literal.assert(one);
-        assert.strictEqual(one.value, 1);
-        assert.strictEqual(recast.print(one).code, [
-            "/*",
-            " * off-by-*/ 1"
-        ].join(eol));
-    });
+  ["../parsers/acorn",
+   "../parsers/babylon",
+   "../parsers/esprima",
+   "../parsers/flow",
+   "../parsers/typescript",
+  ].forEach(runTestsForParser);
+});
 
-    var trailing = [
-        "Foo.prototype = {",
-        "// Copyright (c) 2013 Ben Newman <bn at cs.stanford.edu>",
-        "",
-        "  /**",
-        "   * Leading comment.",
-        "   */",
-        "  constructor: Foo, // Important for instanceof",
-        "                    // to work in all browsers.",
-        '  bar: "baz", // Just in case we need it.',
-        "  qux: { // Here is an object literal.",
-        "    zxcv: 42",
-        "    // Put more properties here when you think of them.",
-        "  } // There was an object literal...",
-        "    // ... and here I am continuing this comment.",
-        "",
-        "};"
-    ];
+function runTestsForParser(parserId) {
+  const parserName = parserId.split("/").pop();
+  const parser = require(parserId);
+
+  function pit(message, callback) {
+    it("[" + parserName + "] " + message, callback);
+  }
+
+  pit("attachment and reprinting", function() {
+    var code = annotated.join(eol);
+    var ast = recast.parse(code, { parser });
+
+    var dup = ast.program.body[0];
+    n.FunctionDeclaration.assert(dup);
+    assert.strictEqual(dup.id.name, "dup");
+
+    // More of a basic sanity test than a comment test.
+    assert.strictEqual(recast.print(ast).code, code);
+    assert.strictEqual(recast.print(ast.program).code, code);
+    assert.strictEqual(recast.print(dup).code, code);
+
+    assert.strictEqual(
+      recast.print(dup.params[0]).code,
+      "/* string */ s"
+    );
+
+    assert.strictEqual(
+      recast.print(dup.params[1]).code,
+      "/* int */ n"
+    );
+
+    assert.strictEqual(
+      recast.print(dup.body).code,
+      ["/* string */"].concat(annotated.slice(2)).join(eol)
+    );
+
+    var retStmt = dup.body.body[0];
+    n.ReturnStatement.assert(retStmt);
+
+    var indented = annotated.slice(3, 6).join(eol);
+    var flush = fromString(indented).indent(-2);
+
+    assert.strictEqual(
+      recast.print(retStmt).code,
+      flush.toString()
+    );
+
+    var join = retStmt.argument;
+    n.CallExpression.assert(join);
+
+    var one = join.callee.object.arguments[0].right;
+    n.Literal.assert(one);
+    assert.strictEqual(one.value, 1);
+    assert.strictEqual(recast.print(one).code, [
+      "/*",
+      " * off-by-*/ 1"
+    ].join(eol));
+  });
 
-    var trailingExpected = [
-        "Foo.prototype = {",
-        "  // Copyright (c) 2013 Ben Newman <bn at cs.stanford.edu>",
-        "",
-        "  /**",
-        "   * Leading comment.",
-        "   */",
-        "  // Important for instanceof",
-        "  // to work in all browsers.",
-        "  constructor: Foo,",
-        "",
-        "  // Just in case we need it.",
-        '  bar: "baz",',
-        "",
-        "  // There was an object literal...",
-        "  // ... and here I am continuing this comment.",
-        "  qux: {",
-        "    // Here is an object literal.",
-        "    // Put more properties here when you think of them.",
-        "    zxcv: 42,",
-        "",
-        "    asdf: 43",
-        "  },",
-        "",
-        '  extra: "property"',
-        "};"
-    ];
+  var trailing = [
+    "Foo.prototype = {",
+    "// Copyright (c) 2013 Ben Newman <bn at cs.stanford.edu>",
+    "",
+    "  /**",
+    "   * Leading comment.",
+    "   */",
+    "  constructor: Foo, // Important for instanceof",
+    "                    // to work in all browsers.",
+    '  bar: "baz", // Just in case we need it.',
+    "  qux: { // Here is an object literal.",
+    "    zxcv: 42",
+    "    // Put more properties here when you think of them.",
+    "  } // There was an object literal...",
+    "    // ... and here I am continuing this comment.",
+    "",
+    "};"
+  ];
+
+  var trailingExpected = [
+    "Foo.prototype = {",
+    "  // Copyright (c) 2013 Ben Newman <bn at cs.stanford.edu>",
+    "",
+    "  /**",
+    "   * Leading comment.",
+    "   */",
+    "  // Important for instanceof",
+    "  // to work in all browsers.",
+    "  constructor: Foo,",
+    "",
+    "  // Just in case we need it.",
+    '  bar: "baz",',
+    "",
+    "  // There was an object literal...",
+    "  // ... and here I am continuing this comment.",
+    "  qux: {",
+    "    // Here is an object literal.",
+    "    // Put more properties here when you think of them.",
+    "    zxcv: 42,",
+    "",
+    "    asdf: 43",
+    "  },",
+    "",
+    '  extra: "property"',
+    "};"
+  ];
+
+  pit("TrailingComments", function() {
+    var code = trailing.join(eol);
+    var ast = recast.parse(code, { parser });
+    assert.strictEqual(recast.print(ast).code, code);
+
+    // Drop all original source information to force reprinting.
+    recast.visit(ast, {
+      visitNode: function(path) {
+        this.traverse(path);
+        path.value.original = null;
+      }
+    });
+
+    var assign = ast.program.body[0].expression;
+    n.AssignmentExpression.assert(assign);
+
+    const esprimaInfo = {
+      Property: n.Property,
+      propBuilder(key, value) {
+        return b.property("init", key, value);
+      },
+      literalBuilder(value) {
+        return b.literal(value);
+      }
+    };
+
+    const babylonInfo = {
+      Property: n.ObjectProperty,
+      propBuilder(key, value) {
+        return b.objectProperty(key, value);
+      },
+      literalBuilder(value) {
+        if (typeof value === "string") {
+          return b.stringLiteral(value);
+        }
+        if (typeof value === "number") {
+          return b.numericLiteral(value);
+        }
+        throw new Error("unexpected literal: " + value);
+      }
+    };
+
+    const info = {
+      acorn: esprimaInfo,
+      babylon: babylonInfo,
+      esprima: esprimaInfo,
+      flow: babylonInfo,
+      typescript: babylonInfo
+    }[parserName];
+
+    var props = assign.right.properties;
+    info.Property.arrayOf().assert(props);
+
+    props.push(info.propBuilder(
+      b.identifier("extra"),
+      info.literalBuilder("property")
+    ));
+
+    var quxVal = props[2].value;
+    n.ObjectExpression.assert(quxVal);
+    quxVal.properties.push(info.propBuilder(
+      b.identifier("asdf"),
+      info.literalBuilder(43)
+    ));
+
+    var actual = recast.print(ast, { tabWidth: 2 }).code;
+    var expected = trailingExpected.join(eol);
+
+    // Check semantic equivalence:
+    recast.types.astNodesAreEquivalent.assert(
+      ast,
+      recast.parse(actual, { parser })
+    );
+
+    assert.strictEqual(actual, expected);
+  });
 
-    it("TrailingComments", function() {
-        var code = trailing.join(eol);
-        var ast = recast.parse(code);
-        assert.strictEqual(recast.print(ast).code, code);
-
-        // Drop all original source information to force reprinting.
-        recast.visit(ast, {
-            visitNode: function(path) {
-                this.traverse(path);
-                path.value.original = null;
-            }
-        });
-
-        var assign = ast.program.body[0].expression;
-        n.AssignmentExpression.assert(assign);
-
-        var props = assign.right.properties;
-        n.Property.arrayOf().assert(props);
-
-        props.push(b.property(
-            "init",
-            b.identifier("extra"),
-            b.literal("property")
-        ));
-
-        var quxVal = props[2].value;
-        n.ObjectExpression.assert(quxVal);
-        quxVal.properties.push(b.property(
-            "init",
-            b.identifier("asdf"),
-            b.literal(43)
-        ));
-
-        var actual = recast.print(ast, { tabWidth: 2 }).code;
-        var expected = trailingExpected.join(eol);
-
-        // Check semantic equivalence:
-        recast.types.astNodesAreEquivalent.assert(
-            ast,
-            recast.parse(actual)
-        );
-
-        assert.strictEqual(actual, expected);
+  var bodyTrailing = [
+    "module.exports = {};",
+    "/**",
+    " * Trailing comment.",
+    " */"
+  ];
+
+  var bodyTrailingExpected = [
+    "module.exports = {};",
+    "/**",
+    " * Trailing comment.",
+    " */"
+  ];
+
+  pit("BodyTrailingComments", function() {
+    var code = bodyTrailing.join(eol);
+    var ast = recast.parse(code, { parser });
+
+    // Drop all original source information to force reprinting.
+    recast.visit(ast, {
+      visitNode: function(path) {
+        this.traverse(path);
+        path.value.original = null;
+      }
     });
 
-    var bodyTrailing = [
-        "module.exports = {};",
-        "/**",
-        " * Trailing comment.",
-        " */"
-    ];
+    var actual = recast.print(ast, { tabWidth: 2 }).code;
+    var expected = bodyTrailingExpected.join(eol);
 
-    var bodyTrailingExpected = [
-        "module.exports = {};",
-        "/**",
-        " * Trailing comment.",
-        " */"
-    ];
+    assert.strictEqual(actual, expected);
+  });
 
-    it("BodyTrailingComments", function() {
-        var code = bodyTrailing.join(eol);
-        var ast = recast.parse(code);
+  var paramTrailing = [
+    "function foo(bar, baz /* = null */) {",
+    "  assert.strictEqual(baz, null);",
+    "}"
+  ];
 
-        // Drop all original source information to force reprinting.
-        recast.visit(ast, {
-            visitNode: function(path) {
-                this.traverse(path);
-                path.value.original = null;
-            }
-        });
+  var paramTrailingExpected = [
+    "function foo(zxcv, bar, baz /* = null */) {",
+    "  assert.strictEqual(baz, null);",
+    "}"
+  ];
 
-        var actual = recast.print(ast, { tabWidth: 2 }).code;
-        var expected = bodyTrailingExpected.join(eol);
+  pit("ParamTrailingComments", function() {
+    var code = paramTrailing.join(eol);
+    var ast = recast.parse(code, { parser });
 
-        assert.strictEqual(actual, expected);
-    });
+    var func = ast.program.body[0];
+    n.FunctionDeclaration.assert(func);
 
-    var paramTrailing = [
-        "function foo(bar, baz /* = null */) {",
-        "  assert.strictEqual(baz, null);",
-        "}"
-    ];
+    func.params.unshift(b.identifier("zxcv"));
 
-    var paramTrailingExpected = [
-        "function foo(zxcv, bar, baz /* = null */) {",
-        "  assert.strictEqual(baz, null);",
-        "}"
-    ];
+    var actual = recast.print(ast, { tabWidth: 2 }).code;
+    var expected = paramTrailingExpected.join(eol);
 
-    it("ParamTrailingComments", function() {
-        var code = paramTrailing.join(eol);
-        var ast = recast.parse(code);
+    assert.strictEqual(actual, expected);
+  });
 
-        var func = ast.program.body[0];
-        n.FunctionDeclaration.assert(func);
+  var statementTrailing = [
+    "if (true) {",
+    "  f();",
+    "  // trailing 1",
+    "  /* trailing 2 */",
+    "  // trailing 3",
+    "  /* trailing 4 */",
+    "}"
+  ];
+
+  var statementTrailingExpected = [
+    "if (true) {",
+    "  e();",
+    "  f();",
+    "  // trailing 1",
+    "  /* trailing 2 */",
+    "  // trailing 3",
+    "  /* trailing 4 */",
+    "}"
+  ];
 
-        func.params.unshift(b.identifier("zxcv"));
+  pit("StatementTrailingComments", function() {
+    var code = statementTrailing.join(eol);
+    var ast = recast.parse(code, { parser });
 
-        var actual = recast.print(ast, { tabWidth: 2 }).code;
-        var expected = paramTrailingExpected.join(eol);
+    var block = ast.program.body[0].consequent;
+    n.BlockStatement.assert(block);
 
-        assert.strictEqual(actual, expected);
-    });
+    block.body.unshift(b.expressionStatement(
+      b.callExpression(b.identifier("e"), [])));
 
-    var statementTrailing = [
-        "if (true) {",
-        "  f();",
-        "  // trailing 1",
-        "  /* trailing 2 */",
-        "  // trailing 3",
-        "  /* trailing 4 */",
-        "}"
-    ];
+    var actual = recast.print(ast, { tabWidth: 2 }).code;
+    var expected = statementTrailingExpected.join(eol);
 
-    var statementTrailingExpected = [
-        "if (true) {",
-        "  e();",
-        "  f();",
-        "  // trailing 1",
-        "  /* trailing 2 */",
-        "  // trailing 3",
-        "  /* trailing 4 */",
-        "}"
-    ];
+    assert.strictEqual(actual, expected);
+  });
 
-    it("StatementTrailingComments", function() {
-        var code = statementTrailing.join(eol);
-        var ast = recast.parse(code);
+  var protoAssign = [
+    "A.prototype.foo = function() {",
+    "  return this.bar();",
+    "}", // Lack of semicolon screws up location info.
+    "",
+    "// Comment about the bar method.",
+    "A.prototype.bar = function() {",
+    "  return this.foo();",
+    "}"
+  ];
 
-        var block = ast.program.body[0].consequent;
-        n.BlockStatement.assert(block);
+  pit("ProtoAssignComment", function() {
+    var code = protoAssign.join(eol);
+    var ast = recast.parse(code, { parser });
 
-        block.body.unshift(b.expressionStatement(
-            b.callExpression(b.identifier("e"), [])));
+    var foo = ast.program.body[0];
+    var bar = ast.program.body[1];
 
-        var actual = recast.print(ast, { tabWidth: 2 }).code;
-        var expected = statementTrailingExpected.join(eol);
+    n.ExpressionStatement.assert(foo);
+    n.ExpressionStatement.assert(bar);
 
-        assert.strictEqual(actual, expected);
-    });
+    assert.strictEqual(foo.expression.left.property.name, "foo");
+    assert.strictEqual(bar.expression.left.property.name, "bar");
+
+    assert.ok(!foo.comments);
+    assert.ok(bar.comments);
+    assert.strictEqual(bar.comments.length, 1);
+
+    var barComment = bar.comments[0];
+    assert.strictEqual(barComment.leading, true);
+    assert.strictEqual(barComment.trailing, false);
 
-    var protoAssign = [
-        "A.prototype.foo = function() {",
-        "  return this.bar();",
-        "}", // Lack of semicolon screws up location info.
-        "",
-        "// Comment about the bar method.",
-        "A.prototype.bar = function() {",
-        "  return this.foo();",
-        "}"
+    assert.strictEqual(
+      barComment.value,
+      " Comment about the bar method."
+    );
+  });
+
+  var conciseMethods = [
+    "var obj = {",
+    "  a(/*before*/ param) {},",
+    "  b(param /*after*/) {},",
+    "  c(param) /*body*/ {}",
+    "};",
+  ];
+
+  pit("should correctly attach to concise methods", function() {
+    var code = conciseMethods.join(eol);
+    var ast = recast.parse(code, { parser });
+
+    var objExpr = ast.program.body[0].declarations[0].init;
+    n.ObjectExpression.assert(objExpr);
+
+    var a = objExpr.properties[0];
+    n.Identifier.assert(a.key);
+    assert.strictEqual(a.key.name, "a");
+
+    var aComments = (a.value || a).params[0].comments;
+    assert.strictEqual(aComments.length, 1);
+
+    var aComment = aComments[0];
+    assert.strictEqual(aComment.leading, true);
+    assert.strictEqual(aComment.trailing, false);
+    assert.ok(aComment.type.endsWith("Block"));
+    assert.strictEqual(aComment.value, "before");
+
+    assert.strictEqual(
+      recast.print(a).code,
+      "a(/*before*/ param) {}"
+    );
+
+    var b = objExpr.properties[1];
+    n.Identifier.assert(b.key);
+    assert.strictEqual(b.key.name, "b");
+
+    var bComments = (b.value || b).params[0].comments;
+    assert.strictEqual(bComments.length, 1);
+
+    var bComment = bComments[0];
+    assert.strictEqual(bComment.leading, false);
+    assert.strictEqual(bComment.trailing, true);
+    assert.ok(bComment.type.endsWith("Block"));
+    assert.strictEqual(bComment.value, "after");
+
+    assert.strictEqual(
+      recast.print(b).code,
+      "b(param /*after*/) {}"
+    );
+
+    var c = objExpr.properties[2];
+    n.Identifier.assert(c.key);
+    assert.strictEqual(c.key.name, "c");
+
+    var cComments = (c.value || c).body.comments;
+    assert.strictEqual(cComments.length, 1);
+
+    var cComment = cComments[0];
+    assert.strictEqual(cComment.leading, true);
+    assert.strictEqual(cComment.trailing, false);
+    assert.ok(cComment.type.endsWith("Block"));
+    assert.strictEqual(cComment.value, "body");
+
+    assert.strictEqual(
+      recast.print(c).code,
+      "c(param) /*body*/ {}"
+    );
+  });
+
+  pit("should attach comments as configurable", function() {
+    // Given
+    var simpleCommentedCode = [
+      "// A comment",
+      "var obj = {",
+      "};",
     ];
+    var code = simpleCommentedCode.join(eol);
+    var ast = recast.parse(code, { parser });
 
-    it("ProtoAssignComment", function() {
-        var code = protoAssign.join(eol);
-        var ast = recast.parse(code);
+    // When
+    Object.defineProperty(ast.program, 'comments', {
+      value: undefined,
+      enumerable: false
+    });
 
-        var foo = ast.program.body[0];
-        var bar = ast.program.body[1];
+    // Then
+    // An exception will be thrown if `comments` aren't configurable.
+  });
 
-        n.ExpressionStatement.assert(foo);
-        n.ExpressionStatement.assert(bar);
+  pit("should be reprinted when modified", function() {
+    var code = [
+      "foo;",
+      "// bar",
+      "bar;"
+    ].join(eol);
 
-        assert.strictEqual(foo.expression.left.property.name, "foo");
-        assert.strictEqual(bar.expression.left.property.name, "bar");
+    var ast = recast.parse(code, { parser });
 
-        assert.ok(!foo.comments);
-        assert.ok(bar.comments);
-        assert.strictEqual(bar.comments.length, 1);
+    var comments = ast.program.body[1].comments;
+    assert.strictEqual(comments.length, 1);
+    var comment = comments[0];
+    assert.ok(comment.type.endsWith("Line"));
+    assert.strictEqual(comment.value, " bar");
 
-        var barComment = bar.comments[0];
-        assert.strictEqual(barComment.leading, true);
-        assert.strictEqual(barComment.trailing, false);
+    comment.value = " barbara";
+    assert.strictEqual(recast.print(ast).code, [
+      "foo;",
+      "// barbara",
+      "bar;"
+    ].join(eol));
 
-        assert.strictEqual(
-            barComment.value,
-            " Comment about the bar method."
-        );
-    });
+    ast.program.body[0].comments = comments;
+    delete ast.program.body[1].comments;
+    assert.strictEqual(recast.print(ast).code, [
+      "// barbara",
+      "foo;",
+      "bar;"
+    ].join(eol));
 
-    var conciseMethods = [
-        "var obj = {",
-        "  a(/*before*/ param) {},",
-        "  b(param /*after*/) {},",
-        "  c(param) /*body*/ {}",
-        "};",
-    ];
+    ast.program.body[0] = b.blockStatement([
+      ast.program.body[0]
+    ]);
+    assert.strictEqual(recast.print(ast).code, [
+      "{",
+      "  // barbara",
+      "  foo;",
+      "}",
+      "",
+      "bar;"
+    ].join(eol));
 
-    it("should correctly attach to concise methods", function() {
-        var code = conciseMethods.join(eol);
-        var ast = recast.parse(code);
-
-        var objExpr = ast.program.body[0].declarations[0].init;
-        n.ObjectExpression.assert(objExpr);
-
-        var a = objExpr.properties[0];
-        n.Identifier.assert(a.key);
-        assert.strictEqual(a.key.name, "a");
-
-        var aComments = a.value.params[0].comments;
-        assert.strictEqual(aComments.length, 1);
-
-        var aComment = aComments[0];
-        assert.strictEqual(aComment.leading, true);
-        assert.strictEqual(aComment.trailing, false);
-        assert.strictEqual(aComment.type, "Block");
-        assert.strictEqual(aComment.value, "before");
-
-        assert.strictEqual(
-            recast.print(a).code,
-            "a(/*before*/ param) {}"
-        );
-
-        var b = objExpr.properties[1];
-        n.Identifier.assert(b.key);
-        assert.strictEqual(b.key.name, "b");
-
-        var bComments = b.value.params[0].comments;
-        assert.strictEqual(bComments.length, 1);
-
-        var bComment = bComments[0];
-        assert.strictEqual(bComment.leading, false);
-        assert.strictEqual(bComment.trailing, true);
-        assert.strictEqual(bComment.type, "Block");
-        assert.strictEqual(bComment.value, "after");
-
-        assert.strictEqual(
-            recast.print(b).code,
-            "b(param /*after*/) {}"
-        );
-
-        var c = objExpr.properties[2];
-        n.Identifier.assert(c.key);
-        assert.strictEqual(c.key.name, "c");
-
-        var cComments = c.value.body.comments;
-        assert.strictEqual(cComments.length, 1);
-
-        var cComment = cComments[0];
-        assert.strictEqual(cComment.leading, true);
-        assert.strictEqual(cComment.trailing, false);
-        assert.strictEqual(cComment.type, "Block");
-        assert.strictEqual(cComment.value, "body");
-
-        assert.strictEqual(
-            recast.print(c).code,
-            "c(param) /*body*/ {}"
-        );
-    });
+    var comment = ast.program.body[0].body[0].comments[0];
+    comment.type = "Block";
+    assert.strictEqual(recast.print(ast).code, [
+      "{",
+      "  /* barbara*/",
+      "  foo;",
+      "}",
+      "",
+      "bar;"
+    ].join(eol));
 
-    it("should attach comments as configurable", function() {
-        // Given
-        var simpleCommentedCode = [
-            "// A comment",
-            "var obj = {",
-            "};",
-        ];
-        var code = simpleCommentedCode.join(eol);
-        var ast = recast.parse(code);
-
-        // When
-        Object.defineProperty(ast.program, 'comments', {
-            value: undefined,
-            enumerable: false
-        });
-
-        // Then
-        // An exception will be thrown if `comments` aren't configurable.
-    });
+    comment.value += "\n * babar\n ";
+    assert.strictEqual(recast.print(ast).code, [
+      "{",
+      "  /* barbara",
+      "   * babar",
+      "   */",
+      "  foo;",
+      "}",
+      "",
+      "bar;"
+    ].join(eol));
 
-    it("should be reprinted when modified", function() {
-        var code = [
-            "foo;",
-            "// bar",
-            "bar;"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-
-        var comments = ast.program.body[1].comments;
-        assert.strictEqual(comments.length, 1);
-        var comment = comments[0];
-        assert.strictEqual(comment.type, "Line");
-        assert.strictEqual(comment.value, " bar");
-
-        comment.value = " barbara";
-        assert.strictEqual(recast.print(ast).code, [
-            "foo;",
-            "// barbara",
-            "bar;"
-        ].join(eol));
-
-        ast.program.body[0].comments = comments;
-        delete ast.program.body[1].comments;
-        assert.strictEqual(recast.print(ast).code, [
-            "// barbara",
-            "foo;",
-            "bar;"
-        ].join(eol));
-
-        ast.program.body[0] = b.blockStatement([
-            ast.program.body[0]
-        ]);
-        assert.strictEqual(recast.print(ast).code, [
-            "{",
-            "  // barbara",
-            "  foo;",
-            "}",
-            "",
-            "bar;"
-        ].join(eol));
-
-        var comment = ast.program.body[0].body[0].comments[0];
-        comment.type = "Block";
-        assert.strictEqual(recast.print(ast).code, [
-            "{",
-            "  /* barbara*/",
-            "  foo;",
-            "}",
-            "",
-            "bar;"
-        ].join(eol));
-
-        comment.value += "\n * babar\n ";
-        assert.strictEqual(recast.print(ast).code, [
-            "{",
-            "  /* barbara",
-            "   * babar",
-            "   */",
-            "  foo;",
-            "}",
-            "",
-            "bar;"
-        ].join(eol));
-
-        ast.program.body[1].comments = [comment];
-        assert.strictEqual(recast.print(ast).code, [
-            "{",
-            "  /* barbara",
-            "   * babar",
-            "   */",
-            "  foo;",
-            "}",
-            "",
-            "/* barbara",
-            " * babar",
-            " */",
-            "bar;"
-        ].join(eol));
-
-        delete ast.program.body[0].body[0].comments;
-        ast.program.comments = [b.line(" program comment")];
-        assert.strictEqual(recast.print(ast).code, [
-            "// program comment",
-            "{",
-            "  foo;",
-            "}",
-            "",
-            "/* barbara",
-            " * babar",
-            " */",
-            "bar;"
-        ].join(eol));
-
-        ast.program.body.push(
-            ast.program.body.shift()
-        );
-        assert.strictEqual(recast.print(ast).code, [
-            "// program comment",
-            "/* barbara",
-            " * babar",
-            " */",
-            "bar;",
-            "",
-            "{",
-            "  foo;",
-            "}"
-        ].join(eol));
-
-        recast.visit(ast, {
-            visitNode: function(path) {
-                delete path.value.comments;
-                this.traverse(path);
-            }
-        });
-        assert.strictEqual(recast.print(ast).code, [
-            "bar;",
-            "",
-            "{",
-            "  foo;",
-            "}"
-        ].join(eol));
-
-        ast.program.body[1] = ast.program.body[1].body[0];
-        assert.strictEqual(recast.print(ast).code, [
-            "bar;",
-            "foo;"
-        ].join(eol));
-    });
+    ast.program.body[1].comments = [comment];
+    assert.strictEqual(recast.print(ast).code, [
+      "{",
+      "  /* barbara",
+      "   * babar",
+      "   */",
+      "  foo;",
+      "}",
+      "",
+      "/* barbara",
+      " * babar",
+      " */",
+      "bar;"
+    ].join(eol));
 
-    it("should preserve stray non-comment syntax", function() {
-        var code = [
-            "[",
-            "  foo",
-            "  , /* comma */",
-            "  /* hole */",
-            "  , /* comma */",
-            "  bar",
-            "]"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        assert.strictEqual(recast.print(ast).code, code);
-
-        var elems = ast.program.body[0].expression.elements;
-        elems[0].comments.push(b.line(" line comment", true, false));
-        assert.strictEqual(recast.print(ast).code, [
-            "[",
-            "  // line comment",
-            "  foo /* comma */",
-            "  /* hole */",
-            "  ,",
-            "  , /* comma */",
-            "  bar",
-            "]"
-        ].join(eol));
-    });
+    delete ast.program.body[0].body[0].comments;
+    ast.program.comments = [b.line(" program comment")];
+    assert.strictEqual(recast.print(ast).code, [
+      "// program comment",
+      "{",
+      "  foo;",
+      "}",
+      "",
+      "/* barbara",
+      " * babar",
+      " */",
+      "bar;"
+    ].join(eol));
 
-    it("should be reprinted even if dangling", function() {
-        var code = [
-            "[/*dangling*/] // array literal"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        var array = ast.program.body[0].expression;
-        var danglingComment = array.comments[0];
-        var trailingComment = array.comments[1];
-
-        assert.strictEqual(danglingComment.leading, false);
-        assert.strictEqual(danglingComment.trailing, false);
-
-        assert.strictEqual(trailingComment.leading, false);
-        assert.strictEqual(trailingComment.trailing, true);
-
-        danglingComment.value = " neither leading nor trailing ";
-        assert.strictEqual(recast.print(ast).code, [
-            "[/* neither leading nor trailing */] // array literal"
-        ].join(eol));
-
-        trailingComment.value = " trailing";
-        assert.strictEqual(recast.print(ast).code, [
-            "[/* neither leading nor trailing */] // trailing"
-        ].join(eol));
-
-        // Unfortuantely altering the elements of the array leads to
-        // reprinting which blows away the dangling comment.
-        array.elements.push(b.literal(1));
-        assert.strictEqual(
-            recast.print(ast).code,
-            "[1] // trailing"
-        );
-    });
+    ast.program.body.push(
+      ast.program.body.shift()
+    );
+    assert.strictEqual(recast.print(ast).code, [
+      "// program comment",
+      "/* barbara",
+      " * babar",
+      " */",
+      "bar;",
+      "",
+      "{",
+      "  foo;",
+      "}"
+    ].join(eol));
 
-    it("should attach to program.body[0] instead of program", function() {
-        var code = [
-            "// comment 1",
-            "var a;",
-            "// comment 2",
-            "var b;",
-            "if (true) {",
-            "  // comment 3",
-            "  var c;",
-            "}"
-        ].join('\n');
-
-        var ast = recast.parse(code);
-
-        assert.ok(!ast.program.comments);
-
-        var aDecl = ast.program.body[0];
-        n.VariableDeclaration.assert(aDecl);
-        assert.strictEqual(aDecl.comments.length, 1);
-        assert.strictEqual(aDecl.comments[0].leading, true);
-        assert.strictEqual(aDecl.comments[0].trailing, false);
-        assert.strictEqual(aDecl.comments[0].value, " comment 1");
-
-        var bDecl = ast.program.body[1];
-        n.VariableDeclaration.assert(bDecl);
-        assert.strictEqual(bDecl.comments.length, 1);
-        assert.strictEqual(bDecl.comments[0].leading, true);
-        assert.strictEqual(bDecl.comments[0].trailing, false);
-        assert.strictEqual(bDecl.comments[0].value, " comment 2");
-
-        var cDecl = ast.program.body[2].consequent.body[0];
-        n.VariableDeclaration.assert(cDecl);
-        assert.strictEqual(cDecl.comments.length, 1);
-        assert.strictEqual(cDecl.comments[0].leading, true);
-        assert.strictEqual(cDecl.comments[0].trailing, false);
-        assert.strictEqual(cDecl.comments[0].value, " comment 3");
+    recast.visit(ast, {
+      visitNode: function(path) {
+        delete path.value.comments;
+        this.traverse(path);
+      }
     });
+    assert.strictEqual(recast.print(ast).code, [
+      "bar;",
+      "",
+      "{",
+      "  foo;",
+      "}"
+    ].join(eol));
 
-    it("should not collapse multi line function definitions", function() {
-        var code = [
-            "var obj = {",
-            "  a(",
-            "    /*before*/ param",
-            "  ) /*after*/ {",
-            "  },",
-            "};",
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        var printer = new Printer({
-            tabWidth: 2
-        });
-
-        assert.strictEqual(
-            printer.print(ast).code,
-            code
-        );
-    });
+    ast.program.body[1] = ast.program.body[1].body[0];
+    assert.strictEqual(recast.print(ast).code, [
+      "bar;",
+      "foo;"
+    ].join(eol));
+  });
 
-    it("should be pretty-printable in illegal positions", function() {
-        var code = [
-            "var sum = function /*anonymous*/(/*...args*/) /*int*/ {",
-            "  // TODO",
-            "};"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        var funExp = ast.program.body[0].declarations[0].init;
-        n.FunctionExpression.assert(funExp);
-
-        funExp.original = null;
-
-        var comments = funExp.body.comments;
-        assert.strictEqual(comments.length, 4);
-        funExp.id = comments.shift();
-        funExp.params.push(comments.shift());
-        funExp.body.body.push(comments.pop());
-
-        assert.strictEqual(
-            recast.print(ast).code,
-            code
-        );
-    });
+  pit("should preserve stray non-comment syntax", function() {
+    var code = [
+      "[",
+      "  foo",
+      "  , /* comma */",
+      "  /* hole */",
+      "  , /* comma */",
+      "  bar",
+      "]"
+    ].join(eol);
+
+    var ast = recast.parse(code, { parser });
+    assert.strictEqual(recast.print(ast).code, code);
+
+    var elems = ast.program.body[0].expression.elements;
+    elems[0].comments.push(b.line(" line comment", true, false));
+    assert.strictEqual(recast.print(ast).code, [
+      "[",
+      "  // line comment",
+      "  foo /* comma */",
+      "  /* hole */",
+      "  ,",
+      "  , /* comma */",
+      "  bar",
+      "]"
+    ].join(eol));
+  });
 
-    it("should preserve correctness when a return expression has a comment", function () {
-        var code = [
-            "function f() {",
-            "  return 3;",
-            "}"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        ast.program.body[0].body.body[0].argument.comments = [b.line('Foo')];
-
-        assert.strictEqual(recast.print(ast).code, [
-            "function f() {",
-            "  return (",
-            "    //Foo",
-            "    3",
-            "  );",
-            "}"
-        ].join(eol));
+  pit("should be reprinted even if dangling", function() {
+    const code = "[/*dangling*/] // array literal";
+    const ast = recast.parse(code, { parser });
+    const array = ast.program.body[0].expression;
+    const stmt = ast.program.body[0];
+    let danglingComment;
+    let trailingComment;
+
+    function handleComment(comment) {
+      if (comment.trailing) {
+        trailingComment = comment;
+      } else if (! comment.leading) {
+        danglingComment = comment;
+      }
+    }
+
+    (stmt.comments || []).forEach(handleComment);
+    (stmt.expression.comments || []).forEach(handleComment);
+
+    assert.strictEqual(danglingComment.leading, false);
+    assert.strictEqual(danglingComment.trailing, false);
+
+    assert.strictEqual(trailingComment.leading, false);
+    assert.strictEqual(trailingComment.trailing, true);
+
+    danglingComment.value = " neither leading nor trailing ";
+    assert.strictEqual(recast.print(ast).code, [
+      "[/* neither leading nor trailing */] // array literal"
+    ].join(eol));
+
+    trailingComment.value = " trailing";
+    assert.strictEqual(recast.print(ast).code, [
+      "[/* neither leading nor trailing */] // trailing"
+    ].join(eol));
+
+    // Unfortuantely altering the elements of the array leads to
+    // reprinting which blows away the dangling comment.
+    array.elements.push(b.literal(1));
+    assert.strictEqual(
+      recast.print(ast).code,
+      "[1] // trailing"
+    );
+  });
+
+  pit("should attach to program.body[0] instead of program", function() {
+    var code = [
+      "// comment 1",
+      "var a;",
+      "// comment 2",
+      "var b;",
+      "if (true) {",
+      "  // comment 3",
+      "  var c;",
+      "}"
+    ].join('\n');
+
+    var ast = recast.parse(code, { parser });
+
+    assert.ok(!ast.program.comments);
+
+    var aDecl = ast.program.body[0];
+    n.VariableDeclaration.assert(aDecl);
+    assert.strictEqual(aDecl.comments.length, 1);
+    assert.strictEqual(aDecl.comments[0].leading, true);
+    assert.strictEqual(aDecl.comments[0].trailing, false);
+    assert.strictEqual(aDecl.comments[0].value, " comment 1");
+
+    var bDecl = ast.program.body[1];
+    n.VariableDeclaration.assert(bDecl);
+    assert.strictEqual(bDecl.comments.length, 1);
+    assert.strictEqual(bDecl.comments[0].leading, true);
+    assert.strictEqual(bDecl.comments[0].trailing, false);
+    assert.strictEqual(bDecl.comments[0].value, " comment 2");
+
+    var cDecl = ast.program.body[2].consequent.body[0];
+    n.VariableDeclaration.assert(cDecl);
+    assert.strictEqual(cDecl.comments.length, 1);
+    assert.strictEqual(cDecl.comments[0].leading, true);
+    assert.strictEqual(cDecl.comments[0].trailing, false);
+    assert.strictEqual(cDecl.comments[0].value, " comment 3");
+  });
+
+  pit("should not collapse multi line function definitions", function() {
+    var code = [
+      "var obj = {",
+      "  a(",
+      "    /*before*/ param",
+      "  ) /*after*/ {",
+      "  },",
+      "};",
+    ].join(eol);
+
+    var ast = recast.parse(code, { parser });
+    var printer = new Printer({
+      tabWidth: 2
     });
 
-  it("should wrap in parens when the return expression has nested leftmost comment", function () {
+    assert.strictEqual(
+      printer.print(ast).code,
+      code
+    );
+  });
+
+  pit("should be pretty-printable in illegal positions", function() {
+    var code = [
+      "var sum = function /*anonymous*/(/*...args*/) /*int*/ {",
+      "  // TODO",
+      "};"
+    ].join(eol);
+
+    var ast = recast.parse(code, { parser });
+    var funExp = ast.program.body[0].declarations[0].init;
+    n.FunctionExpression.assert(funExp);
+
+    funExp.original = null;
+
+    var comments = funExp.body.comments;
+    assert.strictEqual(comments.length, 4);
+    funExp.id = comments.shift();
+    funExp.params.push(comments.shift());
+    funExp.body.body.push(comments.pop());
+
+    assert.strictEqual(
+      recast.print(ast).code,
+      code
+    );
+  });
+
+  pit("should preserve correctness when a return expression has a comment", function () {
+    var code = [
+      "function f() {",
+      "  return 3;",
+      "}"
+    ].join(eol);
+
+    var ast = recast.parse(code, { parser });
+    ast.program.body[0].body.body[0].argument.comments = [b.line('Foo')];
+
+    assert.strictEqual(recast.print(ast).code, [
+      "function f() {",
+      "  return (",
+      "    //Foo",
+      "    3",
+      "  );",
+      "}"
+    ].join(eol));
+  });
+
+  pit("should wrap in parens when the return expression has nested leftmost comment", function () {
     var code = [
       "function f() {",
       "  return 1 + 2;",
       "}"
     ].join(eol);
 
-    var ast = recast.parse(code);
+    var ast = recast.parse(code, { parser });
     ast.program.body[0].body.body[0].argument.left.comments = [b.line('Foo')];
 
     assert.strictEqual(recast.print(ast).code, [
@@ -702,53 +761,53 @@ describe("comments", function() {
     ].join(eol));
   });
 
-    it("should not wrap in parens when the return expression has an interior comment", function () {
-        var code = [
-            "function f() {",
-            "  return 1 + 2;",
-            "}"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        ast.program.body[0].body.body[0].argument.right.comments = [b.line('Foo')];
-
-        assert.strictEqual(recast.print(ast).code, [
-            "function f() {",
-            "  return 1 + //Foo",
-            "  2;",
-            "}"
-        ].join(eol));
-    });
+  pit("should not wrap in parens when the return expression has an interior comment", function () {
+    var code = [
+      "function f() {",
+      "  return 1 + 2;",
+      "}"
+    ].join(eol);
 
-    it("should not reformat a return statement that is not modified", function () {
-        var code = [
-            "function f() {",
-            "  return      {",
-            "    a:     1,",
-            "    b: 2,",
-            "  };",
-            "}"
-        ].join(eol);
+    var ast = recast.parse(code, { parser });
+    ast.program.body[0].body.body[0].argument.right.comments = [b.line('Foo')];
 
-        var ast = recast.parse(code);
+    assert.strictEqual(recast.print(ast).code, [
+      "function f() {",
+      "  return 1 + //Foo",
+      "  2;",
+      "}"
+    ].join(eol));
+  });
 
-        assert.strictEqual(recast.print(ast).code, code);
-    });
+  pit("should not reformat a return statement that is not modified", function () {
+    var code = [
+      "function f() {",
+      "  return      {",
+      "    a:     1,",
+      "    b: 2,",
+      "  };",
+      "}"
+    ].join(eol);
 
-    it("should correctly handle a removing the argument from a return", function () {
-        var code = [
-            "function f() {",
-            "  return 'foo';",
-            "}"
-        ].join(eol);
-
-        var ast = recast.parse(code);
-        ast.program.body[0].body.body[0].argument = null;
-
-        assert.strictEqual(recast.print(ast).code, [
-            "function f() {",
-            "  return;",
-            "}"
-        ].join(eol));
-    });
-});
+    var ast = recast.parse(code, { parser });
+
+    assert.strictEqual(recast.print(ast).code, code);
+  });
+
+  pit("should correctly handle a removing the argument from a return", function () {
+    var code = [
+      "function f() {",
+      "  return 'foo';",
+      "}"
+    ].join(eol);
+
+    var ast = recast.parse(code, { parser });
+    ast.program.body[0].body.body[0].argument = null;
+
+    assert.strictEqual(recast.print(ast).code, [
+      "function f() {",
+      "  return;",
+      "}"
+    ].join(eol));
+  });
+}
diff --git a/test/jsx.js b/test/jsx.js
index ba3aef1..39c2c21 100644
--- a/test/jsx.js
+++ b/test/jsx.js
@@ -5,7 +5,7 @@ var types = require("../lib/types");
 describe("JSX Compatability", function() {
   var printer = new Printer({ tabWidth: 2 });
   var parseOptions = {
-    parser: require("reify/lib/parsers/babylon")
+    parser: require("../parsers/babylon")
   };
 
   function check(source) {
diff --git a/test/parser.js b/test/parser.js
index 5839460..aa6031f 100644
--- a/test/parser.js
+++ b/test/parser.js
@@ -15,11 +15,51 @@ var eol = require("os").EOL;
 // test functions with names and then export them later.
 
 describe("parser", function() {
-  it("empty source", function () {
+  ["../parsers/acorn",
+   "../parsers/babylon",
+   "../parsers/esprima",
+   "../parsers/flow",
+   "../parsers/typescript",
+  ].forEach(runTestsForParser);
+
+  it("AlternateParser", function() {
+    var types = require("../lib/types");
+    var b = types.builders;
+    var parser = {
+      parse: function(code) {
+        var program = b.program([
+          b.expressionStatement(b.identifier("surprise"))
+        ]);
+        program.comments = [];
+        return program;
+      }
+    };
+
+    function check(options) {
+      var ast = parse("ignored", options);
+      var printer = new Printer;
+
+      types.namedTypes.File.assert(ast, true);
+      assert.strictEqual(
+        printer.printGenerically(ast).code,
+        "surprise;"
+      );
+    }
+
+    check({ esprima: parser });
+    check({ parser: parser });
+  });
+});
+
+function runTestsForParser(parserId) {
+  const parserName = parserId.split("/").pop();
+  const parser = require(parserId);
+
+  it("[" + parserName + "] empty source", function () {
     var printer = new Printer;
 
     function check(code) {
-      var ast = parse(code);
+      var ast = parse(code, { parser });
       assert.strictEqual(printer.print(ast).code, code);
     }
 
@@ -32,9 +72,17 @@ describe("parser", function() {
     check("    ");
   });
 
-  it("Parser", function testParser(done) {
+  const lineCommentTypes = {
+    acorn: "Line",
+    babylon: "CommentLine",
+    esprima: "Line",
+    flow: "CommentLine",
+    typescript: "CommentLine"
+  };
+
+  it("[" + parserName + "] parser basics", function testParser(done) {
     var code = testParser + "";
-    var ast = parse(code);
+    var ast = parse(code, { parser });
 
     namedTypes.File.assert(ast);
     assert.ok(getReprinter(FastPath.from(ast)));
@@ -60,7 +108,12 @@ describe("parser", function() {
     assert.strictEqual(lastStatement.comments.length, 2);
 
     var firstComment = lastStatement.comments[0];
-    assert.strictEqual(firstComment.type, "Line");
+
+    assert.strictEqual(
+      firstComment.type,
+      lineCommentTypes[parserName]
+    );
+
     assert.strictEqual(firstComment.leading, true);
     assert.strictEqual(firstComment.trailing, false);
     assert.strictEqual(
@@ -69,7 +122,12 @@ describe("parser", function() {
     );
 
     var secondComment = lastStatement.comments[1];
-    assert.strictEqual(secondComment.type, "Line");
+
+    assert.strictEqual(
+      secondComment.type,
+      lineCommentTypes[parserName]
+    );
+
     assert.strictEqual(secondComment.leading, true);
     assert.strictEqual(secondComment.trailing, false);
     assert.strictEqual(
@@ -82,14 +140,14 @@ describe("parser", function() {
     done();
   });
 
-  it("LocationFixer", function() {
+  it("[" + parserName + "] LocationFixer", function() {
     var code = [
       "function foo() {",
       "    a()",
       "    b()",
       "}"
     ].join(eol);
-    var ast = parse(code);
+    var ast = parse(code, { parser });
     var printer = new Printer;
 
     types.visit(ast, {
@@ -107,12 +165,15 @@ describe("parser", function() {
     assert.strictEqual(altered, printer.print(ast).code);
   });
 
-  it("TabHandling", function() {
+  it("[" + parserName + "] TabHandling", function() {
     function check(code, tabWidth) {
       var lines = fromString(code, { tabWidth: tabWidth });
       assert.strictEqual(lines.length, 1);
 
-      types.visit(parse(code, { tabWidth: tabWidth }), {
+      types.visit(parse(code, {
+        tabWidth: tabWidth,
+        parser,
+      }), {
         check: function(s, loc) {
           var sliced = lines.slice(loc.start, loc.end);
           assert.strictEqual(s + "", sliced.toString());
@@ -142,31 +203,34 @@ describe("parser", function() {
     }
   });
 
-  it("AlternateParser", function() {
-    var types = require("../lib/types");
-    var b = types.builders;
-    var parser = {
-      parse: function(code) {
-        var program = b.program([
-          b.expressionStatement(b.identifier("surprise"))
-        ]);
-        program.comments = [];
-        return program;
-      }
-    };
-
-    function check(options) {
-      var ast = parse("ignored", options);
-      var printer = new Printer;
+  it("[" + parserName + "] Only comment followed by space", function () {
+    const printer = new Printer;
 
-      types.namedTypes.File.assert(ast, true);
+    function check(code) {
+      const ast = parse(code, { parser });
       assert.strictEqual(
-        printer.printGenerically(ast).code,
-        "surprise;"
+        printer.print(ast).code,
+        code
       );
     }
 
-    check({ esprima: parser });
-    check({ parser: parser });
+    check("// comment");
+    check("// comment ");
+    check("// comment\n");
+    check("// comment\n\n");
+    check(" // comment\n");
+    check(" // comment\n ");
+    check(" // comment \n ");
+
+    check("/* comment */");
+    check("/* comment */ ");
+    check(" /* comment */");
+    check("\n/* comment */");
+    check("\n/* comment */\n");
+    check("\n /* comment */\n ");
+    check("/* comment */\n ");
+    check("/* com\n\nment */");
+    check("/* com\n\nment */ ");
+    check(" /* com\n\nment */ ");
   });
-});
+}
diff --git a/test/printer.js b/test/printer.js
index 171fd1a..158d0bc 100644
--- a/test/printer.js
+++ b/test/printer.js
@@ -1666,16 +1666,11 @@ describe("printer", function() {
       check("let i = 0 ; ; ", parser);
     }
 
-    checkWith(require("esprima"));
-
-    try {
-      checkWith(require("reify/lib/parsers/acorn.js"));
-      checkWith(require("reify/lib/parsers/babylon.js"));
-    } catch (e) {
-      if (require("semver").gte(process.version, "4.0.0")) {
-        throw e;
-      }
-    }
+    checkWith(require("../parsers/esprima"));
+    checkWith(require("../parsers/acorn"));
+    checkWith(require("../parsers/babylon"));
+    checkWith(require("../parsers/typescript"));
+    checkWith(require("../parsers/flow"));
   });
 
   it("parenthesizes NumericLiteral MemberExpression objects", function () {
diff --git a/test/run.js b/test/run.js
new file mode 100644
index 0000000..4221225
--- /dev/null
+++ b/test/run.js
@@ -0,0 +1,16 @@
+require("./babylon.js");
+require("./comments.js");
+require("./es6tests.js");
+require("./identity.js");
+require("./jsx.js");
+require("./lines.js");
+require("./mapping.js");
+require("./parens.js");
+require("./parser.js");
+require("./patcher.js");
+require("./perf.js");
+require("./printer.js");
+require("./syntax.js");
+require("./type-syntax.js");
+require("./typescript.js");
+require("./visit.js");
diff --git a/test/run.sh b/test/run.sh
new file mode 100755
index 0000000..4a0765a
--- /dev/null
+++ b/test/run.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+set -ex
+
+cd $(dirname $0)/data
+
+BAB_TAG=v$(node -p 'require("babylon/package.json").version')
+
+if [ ! -d babylon-typescript-fixtures ]
+then
+    git clone --branch "$BAB_TAG" --depth 1 \
+        https://github.com/babel/babel.git
+    mv babel/packages/babylon/test/fixtures/typescript \
+       babylon-typescript-fixtures
+    rm -rf babel
+fi
+
+if [ ! -d graphql-tools-src ]
+then
+    git clone --depth 1 https://github.com/apollographql/graphql-tools.git
+    mv graphql-tools/src \
+       graphql-tools-src
+    rm -rf graphql-tools
+fi
+
+cd .. # back to the recast/test/ directory
+
+exec mocha --reporter spec --full-trace $@ run.js
diff --git a/test/syntax.js b/test/syntax.js
index 7cd9e73..3a15a14 100644
--- a/test/syntax.js
+++ b/test/syntax.js
@@ -3,52 +3,53 @@ var fs = require("fs");
 var path = require("path");
 var types = require("../lib/types");
 var parse = require("../lib/parser").parse;
+var hasOwn = Object.prototype.hasOwnProperty;
 
 describe("syntax", function() {
-    // Make sure we handle all possible node types in Syntax, and no additional
-    // types that are not present in Syntax.
-    it("Completeness", function(done) {
-        var printer = path.join(__dirname, "../lib/printer.js");
+  // Make sure we handle all possible node types in Syntax, and no additional
+  // types that are not present in Syntax.
+  it("Completeness", function(done) {
+    var printer = path.join(__dirname, "../lib/printer.js");
 
-        fs.readFile(printer, "utf-8", function(err, data) {
-            assert.ok(!err);
+    fs.readFile(printer, "utf-8", function(err, data) {
+      assert.ok(!err);
 
-            var ast = parse(data);
-            assert.ok(ast);
+      var ast = parse(data);
+      assert.ok(ast);
 
-            var typeNames = {};
-            types.visit(ast, {
-                visitFunctionDeclaration: function(path) {
-                    var decl = path.node;
-                    if (types.namedTypes.Identifier.check(decl.id) &&
-                        decl.id.name === "genericPrintNoParens") {
-                        this.traverse(path, {
-                            visitSwitchCase: function(path) {
-                                var test = path.node.test;
-                                if (test &&
-                                    test.type === "Literal" &&
-                                    typeof test.value === "string") {
-                                    var name = test.value;
-                                    typeNames[name] = name;
-                                }
-                                return false;
-                            }
-                        });
-                    } else {
-                        this.traverse(path);
-                    }
+      var typeNames = {};
+      types.visit(ast, {
+        visitFunctionDeclaration(path) {
+          var decl = path.node;
+          if (types.namedTypes.Identifier.check(decl.id) &&
+              decl.id.name === "genericPrintNoParens") {
+            this.traverse(path, {
+              visitSwitchCase(path) {
+                var test = path.node.test;
+                if (test &&
+                    test.type === "Literal" &&
+                    typeof test.value === "string") {
+                  var name = test.value;
+                  typeNames[name] = name;
                 }
+                return false;
+              }
             });
+          } else {
+            this.traverse(path);
+          }
+        }
+      });
 
-            for (var name in types.namedTypes) {
-                if (types.namedTypes.hasOwnProperty(name)) {
-                    assert.ok(typeNames.hasOwnProperty(name), "unhandled type: " + name);
-                    assert.strictEqual(name, typeNames[name]);
-                    delete typeNames[name];
-                }
-            }
+      for (var name in types.namedTypes) {
+        if (hasOwn.call(types.namedTypes, name)) {
+          assert.ok(hasOwn.call(typeNames, name), "unhandled type: " + name);
+          assert.strictEqual(name, typeNames[name]);
+          delete typeNames[name];
+        }
+      }
 
-            done();
-        });
+      done();
     });
+  });
 });
diff --git a/test/type-syntax.js b/test/type-syntax.js
index 957677d..dc625de 100644
--- a/test/type-syntax.js
+++ b/test/type-syntax.js
@@ -28,6 +28,10 @@ describe("type syntax", function() {
     // Import type annotations
     check("import type foo from 'foo';");
     check("import typeof foo from 'foo';");
+    check("import { type foo } from 'foo';", flowParserParseOptions);
+
+    // Export type annotations
+    check("export type { foo };");
 
     // Scalar type annotations
     check("var a: number;");
diff --git a/test/typescript.js b/test/typescript.js
new file mode 100644
index 0000000..8d2994d
--- /dev/null
+++ b/test/typescript.js
@@ -0,0 +1,350 @@
+"use strict";
+
+const assert = require("assert");
+const path = require("path");
+const fs = require("fs");
+const recast = require("../main.js");
+const parse = require("../lib/parser").parse;
+const Printer = require("../lib/printer").Printer;
+const types = require("../lib/types");
+const eol = require("os").EOL;
+const parser = require("../parsers/typescript");
+
+describe("TypeScript", function() {
+  it('basic printing', function() {
+    function check(lines) {
+      const code = lines.join(eol);
+      const ast = recast.parse(code, { parser });
+      const output = recast.prettyPrint(ast, { tabWidth: 2 }).code;
+      assert.strictEqual(code, output);
+    }
+
+    check([
+      'let color: string = "blue";',
+      'let isDone: boolean = false;',
+      'let decimal: number = 6;',
+      'let hex: number = 0xf00d;',
+      'let binary: number = 0b1010;',
+      'let octal: number = 0o744;',
+      'let list: number[] = [1, 2, 3];',
+      'let matrix: number[][];',
+      'let x: [string, number];',
+      'let f: <E>(e: E) => void;',
+      'let sn: string | null = "isNull";'
+    ]);
+
+    check([
+      'type A = number;',
+      'type B = string;',
+      'type C = never;',
+      'type D = any;',
+      'type E = [string, number];',
+      'type F = void;',
+      'type G = undefined;',
+      '',
+      'type C = {',
+      '  a: string,',
+      '  b?: number',
+      '};'
+    ]);
+
+    check([
+      'type c = T & U & V;'
+    ]);
+
+    check([
+      'let list: Array<number> = [1, 2, 3];'
+    ]);
+
+    check([
+      'let n = a!.c();'
+    ]);
+
+    check([
+      'type A = "cat" | "dog" | "bird";'
+    ]);
+
+    check([
+      'type A<T, U> = {',
+      '  u: "cat",',
+      '  x: number,',
+      '  y: T,',
+      '  z: U',
+      '};'
+    ]);
+
+    check([
+      'type F = <T, U>(',
+      '  a: string,',
+      '  b: {',
+      '    y: T,',
+      '    z: U',
+      '  }',
+      ') => void;'
+    ]);
+
+    check([
+      'type Readonly<T> = {',
+      '  readonly [P in keyof T]: T[P];',
+      '};',
+      '',
+      'type Pick<T, K extends keyof T> = {',
+      '  [P in K]: T[P];',
+      '};'
+    ]);
+
+    check([
+      'let strLength: string = (<string> someValue).length;',
+      'let strLength: string = <string> someValue;',
+      'let square = <Square> {};',
+      'let strLength: number = (someValue as string).length;',
+      'let strLength: number = someValue as string;'
+    ]);
+
+    check([
+      'let counter = <Counter> function(start: number) {};'
+    ]);
+
+    check([
+      'if ((<F> p).s) {',
+      '  (<F> p).s();',
+      '}'
+    ]);
+
+    check([
+      'function i(p): p is F {}',
+      'function i(p): p is string | number {}'
+    ]);
+
+    check([
+      'function f<T, U>(a: T, b: U): void {',
+      '  let c: number;',
+      '}'
+    ]);
+
+    check([
+      'function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {',
+      '  console.log(o);',
+      '}'
+    ]);
+
+    check([
+      'let myAdd: <T, U>(x: T, y?: number) => U = function(x: number, y?: number): number {};',
+      'function bb(f: string, ...r: string[]): void {}',
+      'function f(this: void) {}',
+      'function l<T extends L>(arg: T): T {}',
+      'function l<T extends A.B.C>(arg: T): T {}',
+      'function l<T extends keyof U>(obj: T) {}',
+      '',
+      'function create<T>(',
+      '  c: {',
+      '    new<U>(a: U): T',
+      '  }',
+      '): void {}'
+    ]);
+
+    check([
+      'const a = b as U as V;'
+    ]);
+
+    check([
+      'enum Color {',
+      '  Red,',
+      '  Green,',
+      '  Blue',
+      '}',
+      '',
+      'enum Color {',
+      '  Red = 1,',
+      '  Green = 2,',
+      '  Blue = 3',
+      '}',
+      '',
+      'enum Color {',
+      '  Red = 1,',
+      '  Green',
+      '}',
+      '',
+      'enum Color {',
+      '  Red = "RED",',
+      '  Green = "GREEN",',
+      '  Blue = "BLUE"',
+      '}',
+      '',
+      'enum Color {',
+      '  Red = init(),',
+      '  Green = "GREEN"',
+      '}',
+      '',
+      'enum E {',
+      '  A = 1,',
+      '  B,',
+      '  C',
+      '}',
+      '',
+      'enum F {',
+      '  A = 1 << 1,',
+      '  B = C | D.G,',
+      '  E = "1".length',
+      '}',
+      '',
+      'const enum G {',
+      '  A = 1',
+      '}',
+      '',
+      'declare enum H {',
+      '  A = 1',
+      '}'
+    ]);
+
+    check([
+      'class C<T> extends B {',
+      '  f(a: T) {',
+      '    c(a as D);',
+      '  }',
+      '}'
+    ]);
+
+    check([
+      'interface LabelledContainer<T> {',
+      '  label: string;',
+      '  content: T;',
+      '  option?: boolean;',
+      '  readonly x: number;',
+      '  [index: number]: string;',
+      '  [propName: string]: any;',
+      '  readonly [index: number]: string;',
+      '  (source: string, subString: string): boolean;',
+      '  (start: number): string;',
+      '  reset(): void;',
+      '  a(c: (this: void, e: E) => void): void;',
+      '}'
+    ]);
+
+    check([
+      'interface Square<T, U> extends Shape<T, U>, Visible<T, U> {',
+      '  sideLength: number;',
+      '}'
+    ]);
+
+    check([
+      'class Button extends Control<T, U> implements SelectableControl<T, U>, ClickableControl<U> {',
+      '  select() {}',
+      '}'
+    ]);
+
+    check([
+      'class Animal {',
+      '  static className: string = "Animal";',
+      '',
+      '  constructor(theName: string) {',
+      '    this.name = theName;',
+      '  }',
+      '',
+      '  private name: string;',
+      '  public fur: boolean;',
+      '  protected sound: string;',
+      '  private getName() {}',
+      '  public talk() {}',
+      '  protected getSound() {}',
+      '  static createAnimal() {}',
+      '}'
+    ]);
+
+    check([
+      'export interface S {',
+      '  i(s: string): boolean;',
+      '}',
+    ]);
+
+    check([
+      'namespace Validation {',
+      '  export interface S {',
+      '    i(j: string): boolean;',
+      '  }',
+      '}'
+    ]);
+
+    check([
+      'export interface S {',
+      '  i(j: string): boolean;',
+      '}'
+    ]);
+
+    check([
+      'declare namespace D3 {',
+      '  export const f: number = 2;',
+      '}'
+    ]);
+
+    check([
+      'declare function foo<K, V>(arg: T = getDefault()): R'
+    ]);
+
+    check([
+      'class Animal {',
+      '  public static async *[name]<T>(arg: U): V;',
+      '}'
+    ]);
+  });
+});
+
+testReprinting(
+  "data/babylon-typescript-fixtures/**/input.js",
+  "Reprinting Babylon TypeScript test fixtures"
+);
+
+testReprinting(
+  "data/graphql-tools-src/**/*.ts",
+  "Reprinting GraphQL-Tools TypeScript files"
+);
+
+function testReprinting(pattern, description) {
+  describe(description, function () {
+    require("glob").sync(pattern, {
+      cwd: __dirname
+    }).forEach(file => it(file, function () {
+      if (file.indexOf("tsx/brace-is-block") >= 0 ||
+          file.endsWith("stitching/errors.ts")) {
+        return;
+      }
+
+      const absPath = path.join(__dirname, file);
+      const source = fs.readFileSync(absPath, "utf8");
+      const ast = tryToParseFile(source, absPath);
+
+      if (ast === null) {
+        return;
+      }
+
+      this.timeout(20000);
+
+      assert.strictEqual(recast.print(ast).code, source);
+      const reprintedCode = recast.prettyPrint(ast).code;
+      const reparsedAST = recast.parse(reprintedCode, { parser });
+      types.astNodesAreEquivalent(ast, reparsedAST);
+    }));
+  });
+}
+
+function tryToParseFile(source, absPath) {
+  try {
+    return recast.parse(source, { parser });
+  } catch (e1) {
+    try {
+      var options = JSON.parse(fs.readFileSync(
+        path.join(path.dirname(absPath), "options.json")));
+    } catch (e2) {
+      if (e2.code !== "ENOENT") {
+        console.error(e2);
+      }
+      throw e1;
+    }
+
+    if (options.throws === e1.message) {
+      return null;
+    }
+
+    throw e1;
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index a2fbf76..f782252 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,9 +2,9 @@
 # yarn lockfile v1
 
 
-acorn@~5.1.1:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7"
+acorn@^5.2.1:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822"
 
 ansi-regex@^2.0.0:
   version "2.1.1"
@@ -14,9 +14,9 @@ ansi-styles@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
 
-ast-types at 0.10.1:
-  version "0.10.1"
-  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd"
+ast-types at 0.10.2:
+  version "0.10.2"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.2.tgz#aef76a04fde54634976fc94defaad1a67e2eadb0"
 
 babel-code-frame@^6.26.0:
   version "6.26.0"
@@ -416,9 +416,9 @@ babylon@^6.18.0:
   version "6.18.0"
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
 
-babylon@~7.0.0-beta.31:
-  version "7.0.0-beta.40"
-  resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a"
+babylon@~7.0.0-beta.39:
+  version "7.0.0-beta.39"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.39.tgz#512833ea788f6570c6db026d743a7565e58d3aeb"
 
 balanced-match@^1.0.0:
   version "1.0.0"
@@ -499,9 +499,9 @@ esutils@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
 
-flow-parser@^0.59.0:
-  version "0.59.0"
-  resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.59.0.tgz#f6ebcae61ffa187e420999d40ce0a801f39b2635"
+flow-parser@^0.66.0:
+  version "0.66.0"
+  resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.66.0.tgz#be583fefb01192aa5164415d31a6241b35718983"
 
 fs.realpath@^1.0.0:
   version "1.0.0"
@@ -612,7 +612,7 @@ minipass@^2.2.1:
   dependencies:
     yallist "^3.0.0"
 
-minizlib@^1.0.3:
+minizlib@^1.0.4:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
   dependencies:
@@ -624,9 +624,9 @@ mkdirp at 0.5.1, mkdirp@^0.5.1:
   dependencies:
     minimist "0.0.8"
 
-mocha@~4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.0.1.tgz#0aee5a95cf69a4618820f5e51fa31717117daf1b"
+mocha@~5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.1.tgz#759b62c836b0732382a62b6b1fb245ec1bc943ac"
   dependencies:
     browser-stdout "1.3.0"
     commander "2.11.0"
@@ -703,13 +703,13 @@ regjsparser@^0.1.4:
   dependencies:
     jsesc "~0.5.0"
 
-reify@^0.12.3:
-  version "0.12.3"
-  resolved "https://registry.yarnpkg.com/reify/-/reify-0.12.3.tgz#b1aa0c196e7dc7fb7e9ad42b87c1e10fe7f97f97"
+reify@^0.14.1:
+  version "0.14.1"
+  resolved "https://registry.yarnpkg.com/reify/-/reify-0.14.1.tgz#2f79c546f72812afaaaf3afddf560b0eca759afd"
   dependencies:
-    acorn "~5.1.1"
-    minizlib "^1.0.3"
-    semver "^5.3.0"
+    acorn "^5.2.1"
+    minizlib "^1.0.4"
+    semver "^5.4.1"
 
 repeating@^2.0.0:
   version "2.0.1"
@@ -721,6 +721,10 @@ semver@^5.3.0:
   version "5.4.1"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
 
+semver@^5.4.1:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+
 slash@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-recast.git



More information about the Pkg-javascript-commits mailing list