[Pkg-javascript-commits] [node-ast-types] 01/03: New upstream version 0.11.1

Julien Puydt julien.puydt at laposte.net
Mon Feb 19 22:43:01 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-ast-types.

commit 7d643b2bef6f4a22c41b597f92737c0eff41c246
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Mon Feb 19 23:39:32 2018 +0100

    New upstream version 0.11.1
---
 .gitignore                     |    2 +
 .travis.yml                    |    1 +
 def/babel-core.js              |   23 +-
 def/core.js                    |   10 +-
 def/es6.js                     |   45 +-
 def/es7.js                     |   64 +-
 def/esprima.js                 |  154 ++-
 def/flow.js                    |   23 +
 def/jsx.js                     |   22 +
 def/typescript.js              |  432 ++++++++
 lib/scope.js                   |    4 +
 main.js                        |    3 +-
 package-lock.json              |   98 +-
 package.json                   |   12 +-
 test/{run.js => ecmascript.js} |   58 +-
 test/flow.js                   |   44 +
 test/run.js                    | 2326 +---------------------------------------
 test/run.sh                    |   24 +
 test/shared.js                 |   46 +
 test/typescript.js             |  143 +++
 20 files changed, 970 insertions(+), 2564 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3c3629e..c7ffa17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 node_modules
+test/data/babylon-typescript-fixtures
+test/data/typescript-compiler
diff --git a/.travis.yml b/.travis.yml
index c96c1f4..9d6d0ce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
 language: node_js
 node_js:
+  - "9"
   - "8"
   - "7"
   - "6"
diff --git a/def/babel-core.js b/def/babel-core.js
index 50955e4..a428036 100644
--- a/def/babel-core.js
+++ b/def/babel-core.js
@@ -7,7 +7,7 @@ module.exports = function (fork) {
   var or = types.Type.or;
 
   def("Noop")
-    .bases("Node")
+    .bases("Statement")
     .build();
 
   def("DoExpression")
@@ -136,7 +136,17 @@ module.exports = function (fork) {
   def("NumericLiteral")
     .bases("Literal")
     .build("value")
-    .field("value", Number);
+    .field("value", Number)
+    .field("raw", or(String, null), defaults["null"])
+    .field("extra", {
+      rawValue: Number,
+      raw: String
+    }, function getDefault() {
+      return {
+        rawValue: this.value,
+        raw: this.value + ""
+      }
+    });
 
   def("BigIntLiteral")
     .bases("Literal")
@@ -177,7 +187,8 @@ module.exports = function (fork) {
     def("Property"),
     def("ObjectMethod"),
     def("ObjectProperty"),
-    def("SpreadProperty")
+    def("SpreadProperty"),
+    def("SpreadElement")
   );
 
   // Split Property -> ObjectProperty and ObjectMethod
@@ -197,6 +208,9 @@ module.exports = function (fork) {
     .field("computed", Boolean, defaults["false"])
     .field("generator", Boolean, defaults["false"])
     .field("async", Boolean, defaults["false"])
+    .field("accessibility", // TypeScript
+           or(def("Literal"), null),
+           defaults["null"])
     .field("decorators",
            or([def("Decorator")], null),
            defaults["null"]);
@@ -206,6 +220,9 @@ module.exports = function (fork) {
     .build("key", "value")
     .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
     .field("value", or(def("Expression"), def("Pattern")))
+    .field("accessibility", // TypeScript
+           or(def("Literal"), null),
+           defaults["null"])
     .field("computed", Boolean, defaults["false"]);
 
   var ClassBodyElement = or(
diff --git a/def/core.js b/def/core.js
index fce6759..0ed7f36 100644
--- a/def/core.js
+++ b/def/core.js
@@ -131,7 +131,8 @@ module.exports = function (fork) {
     def("CatchClause")
         .bases("Node")
         .build("param", "guard", "body")
-        .field("param", def("Pattern"))
+        // https://github.com/tc39/proposal-optional-catch-binding
+        .field("param", or(def("Pattern"), null), defaults["null"])
         .field("guard", or(def("Expression"), null), defaults["null"])
         .field("body", def("BlockStatement"));
 
@@ -237,7 +238,7 @@ module.exports = function (fork) {
         "==", "!=", "===", "!==",
         "<", "<=", ">", ">=",
         "<<", ">>", ">>>",
-        "+", "-", "*", "/", "%",
+        "+", "-", "*", "/", "%", "**",
         "&", // TODO Missing from the Parser API.
         "|", "^", "in",
         "instanceof", "..");
@@ -329,7 +330,8 @@ module.exports = function (fork) {
         // But aren't Expressions and Patterns already Nodes? TODO Report this.
         .bases("Node", "Expression", "Pattern")
         .build("name")
-        .field("name", String);
+        .field("name", String)
+        .field("optional", Boolean, defaults["false"]);
 
     def("Literal")
         // But aren't Expressions already Nodes? TODO Report this.
@@ -367,4 +369,4 @@ module.exports = function (fork) {
         // e.g. { /*dangling*/ }.
         .field("leading", Boolean, defaults["true"])
         .field("trailing", Boolean, defaults["false"]);
-};
\ No newline at end of file
+};
diff --git a/def/es6.js b/def/es6.js
index 927487c..460f857 100644
--- a/def/es6.js
+++ b/def/es6.js
@@ -16,7 +16,9 @@ module.exports = function (fork) {
   def("RestElement")
     .bases("Pattern")
     .build("argument")
-    .field("argument", def("Pattern"));
+    .field("argument", def("Pattern"))
+    .field("typeAnnotation", // for Babylon. Flow parser puts it on the identifier
+      or(def("TypeAnnotation"), def("TSTypeAnnotation"), null), defaults["null"]);
 
   def("SpreadElementPattern")
     .bases("Pattern")
@@ -107,7 +109,7 @@ module.exports = function (fork) {
     .bases("Declaration")
     .build("kind", "key", "value", "static")
     .field("kind", or("constructor", "method", "get", "set"))
-    .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
+    .field("key", def("Expression"))
     .field("value", def("Function"))
     .field("computed", Boolean, defaults["false"])
     .field("static", Boolean, defaults["false"]);
@@ -179,13 +181,6 @@ module.exports = function (fork) {
     .build("id", "body", "superClass")
     .field("id", or(def("Identifier"), null), defaults["null"])
     .field("body", def("ClassBody"))
-    .field("superClass", or(def("Expression"), null), defaults["null"])
-    .field("implements", [def("ClassImplements")], defaults.emptyArray);
-
-  def("ClassImplements")
-    .bases("Node")
-    .build("id")
-    .field("id", def("Identifier"))
     .field("superClass", or(def("Expression"), null), defaults["null"]);
 
   // Specifier and ModuleSpecifier are abstract non-standard types
@@ -208,6 +203,38 @@ module.exports = function (fork) {
     .field("id", or(def("Identifier"), null), defaults["null"])
     .field("name", or(def("Identifier"), null), defaults["null"]);
 
+  // Like ModuleSpecifier, except type:"ImportSpecifier" and buildable.
+  // import {<id [as name]>} from ...;
+  def("ImportSpecifier")
+    .bases("ModuleSpecifier")
+    .build("id", "name");
+
+  // import <* as id> from ...;
+  def("ImportNamespaceSpecifier")
+    .bases("ModuleSpecifier")
+    .build("id");
+
+  // import <id> from ...;
+  def("ImportDefaultSpecifier")
+    .bases("ModuleSpecifier")
+    .build("id");
+
+  def("ImportDeclaration")
+    .bases("Declaration")
+    .build("specifiers", "source", "importKind")
+    .field("specifiers", [or(
+      def("ImportSpecifier"),
+      def("ImportNamespaceSpecifier"),
+      def("ImportDefaultSpecifier")
+    )], defaults.emptyArray)
+    .field("source", def("Literal"))
+    .field("importKind", or(
+      "value",
+      "type"
+    ), function() {
+      return "value";
+    });
+
   def("TaggedTemplateExpression")
     .bases("Expression")
     .build("tag", "quasi")
diff --git a/def/es7.js b/def/es7.js
index 7760df6..50634b4 100644
--- a/def/es7.js
+++ b/def/es7.js
@@ -1,38 +1,42 @@
 module.exports = function (fork) {
-    fork.use(require('./es6'));
+  fork.use(require('./es6'));
 
-    var types = fork.use(require("../lib/types"));
-    var def = types.Type.def;
-    var or = types.Type.or;
-    var builtin = types.builtInTypes;
-    var defaults = fork.use(require("../lib/shared")).defaults;
+  var types = fork.use(require("../lib/types"));
+  var def = types.Type.def;
+  var or = types.Type.or;
+  var builtin = types.builtInTypes;
+  var defaults = fork.use(require("../lib/shared")).defaults;
 
-    def("Function")
-      .field("async", Boolean, defaults["false"]);
+  def("Function")
+    .field("async", Boolean, defaults["false"]);
 
-    def("SpreadProperty")
-      .bases("Node")
-      .build("argument")
-      .field("argument", def("Expression"));
+  def("SpreadProperty")
+    .bases("Node")
+    .build("argument")
+    .field("argument", def("Expression"));
 
-    def("ObjectExpression")
-      .field("properties", [or(def("Property"), def("SpreadProperty"))]);
+  def("ObjectExpression")
+    .field("properties", [or(
+      def("Property"),
+      def("SpreadProperty"),
+      def("SpreadElement")
+    )]);
 
-    def("SpreadPropertyPattern")
-      .bases("Pattern")
-      .build("argument")
-      .field("argument", def("Pattern"));
+  def("SpreadPropertyPattern")
+    .bases("Pattern")
+    .build("argument")
+    .field("argument", def("Pattern"));
 
-    def("ObjectPattern")
-      .field("properties", [or(
-        def("Property"),
-        def("PropertyPattern"),
-        def("SpreadPropertyPattern")
-      )]);
+  def("ObjectPattern")
+    .field("properties", [or(
+      def("Property"),
+      def("PropertyPattern"),
+      def("SpreadPropertyPattern")
+    )]);
 
-    def("AwaitExpression")
-      .bases("Expression")
-      .build("argument", "all")
-      .field("argument", or(def("Expression"), null))
-      .field("all", Boolean, defaults["false"]);
-};
\ No newline at end of file
+  def("AwaitExpression")
+    .bases("Expression")
+    .build("argument", "all")
+    .field("argument", or(def("Expression"), null))
+    .field("all", Boolean, defaults["false"]);
+};
diff --git a/def/esprima.js b/def/esprima.js
index 3f21bb8..d3916ea 100644
--- a/def/esprima.js
+++ b/def/esprima.js
@@ -1,104 +1,72 @@
 module.exports = function (fork) {
-    fork.use(require("./es7"));
+  fork.use(require("./es7"));
 
-    var types = fork.use(require("../lib/types"));
-    var defaults = fork.use(require("../lib/shared")).defaults;
-    var def = types.Type.def;
-    var or = types.Type.or;
+  var types = fork.use(require("../lib/types"));
+  var defaults = fork.use(require("../lib/shared")).defaults;
+  var def = types.Type.def;
+  var or = types.Type.or;
 
-    def("VariableDeclaration")
-      .field("declarations", [or(
-        def("VariableDeclarator"),
-        def("Identifier") // Esprima deviation.
-      )]);
+  def("VariableDeclaration")
+    .field("declarations", [or(
+      def("VariableDeclarator"),
+      def("Identifier") // Esprima deviation.
+    )]);
 
-    def("Property")
-      .field("value", or(
-        def("Expression"),
-        def("Pattern") // Esprima deviation.
-      ));
+  def("Property")
+    .field("value", or(
+      def("Expression"),
+      def("Pattern") // Esprima deviation.
+    ));
 
-    def("ArrayPattern")
-      .field("elements", [or(
-        def("Pattern"),
-        def("SpreadElement"),
-        null
-      )]);
+  def("ArrayPattern")
+    .field("elements", [or(
+      def("Pattern"),
+      def("SpreadElement"),
+      null
+    )]);
 
-    def("ObjectPattern")
-      .field("properties", [or(
-        def("Property"),
-        def("PropertyPattern"),
-        def("SpreadPropertyPattern"),
-        def("SpreadProperty") // Used by Esprima.
-      )]);
+  def("ObjectPattern")
+    .field("properties", [or(
+      def("Property"),
+      def("PropertyPattern"),
+      def("SpreadPropertyPattern"),
+      def("SpreadProperty") // Used by Esprima.
+    )]);
 
-// Like ModuleSpecifier, except type:"ExportSpecifier" and buildable.
-// export {<id [as name]>} [from ...];
-    def("ExportSpecifier")
-      .bases("ModuleSpecifier")
-      .build("id", "name");
+  // Like ModuleSpecifier, except type:"ExportSpecifier" and buildable.
+  // export {<id [as name]>} [from ...];
+  def("ExportSpecifier")
+    .bases("ModuleSpecifier")
+    .build("id", "name");
 
-// export <*> from ...;
-    def("ExportBatchSpecifier")
-      .bases("Specifier")
-      .build();
+  // export <*> from ...;
+  def("ExportBatchSpecifier")
+    .bases("Specifier")
+    .build();
 
-// Like ModuleSpecifier, except type:"ImportSpecifier" and buildable.
-// import {<id [as name]>} from ...;
-    def("ImportSpecifier")
-      .bases("ModuleSpecifier")
-      .build("id", "name");
+  def("ExportDeclaration")
+    .bases("Declaration")
+    .build("default", "declaration", "specifiers", "source")
+    .field("default", Boolean)
+    .field("declaration", or(
+      def("Declaration"),
+      def("Expression"), // Implies default.
+      null
+    ))
+    .field("specifiers", [or(
+      def("ExportSpecifier"),
+      def("ExportBatchSpecifier")
+    )], defaults.emptyArray)
+    .field("source", or(
+      def("Literal"),
+      null
+    ), defaults["null"]);
 
-// import <* as id> from ...;
-    def("ImportNamespaceSpecifier")
-      .bases("ModuleSpecifier")
-      .build("id");
+  def("Block")
+    .bases("Comment")
+    .build("value", /*optional:*/ "leading", "trailing");
 
-// import <id> from ...;
-    def("ImportDefaultSpecifier")
-      .bases("ModuleSpecifier")
-      .build("id");
-
-    def("ExportDeclaration")
-      .bases("Declaration")
-      .build("default", "declaration", "specifiers", "source")
-      .field("default", Boolean)
-      .field("declaration", or(
-        def("Declaration"),
-        def("Expression"), // Implies default.
-        null
-      ))
-      .field("specifiers", [or(
-        def("ExportSpecifier"),
-        def("ExportBatchSpecifier")
-      )], defaults.emptyArray)
-      .field("source", or(
-        def("Literal"),
-        null
-      ), defaults["null"]);
-
-    def("ImportDeclaration")
-      .bases("Declaration")
-      .build("specifiers", "source", "importKind")
-      .field("specifiers", [or(
-        def("ImportSpecifier"),
-        def("ImportNamespaceSpecifier"),
-        def("ImportDefaultSpecifier")
-      )], defaults.emptyArray)
-      .field("source", def("Literal"))
-      .field("importKind", or(
-        "value",
-        "type"
-      ), function() {
-        return "value";
-      });
-
-    def("Block")
-      .bases("Comment")
-      .build("value", /*optional:*/ "leading", "trailing");
-
-    def("Line")
-      .bases("Comment")
-      .build("value", /*optional:*/ "leading", "trailing");
-};
\ No newline at end of file
+  def("Line")
+    .bases("Comment")
+    .build("value", /*optional:*/ "leading", "trailing");
+};
diff --git a/def/flow.js b/def/flow.js
index d78fd63..140347d 100644
--- a/def/flow.js
+++ b/def/flow.js
@@ -242,11 +242,34 @@ module.exports = function (fork) {
     .field("static", Boolean, defaults["false"])
     .field("variance", LegacyVariance, defaults["null"]);
 
+  ["ClassDeclaration",
+   "ClassExpression",
+  ].forEach(typeName => {
+    def(typeName)
+      .field("typeParameters",
+             or(def("TypeParameterDeclaration"), null),
+             defaults["null"])
+      .field("superTypeParameters",
+             or([def("GenericTypeAnnotation")], null),
+             defaults["null"]);
+  });
+
   def("ClassImplements")
+    .bases("Node")
+    .build("id")
+    .field("id", def("Identifier"))
+    .field("superClass", or(def("Expression"), null), defaults["null"])
     .field("typeParameters",
            or(def("TypeParameterInstantiation"), null),
            defaults["null"]);
 
+  ["ClassDeclaration",
+   "ClassExpression",
+  ].forEach(typeName => {
+    def(typeName)
+      .field("implements", [def("ClassImplements")], defaults.emptyArray);
+  });
+
   def("InterfaceDeclaration")
     .bases("Declaration")
     .build("id", "body", "extends")
diff --git a/def/jsx.js b/def/jsx.js
index 2494eb2..4943593 100644
--- a/def/jsx.js
+++ b/def/jsx.js
@@ -63,6 +63,7 @@ module.exports = function (fork) {
     .field("children", [or(
       def("JSXElement"),
       def("JSXExpressionContainer"),
+      def("JSXFragment"),
       def("JSXText"),
       def("Literal") // TODO Esprima should return JSXText instead.
     )], defaults.emptyArray)
@@ -93,6 +94,27 @@ module.exports = function (fork) {
     .build("name")
     .field("name", JSXElementName);
 
+  def("JSXFragment")
+    .bases("Expression")
+    .build("openingElement", "closingElement", "children")
+    .field("openingElement", def("JSXOpeningFragment"))
+    .field("closingElement", def("JSXClosingFragment"))
+    .field("children", [or(
+      def("JSXElement"),
+      def("JSXExpressionContainer"),
+      def("JSXFragment"),
+      def("JSXText"),
+      def("Literal") // TODO Esprima should return JSXText instead.
+    )], defaults.emptyArray)
+
+  def("JSXOpeningFragment")
+    .bases("Node") // TODO Same concern.
+    .build();
+
+  def("JSXClosingFragment")
+    .bases("Node") // TODO Same concern.
+    .build();
+
   def("JSXText")
     .bases("Literal")
     .build("value")
diff --git a/def/typescript.js b/def/typescript.js
new file mode 100644
index 0000000..6d77165
--- /dev/null
+++ b/def/typescript.js
@@ -0,0 +1,432 @@
+module.exports = function (fork) {
+  // Since TypeScript is parsed by Babylon, include the core Babylon types
+  // but omit the Flow-related types.
+  fork.use(require("./babel-core"));
+
+  var types = fork.use(require("../lib/types"));
+  var n = types.namedTypes;
+  var def = types.Type.def;
+  var or = types.Type.or;
+  var defaults = fork.use(require("../lib/shared")).defaults;
+  var StringLiteral = new types.Type(function (value, deep) {
+    if (n.StringLiteral &&
+        n.StringLiteral.check(value, deep)) {
+      return true
+    }
+    if (n.Literal &&
+        n.Literal.check(value, deep) &&
+        typeof value.value === "string") {
+      return true;
+    }
+    return false;
+  }, "StringLiteral");
+
+  def("TSType")
+    .bases("Node");
+
+  var IdOrQualifiedName = or(
+    def("Identifier"),
+    def("TSQualifiedName")
+  );
+
+  def("TSTypeReference")
+    .bases("TSType")
+    .field("typeName", IdOrQualifiedName)
+    .field("typeParameters",
+           or(def("TSTypeParameterInstantiation"), null),
+           defaults["null"]);
+
+  // An abstract (non-buildable) base type that provide a commonly-needed
+  // optional .typeParameters field.
+  def("TSHasOptionalTypeParameters")
+    .field("typeParameters",
+           or(def("TSTypeParameterDeclaration"), null),
+           defaults["null"]);
+
+  // An abstract (non-buildable) base type that provide a commonly-needed
+  // optional .typeAnnotation field.
+  def("TSHasOptionalTypeAnnotation")
+    .field("typeAnnotation",
+           or(def("TSTypeAnnotation"), null),
+           defaults["null"]);
+
+  def("TSQualifiedName")
+    .bases("Node")
+    .build("left", "right")
+    .field("left", IdOrQualifiedName)
+    .field("right", IdOrQualifiedName);
+
+  def("TSAsExpression")
+    .bases("Expression")
+    .build("expression")
+    .field("expression", def("Expression"))
+    .field("typeAnnotation", def("TSType"))
+    .field("extra",
+           or({ parenthesized: Boolean }, null),
+           defaults["null"]);
+
+  def("TSNonNullExpression")
+    .bases("Expression")
+    .build("expression")
+    .field("expression", def("Expression"));
+
+  [ // Define all the simple keyword types.
+    "TSAnyKeyword",
+    "TSBooleanKeyword",
+    "TSNeverKeyword",
+    "TSNullKeyword",
+    "TSNumberKeyword",
+    "TSObjectKeyword",
+    "TSStringKeyword",
+    "TSSymbolKeyword",
+    "TSUndefinedKeyword",
+    "TSVoidKeyword",
+    "TSThisType",
+  ].forEach(keywordType => {
+    def(keywordType)
+      .bases("TSType")
+      .build();
+  });
+
+  def("TSArrayType")
+    .bases("TSType")
+    .build("elementType")
+    .field("elementType", def("TSType"))
+
+  def("TSLiteralType")
+    .bases("TSType")
+    .build("literal")
+    .field("literal",
+           or(def("NumericLiteral"),
+              def("StringLiteral"),
+              def("BooleanLiteral")));
+
+  ["TSUnionType",
+   "TSIntersectionType",
+  ].forEach(typeName => {
+    def(typeName)
+      .bases("TSType")
+      .build("types")
+      .field("types", [def("TSType")]);
+  });
+
+  def("TSParenthesizedType")
+    .bases("TSType")
+    .build("typeAnnotation")
+    .field("typeAnnotation", def("TSType"));
+
+  var ParametersType = [or(
+    def("Identifier"),
+    def("RestElement")
+  )];
+
+  ["TSFunctionType",
+   "TSConstructorType",
+  ].forEach(typeName => {
+    def(typeName)
+      .bases("TSType",
+             "TSHasOptionalTypeParameters",
+             "TSHasOptionalTypeAnnotation")
+      .build("parameters")
+      .field("parameters", ParametersType);
+  });
+
+  def("TSDeclareFunction")
+    .bases("Declaration", "TSHasOptionalTypeParameters")
+    .build("id", "params", "returnType")
+    .field("declare", Boolean, defaults["false"])
+    .field("async", Boolean, defaults["false"])
+    .field("generator", Boolean, defaults["false"])
+    .field("id", or(def("Identifier"), null), defaults["null"])
+    .field("params", [def("Pattern")])
+    // tSFunctionTypeAnnotationCommon
+    .field("returnType",
+           or(def("TSTypeAnnotation"),
+              def("Noop"), // Still used?
+              null),
+           defaults["null"]);
+
+  def("TSDeclareMethod")
+    .bases("Declaration", "TSHasOptionalTypeParameters")
+    .build("key", "params", "returnType")
+    .field("async", Boolean, defaults["false"])
+    .field("generator", Boolean, defaults["false"])
+    .field("params", [def("Pattern")])
+    // classMethodOrPropertyCommon
+    .field("abstract", Boolean, defaults["false"])
+    .field("accessibility",
+           or("public", "private", "protected", void 0),
+           defaults["undefined"])
+    .field("static", Boolean, defaults["false"])
+    .field("computed", Boolean, defaults["false"])
+    .field("optional", Boolean, defaults["false"])
+    .field("key", or(
+      def("Identifier"),
+      def("StringLiteral"),
+      def("NumericLiteral"),
+      // Only allowed if .computed is true.
+      def("Expression")
+    ))
+    // classMethodOrDeclareMethodCommon
+    .field("kind",
+           or("get", "set", "method", "constructor"),
+           function getDefault() { return "method"; })
+    .field("access", // Not "accessibility"?
+           or("public", "private", "protected", void 0),
+           defaults["undefined"])
+    .field("decorators",
+           or([def("Decorator")], null),
+           defaults["null"])
+    // tSFunctionTypeAnnotationCommon
+    .field("returnType",
+           or(def("TSTypeAnnotation"),
+              def("Noop"), // Still used?
+              null),
+           defaults["null"]);
+
+  def("TSMappedType")
+    .bases("TSType")
+    .build("typeParameter", "typeAnnotation")
+    .field("readonly", Boolean, defaults["false"])
+    .field("typeParameter", def("TSTypeParameter"))
+    .field("optional", Boolean, defaults["false"])
+    .field("typeAnnotation",
+           or(def("TSType"), null),
+           defaults["null"]);
+
+  def("TSTupleType")
+    .bases("TSType")
+    .build("elementTypes")
+    .field("elementTypes", [def("TSType")]);
+
+  def("TSIndexedAccessType")
+    .bases("TSType")
+    .build("objectType", "indexType")
+    .field("objectType", def("TSType"))
+    .field("indexType", def("TSType"))
+
+  def("TSTypeOperator")
+    .bases("TSType")
+    .build("operator")
+    .field("operator", String)
+    .field("typeAnnotation", def("TSType"));
+
+  def("TSTypeAnnotation")
+    .bases("Node")
+    .build("typeAnnotation")
+    .field("typeAnnotation",
+           or(def("TSType"),
+              def("TSTypeAnnotation")));
+
+  def("TSIndexSignature")
+    .bases("Declaration", "TSHasOptionalTypeAnnotation")
+    .build("parameters")
+    .field("parameters", [def("Identifier")]) // Length === 1
+    .field("readonly", Boolean, defaults["false"]);
+
+  def("TSPropertySignature")
+    .bases("Declaration", "TSHasOptionalTypeAnnotation")
+    .build("key")
+    .field("key", def("Expression"))
+    .field("computed", Boolean, defaults["false"])
+    .field("readonly", Boolean, defaults["false"])
+    .field("optional", Boolean, defaults["false"])
+    .field("initializer",
+           or(def("Expression"), null),
+           defaults["null"]);
+
+  def("TSMethodSignature")
+    .bases("Declaration",
+           "TSHasOptionalTypeParameters",
+           "TSHasOptionalTypeAnnotation")
+    .build("key")
+    .field("key", def("Expression"))
+    .field("computed", Boolean, defaults["false"])
+    .field("optional", Boolean, defaults["false"])
+    .field("parameters", ParametersType);
+
+  def("TSTypePredicate")
+    .bases("TSTypeAnnotation")
+    .build("parameterName", "typeAnnotation")
+    .field("parameterName",
+           or(def("Identifier"),
+              def("TSThisType")))
+    .field("typeAnnotation", def("TSTypeAnnotation"));
+
+  ["TSCallSignatureDeclaration",
+   "TSConstructSignatureDeclaration",
+  ].forEach(typeName => {
+    def(typeName)
+      .bases("Declaration",
+             "TSHasOptionalTypeParameters",
+             "TSHasOptionalTypeAnnotation")
+      .build("parameters")
+      .field("parameters", ParametersType);
+  });
+
+  def("TSEnumMember")
+    .bases("Node")
+    .build("id", "initializer")
+    .field("id", or(def("Identifier"), StringLiteral))
+    .field("initializer",
+           or(def("Expression"), null),
+           defaults["null"]);
+
+  def("TSTypeQuery")
+    .bases("TSType")
+    .build("exprName")
+    .field("exprName", def("Identifier"));
+
+  // Inferred from Babylon's tsParseTypeMember method.
+  var TSTypeMember = or(
+    def("TSCallSignatureDeclaration"),
+    def("TSConstructSignatureDeclaration"),
+    def("TSIndexSignature"),
+    def("TSMethodSignature"),
+    def("TSPropertySignature")
+  );
+
+  def("TSTypeLiteral")
+    .bases("TSType")
+    .build("members")
+    .field("members", [TSTypeMember]);
+
+  def("TSTypeParameter")
+    .bases("Identifier")
+    .field("name", String)
+    .field("constraint", or(def("TSType"), null), defaults["null"])
+    .field("default", or(def("TSType"), null), defaults["null"]);
+
+  def("TSTypeAssertion")
+    .bases("Expression")
+    .build("typeAnnotation", "expression")
+    .field("typeAnnotation", def("TSType"))
+    .field("expression", def("Expression"))
+    .field("extra",
+           or({ parenthesized: Boolean }, null),
+           defaults["null"]);
+
+  def("TSTypeParameterDeclaration")
+    .bases("Declaration")
+    .build("params")
+    .field("params", [def("TSTypeParameter")]);
+
+  def("TSTypeParameterInstantiation")
+    .bases("Node")
+    .build("params")
+    .field("params", [def("TSType")]);
+
+  def("TSEnumDeclaration")
+    .bases("Declaration")
+    .build("id", "members")
+    .field("id", def("Identifier"))
+    .field("const", Boolean, defaults["false"])
+    .field("declare", Boolean, defaults["false"])
+    .field("members", [def("TSEnumMember")])
+    .field("initializer",
+           or(def("Expression"), null),
+           defaults["null"]);
+
+  def("TSTypeAliasDeclaration")
+    .bases("Declaration", "TSHasOptionalTypeParameters")
+    .build("id")
+    .field("id", def("Identifier"))
+    .field("declare", Boolean, defaults["false"])
+    .field("typeAnnotation", def("TSType"));
+
+  def("TSModuleBlock")
+    .bases("Node")
+    .build("body")
+    .field("body", [def("Statement")]);
+
+  def("TSModuleDeclaration")
+    .bases("Declaration")
+    .build("id", "body")
+    .field("id", or(StringLiteral, IdOrQualifiedName))
+    .field("declare", Boolean, defaults["false"])
+    .field("global", Boolean, defaults["false"])
+    .field("body",
+           or(def("TSModuleBlock"),
+              def("TSModuleDeclaration"),
+              null),
+           defaults["null"]);
+
+  def("TSImportEqualsDeclaration")
+    .bases("Declaration")
+    .build("id", "moduleReference")
+    .field("id", def("Identifier"))
+    .field("isExport", Boolean, defaults["false"])
+    .field("moduleReference",
+           or(IdOrQualifiedName,
+              def("TSExternalModuleReference")));
+
+  def("TSExternalModuleReference")
+    .bases("Declaration")
+    .build("expression")
+    .field("expression", StringLiteral);
+
+  def("TSExportAssignment")
+    .bases("Statement")
+    .build("expression")
+    .field("expression", def("Expression"));
+
+  def("TSNamespaceExportDeclaration")
+    .bases("Declaration")
+    .build("id")
+    .field("id", def("Identifier"));
+
+  def("TSInterfaceBody")
+    .bases("Node")
+    .build("body")
+    .field("body", [TSTypeMember]);
+
+  def("TSExpressionWithTypeArguments")
+    .bases("TSType")
+    .build("expression", "typeParameters")
+    .field("expression", IdOrQualifiedName)
+    .field("typeParameters",
+           or(def("TSTypeParameterInstantiation"), null),
+           defaults["null"]);
+
+  def("TSInterfaceDeclaration")
+    .bases("Declaration", "TSHasOptionalTypeParameters")
+    .build("id", "body")
+    .field("id", IdOrQualifiedName)
+    .field("declare", Boolean, defaults["false"])
+    .field("extends",
+           or([def("TSExpressionWithTypeArguments")], null),
+           defaults["null"])
+    .field("body", def("TSInterfaceBody"));
+
+  ["ClassDeclaration",
+   "ClassExpression",
+  ].forEach(typeName => {
+    def(typeName)
+      .field("implements",
+             [def("TSExpressionWithTypeArguments")],
+             defaults.emptyArray);
+  });
+
+  def("TSParameterProperty")
+    .bases("Pattern")
+    .build("parameter")
+    .field("accessibility",
+           or("public", "private", "protected", void 0),
+           defaults["undefined"])
+    .field("readonly", Boolean, defaults["false"])
+    .field("parameter", or(def("Identifier"),
+                           def("AssignmentPattern")));
+
+  // Defined already in es6 and babel-core.
+  def("ClassBody")
+    .field("body", [or(
+      def("MethodDefinition"),
+      def("VariableDeclarator"),
+      def("ClassPropertyDefinition"),
+      def("ClassProperty"),
+      def("ClassMethod"),
+      // Just need to add these types:
+      def("TSDeclareMethod"),
+      TSTypeMember
+    )]);
+};
diff --git a/lib/scope.js b/lib/scope.js
index 52b7331..84e668f 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -274,6 +274,10 @@ module.exports = function (fork) {
                 bindings[pattern.name] = [patternPath];
             }
 
+        } else if (namedTypes.AssignmentPattern &&
+          namedTypes.AssignmentPattern.check(pattern)) {
+          addPattern(patternPath.get('left'), bindings);
+
         } else if (namedTypes.ObjectPattern &&
           namedTypes.ObjectPattern.check(pattern)) {
             patternPath.get('properties').each(function(propertyPath) {
diff --git a/main.js b/main.js
index 47d6c56..ef541bb 100644
--- a/main.js
+++ b/main.js
@@ -12,5 +12,6 @@ module.exports = require('./fork')([
   require("./def/jsx"),
   require("./def/flow"),
   require("./def/esprima"),
-  require("./def/babel")
+  require("./def/babel"),
+  require("./def/typescript")
 ]);
diff --git a/package-lock.json b/package-lock.json
index 4e0d67c..0075e5b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,13 +1,13 @@
 {
   "name": "ast-types",
-  "version": "0.10.1",
+  "version": "0.11.1",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
     "acorn": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
-      "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==",
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",
+      "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==",
       "dev": true
     },
     "acorn-jsx": {
@@ -33,8 +33,8 @@
       "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
       "dev": true,
       "requires": {
-        "core-js": "2.5.1",
-        "regenerator-runtime": "0.11.0"
+        "core-js": "2.5.3",
+        "regenerator-runtime": "0.11.1"
       }
     },
     "babel-types": {
@@ -45,14 +45,14 @@
       "requires": {
         "babel-runtime": "6.26.0",
         "esutils": "2.0.2",
-        "lodash": "4.17.4",
+        "lodash": "4.17.5",
         "to-fast-properties": "1.0.3"
       }
     },
     "babylon": {
-      "version": "7.0.0-beta.31",
-      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz",
-      "integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==",
+      "version": "7.0.0-beta.40",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.40.tgz",
+      "integrity": "sha512-AVxF2EcxvGD5hhOuLTOLAXBb0VhwWpEX0HyHdAI2zU+AAP4qEwtQj8voz1JR3uclGai0rfcE+dCTHnNMOnimFg==",
       "dev": true
     },
     "balanced-match": {
@@ -62,9 +62,9 @@
       "dev": true
     },
     "brace-expansion": {
-      "version": "1.1.8",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
-      "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
       "dev": true,
       "requires": {
         "balanced-match": "1.0.0",
@@ -90,9 +90,9 @@
       "dev": true
     },
     "core-js": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
-      "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",
+      "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=",
       "dev": true
     },
     "debug": {
@@ -117,12 +117,12 @@
       "dev": true
     },
     "espree": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
-      "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.3.tgz",
+      "integrity": "sha512-Zy3tAJDORxQZLl2baguiRU1syPERAIg0L+JB2MWorORgTu/CplzvxS9WWA7Xh4+Q+eOQihNs/1o1Xep8cvCxWQ==",
       "dev": true,
       "requires": {
-        "acorn": "5.2.1",
+        "acorn": "5.4.1",
         "acorn-jsx": "3.0.1"
       }
     },
@@ -144,6 +144,12 @@
       "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
       "dev": true
     },
+    "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
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -199,9 +205,9 @@
       "dev": true
     },
     "lodash": {
-      "version": "4.17.4",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
-      "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+      "version": "4.17.5",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
+      "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
       "dev": true
     },
     "minimatch": {
@@ -210,7 +216,7 @@
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
       "dev": true,
       "requires": {
-        "brace-expansion": "1.1.8"
+        "brace-expansion": "1.1.11"
       }
     },
     "minimist": {
@@ -229,9 +235,9 @@
       }
     },
     "minizlib": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.0.4.tgz",
-      "integrity": "sha512-sN4U9tIJtBRwKbwgFh9qJfrPIQ/GGTRr1MGqkgOeMTLy8/lM0FcWU//FqlnZ3Vb7gJ+Mxh3FOg1EklibdajbaQ==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
+      "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
       "dev": true,
       "requires": {
         "minipass": "2.2.1"
@@ -247,9 +253,9 @@
       }
     },
     "mocha": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz",
-      "integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz",
+      "integrity": "sha512-SpwyojlnE/WRBNGtvJSNfllfm5PqEDFxcWluSIgLeSBJtXG4DmoX2NNAeEA7rP5kK+79VgtVq8nG6HskaL1ykg==",
       "dev": true,
       "requires": {
         "browser-stdout": "1.3.0",
@@ -286,34 +292,26 @@
       "dev": true
     },
     "regenerator-runtime": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
-      "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==",
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
       "dev": true
     },
     "reify": {
-      "version": "0.12.3",
-      "resolved": "https://registry.npmjs.org/reify/-/reify-0.12.3.tgz",
-      "integrity": "sha512-s13k0kuZbhBzeRoJQGomWnLj2y10wK3FYXRXbZoydowAMmY0jTiFN98TgLkaE8uZkVCaoq3djnDo7mksWLsx4g==",
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/reify/-/reify-0.14.1.tgz",
+      "integrity": "sha512-HAKYzqlCCWsfAcOTm8gsJZ6FE5I06kvjzHRQTCDD6xqUJaY8Mh4ve9oiCDe8yiYXOqZqpt03gn8yS4+bokRmhQ==",
       "dev": true,
       "requires": {
-        "acorn": "5.1.2",
-        "minizlib": "1.0.4",
-        "semver": "5.4.1"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz",
-          "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==",
-          "dev": true
-        }
+        "acorn": "5.4.1",
+        "minizlib": "1.1.0",
+        "semver": "5.5.0"
       }
     },
     "semver": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
-      "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
       "dev": true
     },
     "supports-color": {
diff --git a/package.json b/package.json
index 8b92b08..9499dc4 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
     "transformation",
     "syntax"
   ],
-  "version": "0.10.1",
+  "version": "0.11.1",
   "homepage": "http://github.com/benjamn/ast-types",
   "repository": {
     "type": "git",
@@ -27,17 +27,19 @@
   "license": "MIT",
   "main": "main.js",
   "scripts": {
-    "test": "mocha --reporter spec --full-trace test/run.js"
+    "test": "test/run.sh"
   },
   "dependencies": {},
   "devDependencies": {
     "babel-types": "^6.26.0",
-    "babylon": "^7.0.0-beta.31",
+    "babylon": "^7.0.0-beta.40",
     "espree": "^3.1.7",
     "esprima": "~4.0.0",
     "esprima-fb": "~14001.1.0-dev-harmony-fb",
-    "mocha": "^4.0.1",
-    "reify": "^0.12.0"
+    "flow-parser": "^0.66.0",
+    "glob": "^7.1.2",
+    "mocha": "^5.0.0",
+    "reify": "^0.14.1"
   },
   "engines": {
     "node": ">= 0.8"
diff --git a/test/run.js b/test/ecmascript.js
similarity index 97%
copy from test/run.js
copy to test/ecmascript.js
index bcf5b2c..83692a7 100644
--- a/test/run.js
+++ b/test/ecmascript.js
@@ -5,6 +5,7 @@ var b = types.builders;
 var path = require("path");
 var fs = require("fs");
 var parse = require("esprima").parse;
+var shared = require("./shared.js");
 var Path = types.Path;
 var NodePath = types.NodePath;
 var PathVisitor = types.PathVisitor;
@@ -15,13 +16,6 @@ var rawTypes = types.use(require("../lib/types"));
 
 var hasOwn = Object.prototype.hasOwnProperty;
 
-var reifyBabylonParse = require("reify/lib/parsers/babylon.js").parse;
-function babylonParse(source) {
-  var ast = reifyBabylonParse(source);
-  if (ast.type === "File") ast = ast.program;
-  return ast;
-}
-
 describe("basic type checking", function() {
   var fooId = b.identifier("foo");
   var ifFoo = b.ifStatement(fooId, b.blockStatement([
@@ -190,42 +184,17 @@ describe("shallow and deep checks", function() {
   });
 });
 
-function validateProgram(file) {
-  var fullPath = path.join(__dirname, "..", file);
-
-  it("should validate " + file + " with Esprima", function(done) {
-    var parse = require("esprima").parse;
-
-    fs.readFile(fullPath, "utf8", function(err, code) {
-      if (err) throw err;
-
-      n.Program.assert(parse(code), true);
-      n.Program.assert(parse(code, { loc: true }), true);
-
-      done();
-    });
-  });
-
-  it("should validate " + file + " with Babel", function(done) {
-    fs.readFile(fullPath, "utf8", function(err, code) {
-      if (err) throw err;
-      var ast = babylonParse(code);
-      n.Program.assert(ast, true);
-      done();
-    });
-  });
-}
 
 describe("whole-program validation", function() {
   this.timeout(20000);
 
-  validateProgram("main.js");
-  validateProgram("lib/shared.js");
-  validateProgram("def/core.js");
-  validateProgram("lib/types.js");
-  validateProgram("test/run.js");
-  validateProgram("test/data/backbone.js");
-  validateProgram("test/data/jquery-1.9.1.js");
+  shared.validateECMAScript("main.js");
+  shared.validateECMAScript("lib/shared.js");
+  shared.validateECMAScript("def/core.js");
+  shared.validateECMAScript("lib/types.js");
+  shared.validateECMAScript("test/run.js");
+  shared.validateECMAScript("test/data/backbone.js");
+  shared.validateECMAScript("test/data/jquery-1.9.1.js");
 });
 
 describe("esprima Syntax types", function() {
@@ -1121,7 +1090,7 @@ describe("scope methods", function () {
   });
 
   it("getBindings should work for import statements (acorn)", function() {
-    var ast = babylonParse([
+    var ast = shared.babylonParse([
       "import {x, y as z} from 'xy';",
       "import xyDefault from 'xy';",
       "import * as xyNamespace from 'xy';"
@@ -2203,10 +2172,7 @@ describe("BigIntLiteral nodes", function () {
     ]);
     var n = types.namedTypes;
     var BigIntLiteral = n.BigIntLiteral;
-    var parse = require("babylon").parse;
-    var parseOptions = {
-      plugins: ["bigInt"]
-    };
+    var parse = shared.babylonParse;
 
     function check(code) {
       parseAndCheck(code);
@@ -2215,8 +2181,8 @@ describe("BigIntLiteral nodes", function () {
     }
 
     function parseAndCheck(code) {
-      var file = parse(code, parseOptions);
-      var exp = file.program.body[0].expression;
+      var program = shared.babylonParse(code);
+      var exp = program.body[0].expression;
       if (n.UnaryExpression.check(exp)) {
         checkExp(exp.argument);
       } else {
diff --git a/test/flow.js b/test/flow.js
new file mode 100644
index 0000000..be0fcad
--- /dev/null
+++ b/test/flow.js
@@ -0,0 +1,44 @@
+var assert = require("assert");
+var types = require("../fork.js")([
+  require("../def/flow"),
+]);
+
+describe("flow types", function () {
+  it("issue #242", function () {
+    const parser = {
+      parse(code) {
+        return require('flow-parser').parse(code, {
+          types: true
+        });
+      }
+    };
+
+    const program = parser.parse([
+      "class A<B> extends C<D> {}",
+      "function f<E>() {}",
+    ].join("\n"));
+
+    const typeParam = program.body[0].typeParameters.params[0];
+    const superTypeParam =
+      program.body[0].superTypeParameters.params[0].id;
+    const functionTypeParam = program.body[1].typeParameters.params[0];
+
+    const identifierNames = [];
+    const typeParamNames = []
+
+    types.visit(program, {
+      visitIdentifier(path) {
+        identifierNames.push(path.node.name);
+        this.traverse(path);
+      },
+
+      visitTypeParameter(path) {
+        typeParamNames.push(path.node.name);
+        this.traverse(path);
+      }
+    });
+
+    assert.deepEqual(identifierNames, ["A", "C", "D", "f"]);
+    assert.deepEqual(typeParamNames, ["B", "E"]);
+  })
+});
diff --git a/test/run.js b/test/run.js
index bcf5b2c..fbdd21d 100644
--- a/test/run.js
+++ b/test/run.js
@@ -1,2323 +1,3 @@
-var assert = require("assert");
-var types = require("../main");
-var n = types.namedTypes;
-var b = types.builders;
-var path = require("path");
-var fs = require("fs");
-var parse = require("esprima").parse;
-var Path = types.Path;
-var NodePath = types.NodePath;
-var PathVisitor = types.PathVisitor;
-var builtin = types.builtInTypes;
-var isRegExp = builtin.RegExp;
-var isString = builtin.string;
-var rawTypes = types.use(require("../lib/types"));
-
-var hasOwn = Object.prototype.hasOwnProperty;
-
-var reifyBabylonParse = require("reify/lib/parsers/babylon.js").parse;
-function babylonParse(source) {
-  var ast = reifyBabylonParse(source);
-  if (ast.type === "File") ast = ast.program;
-  return ast;
-}
-
-describe("basic type checking", function() {
-  var fooId = b.identifier("foo");
-  var ifFoo = b.ifStatement(fooId, b.blockStatement([
-    b.expressionStatement(b.callExpression(fooId, []))
-  ]));
-
-  it("should exhibit sanity", function() {
-    assert.ok(n.IfStatement.check(ifFoo));
-    assert.ok(n.Statement.check(ifFoo));
-    assert.ok(n.Node.check(ifFoo));
-
-    assert.ok(n.BlockStatement.check(ifFoo.consequent));
-    assert.strictEqual(
-      ifFoo.consequent.body[0].expression.arguments.length,
-      0);
-
-    assert.strictEqual(ifFoo.test, fooId);
-    assert.ok(n.Expression.check(ifFoo.test));
-    assert.ok(n.Identifier.check(ifFoo.test));
-    assert.ok(!n.Statement.check(ifFoo.test));
-    assert.equal(
-      b.importDeclaration(
-        [b.importDefaultSpecifier(b.identifier("foo"))], b.literal("bar")
-      ).importKind,
-      "value"
-    );
-    assert.throws(function () {
-      b.importDeclaration(
-        [b.importDefaultSpecifier(b.identifier("foo"))],
-        b.literal("bar"),
-        "baz"
-      )
-    });
-    assert.ok(n.ImportDeclaration.check(
-      b.importDeclaration(
-        [b.importDefaultSpecifier(b.identifier("foo"))], b.literal("bar"),
-        "type")
-    ));
-    assert.ok(n.ImportDeclaration.check(
-      b.importDeclaration(
-        [b.importNamespaceSpecifier(b.identifier("foo"))], b.literal("bar"))
-    ));
-  });
-});
-
-describe("isSupertypeOf", function() {
-  it("should report correct supertype relationships", function() {
-    var def = types.Type.def;
-
-    assert.ok(def("Node").isSupertypeOf(def("Node")));
-    assert.ok(def("Node").isSupertypeOf(def("Expression")));
-    assert.ok(!def("Expression").isSupertypeOf(def("Node")));
-    assert.ok(!def("Expression").isSupertypeOf(
-      def("DebuggerStatement")));
-
-    // TODO Make this test case more exhaustive.
-  });
-});
-
-describe("supertype lookup", function() {
-  it("should resolve the most precise supertypes", function() {
-    var table = types.use(require("../lib/types")).computeSupertypeLookupTable({
-      Function: true,
-      Declaration: true,
-      ArrowFunctionExpression: true,
-      Expression: true,
-      Identifier: true
-    });
-
-    function check(subtype, expectedSupertype) {
-      assert.strictEqual(table[subtype], expectedSupertype);
-    }
-
-    check("FunctionExpression", "Function");
-    check("FunctionDeclaration", "Function");
-    check("VariableDeclaration", "Declaration");
-    check("Identifier", "Identifier");
-    check("ArrowFunctionExpression", "ArrowFunctionExpression");
-    check("ForInStatement");
-    check("Node");
-    check("ThisExpression", "Expression");
-    check("Property");
-  });
-
-  it("should properly linearize the inheritance hierarchy", function() {
-    assert.deepEqual(
-      types.getSupertypeNames("FunctionExpression"),
-      ["Function", "Expression", "Pattern", "Node", "Printable"]
-    );
-  });
-
-  it("should trigger an AssertionError for unknown types", function() {
-    assert.throws(function() {
-      types.getSupertypeNames("AlienBoomerangDeclaration");
-    });
-  });
-});
-
-describe("shallow and deep checks", function() {
-  var index = b.identifier("foo");
-  var decl = b.variableDeclaration("var", [
-    b.variableDeclarator(
-      index,
-      b.literal(42)
-    )
-  ]);
-
-  it("should work when shallow", function() {
-    assert.ok(n.Node.check(decl));
-    assert.ok(n.Statement.check(decl));
-    assert.ok(n.Declaration.check(decl));
-    assert.ok(n.VariableDeclaration.check(decl));
-  });
-
-  it("should work when deep", function() {
-    assert.ok(n.Node.check(decl, true));
-    assert.ok(n.Statement.check(decl, true));
-    assert.ok(n.Declaration.check(decl, true));
-    assert.ok(n.VariableDeclaration.check(decl, true));
-  });
-
-  it("should fail when expected", function() {
-    // Not an Expression.
-    assert.ok(!n.Expression.check(decl));
-
-    // This makes decl cease to conform to n.VariableDeclaration.
-    decl.declarations.push(b.literal("bar"));
-
-    assert.ok(n.Node.check(decl));
-    assert.ok(n.Statement.check(decl));
-    assert.ok(n.Declaration.check(decl));
-    assert.ok(n.VariableDeclaration.check(decl));
-
-    assert.ok(!n.Node.check(decl, true));
-    assert.ok(!n.Statement.check(decl, true));
-    assert.ok(!n.Declaration.check(decl, true));
-
-    // As foretold above.
-    assert.ok(!n.VariableDeclaration.check(decl, true));
-
-    // Still not an Expression.
-    assert.ok(!n.Expression.check(decl));
-  });
-
-  var fs = b.forStatement(
-    decl,
-    b.binaryExpression("<", index, b.literal(48)),
-    b.updateExpression("++", index, true),
-    b.blockStatement([
-      b.expressionStatement(
-        b.callExpression(index, [])
-      )
-    ])
-  );
-
-  it("should disagree according to depth", function() {
-    assert.ok(n.Node.check(fs));
-    assert.ok(n.Statement.check(fs));
-    assert.ok(n.ForStatement.check(fs));
-
-    // Not a true ForStatement because fs.init is not a true
-    // VariableDeclaration.
-    assert.ok(!n.Node.check(fs, true));
-    assert.ok(!n.Statement.check(fs, true));
-    assert.ok(!n.ForStatement.check(fs, true));
-  });
-});
-
-function validateProgram(file) {
-  var fullPath = path.join(__dirname, "..", file);
-
-  it("should validate " + file + " with Esprima", function(done) {
-    var parse = require("esprima").parse;
-
-    fs.readFile(fullPath, "utf8", function(err, code) {
-      if (err) throw err;
-
-      n.Program.assert(parse(code), true);
-      n.Program.assert(parse(code, { loc: true }), true);
-
-      done();
-    });
-  });
-
-  it("should validate " + file + " with Babel", function(done) {
-    fs.readFile(fullPath, "utf8", function(err, code) {
-      if (err) throw err;
-      var ast = babylonParse(code);
-      n.Program.assert(ast, true);
-      done();
-    });
-  });
-}
-
-describe("whole-program validation", function() {
-  this.timeout(20000);
-
-  validateProgram("main.js");
-  validateProgram("lib/shared.js");
-  validateProgram("def/core.js");
-  validateProgram("lib/types.js");
-  validateProgram("test/run.js");
-  validateProgram("test/data/backbone.js");
-  validateProgram("test/data/jquery-1.9.1.js");
-});
-
-describe("esprima Syntax types", function() {
-  var def = types.Type.def;
-  var typeNames = {};
-
-  function addTypeName(name) {
-    typeNames[name] = name;
-  }
-
-  Object.keys(require("esprima").Syntax).forEach(addTypeName);
-  Object.keys(require("esprima-fb").Syntax).forEach(addTypeName);
-  Object.keys(
-    require("babel-types").VISITOR_KEYS
-  ).forEach(addTypeName);
-
-  it("should all be buildable", function() {
-    Object.keys(typeNames).forEach(function(name) {
-      assert.ok(hasOwn.call(n, name), name);
-      assert.strictEqual(def(name).buildable, true, name);
-    });
-  });
-
-  it("builders for subtypes of Expression should have equivalent ExpressionStatement builders", function() {
-    Object.keys(typeNames).forEach(function(name) {
-      if (def(name).buildable &&
-          def("Expression").isSupertypeOf(def(name))) {
-        var statementBuilderName = rawTypes.getStatementBuilderName(name);
-        assert.ok(b[statementBuilderName], name + ":" +statementBuilderName);
-      }
-    });
-
-    // sanity check
-    var expStmt = b.assignmentStatement("=", b.identifier("a"), b.identifier("b"));
-    assert.strictEqual(expStmt.type, "ExpressionStatement");
-  });
-});
-
-describe("types.getFieldValue", function() {
-  it("should work for explicit fields", function() {
-    assert.strictEqual(
-      types.getFieldValue({
-        type: "CatchClause"
-      }, "type"),
-      "CatchClause"
-    );
-
-    assert.strictEqual(
-      types.getFieldValue({
-        type: "CatchClause",
-        guard: b.identifier("test")
-      }, "guard").name,
-      "test"
-    );
-  });
-
-  it("should work for implicit/default fields", function() {
-    assert.strictEqual(
-      types.getFieldValue({
-        type: "CatchClause"
-      }, "guard"),
-      null
-    );
-
-    assert.strictEqual(
-      types.getFieldValue({
-        type: "CatchClause"
-      }, "asdf"),
-      void 0
-    );
-
-    assert.deepEqual(
-      types.getFieldValue({
-        type: "TryStatement",
-      }, "handler"),
-      null
-    );
-
-    assert.deepEqual(
-      types.getFieldValue({
-        type: "TryStatement",
-      }, "handlers"),
-      []
-    );
-
-    assert.deepEqual(
-      types.getFieldValue({
-        type: "TryStatement",
-      }, "guardedHandlers"),
-      []
-    );
-  });
-
-  it("should work for explicitly undefined fields", function() {
-    assert.deepEqual(
-      types.getFieldValue({
-        type: "TryStatement",
-        guardedHandlers: void 0
-      }, "guardedHandlers"),
-      []
-    );
-  });
-
-  it("should handle undefined objects", function() {
-    assert.equal(
-      types.getFieldValue(undefined, "name"),
-      undefined
-    );
-  });
-});
-
-describe("types.eachField", function() {
-  var context = {};
-
-  function check(node, names) {
-    var seen = [];
-
-    types.eachField(node, function(name, value) {
-      assert.strictEqual(this, context);
-      if (name === "type")
-        assert.strictEqual(node.type, value);
-      seen.push(name);
-    }, context);
-
-    assert.deepEqual(seen.sort(), names.sort());
-  }
-
-  it("should give correct keys for supertypes", function() {
-    check({ type: "Expression" }, ["type"]);
-  });
-
-  it("should work for non-buildable types", function() {
-    check({ type: "Position" }, [
-      "type", "line", "column"
-    ]);
-
-    check({ type: "SourceLocation" }, [
-      "type", "start", "end", "source"
-    ]);
-  });
-
-  it("should respect hidden fields", function() {
-    check({ type: "TryStatement" }, [
-      // Note that the "handlers" field is now hidden from eachField.
-      "type", "block", "handler", "guardedHandlers", "finalizer"
-    ]);
-  });
-
-  check({ type: "CatchClause" }, [
-    "type", "param", "guard", "body"
-  ]);
-
-  it("should complain about invalid types", function() {
-    assert.throws(function() {
-      check({ type: "asdf" }, ["type"]);
-    }, "did not recognize object of type " + JSON.stringify("asdf"));
-  });
-
-  it("should infer SourceLocation types", function() {
-    check({
-      line: 10,
-      column: 37
-    }, ["line", "column"]);
-  });
-});
-
-describe("types.visit", function() {
-  var call = b.expressionStatement(
-    b.callExpression(
-      b.memberExpression(
-        b.identifier("foo"),
-        b.identifier("bar"),
-        false
-      ),
-      [b.literal("baz")]
-    )
-  );
-
-  var ts = b.tryStatement(
-    b.blockStatement([call, call]),
-    b.catchClause(
-      b.identifier("err"),
-      null,
-      b.blockStatement([])
-    )
-  );
-
-  it("should have correct .parent path", function() {
-    var literalCount = 0;
-
-    n.TryStatement.assert(types.visit(ts, {
-      visitLiteral: function(path) {
-        var node = path.node;
-        literalCount += 1;
-        assert.strictEqual(node.value, "baz");
-        assert.strictEqual(path.parent.node, call.expression);
-        assert.strictEqual(path.parent.parent.node, call);
-        assert.strictEqual(path.parent.parent.parent.node, ts.block);
-        assert.strictEqual(path.parent.parent.parent.parent.node, ts);
-        assert.strictEqual(path.parent.parent.parent.parent.parent, null);
-        this.traverse(path);
-      }
-    }), true);
-
-    assert.strictEqual(literalCount, 2);
-  });
-
-  it("should abort subtree traversal when false returned", function() {
-    var ids = {};
-
-    types.visit(ts, {
-      visitMemberExpression: function(path) {
-        return false;
-      },
-
-      visitIdentifier: function(path) {
-        ids[path.node.name] = true;
-        this.traverse(path);
-      }
-    });
-
-    // Make sure all identifers beneath member expressions were skipped.
-    assert.deepEqual(ids, { err: true });
-
-    ids = {};
-
-    types.visit(ts, {
-      visitIdentifier: function(path) {
-        ids[path.node.name] = true;
-        this.traverse(path);
-      }
-    });
-
-    // Now make sure those identifiers (foo and bar) were visited.
-    assert.deepEqual(ids, {
-      err: true,
-      foo: true,
-      bar: true
-    });
-  });
-
-  it("this.abort() should abort entire traversal", function() {
-    var literal = "not visited";
-    var unvisitedTypes = [];
-    var root = types.visit(call, {
-      visitIdentifier: function(path) {
-        if (path.value.name === "foo") {
-          this.abort();
-        }
-      },
-
-      visitLiteral: function(path) {
-        literal = path.value;
-        this.traverse(path);
-      },
-
-      visitNode: function(path) {
-        unvisitedTypes.push(path.value.type);
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(root, call);
-    assert.strictEqual(literal, "not visited");
-    assert.deepEqual(unvisitedTypes, [
-      "ExpressionStatement",
-      "CallExpression",
-      "MemberExpression"
-    ]);
-  });
-
-  it("this.abort() should be cancelable", function() {
-    var literal = "not visited";
-    var unvisitedTypes = [];
-    var root = types.visit(call, {
-      visitIdentifier: function(path) {
-        if (path.value.name === "foo") {
-          this.abort();
-        }
-      },
-
-      visitMemberExpression: function(path) {
-        try {
-          this.traverse(path);
-        } catch (err) {
-          assert.ok(err instanceof this.AbortRequest);
-          err.cancel();
-        }
-      },
-
-      visitLiteral: function(path) {
-        literal = path.value;
-        this.traverse(path);
-      },
-
-      visitNode: function(path) {
-        unvisitedTypes.push(path.value.type);
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(root, call);
-
-    n.Literal.assert(literal);
-    assert.strictEqual(literal.value, "baz");
-    assert.strictEqual(literal, call.expression.arguments[0]);
-
-    assert.deepEqual(unvisitedTypes, [
-      "ExpressionStatement",
-      "CallExpression"
-      // Note that the MemberExpression and the Literal were visited
-      // by their type-specific methods, so they were not visited by
-      // the catch-all visitNode method.
-    ]);
-  });
-
-  it("should visit comments", function() {
-    var ast = parse([
-      "function getArgs(/*arguments*/) {",
-      "  // Turn arguments into an array.",
-      "  return Array.prototype.slice.call(arguments);",
-      "}"
-    ].join("\n"), {
-      comment: true
-    });
-
-    var blockComments = [];
-    var lineComments = [];
-
-    types.visit(ast, {
-      visitComment: function(path) {
-        this.traverse(path);
-        if (n.Block.check(path.value)) {
-          blockComments.push(path.value);
-        } else if (n.Line.check(path.value)) {
-          lineComments.push(path.value);
-        }
-      }
-    });
-
-    assert.strictEqual(blockComments.length, 1);
-    assert.strictEqual(blockComments[0].value, "arguments");
-
-    assert.strictEqual(lineComments.length, 1);
-    assert.strictEqual(
-      lineComments[0].value,
-      " Turn arguments into an array."
-    );
-
-    blockComments.length = 0;
-    lineComments.length = 0;
-
-    types.visit(ast, {
-      visitBlock: function(path) {
-        blockComments.push(path.value);
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(blockComments.length, 1);
-    assert.strictEqual(blockComments[0].value, "arguments");
-
-    assert.strictEqual(lineComments.length, 0);
-
-    blockComments.length = 0;
-    lineComments.length = 0;
-
-    types.visit(ast, {
-      visitLine: function(path) {
-        lineComments.push(path.value);
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(blockComments.length, 0);
-
-    assert.strictEqual(lineComments.length, 1);
-    assert.strictEqual(
-      lineComments[0].value,
-      " Turn arguments into an array."
-    );
-
-    blockComments.length = 0;
-    lineComments.length = 0;
-
-    types.visit(ast, {
-      visitBlock: function(path) {
-        blockComments.push(path.value);
-        this.traverse(path);
-      },
-
-      visitLine: function(path) {
-        lineComments.push(path.value);
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(blockComments.length, 1);
-    assert.strictEqual(blockComments[0].value, "arguments");
-
-    assert.strictEqual(lineComments.length, 1);
-    assert.strictEqual(
-      lineComments[0].value,
-      " Turn arguments into an array."
-    );
-  });
-});
-
-describe("path traversal", function() {
-  var call = b.expressionStatement(
-    b.callExpression(
-      b.memberExpression(
-        b.identifier("foo"),
-        b.identifier("bar"),
-        false
-      ),
-      [b.literal("baz")]
-    )
-  );
-
-  it("should accept root paths as well as AST nodes", function() {
-    var path = new NodePath(call).get("expression", "callee");
-    var idCount = 0;
-
-    // Note that we're passing a path instead of a node as the first
-    // argument to types.traverse.
-    types.visit(path, {
-      visitIdentifier: function(path) {
-        var node = path.node;
-        ++idCount;
-
-        if (node.name === "bar") {
-          n.MemberExpression.assert(path.parent.node);
-          n.CallExpression.assert(path.parent.parent.node);
-          n.ExpressionStatement.assert(path.parent.parent.parent.node);
-        }
-
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(idCount, 2);
-  });
-});
-
-describe("replacing the root", function() {
-  var ast = b.expressionStatement(
-    b.unaryExpression("!", b.sequenceExpression([
-      b.identifier("a"),
-      b.identifier("b"),
-      b.identifier("c")
-    ]))
-  );
-
-  it("should be possible", function() {
-    var callExp = types.visit(ast, {
-      visitExpressionStatement: function(path) {
-        path.replace(b.callExpression(b.identifier("f"), [
-          path.node.expression
-        ]));
-
-        this.traverse(path);
-      }
-    });
-
-    n.CallExpression.assert(callExp, true);
-  });
-});
-
-describe("NodePath", function() {
-  it("should have the expected type hierarchy", function() {
-    assert.strictEqual(new Path({}).constructor, Path);
-
-    var np = new NodePath(b.identifier("foo"));
-    assert.strictEqual(np.constructor, NodePath);
-    assert.ok(np.get("name") instanceof NodePath);
-  });
-
-  var ast = b.expressionStatement(
-    b.unaryExpression("!", b.sequenceExpression([
-      b.identifier("a"),
-      b.identifier("b"),
-      b.identifier("c")
-    ]))
-  );
-
-  var path = new NodePath(ast);
-
-  it("should have sane values, nodes, parents", function() {
-    var opPath = path.get("expression", "operator");
-    assert.strictEqual(opPath.value, "!");
-    assert.strictEqual(opPath.node, ast.expression);
-    assert.strictEqual(opPath.parent, path);
-    assert.strictEqual(opPath.parent.node, ast);
-  });
-
-  var binaryYield = b.expressionStatement(
-    b.logicalExpression(
-      "&&",
-      b.yieldExpression(b.identifier("a"), false),
-      b.yieldExpression(b.identifier("b"), true)
-    )
-  );
-
-  it("should support .needsParens()", function() {
-    var argPath = path.get("expression", "argument");
-    assert.ok(argPath.needsParens());
-
-    var exprsPath = argPath.get("expressions");
-    assert.ok(!exprsPath.needsParens());
-    assert.strictEqual(exprsPath.get("length").value, 3);
-    assert.ok(!exprsPath.get(1).needsParens());
-
-    var byPath = new NodePath(binaryYield);
-    assert.ok(!byPath.get("expression").needsParens());
-    assert.ok(byPath.get("expression", "left").needsParens());
-    assert.ok(byPath.get("expression", "right").needsParens());
-
-    var sequenceAssignmentAST = b.assignmentExpression(
-      '=',
-      b.identifier('a'),
-      b.sequenceExpression([b.literal(1), b.literal(2)])
-    );
-
-    var sequenceAssignmentPath = new NodePath(sequenceAssignmentAST);
-    assert.ok(sequenceAssignmentPath.get("right").needsParens());
-  });
-
-  it("should support .needsParens(true)", function() {
-    var programPath = new NodePath(parse("(function(){})"));
-    var funExpPath = programPath.get("body", 0, "expression");
-    n.FunctionExpression.assert(funExpPath.value);
-    assert.strictEqual(funExpPath.needsParens(), true);
-    assert.strictEqual(funExpPath.canBeFirstInStatement(), false);
-    assert.strictEqual(funExpPath.firstInStatement(), true);
-    assert.strictEqual(funExpPath.needsParens(true), false);
-
-    programPath = new NodePath(parse("({ foo: 42 })"));
-    var objLitPath = programPath.get("body", 0, "expression");
-    n.ObjectExpression.assert(objLitPath.value);
-    assert.strictEqual(objLitPath.needsParens(), true);
-    assert.strictEqual(objLitPath.canBeFirstInStatement(), false);
-    assert.strictEqual(objLitPath.firstInStatement(), true);
-    assert.strictEqual(objLitPath.needsParens(true), false);
-  });
-
-  it("should prune redundant variable declaration nodes", function() {
-    var programPath = new NodePath(parse("(function(){var y = 1,x = 2;})"));
-    var funBlockStatementPath = programPath.get("body", 0, "expression", "body");
-    var variableDeclaration = funBlockStatementPath.get("body", 0);
-    var yVariableDeclaratorPath = variableDeclaration.get("declarations", 0);
-    var xVariableDeclaratorPath = variableDeclaration.get("declarations", 1);
-
-    n.VariableDeclarator.assert(yVariableDeclaratorPath.node);
-    n.VariableDeclarator.assert(xVariableDeclaratorPath.node);
-
-    var remainingNodePath = yVariableDeclaratorPath.prune();
-
-    assert.strictEqual(remainingNodePath, variableDeclaration);
-
-    remainingNodePath = xVariableDeclaratorPath.prune();
-
-    assert.strictEqual(remainingNodePath, funBlockStatementPath);
-    assert.strictEqual(funBlockStatementPath.get("body", 0).value, undefined);
-  });
-
-  it("should prune redundant expression statement nodes", function() {
-    var programPath = new NodePath(parse("(function(){key = 'value';})"));
-    var funBlockStatementPath = programPath.get("body", 0, "expression", "body");
-    var assignmentExpressionPath = funBlockStatementPath.get("body", 0, "expression");
-
-    n.AssignmentExpression.assert(assignmentExpressionPath.node);
-
-    var remainingNodePath = assignmentExpressionPath.prune();
-
-    assert.strictEqual(remainingNodePath, funBlockStatementPath);
-    assert.strictEqual(funBlockStatementPath.value.body.length, 0);
-  });
-
-  it("should prune redundant if statement node if no consequent and alternate remain after prune", function() {
-    var programPath = new NodePath(parse("if(true){var t = 0;}"));
-    var consequentNodePath = programPath.get("body", 0, "consequent");
-
-    n.BlockStatement.assert(consequentNodePath.node);
-
-    var remainingNodePath = consequentNodePath.prune();
-
-    var testExpressionNodePath = programPath.get("body", 0);
-
-    n.ExpressionStatement.assert(remainingNodePath.node);
-    assert.strictEqual(remainingNodePath, testExpressionNodePath);
-  });
-
-  it("should modify if statement node if consequent is pruned and alternate remains", function() {
-    var programPath = new NodePath(parse("if(x > 10){var t = 0;}else{var f = 2;}"));
-    var consequentNodePath = programPath.get("body", 0, "consequent");
-
-    n.BlockStatement.assert(consequentNodePath.node);
-
-    var remainingNodePath = consequentNodePath.prune();
-
-    var modifiedIfStatementNodePath = programPath.get("body", 0);
-    var negatedTestExpression = modifiedIfStatementNodePath.get("test");
-
-    n.IfStatement.assert(remainingNodePath.node);
-    n.UnaryExpression.assert(negatedTestExpression.node);
-    assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
-    assert.strictEqual(negatedTestExpression.node.operator, "!");
-  });
-
-  it("should modify if statement node if consequent is pruned, alternate remains with no double negation", function() {
-    var programPath = new NodePath(parse("if(!condition){var t = 0;}else{var f = 2;}"));
-    var consequentNodePath = programPath.get("body", 0, "consequent");
-
-    n.BlockStatement.assert(consequentNodePath.node);
-
-    var remainingNodePath = consequentNodePath.prune();
-
-    var modifiedIfStatementNodePath = programPath.get("body", 0);
-    var testExpression = modifiedIfStatementNodePath.get("test");
-
-    n.IfStatement.assert(remainingNodePath.node);
-    n.Identifier.assert(testExpression.node);
-    assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
-  });
-});
-
-describe("path.replace", function() {
-  var ast;
-
-  beforeEach(function() {
-    ast = b.functionDeclaration(
-      b.identifier("fn"),
-      [],
-      b.blockStatement([
-        b.variableDeclaration(
-          "var",
-          [b.variableDeclarator(b.identifier("a"), null)]
-        )
-      ])
-    );
-  });
-
-  it("should support replacement with a single node", function() {
-    types.visit(ast, {
-      visitIdentifier: function(path) {
-        if (path.node.name === "a") {
-          path.replace(b.identifier("b"));
-        }
-        this.traverse(path);
-      }
-    });
-
-    assert.equal(ast.body.body[0].declarations[0].id.name, "b");
-  });
-
-  it("should support replacement in an array with a single node", function() {
-    types.visit(ast, {
-      visitVariableDeclaration: function(path) {
-        path.replace(b.returnStatement(null));
-        this.traverse(path);
-      }
-    });
-
-    assert.equal(ast.body.body.length, 1);
-    assert.ok(n.ReturnStatement.check(ast.body.body[0]));
-  });
-
-  it("should support replacement with nothing", function() {
-    types.visit(ast, {
-      visitVariableDeclaration: function(path) {
-        path.replace();
-        this.traverse(path);
-      }
-    });
-
-    assert.equal(ast.body.body.length, 0);
-  });
-
-  it("should support replacement with itself plus more in an array", function() {
-    types.visit(ast, {
-      visitVariableDeclaration: function(path) {
-        var scopeBody = path.scope.path.get("body", "body");
-
-        // This is contrived such that we just happen to be replacing
-        // the same node we're currently processing, perhaps using a
-        // helper function to create variables at the top of the scope.
-        assert.strictEqual(scopeBody.get(0), path);
-
-        // Prepend `var $$;` inside the block. This should update our
-        // `this` NodePath to correct its array index so that a
-        // subsequent replace will still work.
-        scopeBody.get(0).replace(
-          b.variableDeclaration(
-            "var",
-            [b.variableDeclarator(b.identifier("$$"), null)]
-          ),
-          scopeBody.get(0).value
-        );
-
-        // Now do it again to make sure all the other indexes are
-        // updated, too.
-        scopeBody.get(0).replace(
-          b.variableDeclaration(
-            "var",
-            [b.variableDeclarator(b.identifier("$2"), null)]
-          ),
-          scopeBody.get(0).value
-        );
-
-        assert.strictEqual(scopeBody.get(0), path);
-
-        // Then replace the node, not the one we just added.
-        return b.returnStatement(b.identifier("$3"));
-      }
-    });
-
-    var statements = ast.body.body;
-    assert.deepEqual(
-      statements.map(function(node) { return node.type; }),
-      ['ReturnStatement', 'VariableDeclaration', 'VariableDeclaration']
-    );
-
-    n.ReturnStatement.assert(statements[0]);
-    assert.equal(statements[0].argument.name, "$3");
-
-    n.VariableDeclaration.assert(statements[1]);
-    assert.equal(statements[1].declarations[0].id.name, "$$");
-
-    n.VariableDeclaration.assert(statements[2]);
-    assert.equal(statements[2].declarations[0].id.name, "a");
-  });
-
-  it("should not throw when replacing the same node twice", function() {
-    types.visit(ast, {
-      visitVariableDeclaration: function(path) {
-        path.replace(b.expressionStatement(b.literal(null)));
-        n.ExpressionStatement.assert(path.value);
-        n.Literal.assert(path.value.expression);
-        assert.strictEqual(path.value.expression.value, null);
-
-        path.replace(b.expressionStatement(b.literal("OK")));
-        n.ExpressionStatement.assert(path.value);
-        n.Literal.assert(path.value.expression);
-        assert.strictEqual(path.value.expression.value, "OK");
-
-        if (path.parentPath.get(path.name) !== path) {
-          assert.ok(false, "Should have reused the same path");
-        }
-
-        this.traverse(path);
-      }
-    });
-  });
-});
-
-describe("global scope", function() {
-  var scope = [
-    "var foo = 42;",
-    "function bar(baz) {",
-    "  return baz + foo;",
-    "}"
-  ];
-
-  var ast = parse(scope.join("\n"));
-
-  it("should be reachable from nested scopes", function() {
-    var globalScope;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        assert.strictEqual(path.scope.isGlobal, true);
-        globalScope = path.scope;
-        this.traverse(path);
-      },
-
-      visitFunctionDeclaration: function(path) {
-        var node = path.node;
-        assert.strictEqual(path.scope.isGlobal, false);
-
-        assert.strictEqual(node.id.name, "bar");
-        assert.notStrictEqual(path.scope, globalScope);
-        assert.strictEqual(path.scope.isGlobal, false);
-        assert.strictEqual(path.scope.parent, globalScope);
-
-        assert.strictEqual(path.scope.getGlobalScope(), globalScope);
-
-        this.traverse(path);
-      }
-    });
-  });
-
-  it("should be found by .lookup and .declares", function() {
-    var globalScope;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        assert.strictEqual(path.scope.isGlobal, true);
-        globalScope = path.scope;
-        this.traverse(path);
-      },
-
-      visitFunctionDeclaration: function(path) {
-        assert.ok(globalScope.declares("foo"));
-        assert.ok(globalScope.declares("bar"));
-        assert.strictEqual(path.scope.lookup("foo"), globalScope);
-        assert.strictEqual(path.scope.lookup("bar"), globalScope);
-
-        assert.ok(path.scope.declares("baz"));
-        assert.strictEqual(path.scope.lookup("baz"), path.scope);
-
-        assert.strictEqual(path.scope.lookup("qux"), null);
-        assert.strictEqual(globalScope.lookup("baz"), null);
-
-        this.traverse(path);
-      }
-    });
-  });
-});
-
-describe("scope methods", function () {
-  var scope = [
-    "var foo = 42;",
-    "function bar(baz) {",
-    "  return baz + foo;",
-    "}",
-    "var nom = function rom(pom) {",
-    "  var zom;",
-    "  return rom(pom);",
-    "};"
-  ];
-
-  it("getBindings should get local and global scope bindings", function() {
-    var ast = parse(scope.join("\n"));
-    var checked = [];
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        var bindings = path.scope.getBindings();
-        assert.deepEqual(["bar", "foo", "nom"], Object.keys(bindings).sort());
-        assert.equal(1, bindings.foo.length);
-        assert.equal(1, bindings.bar.length);
-        checked.push(path.node);
-        this.traverse(path);
-      },
-
-      visitFunctionDeclaration: function(path) {
-        var bindings = path.scope.getBindings();
-        assert.deepEqual(["baz"], Object.keys(bindings));
-        assert.equal(1, bindings.baz.length);
-        checked.push(path.node);
-        this.traverse(path);
-      },
-
-      visitReturnStatement: function(path) {
-        var node = path.node;
-        if (n.CallExpression.check(node.argument) &&
-            node.argument.callee.name === "rom") {
-          var bindings = path.scope.getBindings();
-          assert.deepEqual(["pom", "rom", "zom"], Object.keys(bindings).sort());
-          checked.push(node);
-        }
-        this.traverse(path);
-      }
-    });
-
-    assert.deepEqual(
-      checked.map(function(node) { return node.type; }),
-      ['Program', 'FunctionDeclaration', 'ReturnStatement']
-    );
-  });
-
-  it("getBindings should work for import statements (esprima-fb)", function() {
-    var ast = require("esprima-fb").parse(
-      [
-        "import {x, y as z} from 'xy';",
-        "import xyDefault from 'xy';",
-        "import * as xyNamespace from 'xy';"
-      ].join("\n"),
-      {sourceType: "module"}
-    );
-
-    var names;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        names = Object.keys(path.scope.getBindings()).sort();
-        this.traverse(path);
-      }
-    });
-
-    assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
-  });
-
-  it("getBindings should work for import statements (acorn)", function() {
-    var ast = babylonParse([
-      "import {x, y as z} from 'xy';",
-      "import xyDefault from 'xy';",
-      "import * as xyNamespace from 'xy';"
-    ].join("\n"), {
-      sourceType: "module",
-      ecmaVersion: 6
-    });
-
-    var names;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        names = Object.keys(path.scope.getBindings()).sort();
-        this.traverse(path);
-      }
-    });
-
-    assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
-  });
-
-  it("should work for ES6 syntax (espree)", function() {
-    var names;
-
-    var ast = require("espree").parse([
-      "var zap;",
-      "export default function(zom) {",
-      "    var innerFn = function(zip) {};",
-      "    return innerFn(zom);",
-      "};"
-    ].join("\n"), {
-      sourceType: "module",
-      ecmaVersion: 6
-    });
-
-    types.visit(ast, {
-      visitFunctionDeclaration: function(path) {
-        names = Object.keys(path.scope.lookup("zap").getBindings()).sort();
-        assert.deepEqual(names, ["zap"]);
-        this.traverse(path);
-      }
-    });
-  });
-
-  it("should inject temporary into current scope", function() {
-    var ast = parse(scope.join("\n"));
-    var bindings;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        path.scope.injectTemporary();
-        bindings = path.scope.getBindings();
-        assert.deepEqual(["bar", "foo", "nom", "t$0$0"], Object.keys(bindings).sort());
-        this.traverse(path);
-      },
-
-      visitFunctionDeclaration: function(path) {
-        path.scope.injectTemporary(
-          path.scope.declareTemporary("t$")
-        )
-        bindings = path.scope.getBindings();
-        assert.deepEqual(["baz", "t$1$0"], Object.keys(bindings));
-        this.traverse(path);
-      }
-    });
-  });
-
-  it("declareTemporary should use distinct names in nested scopes", function() {
-    var ast = parse(scope.join("\n"));
-    var globalVarDecl;
-    var barVarDecl;
-    var romVarDecl;
-
-    types.visit(ast, {
-      visitProgram: function(path) {
-        path.get("body").unshift(
-          globalVarDecl = b.variableDeclaration("var", [
-            b.variableDeclarator(
-              path.scope.declareTemporary("$"),
-              b.literal("global")
-            ),
-            b.variableDeclarator(
-              path.scope.declareTemporary("$"),
-              b.literal("global")
-            )
-          ])
-        );
-
-        this.traverse(path);
-      },
-
-      visitFunction: function(path) {
-        var funcId = path.value.id;
-
-        var varDecl = b.variableDeclaration("var", [
-          b.variableDeclarator(
-            path.scope.declareTemporary("$"),
-            b.literal(funcId.name + 1)
-          ),
-          b.variableDeclarator(
-            path.scope.declareTemporary("$"),
-            b.literal(funcId.name + 2)
-          )
-        ]);
-
-        path.get("body", "body").unshift(varDecl);
-
-        if (funcId.name === "bar") {
-          barVarDecl = varDecl;
-        } else if (funcId.name === "rom") {
-          romVarDecl = varDecl;
-        }
-
-        this.traverse(path);
-      }
-    });
-
-    assert.strictEqual(globalVarDecl.declarations[0].id.name, "$0$0");
-    assert.strictEqual(globalVarDecl.declarations[1].id.name, "$0$1");
-    assert.strictEqual(barVarDecl.declarations[0].id.name, "$1$0");
-    assert.strictEqual(barVarDecl.declarations[1].id.name, "$1$1");
-    assert.strictEqual(romVarDecl.declarations[0].id.name, "$1$0");
-    assert.strictEqual(romVarDecl.declarations[1].id.name, "$1$1");
-  });
-});
-
-describe("catch block scope", function() {
-  var catchWithVarDecl = [
-    "function foo(e) {",
-    "  try {",
-    "    bar();",
-    "  } catch (e) {",
-    "    var f = e + 1;",
-    "    return function(g) {",
-    "      return e + g;",
-    "    };",
-    "  }",
-    "  return f;",
-    "}"
-  ];
-
-  var path = new NodePath(parse(catchWithVarDecl.join("\n")));
-  var fooPath = path.get("body", 0);
-  var fooScope = fooPath.scope;
-  var catchPath = fooPath.get("body", "body", 0, "handler");
-  var catchScope = catchPath.scope;
-
-  it("should not affect outer scope declarations", function() {
-    n.FunctionDeclaration.assert(fooScope.node);
-    assert.strictEqual(fooScope.declares("e"), true);
-    assert.strictEqual(fooScope.declares("f"), true);
-    assert.strictEqual(fooScope.lookup("e"), fooScope);
-  });
-
-  it("should declare only the guard parameter", function() {
-    n.CatchClause.assert(catchScope.node);
-    assert.strictEqual(catchScope.declares("e"), true);
-    assert.strictEqual(catchScope.declares("f"), false);
-    assert.strictEqual(catchScope.lookup("e"), catchScope);
-    assert.strictEqual(catchScope.lookup("f"), fooScope);
-  });
-
-  it("should shadow only the parameter in nested scopes", function() {
-    var closurePath = catchPath.get("body", "body", 1, "argument");
-    var closureScope = closurePath.scope;
-    n.FunctionExpression.assert(closureScope.node);
-    assert.strictEqual(closureScope.declares("e"), false);
-    assert.strictEqual(closureScope.declares("f"), false);
-    assert.strictEqual(closureScope.declares("g"), true);
-    assert.strictEqual(closureScope.lookup("g"), closureScope);
-    assert.strictEqual(closureScope.lookup("e"), catchScope);
-    assert.strictEqual(closureScope.lookup("f"), fooScope);
-  });
-});
-
-describe("array and object pattern scope", function() {
-
-  function scopeFromPattern(pattern) {
-    return new NodePath(
-      b.program([
-        b.variableDeclaration('var', [
-          b.variableDeclarator(pattern, null)
-        ])
-      ])
-    ).scope;
-  }
-
-  // ObjectPattern with Property and SpreadProperty
-  // ArrayPattern with SpreadElement
-  describe("esprima", function() {
-    var types = require('../fork')([
-      require("../def/esprima")
-    ]);
-    var b = types.builders;
-
-    var objectPattern;
-    var arrayPattern;
-
-    beforeEach(function() {
-      // {a, b: c, ...d}
-      objectPattern = b.objectPattern([
-        b.property('init', b.identifier('a'), b.identifier('a')),
-        b.property('init', b.identifier('b'), b.identifier('c')),
-        b.spreadProperty(b.identifier('d')),
-      ]);
-
-      // [foo, bar, ...baz]
-      arrayPattern = b.arrayPattern([
-        b.identifier('foo'),
-        b.identifier('bar'),
-        b.spreadElement(b.identifier('baz'))
-      ]);
-    });
-
-    it("should handle object patterns variable declarations", function() {
-      var scope = scopeFromPattern(objectPattern);
-
-      assert.strictEqual(scope.declares("a"), true);
-      assert.strictEqual(scope.declares("b"), false);
-      assert.strictEqual(scope.declares("c"), true);
-      assert.strictEqual(scope.declares("d"), true);
-    });
-
-    it("should handle array patterns in variable declarations", function() {
-      var scope = scopeFromPattern(arrayPattern);
-
-      assert.strictEqual(scope.declares("foo"), true);
-      assert.strictEqual(scope.declares("bar"), true);
-      assert.strictEqual(scope.declares("baz"), true);
-    });
-
-    it("should handle nested patterns in variable declarations", function() {
-      // {a, b: c, ...d, e: [foo, bar, ...baz]}
-      objectPattern.properties.push(
-        b.property('init', b.identifier('e'), arrayPattern)
-      );
-
-      var scope = scopeFromPattern(objectPattern);
-      assert.strictEqual(scope.declares("a"), true);
-      assert.strictEqual(scope.declares("b"), false);
-      assert.strictEqual(scope.declares("c"), true);
-      assert.strictEqual(scope.declares("d"), true);
-      assert.strictEqual(scope.declares("e"), false);
-      assert.strictEqual(scope.declares("foo"), true);
-      assert.strictEqual(scope.declares("bar"), true);
-      assert.strictEqual(scope.declares("baz"), true);
-    });
-  });
-
-  // ObjectPattern with PropertyPattern and SpreadPropertyPattern
-  // ArrayPatterhn with SpreadElementPattern
-  describe("Mozilla Parser API", function() {
-    var types = require('../fork')([
-      require("../def/core"),
-      require("../def/es6"),
-      require("../def/es7"),
-      require("../def/mozilla"),
-    ]);
-    var b = types.builders;
-
-    var objectPattern;
-    var arrayPattern;
-
-    beforeEach(function() {
-      // {a, b: c, ...d}
-      objectPattern = b.objectPattern([
-        b.propertyPattern(b.identifier('a'), b.identifier('a')),
-        b.propertyPattern(b.identifier('b'), b.identifier('c')),
-        b.spreadPropertyPattern(b.identifier('d')),
-      ]);
-
-      // [foo, bar, ...baz]
-      arrayPattern = b.arrayPattern([
-        b.identifier('foo'),
-        b.identifier('bar'),
-        b.spreadElementPattern(b.identifier('baz'))
-      ]);
-    });
-
-    it("should handle object patterns variable declarations", function() {
-      var scope = scopeFromPattern(objectPattern);
-
-      assert.strictEqual(scope.declares("a"), true);
-      assert.strictEqual(scope.declares("b"), false);
-      assert.strictEqual(scope.declares("c"), true);
-      assert.strictEqual(scope.declares("d"), true);
-    });
-
-    it("should handle array patterns in variable declarations", function() {
-      var scope = scopeFromPattern(arrayPattern);
-
-      assert.strictEqual(scope.declares("foo"), true);
-      assert.strictEqual(scope.declares("bar"), true);
-      assert.strictEqual(scope.declares("baz"), true);
-    });
-
-    it("should handle nested patterns in variable declarations", function() {
-      // {a, b: c, ...d, e: [foo, bar, ...baz]}
-      objectPattern.properties.push(
-        b.propertyPattern(b.identifier('e'), arrayPattern)
-      );
-
-      var scope = scopeFromPattern(objectPattern);
-      assert.strictEqual(scope.declares("a"), true);
-      assert.strictEqual(scope.declares("b"), false);
-      assert.strictEqual(scope.declares("c"), true);
-      assert.strictEqual(scope.declares("d"), true);
-      assert.strictEqual(scope.declares("e"), false);
-      assert.strictEqual(scope.declares("foo"), true);
-      assert.strictEqual(scope.declares("bar"), true);
-      assert.strictEqual(scope.declares("baz"), true);
-    });
-  });
-});
-
-describe("types.defineMethod", function() {
-  function at(loc) {
-    types.namedTypes.SourceLocation.assert(loc);
-    this.loc = loc;
-  }
-
-  var thisExpr = b.thisExpression();
-
-  it("should allow defining an .at method", function() {
-    assert.strictEqual(types.defineMethod("at", at), void 0);
-    assert.strictEqual(thisExpr.loc, null);
-
-    thisExpr.at(b.sourceLocation(
-      b.position(1, 0),
-      b.position(1, 4)
-    ));
-
-    assert.strictEqual(thisExpr.loc.start.line, 1);
-    assert.strictEqual(thisExpr.loc.start.column, 0);
-    assert.strictEqual(thisExpr.loc.end.line, 1);
-    assert.strictEqual(thisExpr.loc.end.column, 4);
-  });
-
-  it("should allow methods to be removed", function() {
-    // Now try removing the method.
-    assert.strictEqual(types.defineMethod("at"), at);
-    assert.strictEqual(thisExpr.at, void 0);
-    assert.strictEqual("at" in thisExpr, false);
-  });
-});
-
-describe("types.visit", function() {
-  var objProp;
-
-  beforeEach(function() {
-    objProp = b.memberExpression(
-      b.identifier("object"),
-      b.identifier("property"),
-      false
-    );
-  });
-
-  it("should be identical to PathVisitor.visit", function() {
-    assert.strictEqual(types.visit, PathVisitor.visit);
-  });
-
-  it("should work with no visitors", function() {
-    var foo = b.identifier("foo");
-    assert.strictEqual(types.visit(foo), foo);
-  });
-
-  it("should allow simple tree modifications", function() {
-    var bar = types.visit(b.identifier("foo"), {
-      visitIdentifier: function(path) {
-        assert.ok(path instanceof NodePath);
-        path.value.name = "bar";
-        return false;
-      }
-    });
-
-    n.Identifier.assert(bar);
-    assert.strictEqual(bar.name, "bar");
-  });
-
-  it("should complain about missing this.traverse", function() {
-    try {
-      types.visit(objProp, {
-        visitIdentifier: function(path) {
-          // buh?
-        }
-      });
-
-      assert.ok(false, "should have thrown an exception");
-
-    } catch (err) {
-      assert.strictEqual(
-        err.message,
-        "Must either call this.traverse or return false in visitIdentifier"
-      );
-    }
-  });
-
-  it("should support this.traverse", function() {
-    var idNames = [];
-
-    types.visit(objProp, {
-      visitMemberExpression: function(path) {
-        this.traverse(path, {
-          visitIdentifier: function(path) {
-            idNames.push("*" + path.value.name + "*");
-            return false;
-          }
-        });
-
-        path.get("object", "name").replace("asdfasdf");
-        path.get("property", "name").replace("zxcvzxcv");
-
-        this.visit(path.get("property"));
-      },
-
-      visitIdentifier: function(path) {
-        idNames.push(path.value.name);
-        return false;
-      }
-    });
-
-    assert.deepEqual(idNames, ["*object*", "*property*", "zxcvzxcv"]);
-
-    idNames.length = 0;
-
-    types.visit(objProp, {
-      visitMemberExpression: function(path) {
-        path.get("object", "name").replace("asdfasdf");
-        path.get("property", "name").replace("zxcvzxcv");
-        this.traverse(path, {
-          visitIdentifier: function(path) {
-            idNames.push(path.value.name);
-            return false;
-          }
-        });
-      }
-    });
-
-    assert.deepEqual(idNames, ["asdfasdf", "zxcvzxcv"]);
-  });
-
-  it("should support this.replace", function() {
-    var seqExpr = b.sequenceExpression([
-      b.literal("asdf"),
-      b.identifier("zxcv"),
-      b.thisExpression()
-    ]);
-
-    types.visit(seqExpr, {
-      visitIdentifier: function(path) {
-        assert.strictEqual(path.value.name, "zxcv");
-        path.replace(
-          b.identifier("foo"),
-          b.identifier("bar")
-        );
-        return false;
-      }
-    });
-
-    assert.strictEqual(seqExpr.expressions.length, 4);
-
-    var foo = seqExpr.expressions[1];
-    n.Identifier.assert(foo);
-    assert.strictEqual(foo.name, "foo");
-
-    var bar = seqExpr.expressions[2];
-    n.Identifier.assert(bar);
-    assert.strictEqual(bar.name, "bar");
-
-    types.visit(seqExpr, {
-      visitIdentifier: function(path) {
-        if (path.value.name === "foo") {
-          path.replace(path.value, path.value);
-        }
-
-        return false;
-      }
-    });
-
-    assert.strictEqual(seqExpr.expressions.length, 5);
-
-    var foo = seqExpr.expressions[1];
-    n.Identifier.assert(foo);
-    assert.strictEqual(foo.name, "foo");
-
-    var foo = seqExpr.expressions[2];
-    n.Identifier.assert(foo);
-    assert.strictEqual(foo.name, "foo");
-
-    var bar = seqExpr.expressions[3];
-    n.Identifier.assert(bar);
-    assert.strictEqual(bar.name, "bar");
-
-    types.visit(seqExpr, {
-      visitLiteral: function(path) {
-        path.replace();
-        return false;
-      },
-
-      visitIdentifier: function(path) {
-        if (path.value.name === "bar") {
-          path.replace();
-        }
-
-        return false;
-      }
-    });
-
-    assert.strictEqual(seqExpr.expressions.length, 3);
-
-    var first = seqExpr.expressions[0];
-    n.Identifier.assert(first);
-    assert.strictEqual(first.name, "foo");
-
-    var second = seqExpr.expressions[1];
-    assert.strictEqual(second, first);
-
-    var third = seqExpr.expressions[2];
-    n.ThisExpression.assert(third);
-  });
-
-  it("should reuse old VisitorContext objects", function() {
-    var objectContext;
-    var propertyContext;
-
-    types.visit(objProp, {
-      visitIdentifier: function(path) {
-        assert.strictEqual(this.needToCallTraverse, true);
-        this.traverse(path);
-        assert.strictEqual(path.name, path.value.name);
-        if (path.name === "object") {
-          objectContext = this;
-        } else if (path.name === "property") {
-          propertyContext = this;
-        }
-      }
-    });
-
-    assert.ok(objectContext);
-    assert.ok(propertyContext);
-    assert.strictEqual(objectContext, propertyContext);
-  });
-
-  it("should dispatch to closest visitSupertype method", function() {
-    var foo = b.identifier("foo");
-    var bar = b.identifier("bar");
-    var callExpr = b.callExpression(
-      b.memberExpression(
-        b.functionExpression(
-          b.identifier("add"),
-          [foo, bar],
-          b.blockStatement([
-            b.returnStatement(
-              b.binaryExpression("+", foo, bar)
-            )
-          ])
-        ),
-        b.identifier("bind"),
-        false
-      ),
-      [b.thisExpression()]
-    );
-
-    var nodes = [];
-    var expressions = [];
-    var identifiers = [];
-    var statements = [];
-    var returnStatements = [];
-    var functions = [];
-
-    function makeVisitorMethod(array) {
-      return function(path) {
-        array.push(path.value);
-        this.traverse(path);
-      };
-    }
-
-    types.visit(callExpr, {
-      visitNode:            makeVisitorMethod(nodes),
-      visitExpression:      makeVisitorMethod(expressions),
-      visitIdentifier:      makeVisitorMethod(identifiers),
-      visitStatement:       makeVisitorMethod(statements),
-      visitReturnStatement: makeVisitorMethod(returnStatements),
-      visitFunction:        makeVisitorMethod(functions)
-    });
-
-    function check(array) {
-      var rest = Array.prototype.slice.call(arguments, 1);
-      assert.strictEqual(array.length, rest.length);
-      for (var i = 0; i < rest.length; ++i) {
-        assert.strictEqual(array[i], rest[i]);
-      }
-    }
-
-    check(nodes);
-
-    check(expressions,
-          callExpr,
-          callExpr.callee,
-          callExpr.callee.object.body.body[0].argument,
-          callExpr.arguments[0]);
-
-    check(identifiers,
-          callExpr.callee.object.id,
-          foo,
-          bar,
-          foo,
-          bar,
-          callExpr.callee.property);
-
-    check(statements,
-          callExpr.callee.object.body);
-
-    check(returnStatements,
-          callExpr.callee.object.body.body[0]);
-
-    check(functions,
-          callExpr.callee.object);
-  });
-
-  it("should replace this.currentPath with returned value", function() {
-    assert.strictEqual(objProp.computed, false);
-
-    types.visit(objProp, {
-      visitIdentifier: function(path) {
-        if (path.value.name === "property") {
-          path.parent.get("computed").replace(true);
-          return b.callExpression(
-            b.memberExpression(
-              b.thisExpression(),
-              b.identifier("toString"),
-              false
-            ),
-            []
-          );
-        }
-
-        this.traverse(path);
-      },
-
-      visitThisExpression: function(path) {
-        return b.identifier("self");
-      }
-    });
-
-    assert.strictEqual(objProp.computed, true);
-    n.CallExpression.assert(objProp.property);
-
-    var callee = objProp.property.callee;
-    n.MemberExpression.assert(callee);
-
-    n.Identifier.assert(callee.object);
-    assert.strictEqual(callee.object.name, "self");
-
-    n.Identifier.assert(callee.property);
-    assert.strictEqual(callee.property.name, "toString");
-
-    assert.deepEqual(objProp.property.arguments, []);
-  });
-});
-
-describe("path.shift", function() {
-  it("should work like Array.prototype.shift", function() {
-    var path = new NodePath({
-      elements: [0, "foo", true]
-    });
-
-    var first = path.get("elements", 0);
-    assert.strictEqual(first.name, 0);
-
-    var second = path.get("elements", 1);
-    assert.strictEqual(second.name, 1);
-
-    var third = path.get("elements", 2);
-    assert.strictEqual(third.name, 2);
-
-    assert.strictEqual(path.get("elements", "length").value, 3);
-
-    assert.strictEqual(path.get("elements").shift(), first.value);
-    assert.strictEqual(path.get("elements", "length").value, 2);
-    assert.strictEqual(path.get("elements", 0), second);
-    assert.strictEqual(path.get("elements", 1), third);
-    assert.strictEqual(second.name, 0);
-    assert.strictEqual(third.name, 1);
-
-    assert.strictEqual(path.get("elements").shift(), second.value);
-    assert.strictEqual(path.get("elements", "length").value, 1);
-    assert.strictEqual(path.get("elements", 0), third);
-    assert.strictEqual(third.name, 0);
-
-    assert.strictEqual(path.get("elements").shift(), third.value);
-    assert.strictEqual(path.get("elements").shift(), void 0);
-    assert.strictEqual(path.get("elements", "length").value, 0);
-  });
-
-  it("should throw when path.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").shift();
-    });
-  });
-});
-
-describe("path.unshift", function() {
-  it("should work like Array.prototype.unshift", function() {
-    var path = new NodePath(b.sequenceExpression([]));
-    var elems = path.get("expressions");
-
-    var one = b.literal(1);
-    var two = b.literal(2);
-    var three = b.literal(3);
-    var four = b.literal(4);
-    var five = b.literal(5);
-
-    assert.strictEqual(elems.get(1).parentPath, elems);
-    assert.strictEqual(elems.get(1).node, path.value);
-    assert.strictEqual(elems.get(1).parent, null);
-
-    assert.strictEqual(elems.get("length").value, 0);
-    elems.unshift(three, four, five);
-    assert.deepEqual(path.value.expressions, [three, four, five]);
-    var fourPath = elems.get(1);
-    assert.strictEqual(fourPath.value.value, 4);
-    elems.unshift(one, two);
-    assert.deepEqual(elems.value, [one, two, three, four, five]);
-    elems.unshift();
-    assert.deepEqual(elems.value, [one, two, three, four, five]);
-    assert.strictEqual(fourPath.name, 3);
-    assert.strictEqual(elems.get("length").value, 5);
-
-    assert.strictEqual(elems.get(1).parentPath, elems);
-    assert.strictEqual(elems.get(1).node, two);
-    assert.strictEqual(elems.get(1).parent, path);
-  });
-
-  it("should throw when path.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").unshift();
-    });
-  });
-});
-
-describe("path.push", function() {
-  it("should work like Array.prototype.push", function() {
-    var path = new NodePath({ elements: [0] });
-    var elems = path.get("elements");
-    assert.strictEqual(elems.get("length").value, 1);
-    elems.push(1, 2, 3);
-    assert.deepEqual(path.value.elements, [0, 1, 2, 3]);
-    var two = elems.get(2);
-    assert.strictEqual(two.value, 2);
-    elems.push(4, 5);
-    assert.deepEqual(elems.value, [0, 1, 2, 3, 4, 5]);
-    elems.push();
-    assert.deepEqual(elems.value, [0, 1, 2, 3, 4, 5]);
-    assert.strictEqual(two.name, 2);
-    assert.strictEqual(elems.get("length").value, 6);
-  });
-
-  it("should throw when path.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").push("asdf");
-    });
-  });
-});
-
-describe("path.pop", function() {
-  it("should work like Array.prototype.pop", function() {
-    var path = new NodePath({
-      elements: [0, "foo", true]
-    });
-
-    var first = path.get("elements", 0);
-    assert.strictEqual(first.name, 0);
-
-    var second = path.get("elements", 1);
-    assert.strictEqual(second.name, 1);
-
-    var third = path.get("elements", 2);
-    assert.strictEqual(third.name, 2);
-
-    assert.strictEqual(path.get("elements", "length").value, 3);
-
-    assert.strictEqual(path.get("elements").pop(), third.value);
-    assert.strictEqual(path.get("elements", "length").value, 2);
-    assert.strictEqual(path.get("elements", 0), first);
-    assert.strictEqual(path.get("elements", 1), second);
-    assert.strictEqual(first.name, 0);
-    assert.strictEqual(second.name, 1);
-
-    assert.strictEqual(path.get("elements").pop(), second.value);
-    assert.strictEqual(path.get("elements", "length").value, 1);
-    assert.strictEqual(path.get("elements", 0), first);
-    assert.strictEqual(first.name, 0);
-
-    assert.strictEqual(path.get("elements").pop(), first.value);
-    assert.strictEqual(path.get("elements").pop(), void 0);
-    assert.strictEqual(path.get("elements", "length").value, 0);
-  });
-
-  it("should throw when path.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").pop();
-    });
-  });
-});
-
-describe("path.insertAt", function() {
-  it("should insert nodes at the given index", function() {
-    var path = new NodePath({
-      elements: [0, "foo", true]
-    });
-
-    var elems = path.get("elements");
-    elems.insertAt(1, "a", "b");
-    assert.deepEqual(elems.value, [0, "a", "b", "foo", true]);
-
-    elems.insertAt(elems.get("length").value + 1, []);
-    assert.deepEqual(elems.value, [0, "a", "b", "foo", true,, []]);
-    assert.strictEqual(elems.get("length").value, 7);
-
-    elems.insertAt(elems.get("length").value + 12345);
-    assert.deepEqual(elems.value, [0, "a", "b", "foo", true,, []]);
-    assert.strictEqual(elems.get("length").value, 7);
-
-    elems.insertAt(-2, -2, -1);
-    assert.deepEqual(elems.value, [-2, -1, 0, "a", "b", "foo", true,, []]);
-    assert.strictEqual(elems.get("length").value, 9);
-  });
-
-  it("should throw when path.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").insertAt(0);
-    });
-  });
-});
-
-describe("path.insertBefore", function() {
-  it("should insert nodes before the current path", function() {
-    var zero = b.literal(0);
-    var one = b.literal(1);
-    var two = b.literal(2);
-    var foo = b.literal("foo");
-    var truth = b.literal(true);
-
-    var path = new NodePath(b.sequenceExpression([zero, foo, truth]));
-    var fooPath = path.get("expressions", 1);
-    var truePath = path.get("expressions", 2);
-    fooPath.insertBefore(one, two);
-    assert.deepEqual(
-      fooPath.parent.node.expressions,
-      [zero, one, two, foo, truth]
-    );
-
-    assert.strictEqual(path.get("expressions", 3), fooPath);
-    assert.strictEqual(fooPath.value.value, "foo");
-
-    assert.strictEqual(path.get("expressions", 4), truePath);
-    assert.strictEqual(truePath.value.value, true);
-  });
-
-  it("should throw when path.parentPath.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").insertBefore(0);
-    });
-  });
-});
-
-describe("path.insertAfter", function() {
-  it("should insert nodes after the current path", function() {
-    var zero = b.literal(0);
-    var one = b.literal(1);
-    var two = b.literal(2);
-    var foo = b.literal("foo");
-    var truth = b.literal(true);
-
-    var path = new NodePath(b.sequenceExpression([zero, foo, truth]));
-    var fooPath = path.get("expressions", 1);
-    var truePath = path.get("expressions", 2);
-    fooPath.insertAfter(one, two);
-    assert.deepEqual(
-      fooPath.parent.node.expressions,
-      [zero, foo, one, two, truth]
-    );
-
-    assert.strictEqual(path.get("expressions", 1), fooPath);
-    assert.strictEqual(fooPath.value.value, "foo");
-
-    assert.strictEqual(path.get("expressions", 2).value.value, 1);
-    assert.strictEqual(path.get("expressions", 3).value.value, 2);
-
-    assert.strictEqual(path.get("expressions", 4), truePath);
-    assert.strictEqual(truePath.value.value, true);
-
-    var three = b.literal(3)
-    truePath.insertAfter(three);
-    assert.deepEqual(
-      fooPath.parent.node.expressions,
-      [zero, foo, one, two, truth, three]
-    );
-  });
-
-  it("should throw when path.parentPath.value not an array", function() {
-    assert.throws(function() {
-      new NodePath({ foo: 42 }).get("foo").insertAfter(0);
-    });
-  });
-});
-
-describe("types.astNodesAreEquivalent", function() {
-  it("should work for simple values", function() {
-    types.astNodesAreEquivalent.assert(1, 2 - 1);
-    types.astNodesAreEquivalent.assert("1", 1);
-    types.astNodesAreEquivalent.assert(true, !false);
-
-    var d1 = new Date;
-    var d2 = new Date(+d1);
-    assert.notStrictEqual(d1, d2);
-    types.astNodesAreEquivalent.assert(d1, d2);
-
-    types.astNodesAreEquivalent.assert(/x/, /x/);
-    assert.strictEqual(types.astNodesAreEquivalent(/x/g, /x/), false);
-  });
-
-  it("should work for arrays", function() {
-    types.astNodesAreEquivalent.assert([], [1, 2, 3].slice(10));
-    types.astNodesAreEquivalent.assert([1, 2, 3], [1].concat(2, [3]));
-    types.astNodesAreEquivalent.assert([1,, 3], [1,, 3,]);
-    assert.strictEqual(
-      types.astNodesAreEquivalent([1,, 3], [1, void 0, 3]),
-      false
-    );
-  });
-
-  it("should work for objects", function() {
-    types.astNodesAreEquivalent.assert({
-      foo: 42,
-      bar: "asdf"
-    }, {
-      bar: "asdf",
-      foo: 42
-    });
-
-    assert.strictEqual(types.astNodesAreEquivalent({
-      foo: 42,
-      bar: "asdf",
-      baz: true
-    }, {
-      bar: "asdf",
-      foo: 42
-    }), false);
-
-    assert.strictEqual(types.astNodesAreEquivalent({
-      foo: 42,
-      bar: "asdf"
-    }, {
-      bar: "asdf",
-      foo: 42,
-      baz: true
-    }), false);
-  });
-
-  it("should work for AST nodes", function() {
-    function check(src1, src2) {
-      types.astNodesAreEquivalent.assert(parse(src1), parse(src2));
-    }
-
-    function checkNot(src1, src2) {
-      var ast1 = parse(src1, { loc: true, range: true });
-      var ast2 = parse(src2, { loc: true });
-
-      assert.throws(function() {
-        types.astNodesAreEquivalent.assert(ast1, ast2);
-      });
-
-      var problemPath = [];
-      types.astNodesAreEquivalent(parse(src1), parse(src2), problemPath);
-      assert.notStrictEqual(problemPath.length, 0);
-
-      var a = ast1;
-      var b = ast2;
-
-      problemPath.forEach(function(name) {
-        assert.strictEqual(name in a, true);
-        assert.strictEqual(name in b, true);
-        a = a[name];
-        b = b[name];
-      });
-
-      assert.notStrictEqual(a, b);
-    }
-
-    check("1\n;", "1;");
-
-    check("console.log(this.toString(36));", [
-      "// leading comment",
-      "console.log(",
-      "  this.toString(36)",
-      "/* trailing comment */)"
-    ].join("\n"));
-
-    check("foo()", "foo /*anonymous*/ ()");
-
-    check("new (bar(1,2)(3,4)).baz.call(null)",
-          "new(  bar(     1,2)  \n  (3,4)).  baz.call(   null)");
-
-    check([
-      "(function(x) {",
-      "  Foo = /asdf/.test(x);",
-      "}());"
-    ].join("\n"), [
-      "(function(x) {",
-      "  Foo = /asdf/.test(x);",
-      "})();"
-    ].join("\n\n"));
-
-    checkNot([
-      "(function(x) {",
-      "  Foo = /asdf/.test(x);",
-      "}());"
-    ].join("\n"), [
-      "(function(x) {",
-      "  Foo = /asdf/.test(x);",
-      "})('~asdf~');"
-    ].join("\n\n"));
-
-    checkNot([
-      "(function(x) {",
-      "  var Foo = /asdf/.test(x);",
-      "}());"
-    ].join("\n"), [
-      "(function(x) {",
-      "  Foo = /asdf/.test(x);",
-      "})(/*'~asdf~'*/);"
-    ].join("\n\n"));
-  });
-});
-
-describe("RegExpLiteral nodes", function() {
-  it("should have a default-computable .regex field", function() {
-    var ast = parse('/x*/gmi.test("xxx")');
-    var regExp = ast.body[0].expression.callee.object;
-
-    n.Literal.assert(regExp);
-    isRegExp.assert(regExp.value);
-
-    var regex = types.getFieldValue(regExp, "regex");
-
-    regex.flags = regex.flags.split("").sort().join("");
-
-    assert.deepEqual(regex, {
-      pattern: "x*",
-      flags: "gim"
-    });
-
-    types.Type.fromObject({
-      pattern: isString,
-      flags: isString
-    }).assert(regex);
-  });
-
-  it("should typecheck with explicit .regex field", function() {
-    var stringLiteral = b.literal("asdf");
-    assert.strictEqual(stringLiteral.regex, null);
-    n.Literal.assert(stringLiteral, true);
-
-    var regExpLiteral = b.literal(/a.b/gi);
-    assert.strictEqual(regExpLiteral.regex.pattern, "a.b");
-    assert.strictEqual(regExpLiteral.regex.flags, "ig");
-    n.Literal.assert(regExpLiteral, true);
-
-    regExpLiteral.regex.pattern = 1234;
-    assert.strictEqual(n.Literal.check(regExpLiteral, true), false);
-  });
-});
-
-describe("BigIntLiteral nodes", function () {
-  it("should parse correctly with Babylon", function () {
-    var types = require('../fork')([
-      require("../def/babel"),
-    ]);
-    var n = types.namedTypes;
-    var BigIntLiteral = n.BigIntLiteral;
-    var parse = require("babylon").parse;
-    var parseOptions = {
-      plugins: ["bigInt"]
-    };
-
-    function check(code) {
-      parseAndCheck(code);
-      parseAndCheck("-" + code);
-      parseAndCheck("+" + code);
-    }
-
-    function parseAndCheck(code) {
-      var file = parse(code, parseOptions);
-      var exp = file.program.body[0].expression;
-      if (n.UnaryExpression.check(exp)) {
-        checkExp(exp.argument);
-      } else {
-        checkExp(exp);
-      }
-    }
-
-    function checkExp(exp) {
-      BigIntLiteral.assert(exp, true);
-
-      assert.strictEqual(
-        exp.extra.rawValue,
-        exp.value
-      );
-
-      assert.strictEqual(
-        exp.extra.raw,
-        exp.value + "n"
-      );
-
-      delete exp.extra;
-
-      BigIntLiteral.assert(exp, true);
-
-      var extra = types.getFieldValue(exp, "extra");
-
-      assert.strictEqual(
-        extra.rawValue,
-        exp.value
-      );
-
-      assert.strictEqual(
-        extra.raw,
-        exp.value + "n"
-      );
-    }
-
-    check("0n");
-    check("12345n");
-    check("0b101011101n");
-    check("0xFFF123n");
-    check("0xfff123n");
-    check("728374682736419273912879879610912837401293846n");
-    check("0xc00cda0a30d6312b54c55789befdea84f5949d92n");
-    check("0o16432n");
-  });
-});
-
-describe("MemberExpression", function() {
-  it("should set computed flag to false by default", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.identifier('bar')
-    )
-
-    assert.strictEqual(memberExpression.computed, false)
-  });
-
-  it("should not set computed to true if property is a callExpression", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.callExpression(b.identifier('bar'), [])
-    )
-
-    assert.strictEqual(memberExpression.computed, false)
-  });
-
-  it("should set computed flag to true if property is a literal", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.literal('bar')
-    )
-
-    assert.strictEqual(memberExpression.computed, true)
-  });
-
-  it("should set computed flag to true if property is a memberExpression", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.memberExpression(b.identifier('foo'), b.literal('bar'))
-    )
-
-    assert.strictEqual(memberExpression.computed, true)
-  });
-
-  it("should set computed flag to true if property is a binaryExpression", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.memberExpression(b.identifier('foo'), b.literal('bar'))
-    )
-
-    assert.strictEqual(memberExpression.computed, true)
-  });
-
-  it("should override computed value when passed as a third argument to the builder", function(){
-    var memberExpression = b.memberExpression(
-      b.identifier('foo'),
-      b.callExpression(b.identifier('bar'), []),
-      true
-    )
-
-    assert.strictEqual(memberExpression.computed, true);
-  });
-});
+require("./ecmascript.js");
+require("./typescript.js");
+require("./flow.js");
diff --git a/test/run.sh b/test/run.sh
new file mode 100755
index 0000000..80f8e84
--- /dev/null
+++ b/test/run.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+set -ex
+
+cd $(dirname $0)/data
+
+if [ ! -d babylon-typescript-fixtures ]
+then
+    git clone --depth 1 https://github.com/babel/babel.git
+    mv babel/packages/babylon/test/fixtures/typescript \
+       babylon-typescript-fixtures
+    rm -rf babel
+fi
+
+if [ ! -d typescript-compiler ]
+then
+    git clone --depth 1 https://github.com/Microsoft/TypeScript.git
+    mv TypeScript/src/compiler typescript-compiler
+    rm -rf TypeScript
+fi
+
+cd .. # back to the ast-types/test/ directory
+
+exec mocha --reporter spec --full-trace $@ run.js
diff --git a/test/shared.js b/test/shared.js
new file mode 100644
index 0000000..4a57535
--- /dev/null
+++ b/test/shared.js
@@ -0,0 +1,46 @@
+"use strict";
+
+var types = require("../main");
+var n = types.namedTypes;
+var path = require("path");
+var fs = require("fs");
+
+exports.esprimaParse = require("esprima").parse;
+
+exports.validateECMAScript = function (file) {
+  var fullPath = path.join(__dirname, "..", file);
+
+  it("should validate " + file + " with Esprima", function (done) {
+    fs.readFile(fullPath, "utf8", function(err, code) {
+      if (err) {
+        throw err;
+      }
+
+      n.Program.assert(exports.esprimaParse(code), true);
+      n.Program.assert(exports.esprimaParse(code, {
+        loc: true
+      }), true);
+
+      done();
+    });
+  });
+
+  it("should validate " + file + " with Babylon", function (done) {
+    fs.readFile(fullPath, "utf8", function (err, code) {
+      if (err) {
+        throw err;
+      }
+      var ast = babylonParse(code);
+      n.Program.assert(ast, true);
+      done();
+    });
+  });
+};
+
+var reifyBabylonParse = require("reify/lib/parsers/babylon.js").parse;
+function babylonParse(source) {
+  var ast = reifyBabylonParse(source);
+  if (ast.type === "File") ast = ast.program;
+  return ast;
+}
+exports.babylonParse = babylonParse;
diff --git a/test/typescript.js b/test/typescript.js
new file mode 100644
index 0000000..0029c30
--- /dev/null
+++ b/test/typescript.js
@@ -0,0 +1,143 @@
+var assert = require("assert");
+var fs = require("fs");
+var path = require("path");
+var shared = require("./shared.js");
+var pkgRootDir = path.resolve(__dirname, "..");
+var tsTypes = require("../fork.js")([
+  require("../def/typescript"),
+  require("../def/jsx"),
+]);
+
+var babylonTSFixturesDir =
+  path.resolve(__dirname, "data", "babylon-typescript-fixtures");
+
+require("glob")("**/input.js", {
+  cwd: babylonTSFixturesDir,
+}, (error, files) => {
+  if (error) {
+    throw error;
+  }
+
+  describe("Whole-program validation for Babylon TypeScript tests", function () {
+    if (error) {
+      throw error;
+    }
+
+    files.forEach(tsPath => {
+      var fullPath = path.join(babylonTSFixturesDir, tsPath);
+
+      it("should validate " + path.relative(pkgRootDir, fullPath), function (done) {
+        fs.readFile(fullPath, "utf8", function (error, code) {
+          if (error) {
+            throw error;
+          }
+          var program = tryParse(code, fullPath);
+          if (program !== null) {
+            tsTypes.namedTypes.Program.assert(program, true);
+          }
+          done();
+        });
+      });
+    });
+  });
+
+  function tryParse(code, fullPath) {
+    var parseOptions = getOptions(fullPath);
+
+    try {
+      return require("babylon").parse(code, parseOptions).program;
+
+    } catch (error) {
+      // If parsing fails, check options.json to see if the failure was
+      // expected.
+      try {
+        var options = JSON.parse(fs.readFileSync(
+          path.join(path.dirname(fullPath), "options.json")));
+      } catch (optionsError) {
+        console.error(optionsError.message);
+      }
+
+      if (options &&
+          options.throws === error.message) {
+        return null;
+      }
+
+      throw error;
+    }
+  }
+
+  function getOptions(fullPath) {
+    var plugins = getPlugins(path.dirname(fullPath));
+    return {
+      sourceType: "module",
+      plugins,
+    };
+  }
+
+  function getPlugins(dir) {
+    try {
+      var options = JSON.parse(fs.readFileSync(
+        path.join(dir, "options.json")
+      ));
+    } catch (ignored) {
+      options = {};
+    }
+
+    if (options.plugins) {
+      return options.plugins;
+    }
+
+    if (dir !== babylonTSFixturesDir) {
+      return getPlugins(path.dirname(dir));
+    }
+
+    return [
+      "typescript",
+    ];
+  }
+});
+
+var tsCompilerDir =
+  path.resolve( __dirname, "data", "typescript-compiler");
+
+require("glob")("**/*.ts", {
+  cwd: tsCompilerDir,
+}, (error, files) => {
+  if (error) {
+    throw error;
+  }
+
+  describe("Whole-program validation for TypeScript codebase", function () {
+    if (error) {
+      throw error;
+    }
+
+    this.timeout(20000);
+
+    files.forEach(tsPath => {
+      var fullPath = path.join(tsCompilerDir, tsPath);
+
+      it("should validate " + path.relative(pkgRootDir, fullPath), function (done) {
+        fs.readFile(fullPath, "utf8", function (error, code) {
+          if (error) {
+            throw error;
+          }
+
+          var program = require("babylon").parse(code, {
+            sourceType: "module",
+            plugins: [
+              "typescript",
+              "objectRestSpread",
+              "classProperties",
+              "optionalCatchBinding",
+            ]
+          }).program;
+
+          tsTypes.namedTypes.Program.assert(program, true);
+
+          done();
+        });
+      });
+    });
+  });
+});

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



More information about the Pkg-javascript-commits mailing list